Merge with rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
authorSteve French <sfrench@hera.kernel.org>
Fri, 1 Jul 2005 03:57:39 +0000 (20:57 -0700)
committerSteve French <sfrench@hera.kernel.org>
Fri, 1 Jul 2005 03:57:39 +0000 (20:57 -0700)
1834 files changed:
Documentation/00-INDEX
Documentation/Changes
Documentation/DocBook/Makefile
Documentation/DocBook/kernel-api.tmpl
Documentation/DocBook/libata.tmpl
Documentation/DocBook/stylesheet.xsl
Documentation/IPMI.txt
Documentation/SubmittingDrivers
Documentation/SubmittingPatches
Documentation/basic_profiling.txt
Documentation/block/ioprio.txt [new file with mode: 0644]
Documentation/cciss.txt
Documentation/cdrom/sbpcd
Documentation/cpu-freq/governors.txt
Documentation/cpusets.txt
Documentation/devices.txt
Documentation/dvb/README.dibusb [deleted file]
Documentation/dvb/README.dvb-usb [new file with mode: 0644]
Documentation/dvb/bt8xx.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/ext2.txt
Documentation/filesystems/xip.txt [new file with mode: 0644]
Documentation/kdump/gdbmacros.txt [new file with mode: 0644]
Documentation/kdump/kdump.txt [new file with mode: 0644]
Documentation/kernel-parameters.txt
Documentation/keys.txt
Documentation/networking/00-INDEX
Documentation/networking/dmfe.txt
Documentation/networking/wanpipe.txt [deleted file]
Documentation/pcmcia/devicetable.txt [new file with mode: 0644]
Documentation/pcmcia/driver-changes.txt [new file with mode: 0644]
Documentation/power/kernel_threads.txt
Documentation/power/pci.txt
Documentation/power/swsusp.txt
Documentation/power/video.txt
Documentation/power/video_extension.txt
Documentation/s390/s390dbf.txt
Documentation/serial/driver
Documentation/sysrq.txt
Documentation/video4linux/API.html
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.cx88 [new file with mode: 0644]
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/README.saa7134
Documentation/video4linux/hauppauge-wintv-cx88-ir.txt [new file with mode: 0644]
Documentation/video4linux/lifeview.txt [new file with mode: 0644]
Documentation/video4linux/not-in-cx2388x-datasheet.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/arm/Kconfig
arch/arm/configs/enp2611_defconfig
arch/arm/configs/ixdp2400_defconfig
arch/arm/configs/ixdp2401_defconfig
arch/arm/configs/ixdp2800_defconfig
arch/arm/configs/ixdp2801_defconfig
arch/arm/kernel/armksyms.c
arch/arm/kernel/irq.c
arch/arm/kernel/process.c
arch/arm/kernel/setup.c
arch/arm/kernel/signal.c
arch/arm/kernel/smp.c
arch/arm/kernel/time.c
arch/arm/lib/Makefile
arch/arm/lib/longlong.h [deleted file]
arch/arm/lib/udivdi3.c [deleted file]
arch/arm/mach-aaec2000/Makefile.boot [new file with mode: 0644]
arch/arm/mach-aaec2000/core.c
arch/arm/mach-clps711x/Kconfig
arch/arm/mach-clps711x/time.c
arch/arm/mach-clps7500/core.c
arch/arm/mach-ebsa110/core.c
arch/arm/mach-epxa10db/time.c
arch/arm/mach-footbridge/dc21285-timer.c
arch/arm/mach-footbridge/isa-timer.c
arch/arm/mach-h720x/cpu-h7201.c
arch/arm/mach-h720x/cpu-h7202.c
arch/arm/mach-imx/time.c
arch/arm/mach-integrator/core.c
arch/arm/mach-iop3xx/iop321-time.c
arch/arm/mach-iop3xx/iop331-time.c
arch/arm/mach-ixp2000/Kconfig
arch/arm/mach-ixp2000/core.c
arch/arm/mach-ixp2000/enp2611.c
arch/arm/mach-ixp2000/ixdp2800.c
arch/arm/mach-ixp2000/ixdp2x00.c
arch/arm/mach-ixp2000/pci.c
arch/arm/mach-ixp4xx/common.c
arch/arm/mach-lh7a40x/time.c
arch/arm/mach-omap/pm.c
arch/arm/mach-omap/time.c
arch/arm/mach-omap/usb.c
arch/arm/mach-pxa/time.c
arch/arm/mach-s3c2410/Kconfig
arch/arm/mach-s3c2410/Makefile
arch/arm/mach-s3c2410/devs.c
arch/arm/mach-s3c2410/irq.c
arch/arm/mach-s3c2410/mach-bast.c
arch/arm/mach-s3c2410/mach-vr1000.c
arch/arm/mach-s3c2410/pm-simtec.c [new file with mode: 0644]
arch/arm/mach-s3c2410/time.c
arch/arm/mach-sa1100/h3600.c
arch/arm/mach-sa1100/time.c
arch/arm/mach-shark/core.c
arch/arm/mach-versatile/core.c
arch/arm/mm/init.c
arch/arm/mm/mm-armv.c
arch/arm/mm/proc-v6.S
arch/arm/oprofile/Makefile
arch/arm/oprofile/backtrace.c [new file with mode: 0644]
arch/arm/oprofile/init.c
arch/arm/oprofile/op_arm_model.h
arch/arm/tools/mach-types
arch/arm/vfp/vfp.h
arch/arm/vfp/vfpdouble.c
arch/arm/vfp/vfpmodule.c
arch/arm/vfp/vfpsingle.c
arch/frv/kernel/setup.c
arch/frv/kernel/signal.c
arch/h8300/kernel/signal.c
arch/i386/Kconfig
arch/i386/boot/Makefile
arch/i386/boot/compressed/head.S
arch/i386/boot/compressed/misc.c
arch/i386/boot/edd.S
arch/i386/boot/setup.S
arch/i386/boot/tools/build.c
arch/i386/crypto/aes.c
arch/i386/defconfig
arch/i386/kernel/Makefile
arch/i386/kernel/acpi/boot.c
arch/i386/kernel/acpi/sleep.c
arch/i386/kernel/apic.c
arch/i386/kernel/apm.c
arch/i386/kernel/cpu/common.c
arch/i386/kernel/cpu/cpufreq/powernow-k7.c
arch/i386/kernel/cpu/intel.c
arch/i386/kernel/cpu/intel_cacheinfo.c
arch/i386/kernel/cpu/mcheck/k7.c
arch/i386/kernel/cpu/mcheck/mce.c
arch/i386/kernel/cpu/mcheck/p4.c
arch/i386/kernel/cpu/mcheck/p5.c
arch/i386/kernel/cpu/mcheck/p6.c
arch/i386/kernel/cpu/mcheck/winchip.c
arch/i386/kernel/cpu/mtrr/generic.c
arch/i386/kernel/crash.c [new file with mode: 0644]
arch/i386/kernel/dmi_scan.c
arch/i386/kernel/efi.c
arch/i386/kernel/head.S
arch/i386/kernel/i8259.c
arch/i386/kernel/io_apic.c
arch/i386/kernel/irq.c
arch/i386/kernel/kprobes.c
arch/i386/kernel/machine_kexec.c [new file with mode: 0644]
arch/i386/kernel/mpparse.c
arch/i386/kernel/process.c
arch/i386/kernel/reboot.c
arch/i386/kernel/relocate_kernel.S [new file with mode: 0644]
arch/i386/kernel/setup.c
arch/i386/kernel/signal.c
arch/i386/kernel/smp.c
arch/i386/kernel/smpboot.c
arch/i386/kernel/syscall_table.S
arch/i386/kernel/sysenter.c
arch/i386/kernel/time.c
arch/i386/kernel/time_hpet.c
arch/i386/kernel/timers/common.c
arch/i386/kernel/timers/timer_cyclone.c
arch/i386/kernel/timers/timer_pit.c
arch/i386/kernel/timers/timer_tsc.c
arch/i386/kernel/traps.c
arch/i386/kernel/vmlinux.lds.S
arch/i386/mach-default/setup.c
arch/i386/mach-default/topology.c
arch/i386/mach-visws/mpparse.c
arch/i386/mach-voyager/voyager_basic.c
arch/i386/mm/discontig.c
arch/i386/mm/fault.c
arch/i386/mm/highmem.c
arch/i386/mm/init.c
arch/i386/mm/ioremap.c
arch/i386/mm/pgtable.c
arch/i386/pci/common.c
arch/i386/pci/irq.c
arch/i386/pci/legacy.c
arch/i386/pci/mmconfig.c
arch/i386/pci/numa.c
arch/i386/pci/pci.h
arch/i386/power/cpu.c
arch/ia64/configs/sn2_defconfig
arch/ia64/configs/tiger_defconfig
arch/ia64/configs/zx1_defconfig
arch/ia64/hp/common/sba_iommu.c
arch/ia64/hp/sim/simserial.c
arch/ia64/kernel/acpi.c
arch/ia64/kernel/domain.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/fsys.S
arch/ia64/kernel/gate.S
arch/ia64/kernel/ia64_ksyms.c
arch/ia64/kernel/iosapic.c
arch/ia64/kernel/ivt.S
arch/ia64/kernel/kprobes.c
arch/ia64/kernel/process.c
arch/ia64/kernel/ptrace.c
arch/ia64/kernel/setup.c
arch/ia64/kernel/smp.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/vmlinux.lds.S
arch/ia64/pci/pci.c
arch/ia64/sn/kernel/io_init.c
arch/ia64/sn/kernel/iomv.c
arch/ia64/sn/kernel/setup.c
arch/ia64/sn/kernel/sn2/ptc_deadlock.S
arch/ia64/sn/kernel/tiocx.c
arch/ia64/sn/kernel/xpc.h
arch/ia64/sn/kernel/xpc_channel.c
arch/ia64/sn/kernel/xpc_partition.c
arch/ia64/sn/pci/tioca_provider.c
arch/m32r/kernel/signal.c
arch/mips/Kconfig
arch/mips/kernel/setup.c
arch/mips/kernel/signal.c
arch/mips/mm/init.c
arch/mips/mm/pgtable.c
arch/parisc/configs/712_defconfig
arch/parisc/configs/a500_defconfig
arch/parisc/configs/b180_defconfig
arch/parisc/configs/c3000_defconfig
arch/parisc/defconfig
arch/ppc/Kconfig
arch/ppc/Kconfig.debug
arch/ppc/Makefile
arch/ppc/boot/openfirmware/chrpmain.c
arch/ppc/kernel/Makefile
arch/ppc/kernel/cputable.c
arch/ppc/kernel/entry.S
arch/ppc/kernel/head_booke.h
arch/ppc/kernel/head_fsl_booke.S
arch/ppc/kernel/machine_kexec.c [new file with mode: 0644]
arch/ppc/kernel/misc.S
arch/ppc/kernel/pci.c
arch/ppc/kernel/perfmon.c
arch/ppc/kernel/relocate_kernel.S [new file with mode: 0644]
arch/ppc/kernel/signal.c
arch/ppc/kernel/traps.c
arch/ppc/mm/44x_mmu.c
arch/ppc/mm/4xx_mmu.c
arch/ppc/mm/fsl_booke_mmu.c
arch/ppc/mm/init.c
arch/ppc/platforms/83xx/mpc834x_sys.c
arch/ppc/platforms/85xx/mpc8540_ads.c
arch/ppc/platforms/85xx/mpc8560_ads.c
arch/ppc/platforms/85xx/sbc8560.c
arch/ppc/platforms/85xx/stx_gp3.c
arch/ppc/platforms/chrp_pci.c
arch/ppc/platforms/katana.c
arch/ppc/platforms/pmac_pci.c
arch/ppc/platforms/pmac_sleep.S
arch/ppc/platforms/pmac_time.c
arch/ppc/platforms/sandpoint.c
arch/ppc/syslib/cpm2_common.c
arch/ppc/syslib/indirect_pci.c
arch/ppc/syslib/ipic.c
arch/ppc/syslib/mv64x60.c
arch/ppc/syslib/mv64x60_win.c
arch/ppc/syslib/open_pic.c
arch/ppc64/Kconfig
arch/ppc64/boot/Makefile
arch/ppc64/boot/main.c
arch/ppc64/boot/mknote.c [deleted file]
arch/ppc64/boot/piggyback.c [deleted file]
arch/ppc64/boot/prom.c
arch/ppc64/kernel/ItLpQueue.c
arch/ppc64/kernel/LparData.c
arch/ppc64/kernel/Makefile
arch/ppc64/kernel/head.S
arch/ppc64/kernel/iSeries_proc.c
arch/ppc64/kernel/iSeries_setup.c
arch/ppc64/kernel/idle.c
arch/ppc64/kernel/irq.c
arch/ppc64/kernel/kprobes.c
arch/ppc64/kernel/lparcfg.c
arch/ppc64/kernel/machine_kexec.c [new file with mode: 0644]
arch/ppc64/kernel/mf.c
arch/ppc64/kernel/misc.S
arch/ppc64/kernel/mpic.c
arch/ppc64/kernel/mpic.h
arch/ppc64/kernel/nvram.c
arch/ppc64/kernel/pSeries_setup.c
arch/ppc64/kernel/pSeries_smp.c
arch/ppc64/kernel/pacaData.c
arch/ppc64/kernel/pci.c
arch/ppc64/kernel/ppc_ksyms.c
arch/ppc64/kernel/process.c
arch/ppc64/kernel/ptrace.c
arch/ppc64/kernel/setup.c
arch/ppc64/kernel/sysfs.c
arch/ppc64/kernel/time.c
arch/ppc64/kernel/xics.c
arch/ppc64/mm/hash_native.c
arch/s390/Kconfig
arch/s390/defconfig
arch/s390/kernel/Makefile
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/cpcmd.c
arch/s390/kernel/crash.c [new file with mode: 0644]
arch/s390/kernel/debug.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/machine_kexec.c [new file with mode: 0644]
arch/s390/kernel/process.c
arch/s390/kernel/relocate_kernel.S [new file with mode: 0644]
arch/s390/kernel/relocate_kernel64.S [new file with mode: 0644]
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/syscalls.S
arch/s390/kernel/traps.c
arch/s390/mm/extmem.c
arch/sparc/Kconfig
arch/sparc64/kernel/auxio.c
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/semaphore.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/trampoline.S
arch/sparc64/lib/U1memcpy.S
arch/sparc64/lib/VISsave.S
arch/sparc64/lib/atomic.S
arch/sparc64/lib/bitops.S
arch/sparc64/lib/debuglocks.c
arch/sparc64/lib/dec_and_lock.S
arch/sparc64/lib/rwsem.S
arch/sparc64/mm/init.c
arch/sparc64/mm/ultra.S
arch/um/drivers/daemon_user.c
arch/um/drivers/line.c
arch/um/drivers/mconsole_kern.c
arch/um/drivers/net_kern.c
arch/um/drivers/ssl.c
arch/um/drivers/stdio_console.c
arch/um/drivers/ubd_kern.c
arch/um/include/line.h
arch/um/include/mconsole_kern.h
arch/um/include/time_user.h
arch/um/kernel/main.c
arch/um/kernel/process_kern.c
arch/um/kernel/reboot.c
arch/um/kernel/skas/Makefile
arch/um/kernel/skas/include/mode-skas.h
arch/um/kernel/skas/process_kern.c
arch/um/kernel/skas/time.c [deleted file]
arch/um/kernel/syscall_kern.c
arch/um/kernel/time.c
arch/um/kernel/time_kern.c
arch/um/kernel/tt/Makefile
arch/um/kernel/tt/gdb.c
arch/um/kernel/tt/gdb_kern.c
arch/um/kernel/tt/include/debug.h
arch/um/kernel/tt/include/mode-tt.h
arch/um/kernel/tt/process_kern.c
arch/um/kernel/tt/time.c [deleted file]
arch/um/sys-i386/signal.c
arch/um/sys-i386/syscalls.c
arch/um/sys-x86_64/syscalls.c
arch/x86_64/Kconfig
arch/x86_64/Makefile
arch/x86_64/boot/compressed/head.S
arch/x86_64/boot/compressed/misc.c
arch/x86_64/boot/install.sh
arch/x86_64/boot/setup.S
arch/x86_64/boot/tools/build.c
arch/x86_64/ia32/ia32entry.S
arch/x86_64/kernel/Makefile
arch/x86_64/kernel/acpi/wakeup.S
arch/x86_64/kernel/apic.c
arch/x86_64/kernel/crash.c [new file with mode: 0644]
arch/x86_64/kernel/e820.c
arch/x86_64/kernel/genapic_flat.c
arch/x86_64/kernel/head.S
arch/x86_64/kernel/i387.c
arch/x86_64/kernel/i8259.c
arch/x86_64/kernel/io_apic.c
arch/x86_64/kernel/irq.c
arch/x86_64/kernel/kprobes.c
arch/x86_64/kernel/machine_kexec.c [new file with mode: 0644]
arch/x86_64/kernel/mce.c
arch/x86_64/kernel/mce_intel.c
arch/x86_64/kernel/nmi.c
arch/x86_64/kernel/process.c
arch/x86_64/kernel/reboot.c
arch/x86_64/kernel/relocate_kernel.S [new file with mode: 0644]
arch/x86_64/kernel/setup.c
arch/x86_64/kernel/setup64.c
arch/x86_64/kernel/signal.c
arch/x86_64/kernel/smp.c
arch/x86_64/kernel/smpboot.c
arch/x86_64/kernel/suspend.c
arch/x86_64/kernel/traps.c
arch/x86_64/kernel/vmlinux.lds.S
arch/x86_64/mm/numa.c
arch/x86_64/pci/mmconfig.c
arch/xtensa/Kconfig [new file with mode: 0644]
arch/xtensa/Kconfig.debug [new file with mode: 0644]
arch/xtensa/Makefile [new file with mode: 0644]
arch/xtensa/boot/Makefile [new file with mode: 0644]
arch/xtensa/boot/boot-elf/Makefile [new file with mode: 0644]
arch/xtensa/boot/boot-elf/boot.ld [new file with mode: 0644]
arch/xtensa/boot/boot-elf/bootstrap.S [new file with mode: 0644]
arch/xtensa/boot/boot-redboot/Makefile [new file with mode: 0644]
arch/xtensa/boot/boot-redboot/boot.ld [new file with mode: 0644]
arch/xtensa/boot/boot-redboot/bootstrap.S [new file with mode: 0644]
arch/xtensa/boot/lib/Makefile [new file with mode: 0644]
arch/xtensa/boot/lib/zmem.c [new file with mode: 0644]
arch/xtensa/boot/ramdisk/Makefile [new file with mode: 0644]
arch/xtensa/configs/common_defconfig [new file with mode: 0644]
arch/xtensa/configs/iss_defconfig [new file with mode: 0644]
arch/xtensa/kernel/Makefile [new file with mode: 0644]
arch/xtensa/kernel/align.S [new file with mode: 0644]
arch/xtensa/kernel/asm-offsets.c [new file with mode: 0644]
arch/xtensa/kernel/coprocessor.S [new file with mode: 0644]
arch/xtensa/kernel/entry.S [new file with mode: 0644]
arch/xtensa/kernel/head.S [new file with mode: 0644]
arch/xtensa/kernel/irq.c [new file with mode: 0644]
arch/xtensa/kernel/module.c [new file with mode: 0644]
arch/xtensa/kernel/pci-dma.c [new file with mode: 0644]
arch/xtensa/kernel/pci.c [new file with mode: 0644]
arch/xtensa/kernel/platform.c [new file with mode: 0644]
arch/xtensa/kernel/process.c [new file with mode: 0644]
arch/xtensa/kernel/ptrace.c [new file with mode: 0644]
arch/xtensa/kernel/semaphore.c [new file with mode: 0644]
arch/xtensa/kernel/setup.c [new file with mode: 0644]
arch/xtensa/kernel/signal.c [new file with mode: 0644]
arch/xtensa/kernel/syscalls.c [new file with mode: 0644]
arch/xtensa/kernel/syscalls.h [new file with mode: 0644]
arch/xtensa/kernel/time.c [new file with mode: 0644]
arch/xtensa/kernel/traps.c [new file with mode: 0644]
arch/xtensa/kernel/vectors.S [new file with mode: 0644]
arch/xtensa/kernel/vmlinux.lds.S [new file with mode: 0644]
arch/xtensa/kernel/xtensa_ksyms.c [new file with mode: 0644]
arch/xtensa/lib/Makefile [new file with mode: 0644]
arch/xtensa/lib/checksum.S [new file with mode: 0644]
arch/xtensa/lib/memcopy.S [new file with mode: 0644]
arch/xtensa/lib/memset.S [new file with mode: 0644]
arch/xtensa/lib/pci-auto.c [new file with mode: 0644]
arch/xtensa/lib/strcasecmp.c [new file with mode: 0644]
arch/xtensa/lib/strncpy_user.S [new file with mode: 0644]
arch/xtensa/lib/strnlen_user.S [new file with mode: 0644]
arch/xtensa/lib/usercopy.S [new file with mode: 0644]
arch/xtensa/mm/Makefile [new file with mode: 0644]
arch/xtensa/mm/fault.c [new file with mode: 0644]
arch/xtensa/mm/init.c [new file with mode: 0644]
arch/xtensa/mm/misc.S [new file with mode: 0644]
arch/xtensa/mm/pgtable.c [new file with mode: 0644]
arch/xtensa/mm/tlb.c [new file with mode: 0644]
arch/xtensa/platform-iss/Makefile [new file with mode: 0644]
arch/xtensa/platform-iss/console.c [new file with mode: 0644]
arch/xtensa/platform-iss/io.c [new file with mode: 0644]
arch/xtensa/platform-iss/network.c [new file with mode: 0644]
arch/xtensa/platform-iss/setup.c [new file with mode: 0644]
drivers/acpi/Kconfig
drivers/acpi/container.c
drivers/acpi/pci_bind.c
drivers/acpi/pci_irq.c
drivers/acpi/pci_root.c
drivers/acpi/processor_core.c
drivers/acpi/scan.c
drivers/base/base.h
drivers/base/bus.c
drivers/base/core.c
drivers/base/cpu.c
drivers/base/dd.c
drivers/base/driver.c
drivers/base/firmware_class.c
drivers/block/as-iosched.c
drivers/block/cciss.c
drivers/block/cfq-iosched.c
drivers/block/deadline-iosched.c
drivers/block/elevator.c
drivers/block/ll_rw_blk.c
drivers/block/pktcdvd.c
drivers/block/swim3.c
drivers/block/sx8.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/dtl1_cs.c
drivers/cdrom/cm206.c
drivers/cdrom/sonycd535.c
drivers/char/Kconfig
drivers/char/agp/amd64-agp.c
drivers/char/amiserial.c
drivers/char/applicom.c
drivers/char/drm/Kconfig
drivers/char/drm/Makefile
drivers/char/drm/drmP.h
drivers/char/drm/drm_bufs.c
drivers/char/drm/drm_context.c
drivers/char/drm/drm_ioc32.c [new file with mode: 0644]
drivers/char/drm/i915_dma.c
drivers/char/drm/i915_drm.h
drivers/char/drm/i915_drv.c
drivers/char/drm/i915_drv.h
drivers/char/drm/i915_irq.c
drivers/char/drm/i915_mem.c
drivers/char/drm/radeon_drv.c
drivers/char/drm/radeon_drv.h
drivers/char/drm/radeon_ioc32.c [new file with mode: 0644]
drivers/char/drm/radeon_irq.c
drivers/char/ds1620.c
drivers/char/ftape/compressor/zftape-compress.c
drivers/char/hpet.c
drivers/char/i8k.c
drivers/char/ip2/i2cmd.c
drivers/char/ip2/i2cmd.h
drivers/char/ip2main.c
drivers/char/ipmi/ipmi_devintf.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_poweroff.c
drivers/char/isicom.c
drivers/char/istallion.c
drivers/char/mem.c
drivers/char/misc.c
drivers/char/moxa.c
drivers/char/mwave/3780i.c
drivers/char/mwave/3780i.h
drivers/char/mwave/tp3780i.c
drivers/char/nvram.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/rio/func.h
drivers/char/rio/rio_linux.c
drivers/char/rio/rioinit.c
drivers/char/rio/riotty.c
drivers/char/rocket.c
drivers/char/rocket_int.h
drivers/char/rtc.c
drivers/char/sysrq.c
drivers/char/tipar.c
drivers/char/toshiba.c
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_atmel.c
drivers/char/tpm/tpm_nsc.c
drivers/char/tty_io.c
drivers/char/tty_ioctl.c
drivers/char/vt_ioctl.c
drivers/char/watchdog/ixp2000_wdt.c
drivers/char/watchdog/ixp4xx_wdt.c
drivers/firmware/efivars.c
drivers/firmware/pcdp.c
drivers/firmware/pcdp.h
drivers/i2c/busses/i2c-ixp2000.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/chips/atxp1.c
drivers/ide/Kconfig
drivers/ide/ide-disk.c
drivers/ide/ide-dma.c
drivers/ide/ide-iops.c
drivers/ide/legacy/hd.c
drivers/ide/legacy/ide-cs.c
drivers/ide/pci/Makefile
drivers/ide/pci/generic.c
drivers/ide/pci/hpt366.c
drivers/ide/pci/it821x.c [new file with mode: 0644]
drivers/ide/pci/serverworks.c
drivers/ide/ppc/pmac.c
drivers/ieee1394/ieee1394_core.c
drivers/ieee1394/nodemgr.c
drivers/ieee1394/ohci1394.c
drivers/infiniband/core/packer.c
drivers/infiniband/core/sa_query.c
drivers/infiniband/hw/mthca/mthca_av.c
drivers/infiniband/hw/mthca/mthca_cmd.c
drivers/infiniband/hw/mthca/mthca_cmd.h
drivers/infiniband/hw/mthca/mthca_cq.c
drivers/infiniband/hw/mthca/mthca_dev.h
drivers/infiniband/hw/mthca/mthca_doorbell.h
drivers/infiniband/hw/mthca/mthca_eq.c
drivers/infiniband/hw/mthca/mthca_main.c
drivers/infiniband/hw/mthca/mthca_mcg.c
drivers/infiniband/hw/mthca/mthca_memfree.c
drivers/infiniband/hw/mthca/mthca_mr.c
drivers/infiniband/hw/mthca/mthca_provider.c
drivers/infiniband/hw/mthca/mthca_provider.h
drivers/infiniband/hw/mthca/mthca_qp.c
drivers/input/evdev.c
drivers/input/gameport/Kconfig
drivers/input/gameport/Makefile
drivers/input/gameport/cs461x.c [deleted file]
drivers/input/gameport/gameport.c
drivers/input/gameport/ns558.c
drivers/input/gameport/vortex.c [deleted file]
drivers/input/input.c
drivers/input/joydev.c
drivers/input/joystick/a3d.c
drivers/input/joystick/adi.c
drivers/input/joystick/amijoy.c
drivers/input/joystick/analog.c
drivers/input/joystick/db9.c
drivers/input/joystick/gamecon.c
drivers/input/joystick/gf2k.c
drivers/input/joystick/grip_mp.c
drivers/input/joystick/iforce/iforce-main.c
drivers/input/joystick/iforce/iforce-usb.c
drivers/input/joystick/spaceball.c
drivers/input/joystick/spaceorb.c
drivers/input/joystick/tmdc.c
drivers/input/joystick/turbografx.c
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/corgikbd.c
drivers/input/keyboard/lkkbd.c
drivers/input/keyboard/locomokbd.c
drivers/input/keyboard/maple_keyb.c
drivers/input/misc/uinput.c
drivers/input/mouse/Makefile
drivers/input/mouse/alps.c
drivers/input/mouse/amimouse.c
drivers/input/mouse/inport.c
drivers/input/mouse/lifebook.c [new file with mode: 0644]
drivers/input/mouse/lifebook.h [new file with mode: 0644]
drivers/input/mouse/logibm.c
drivers/input/mouse/maplemouse.c
drivers/input/mouse/pc110pad.c
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/psmouse.h
drivers/input/mouse/rpcmouse.c
drivers/input/mouse/vsxxxaa.c
drivers/input/mousedev.c
drivers/input/serio/i8042.c
drivers/input/serio/libps2.c
drivers/input/serio/serio.c
drivers/input/touchscreen/elo.c
drivers/input/touchscreen/h3600_ts_input.c
drivers/input/touchscreen/mk712.c
drivers/isdn/act2000/capi.c
drivers/isdn/act2000/capi.h
drivers/isdn/hardware/avm/avm_cs.c
drivers/isdn/hardware/avm/b1dma.c
drivers/isdn/hardware/avm/c4.c
drivers/isdn/hardware/avm/t1isa.c
drivers/isdn/hardware/eicon/dadapter.c
drivers/isdn/hisax/Makefile
drivers/isdn/hisax/amd7930_fn.c
drivers/isdn/hisax/asuscom.c
drivers/isdn/hisax/avm_pci.c
drivers/isdn/hisax/avma1_cs.c
drivers/isdn/hisax/bkm_a4t.c
drivers/isdn/hisax/bkm_a8.c
drivers/isdn/hisax/callc.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/diva.c
drivers/isdn/hisax/elsa.c
drivers/isdn/hisax/elsa_cs.c
drivers/isdn/hisax/elsa_ser.c
drivers/isdn/hisax/enternow.h [deleted file]
drivers/isdn/hisax/enternow_pci.c
drivers/isdn/hisax/gazel.c
drivers/isdn/hisax/hfc4s8s_l1.c
drivers/isdn/hisax/hfc_2bds0.c
drivers/isdn/hisax/hfc_2bs0.c
drivers/isdn/hisax/hfc_pci.c
drivers/isdn/hisax/hfc_pci.h
drivers/isdn/hisax/hfc_sx.c
drivers/isdn/hisax/hfc_sx.h
drivers/isdn/hisax/hfc_usb.c
drivers/isdn/hisax/hfc_usb.h
drivers/isdn/hisax/hfcscard.c
drivers/isdn/hisax/hisax.h
drivers/isdn/hisax/hscx.c
drivers/isdn/hisax/icc.c
drivers/isdn/hisax/ipacx.c
drivers/isdn/hisax/isac.c
drivers/isdn/hisax/isar.c
drivers/isdn/hisax/isdnl1.c
drivers/isdn/hisax/isdnl2.c
drivers/isdn/hisax/isdnl3.c
drivers/isdn/hisax/isurf.c
drivers/isdn/hisax/ix1_micro.c
drivers/isdn/hisax/jade.c
drivers/isdn/hisax/jade.h
drivers/isdn/hisax/l3_1tr6.c
drivers/isdn/hisax/l3dss1.c
drivers/isdn/hisax/l3ni1.c
drivers/isdn/hisax/mic.c
drivers/isdn/hisax/netjet.c
drivers/isdn/hisax/niccy.c
drivers/isdn/hisax/nj_s.c
drivers/isdn/hisax/nj_u.c
drivers/isdn/hisax/q931.c
drivers/isdn/hisax/s0box.c
drivers/isdn/hisax/saphir.c
drivers/isdn/hisax/sedlbauer.c
drivers/isdn/hisax/sedlbauer_cs.c
drivers/isdn/hisax/sportster.c
drivers/isdn/hisax/st5481.h
drivers/isdn/hisax/st5481_hdlc.c [deleted file]
drivers/isdn/hisax/st5481_hdlc.h [deleted file]
drivers/isdn/hisax/st5481_usb.c
drivers/isdn/hisax/tei.c
drivers/isdn/hisax/teleint.c
drivers/isdn/hisax/teles0.c
drivers/isdn/hisax/teles3.c
drivers/isdn/hisax/teles_cs.c
drivers/isdn/hisax/telespci.c
drivers/isdn/hisax/w6692.c
drivers/isdn/hysdn/hycapi.c
drivers/isdn/hysdn/hysdn_boot.c
drivers/isdn/hysdn/hysdn_defs.h
drivers/isdn/hysdn/hysdn_init.c
drivers/isdn/hysdn/hysdn_proclog.c
drivers/isdn/i4l/isdn_audio.c
drivers/isdn/i4l/isdn_audio.h
drivers/isdn/i4l/isdn_common.c
drivers/isdn/i4l/isdn_common.h
drivers/isdn/i4l/isdn_concap.c
drivers/isdn/i4l/isdn_concap.h
drivers/isdn/i4l/isdn_net.c
drivers/isdn/i4l/isdn_tty.c
drivers/isdn/i4l/isdn_tty.h
drivers/isdn/i4l/isdn_ttyfax.c
drivers/isdn/i4l/isdn_x25iface.c
drivers/isdn/pcbit/callbacks.c
drivers/isdn/pcbit/callbacks.h
drivers/isdn/pcbit/capi.c
drivers/isdn/pcbit/capi.h
drivers/isdn/pcbit/drv.c
drivers/isdn/sc/Makefile
drivers/isdn/sc/command.c
drivers/isdn/sc/debug.c [deleted file]
drivers/isdn/sc/init.c
drivers/isdn/sc/interrupt.c
drivers/isdn/sc/ioctl.c
drivers/isdn/sc/packet.c
drivers/isdn/sc/shmem.c
drivers/isdn/sc/timer.c
drivers/macintosh/Kconfig
drivers/macintosh/Makefile
drivers/macintosh/adb.c
drivers/macintosh/macserial.c [deleted file]
drivers/macintosh/macserial.h [deleted file]
drivers/macintosh/therm_adt746x.c
drivers/macintosh/via-pmu.c
drivers/mca/mca-legacy.c
drivers/md/md.c
drivers/media/common/ir-common.c
drivers/media/common/saa7146_fops.c
drivers/media/dvb/Kconfig
drivers/media/dvb/Makefile
drivers/media/dvb/b2c2/Kconfig
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/b2c2/flexcop-misc.c
drivers/media/dvb/b2c2/flexcop-reg.h
drivers/media/dvb/dibusb/Kconfig [deleted file]
drivers/media/dvb/dibusb/Makefile [deleted file]
drivers/media/dvb/dibusb/dvb-dibusb-core.c [deleted file]
drivers/media/dvb/dibusb/dvb-dibusb-dvb.c [deleted file]
drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c [deleted file]
drivers/media/dvb/dibusb/dvb-dibusb-firmware.c [deleted file]
drivers/media/dvb/dibusb/dvb-dibusb-remote.c [deleted file]
drivers/media/dvb/dibusb/dvb-dibusb-usb.c [deleted file]
drivers/media/dvb/dibusb/dvb-dibusb.h [deleted file]
drivers/media/dvb/dibusb/dvb-fe-dtt200u.c [deleted file]
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-usb/Kconfig [new file with mode: 0644]
drivers/media/dvb/dvb-usb/Makefile [new file with mode: 0644]
drivers/media/dvb/dvb-usb/a800.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dibusb-common.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dibusb-mb.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dibusb-mc.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dibusb.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/digitv.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/digitv.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dtt200u-fe.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dtt200u.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dtt200u.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dvb-usb-common.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dvb-usb-dvb.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dvb-usb-firmware.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dvb-usb-i2c.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dvb-usb-ids.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dvb-usb-init.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dvb-usb-remote.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dvb-usb-urb.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dvb-usb.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/nova-t-usb2.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/umt-010.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/vp7045-fe.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/vp7045.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/vp7045.h [new file with mode: 0644]
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/bcm3510.c [new file with mode: 0644]
drivers/media/dvb/frontends/bcm3510.h [new file with mode: 0644]
drivers/media/dvb/frontends/bcm3510_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/dib3000-common.c
drivers/media/dvb/frontends/dib3000.h
drivers/media/dvb/frontends/dib3000mb.c
drivers/media/dvb/frontends/dib3000mb_priv.h
drivers/media/dvb/frontends/dib3000mc.c
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/dvb-pll.h
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/bt832.c
drivers/media/video/bt832.h
drivers/media/video/bttv-cards.c
drivers/media/video/bttv-driver.c
drivers/media/video/bttv-i2c.c
drivers/media/video/bttv.h
drivers/media/video/bttvp.h
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-reg.h
drivers/media/video/cx88/cx88-tvaudio.c
drivers/media/video/cx88/cx88-vbi.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/ir-kbd-gpio.c
drivers/media/video/msp3400.c
drivers/media/video/msp3400.h
drivers/media/video/mt20xx.c
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-oss.c
drivers/media/video/saa7134/saa7134-tvaudio.c
drivers/media/video/saa7134/saa7134-vbi.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/tda8290.c
drivers/media/video/tda9887.c
drivers/media/video/tea5767.c [new file with mode: 0644]
drivers/media/video/tuner-core.c
drivers/media/video/tuner-simple.c
drivers/media/video/tvaudio.c
drivers/media/video/tveeprom.c
drivers/media/video/tvmixer.c
drivers/media/video/v4l1-compat.c
drivers/media/video/video-buf-dvb.c
drivers/message/fusion/mptfc.c
drivers/message/fusion/mptscsih.c
drivers/message/fusion/mptscsih.h
drivers/message/fusion/mptspi.c
drivers/message/i2o/Kconfig
drivers/message/i2o/Makefile
drivers/message/i2o/bus-osm.c [new file with mode: 0644]
drivers/message/i2o/config-osm.c [new file with mode: 0644]
drivers/message/i2o/core.h [new file with mode: 0644]
drivers/message/i2o/debug.c
drivers/message/i2o/device.c
drivers/message/i2o/driver.c
drivers/message/i2o/exec-osm.c
drivers/message/i2o/i2o_block.c
drivers/message/i2o/i2o_block.h
drivers/message/i2o/i2o_config.c
drivers/message/i2o/i2o_proc.c
drivers/message/i2o/i2o_scsi.c
drivers/message/i2o/iop.c
drivers/message/i2o/pci.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/pcmciamtd.c
drivers/net/3c503.c
drivers/net/3c505.c
drivers/net/3c509.c
drivers/net/3c515.c
drivers/net/3c523.c
drivers/net/3c59x.c
drivers/net/8139cp.c
drivers/net/8139too.c
drivers/net/82596.c
drivers/net/Kconfig
drivers/net/ac3200.c
drivers/net/acenic.c
drivers/net/amd8111e.c
drivers/net/arm/etherh.c
drivers/net/at1700.c
drivers/net/b44.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bonding.h
drivers/net/cs89x0.c
drivers/net/cs89x0.h
drivers/net/defxx.c
drivers/net/dl2k.c
drivers/net/dm9000.c
drivers/net/e100.c
drivers/net/e1000/e1000.h
drivers/net/e1000/e1000_ethtool.c
drivers/net/e1000/e1000_hw.c
drivers/net/e1000/e1000_hw.h
drivers/net/e1000/e1000_main.c
drivers/net/e2100.c
drivers/net/eepro.c
drivers/net/eepro100.c
drivers/net/eexpress.c
drivers/net/epic100.c
drivers/net/es3210.c
drivers/net/eth16i.c
drivers/net/ewrk3.c
drivers/net/fealnx.c
drivers/net/forcedeth.c
drivers/net/gianfar.c
drivers/net/gianfar.h
drivers/net/gianfar_ethtool.c
drivers/net/gianfar_phy.c
drivers/net/hamachi.c
drivers/net/hp-plus.c
drivers/net/hp.c
drivers/net/hp100.c
drivers/net/irda/sir_kthread.c
drivers/net/irda/stir4200.c
drivers/net/isa-skeleton.c
drivers/net/ixgb/ixgb_main.c
drivers/net/lance.c
drivers/net/lasi_82596.c
drivers/net/lne390.c
drivers/net/myri_code.h
drivers/net/natsemi.c
drivers/net/ne-h8300.c
drivers/net/ne.c
drivers/net/ne2.c
drivers/net/ns83820.c
drivers/net/pcmcia/3c574_cs.c
drivers/net/pcmcia/3c589_cs.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/com20020_cs.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/pcmcia/ibmtr_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/pcnet32.c
drivers/net/r8169.c
drivers/net/s2io.c
drivers/net/sb1000.c
drivers/net/sb1250-mac.c
drivers/net/sis900.c
drivers/net/sk98lin/skge.c
drivers/net/skfp/Makefile
drivers/net/skfp/drvfbi.c
drivers/net/skfp/ess.c
drivers/net/skfp/fplustm.c
drivers/net/skfp/h/cmtdef.h
drivers/net/skfp/h/hwmtm.h
drivers/net/skfp/h/osdef1st.h
drivers/net/skfp/hwmtm.c
drivers/net/skfp/lnkstat.c [deleted file]
drivers/net/skfp/pcmplc.c
drivers/net/skfp/pmf.c
drivers/net/skfp/skfddi.c
drivers/net/skfp/smt.c
drivers/net/skfp/smtdef.c
drivers/net/skfp/smtparse.c [deleted file]
drivers/net/skge.c
drivers/net/skge.h
drivers/net/slip.c
drivers/net/smc-mca.c
drivers/net/smc-mca.h [deleted file]
drivers/net/smc-ultra.c
drivers/net/smc91x.c
drivers/net/smc91x.h
drivers/net/starfire.c
drivers/net/sundance.c
drivers/net/sungem.c
drivers/net/tg3.c
drivers/net/tg3.h
drivers/net/tlan.c
drivers/net/tokenring/3c359.c
drivers/net/tokenring/3c359_microcode.h
drivers/net/tokenring/abyss.c
drivers/net/tokenring/ibmtr.c
drivers/net/tokenring/lanstreamer.c
drivers/net/tokenring/madgemc.c
drivers/net/tokenring/proteon.c
drivers/net/tokenring/skisa.c
drivers/net/tokenring/smctr.c
drivers/net/tokenring/smctr_firmware.h
drivers/net/tokenring/tms380tr.c
drivers/net/tokenring/tmspci.c
drivers/net/tulip/de2104x.c
drivers/net/tulip/dmfe.c
drivers/net/tulip/eeprom.c
drivers/net/tulip/interrupt.c
drivers/net/tulip/media.c
drivers/net/tulip/tulip_core.c
drivers/net/tulip/winbond-840.c
drivers/net/tulip/xircom_tulip_cb.c
drivers/net/typhoon.c
drivers/net/via-rhine.c
drivers/net/via-velocity.c
drivers/net/wan/Kconfig
drivers/net/wan/farsync.c
drivers/net/wan/hdlc_cisco.c
drivers/net/wan/wanxl.c
drivers/net/wd.c
drivers/net/wireless/airo.c
drivers/net/wireless/airo_cs.c
drivers/net/wireless/arlan-main.c
drivers/net/wireless/atmel_cs.c
drivers/net/wireless/netwave_cs.c
drivers/net/wireless/orinoco.c
drivers/net/wireless/orinoco.h
drivers/net/wireless/orinoco_cs.c
drivers/net/wireless/prism54/isl_38xx.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/wavelan_cs.c
drivers/net/wireless/wl3501_cs.c
drivers/net/yellowfin.c
drivers/oprofile/buffer_sync.c
drivers/oprofile/event_buffer.h
drivers/parisc/dino.c
drivers/parisc/lba_pci.c
drivers/parport/parport_cs.c
drivers/pci/bus.c
drivers/pci/hotplug/Makefile
drivers/pci/hotplug/acpiphp.h
drivers/pci/hotplug/acpiphp_core.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/acpiphp_pci.c [deleted file]
drivers/pci/hotplug/acpiphp_res.c [deleted file]
drivers/pci/hotplug/cpqphp_core.c
drivers/pci/msi.c
drivers/pci/msi.h
drivers/pci/pci-sysfs.c
drivers/pci/probe.c
drivers/pci/proc.c
drivers/pci/remove.c
drivers/pci/setup-bus.c
drivers/pcmcia/Kconfig
drivers/pcmcia/Makefile
drivers/pcmcia/cistpl.c
drivers/pcmcia/cs.c
drivers/pcmcia/cs_internal.h
drivers/pcmcia/ds.c
drivers/pcmcia/ds_internal.h [new file with mode: 0644]
drivers/pcmcia/i82365.c
drivers/pcmcia/pcmcia_compat.c
drivers/pcmcia/pcmcia_ioctl.c [new file with mode: 0644]
drivers/pcmcia/pcmcia_resource.c [new file with mode: 0644]
drivers/pcmcia/rsrc_mgr.c
drivers/pcmcia/rsrc_nonstatic.c
drivers/pcmcia/socket_sysfs.c
drivers/pcmcia/yenta_socket.c
drivers/pnp/card.c
drivers/pnp/manager.c
drivers/pnp/pnpbios/core.c
drivers/s390/Kconfig
drivers/s390/block/dasd.c
drivers/s390/block/dasd_proc.c
drivers/s390/block/dcssblk.c
drivers/s390/char/Makefile
drivers/s390/char/con3215.c
drivers/s390/char/con3270.c
drivers/s390/char/tape_34xx.c
drivers/s390/char/tape_core.c
drivers/s390/char/tape_proc.c
drivers/s390/char/vmcp.c [new file with mode: 0644]
drivers/s390/char/vmcp.h [new file with mode: 0644]
drivers/s390/char/vmlogrdr.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/cio.c
drivers/s390/cio/css.c
drivers/s390/cio/device.c
drivers/s390/cio/qdio.c
drivers/s390/cio/qdio.h
drivers/s390/net/claw.c
drivers/s390/net/ctcdbug.c
drivers/s390/net/ctcdbug.h
drivers/s390/net/iucv.h
drivers/s390/net/lcs.c
drivers/s390/net/netiucv.c
drivers/s390/net/qeth.h
drivers/s390/net/qeth_main.c
drivers/s390/net/smsgiucv.c
drivers/s390/s390mach.c
drivers/s390/s390mach.h
drivers/scsi/3w-9xxx.c
drivers/scsi/3w-xxxx.c
drivers/scsi/ahci.c
drivers/scsi/dpt_i2o.c
drivers/scsi/dpti.h
drivers/scsi/hosts.c
drivers/scsi/initio.c
drivers/scsi/initio.h
drivers/scsi/ipr.c
drivers/scsi/libata-core.c
drivers/scsi/libata-scsi.c
drivers/scsi/megaraid.c
drivers/scsi/pcmcia/aha152x_stub.c
drivers/scsi/pcmcia/fdomain_stub.c
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/pcmcia/qlogic_stub.c
drivers/scsi/pcmcia/sym53c500_cs.c
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_sysfs.c
drivers/serial/68328serial.c
drivers/serial/68360serial.c
drivers/serial/8250.c
drivers/serial/8250_accent.c [new file with mode: 0644]
drivers/serial/8250_boca.c [new file with mode: 0644]
drivers/serial/8250_fourport.c [new file with mode: 0644]
drivers/serial/8250_hub6.c [new file with mode: 0644]
drivers/serial/8250_mca.c [new file with mode: 0644]
drivers/serial/Kconfig
drivers/serial/Makefile
drivers/serial/au1x00_uart.c
drivers/serial/icom.h
drivers/serial/ip22zilog.c
drivers/serial/m32r_sio.c
drivers/serial/mpsc.c
drivers/serial/pmac_zilog.c
drivers/serial/pxa.c
drivers/serial/serial_core.c
drivers/serial/serial_cs.c
drivers/serial/serial_txx9.c
drivers/serial/sunsab.c
drivers/serial/sunsu.c
drivers/serial/sunzilog.c
drivers/telephony/ixj.c
drivers/telephony/ixj_pcmcia.c
drivers/usb/Makefile
drivers/usb/atm/Kconfig
drivers/usb/atm/Makefile
drivers/usb/atm/cxacru.c [new file with mode: 0644]
drivers/usb/atm/speedtch.c
drivers/usb/atm/usb_atm.c [deleted file]
drivers/usb/atm/usb_atm.h [deleted file]
drivers/usb/atm/usbatm.c [new file with mode: 0644]
drivers/usb/atm/usbatm.h [new file with mode: 0644]
drivers/usb/atm/xusbatm.c [new file with mode: 0644]
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-acm.h
drivers/usb/class/usblp.c
drivers/usb/core/devio.c
drivers/usb/core/hcd.c
drivers/usb/core/hcd.h
drivers/usb/core/hub.c
drivers/usb/core/hub.h
drivers/usb/gadget/Kconfig
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/ndis.h
drivers/usb/gadget/net2280.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/omap_udc.h
drivers/usb/gadget/pxa2xx_udc.c
drivers/usb/gadget/pxa2xx_udc.h
drivers/usb/gadget/rndis.c
drivers/usb/gadget/rndis.h
drivers/usb/gadget/serial.c
drivers/usb/gadget/zero.c
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/ehci-dbg.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/isp116x-hcd.c [new file with mode: 0644]
drivers/usb/host/isp116x.h [new file with mode: 0644]
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-mem.c
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-pci.c
drivers/usb/host/ohci.h
drivers/usb/host/sl811-hcd.c
drivers/usb/host/sl811_cs.c
drivers/usb/host/uhci-debug.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-hcd.h
drivers/usb/host/uhci-hub.c
drivers/usb/host/uhci-q.c
drivers/usb/input/Kconfig
drivers/usb/input/Makefile
drivers/usb/input/acecad.c [new file with mode: 0644]
drivers/usb/input/aiptek.c
drivers/usb/input/ati_remote.c
drivers/usb/input/hid-core.c
drivers/usb/input/hid-debug.h
drivers/usb/input/hid-input.c
drivers/usb/input/hid-lgff.c
drivers/usb/input/hid.h
drivers/usb/input/hiddev.c
drivers/usb/input/itmtouch.c [new file with mode: 0644]
drivers/usb/input/kbtab.c
drivers/usb/input/mtouchusb.c
drivers/usb/input/powermate.c
drivers/usb/input/touchkitusb.c
drivers/usb/input/usbkbd.c
drivers/usb/input/usbmouse.c
drivers/usb/input/wacom.c
drivers/usb/input/xpad.c
drivers/usb/media/stv680.c
drivers/usb/media/stv680.h
drivers/usb/misc/idmouse.c
drivers/usb/misc/usbtest.c
drivers/usb/net/pegasus.c
drivers/usb/net/pegasus.h
drivers/usb/net/rtl8150.c
drivers/usb/net/usbnet.c
drivers/usb/net/zd1201.c
drivers/usb/net/zd1201.h
drivers/usb/serial/cyberjack.c
drivers/usb/serial/generic.c
drivers/usb/serial/ipaq.c
drivers/usb/serial/ipw.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/omninet.c
drivers/usb/serial/safe_serial.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb-serial.h
drivers/usb/storage/scsiglue.c
drivers/usb/storage/scsiglue.h
drivers/usb/storage/transport.c
drivers/usb/storage/transport.h
drivers/usb/storage/usb.c
drivers/video/aty/aty128fb.c
drivers/video/au1100fb.c
drivers/video/chipsfb.c
drivers/video/console/Kconfig
drivers/video/fbsysfs.c
drivers/video/matrox/matroxfb_misc.c
drivers/video/vesafb.c
drivers/w1/w1.c
fs/Kconfig
fs/Makefile
fs/afs/kafsasyncd.c
fs/afs/kafstimod.c
fs/aio.c
fs/buffer.c
fs/char_dev.c
fs/direct-io.c
fs/dquot.c
fs/ext2/Makefile
fs/ext2/ext2.h
fs/ext2/file.c
fs/ext2/inode.c
fs/ext2/namei.c
fs/ext2/super.c
fs/ext2/xip.c [new file with mode: 0644]
fs/ext2/xip.h [new file with mode: 0644]
fs/ext3/acl.c
fs/ext3/balloc.c
fs/ext3/file.c
fs/ext3/inode.c
fs/ext3/namei.c
fs/ext3/super.c
fs/ext3/xattr.c
fs/fat/inode.c
fs/freevxfs/vxfs.h
fs/freevxfs/vxfs_bmap.c
fs/freevxfs/vxfs_fshead.c
fs/freevxfs/vxfs_kcompat.h [deleted file]
fs/freevxfs/vxfs_lookup.c
fs/freevxfs/vxfs_olt.c
fs/freevxfs/vxfs_subr.c
fs/freevxfs/vxfs_super.c
fs/ioprio.c [new file with mode: 0644]
fs/jbd/journal.c
fs/jffs/intrep.c
fs/jffs/intrep.h
fs/jffs/jffs_fm.c
fs/jffs/jffs_fm.h
fs/jffs2/background.c
fs/jfs/jfs_logmgr.c
fs/jfs/jfs_txnmgr.c
fs/libfs.c
fs/lockd/clntproc.c
fs/lockd/svc.c
fs/namespace.c
fs/ncpfs/dir.c
fs/ncpfs/ncplib_kernel.c
fs/ncpfs/ncplib_kernel.h
fs/nfs/nfs3acl.c
fs/nfsd/Makefile
fs/nfsd/nfs4acl.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4idmap.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4recover.c [new file with mode: 0644]
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfssvc.c
fs/nfsd/vfs.c
fs/open.c
fs/partitions/Makefile
fs/partitions/check.c
fs/partitions/check.h
fs/partitions/msdos.c
fs/proc/Makefile
fs/proc/proc_misc.c
fs/proc/vmcore.c [new file with mode: 0644]
fs/qnx4/dir.c
fs/qnx4/inode.c
fs/reiserfs/file.c
fs/reiserfs/inode.c
fs/reiserfs/ioctl.c
fs/reiserfs/journal.c
fs/reiserfs/namei.c
fs/reiserfs/stree.c
fs/reiserfs/super.c
fs/sysfs/file.c
fs/udf/namei.c
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_super.c
include/acpi/acpi_bus.h
include/acpi/acpi_drivers.h
include/asm-alpha/pci.h
include/asm-alpha/serial.h
include/asm-arm/arch-ixp2000/gpio.h
include/asm-arm/arch-ixp2000/io.h
include/asm-arm/arch-ixp2000/ixdp2x00.h
include/asm-arm/arch-ixp2000/ixdp2x01.h
include/asm-arm/arch-ixp2000/ixp2000-regs.h
include/asm-arm/arch-ixp2000/platform.h
include/asm-arm/arch-ixp2000/vmalloc.h
include/asm-arm/arch-ixp4xx/debug-macro.S
include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
include/asm-arm/arch-omap/usb.h
include/asm-arm/arch-pxa/debug-macro.S
include/asm-arm/arch-s3c2410/audio.h [new file with mode: 0644]
include/asm-arm/hardware/arm_timer.h [new file with mode: 0644]
include/asm-arm/ide.h
include/asm-arm/io.h
include/asm-arm/mach/time.h
include/asm-arm/pci.h
include/asm-arm/signal.h
include/asm-arm/system.h
include/asm-arm/tlbflush.h
include/asm-arm26/serial.h
include/asm-frv/pci.h
include/asm-generic/vmlinux.lds.h
include/asm-i386/apic.h
include/asm-i386/apicdef.h
include/asm-i386/cpu.h
include/asm-i386/highmem.h
include/asm-i386/i8253.h [new file with mode: 0644]
include/asm-i386/ide.h
include/asm-i386/irq.h
include/asm-i386/kdebug.h
include/asm-i386/kexec.h [new file with mode: 0644]
include/asm-i386/mach-default/do_timer.h
include/asm-i386/mach-default/mach_ipi.h
include/asm-i386/page.h
include/asm-i386/pci.h
include/asm-i386/processor.h
include/asm-i386/serial.h
include/asm-i386/smp.h
include/asm-i386/string.h
include/asm-i386/tlbflush.h
include/asm-i386/topology.h
include/asm-i386/unistd.h
include/asm-ia64/iosapic.h
include/asm-ia64/kprobes.h
include/asm-ia64/mmu_context.h
include/asm-ia64/pci.h
include/asm-ia64/sections.h
include/asm-ia64/sn/addrs.h
include/asm-ia64/sn/l1.h
include/asm-ia64/sn/shub_mmr.h
include/asm-ia64/sn/simulator.h
include/asm-ia64/sn/sn2/sn_hwperf.h
include/asm-ia64/sn/sn_sal.h
include/asm-ia64/sn/tioca_provider.h
include/asm-ia64/system.h
include/asm-ia64/topology.h
include/asm-ia64/unistd.h
include/asm-ia64/vga.h
include/asm-m68k/serial.h
include/asm-mips/mmzone.h
include/asm-mips/page.h
include/asm-mips/pci.h
include/asm-mips/pgtable.h
include/asm-mips/serial.h
include/asm-mips/system.h
include/asm-parisc/pci.h
include/asm-parisc/serial.h
include/asm-ppc/fsl_ocp.h [deleted file]
include/asm-ppc/kexec.h [new file with mode: 0644]
include/asm-ppc/machdep.h
include/asm-ppc/mmu.h
include/asm-ppc/mmu_context.h
include/asm-ppc/ocp.h
include/asm-ppc/open_pic.h
include/asm-ppc/pc_serial.h
include/asm-ppc/pci.h
include/asm-ppc/ppc_asm.h
include/asm-ppc/reg.h
include/asm-ppc/reg_booke.h
include/asm-ppc/unistd.h
include/asm-ppc64/byteorder.h
include/asm-ppc64/iSeries/ItLpQueue.h
include/asm-ppc64/kdebug.h
include/asm-ppc64/kexec.h [new file with mode: 0644]
include/asm-ppc64/kprobes.h
include/asm-ppc64/machdep.h
include/asm-ppc64/mmu.h
include/asm-ppc64/paca.h
include/asm-ppc64/pci.h
include/asm-ppc64/xics.h
include/asm-s390/cpcmd.h
include/asm-s390/debug.h
include/asm-s390/kexec.h [new file with mode: 0644]
include/asm-s390/lowcore.h
include/asm-s390/processor.h
include/asm-s390/ptrace.h
include/asm-s390/system.h
include/asm-s390/thread_info.h
include/asm-s390/unistd.h
include/asm-sh/bigsur/serial.h
include/asm-sh/ec3104/serial.h
include/asm-sh/pci.h
include/asm-sh/serial.h
include/asm-sh64/pci.h
include/asm-sh64/serial.h
include/asm-sparc/pci.h
include/asm-sparc/system.h
include/asm-sparc64/auxio.h
include/asm-sparc64/floppy.h
include/asm-sparc64/irq.h
include/asm-sparc64/kdebug.h
include/asm-sparc64/pci.h
include/asm-sparc64/rwsem.h
include/asm-sparc64/spinlock.h
include/asm-sparc64/spitfire.h
include/asm-sparc64/system.h
include/asm-sparc64/termios.h
include/asm-um/ptrace-i386.h
include/asm-v850/pci.h
include/asm-x86_64/apic.h
include/asm-x86_64/apicdef.h
include/asm-x86_64/io_apic.h
include/asm-x86_64/irq.h
include/asm-x86_64/kdebug.h
include/asm-x86_64/kexec.h [new file with mode: 0644]
include/asm-x86_64/page.h
include/asm-x86_64/pci.h
include/asm-x86_64/serial.h
include/asm-x86_64/smp.h
include/asm-x86_64/suspend.h
include/asm-x86_64/tlbflush.h
include/asm-x86_64/topology.h
include/asm-x86_64/unistd.h
include/asm-xtensa/a.out.h [new file with mode: 0644]
include/asm-xtensa/atomic.h [new file with mode: 0644]
include/asm-xtensa/bitops.h [new file with mode: 0644]
include/asm-xtensa/bootparam.h [new file with mode: 0644]
include/asm-xtensa/bug.h [new file with mode: 0644]
include/asm-xtensa/bugs.h [new file with mode: 0644]
include/asm-xtensa/byteorder.h [new file with mode: 0644]
include/asm-xtensa/cache.h [new file with mode: 0644]
include/asm-xtensa/cacheflush.h [new file with mode: 0644]
include/asm-xtensa/checksum.h [new file with mode: 0644]
include/asm-xtensa/coprocessor.h [new file with mode: 0644]
include/asm-xtensa/cpumask.h [new file with mode: 0644]
include/asm-xtensa/cputime.h [new file with mode: 0644]
include/asm-xtensa/current.h [new file with mode: 0644]
include/asm-xtensa/delay.h [new file with mode: 0644]
include/asm-xtensa/div64.h [new file with mode: 0644]
include/asm-xtensa/dma-mapping.h [new file with mode: 0644]
include/asm-xtensa/dma.h [new file with mode: 0644]
include/asm-xtensa/elf.h [new file with mode: 0644]
include/asm-xtensa/errno.h [new file with mode: 0644]
include/asm-xtensa/fcntl.h [new file with mode: 0644]
include/asm-xtensa/fixmap.h [new file with mode: 0644]
include/asm-xtensa/hardirq.h [new file with mode: 0644]
include/asm-xtensa/hdreg.h [new file with mode: 0644]
include/asm-xtensa/highmem.h [new file with mode: 0644]
include/asm-xtensa/hw_irq.h [new file with mode: 0644]
include/asm-xtensa/ide.h [new file with mode: 0644]
include/asm-xtensa/io.h [new file with mode: 0644]
include/asm-xtensa/ioctl.h [new file with mode: 0644]
include/asm-xtensa/ioctls.h [new file with mode: 0644]
include/asm-xtensa/ipc.h [new file with mode: 0644]
include/asm-xtensa/ipcbuf.h [new file with mode: 0644]
include/asm-xtensa/irq.h [new file with mode: 0644]
include/asm-xtensa/kmap_types.h [new file with mode: 0644]
include/asm-xtensa/linkage.h [new file with mode: 0644]
include/asm-xtensa/local.h [new file with mode: 0644]
include/asm-xtensa/mman.h [new file with mode: 0644]
include/asm-xtensa/mmu.h [new file with mode: 0644]
include/asm-xtensa/mmu_context.h [new file with mode: 0644]
include/asm-xtensa/module.h [new file with mode: 0644]
include/asm-xtensa/msgbuf.h [new file with mode: 0644]
include/asm-xtensa/namei.h [new file with mode: 0644]
include/asm-xtensa/page.h [new file with mode: 0644]
include/asm-xtensa/page.h.n [new file with mode: 0644]
include/asm-xtensa/param.h [new file with mode: 0644]
include/asm-xtensa/pci-bridge.h [new file with mode: 0644]
include/asm-xtensa/pci.h [new file with mode: 0644]
include/asm-xtensa/percpu.h [new file with mode: 0644]
include/asm-xtensa/pgalloc.h [new file with mode: 0644]
include/asm-xtensa/pgtable.h [new file with mode: 0644]
include/asm-xtensa/platform-iss/hardware.h [new file with mode: 0644]
include/asm-xtensa/platform.h [new file with mode: 0644]
include/asm-xtensa/poll.h [new file with mode: 0644]
include/asm-xtensa/posix_types.h [new file with mode: 0644]
include/asm-xtensa/processor.h [new file with mode: 0644]
include/asm-xtensa/ptrace.h [new file with mode: 0644]
include/asm-xtensa/resource.h [new file with mode: 0644]
include/asm-xtensa/rmap.h [new file with mode: 0644]
include/asm-xtensa/rwsem.h [new file with mode: 0644]
include/asm-xtensa/scatterlist.h [new file with mode: 0644]
include/asm-xtensa/sections.h [new file with mode: 0644]
include/asm-xtensa/segment.h [new file with mode: 0644]
include/asm-xtensa/semaphore.h [new file with mode: 0644]
include/asm-xtensa/sembuf.h [new file with mode: 0644]
include/asm-xtensa/serial.h [new file with mode: 0644]
include/asm-xtensa/setup.h [new file with mode: 0644]
include/asm-xtensa/shmbuf.h [new file with mode: 0644]
include/asm-xtensa/shmparam.h [new file with mode: 0644]
include/asm-xtensa/sigcontext.h [new file with mode: 0644]
include/asm-xtensa/siginfo.h [new file with mode: 0644]
include/asm-xtensa/signal.h [new file with mode: 0644]
include/asm-xtensa/smp.h [new file with mode: 0644]
include/asm-xtensa/socket.h [new file with mode: 0644]
include/asm-xtensa/sockios.h [new file with mode: 0644]
include/asm-xtensa/spinlock.h [new file with mode: 0644]
include/asm-xtensa/stat.h [new file with mode: 0644]
include/asm-xtensa/statfs.h [new file with mode: 0644]
include/asm-xtensa/string.h [new file with mode: 0644]
include/asm-xtensa/system.h [new file with mode: 0644]
include/asm-xtensa/termbits.h [new file with mode: 0644]
include/asm-xtensa/termios.h [new file with mode: 0644]
include/asm-xtensa/thread_info.h [new file with mode: 0644]
include/asm-xtensa/timex.h [new file with mode: 0644]
include/asm-xtensa/tlb.h [new file with mode: 0644]
include/asm-xtensa/tlbflush.h [new file with mode: 0644]
include/asm-xtensa/topology.h [new file with mode: 0644]
include/asm-xtensa/types.h [new file with mode: 0644]
include/asm-xtensa/uaccess.h [new file with mode: 0644]
include/asm-xtensa/ucontext.h [new file with mode: 0644]
include/asm-xtensa/unaligned.h [new file with mode: 0644]
include/asm-xtensa/unistd.h [new file with mode: 0644]
include/asm-xtensa/user.h [new file with mode: 0644]
include/asm-xtensa/vga.h [new file with mode: 0644]
include/asm-xtensa/xor.h [new file with mode: 0644]
include/asm-xtensa/xtensa/cacheasm.h [new file with mode: 0644]
include/asm-xtensa/xtensa/cacheattrasm.h [new file with mode: 0644]
include/asm-xtensa/xtensa/config-linux_be/core.h [new file with mode: 0644]
include/asm-xtensa/xtensa/config-linux_be/defs.h [new file with mode: 0644]
include/asm-xtensa/xtensa/config-linux_be/specreg.h [new file with mode: 0644]
include/asm-xtensa/xtensa/config-linux_be/system.h [new file with mode: 0644]
include/asm-xtensa/xtensa/config-linux_be/tie.h [new file with mode: 0644]
include/asm-xtensa/xtensa/coreasm.h [new file with mode: 0644]
include/asm-xtensa/xtensa/corebits.h [new file with mode: 0644]
include/asm-xtensa/xtensa/hal.h [new file with mode: 0644]
include/asm-xtensa/xtensa/simcall.h [new file with mode: 0644]
include/asm-xtensa/xtensa/xt2000-uart.h [new file with mode: 0644]
include/asm-xtensa/xtensa/xt2000.h [new file with mode: 0644]
include/asm-xtensa/xtensa/xtboard.h [new file with mode: 0644]
include/linux/a.out.h
include/linux/acpi.h
include/linux/atalk.h
include/linux/bio.h
include/linux/blkdev.h
include/linux/bootmem.h
include/linux/byteorder/swabb.h
include/linux/cciss_ioctl.h
include/linux/cpu.h
include/linux/crash_dump.h [new file with mode: 0644]
include/linux/device.h
include/linux/dmi.h
include/linux/dqblk_v1.h
include/linux/dqblk_v2.h
include/linux/elevator.h
include/linux/etherdevice.h
include/linux/ext2_fs.h
include/linux/ext3_fs.h
include/linux/ext3_jbd.h
include/linux/fs.h
include/linux/highmem.h
include/linux/i2c-dev.h
include/linux/i2o-dev.h
include/linux/i2o.h
include/linux/if_bonding.h
include/linux/in6.h
include/linux/init.h
include/linux/init_task.h
include/linux/input.h
include/linux/ioprio.h [new file with mode: 0644]
include/linux/ipmi.h
include/linux/irq.h
include/linux/joystick.h
include/linux/kernel.h
include/linux/kexec.h [new file with mode: 0644]
include/linux/key-ui.h
include/linux/key.h
include/linux/keyctl.h
include/linux/kmod.h
include/linux/kprobes.h
include/linux/libps2.h
include/linux/list.h
include/linux/mod_devicetable.h
include/linux/module.h
include/linux/namespace.h
include/linux/netdevice.h
include/linux/netlink.h
include/linux/nfs4.h
include/linux/nfsd/nfsd.h
include/linux/nfsd/state.h
include/linux/nfsd/xdr4.h
include/linux/nfsd_idmap.h
include/linux/nvram.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/pkt_cls.h
include/linux/pkt_sched.h
include/linux/pm.h
include/linux/pmu.h
include/linux/proc_fs.h
include/linux/qnx4_fs.h
include/linux/qnxtypes.h
include/linux/quota.h
include/linux/reboot.h
include/linux/reiserfs_fs.h
include/linux/reiserfs_fs_sb.h
include/linux/rmap.h
include/linux/rtnetlink.h
include/linux/sched.h
include/linux/seccomp.h
include/linux/serial_8250.h
include/linux/serio.h
include/linux/skbuff.h
include/linux/suspend.h
include/linux/syscalls.h
include/linux/sysctl.h
include/linux/tc_ematch/tc_em_text.h [new file with mode: 0644]
include/linux/tcp.h
include/linux/textsearch.h [new file with mode: 0644]
include/linux/textsearch_fsm.h [new file with mode: 0644]
include/linux/topology.h
include/linux/usb_ch9.h
include/linux/usb_gadget.h
include/linux/usb_isp116x.h [new file with mode: 0644]
include/linux/videodev2.h
include/linux/writeback.h
include/linux/xattr_acl.h [deleted file]
include/media/audiochip.h
include/media/id.h
include/media/ir-common.h
include/media/tuner.h
include/media/tveeprom.h
include/net/ieee80211.h [new file with mode: 0644]
include/net/ipv6.h
include/net/sctp/constants.h
include/net/sctp/sm.h
include/net/sctp/structs.h
include/net/tcp.h
include/pcmcia/ciscode.h
include/pcmcia/cs.h
include/pcmcia/device_id.h [new file with mode: 0644]
include/pcmcia/ds.h
include/pcmcia/ss.h
include/scsi/sg_request.h [new file with mode: 0644]
init/do_mounts_initrd.c
init/main.c
kernel/Kconfig.preempt [new file with mode: 0644]
kernel/Makefile
kernel/cpu.c
kernel/cpuset.c
kernel/crash_dump.c [new file with mode: 0644]
kernel/exit.c
kernel/fork.c
kernel/irq/autoprobe.c
kernel/irq/handle.c
kernel/irq/spurious.c
kernel/itimer.c
kernel/kexec.c [new file with mode: 0644]
kernel/kmod.c
kernel/kprobes.c
kernel/ksysfs.c
kernel/module.c
kernel/panic.c
kernel/power/Kconfig
kernel/power/Makefile
kernel/power/disk.c
kernel/power/main.c
kernel/power/process.c
kernel/power/smp.c
kernel/power/swsusp.c
kernel/printk.c
kernel/resource.c
kernel/sched.c
kernel/signal.c
kernel/sys.c
kernel/sys_ni.c
kernel/sysctl.c
kernel/timer.c
lib/Kconfig
lib/Makefile
lib/bitmap.c
lib/sha1.c
lib/textsearch.c [new file with mode: 0644]
lib/ts_fsm.c [new file with mode: 0644]
lib/ts_kmp.c [new file with mode: 0644]
mm/Makefile
mm/bootmem.c
mm/fadvise.c
mm/filemap.c
mm/filemap.h [new file with mode: 0644]
mm/filemap_xip.c [new file with mode: 0644]
mm/madvise.c
mm/memory.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_io.c
mm/pdflush.c
mm/rmap.c
mm/vmscan.c
net/bridge/br_netfilter.c
net/bridge/netfilter/ebt_log.c
net/core/dev.c
net/core/neighbour.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sysctl_net_core.c
net/core/wireless.c
net/ethernet/eth.c
net/ipv4/Kconfig
net/ipv4/fib_trie.c
net/ipv4/ip_input.c
net/ipv4/ip_output.c
net/ipv4/ipconfig.c
net/ipv4/ipmr.c
net/ipv4/ipvs/ip_vs_conn.c
net/ipv4/ipvs/ip_vs_ctl.c
net/ipv4/ipvs/ip_vs_sync.c
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_ipv4.c
net/ipv6/addrconf.c
net/ipv6/ip6_flowlabel.c
net/ipv6/tcp_ipv6.c
net/netlink/af_netlink.c
net/rxrpc/krxiod.c
net/rxrpc/krxsecd.c
net/rxrpc/krxtimod.c
net/sched/Kconfig
net/sched/Makefile
net/sched/act_api.c
net/sched/cls_api.c
net/sched/cls_rsvp.h
net/sched/em_text.c [new file with mode: 0644]
net/sched/sch_api.c
net/sched/sch_cbq.c
net/sctp/endpointola.c
net/sctp/protocol.c
net/sctp/sm_statefuns.c
net/sctp/sysctl.c
net/sctp/transport.c
net/sunrpc/sunrpc_syms.c
net/sunrpc/svcsock.c
net/sunrpc/xprt.c
scripts/basic/docproc.c
scripts/basic/fixdep.c
scripts/basic/split-include.c
scripts/kconfig/conf.c
scripts/kconfig/confdata.c
scripts/kconfig/mconf.c
scripts/mod/file2alias.c
security/keys/Makefile
security/keys/compat.c
security/keys/internal.h
security/keys/key.c
security/keys/keyctl.c
security/keys/keyring.c
security/keys/proc.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c [new file with mode: 0644]
security/keys/user_defined.c
security/selinux/hooks.c
security/selinux/include/av_perm_to_string.h
security/selinux/include/av_permissions.h
security/selinux/selinuxfs.c
security/selinux/ss/conditional.c
security/selinux/ss/policydb.c
security/selinux/ss/services.c
sound/oss/Kconfig
sound/oss/ad1816.c
sound/oss/ad1848.c
sound/oss/ad1889.c
sound/oss/cmpci.c
sound/oss/dmasound/dmasound_awacs.c
sound/oss/emu10k1/midi.c
sound/oss/emu10k1/passthrough.c
sound/oss/es1370.c
sound/oss/es1371.c
sound/oss/esssolo1.c
sound/oss/mad16.c
sound/oss/maestro.c
sound/oss/mpu401.c
sound/oss/nm256.h
sound/oss/nm256_audio.c
sound/oss/nm256_coeff.h
sound/oss/rme96xx.c
sound/oss/sb_common.c
sound/oss/sonicvibes.c
sound/oss/sscape.c
sound/oss/trident.c
sound/oss/v_midi.c
sound/oss/via82cxxx_audio.c
sound/oss/wavfront.c
sound/pci/cs4281.c
sound/pcmcia/pdaudiocf/pdaudiocf.c
sound/pcmcia/vx/vxpocket.c
sound/ppc/awacs.c
sound/ppc/daca.c
sound/ppc/pmac.c
sound/ppc/pmac.h
sound/ppc/tumbler.c

index 8de8a01a2474bc4ab429e6d97225a1f61af957c0..f28a24e0279b4c01aa8596e3f296ec50ef0ad70a 100644 (file)
@@ -138,6 +138,8 @@ java.txt
        - info on the in-kernel binary support for Java(tm).
 kbuild/
        - directory with info about the kernel build process.
+kdumpt.txt
+       - mini HowTo on getting the crash dump code to work.
 kernel-doc-nano-HOWTO.txt
        - mini HowTo on generation and location of kernel documentation files.
 kernel-docs.txt
index 57542bc25edda3bc8b2a2723dbe661c3b2fd4346..dfec7569d4501742cdaf1e2ca40ec2cb3783a202 100644 (file)
@@ -44,9 +44,9 @@ running, the suggested command should tell you.
 
 Again, keep in mind that this list assumes you are already
 functionally running a Linux 2.4 kernel.  Also, not all tools are
-necessary on all systems; obviously, if you don't have any PCMCIA (PC
-Card) hardware, for example, you probably needn't concern yourself
-with pcmcia-cs.
+necessary on all systems; obviously, if you don't have any ISDN
+hardware, for example, you probably needn't concern yourself with
+isdn4k-utils.
 
 o  Gnu C                  2.95.3                  # gcc --version
 o  Gnu make               3.79.1                  # make --version
@@ -57,13 +57,14 @@ o  e2fsprogs              1.29                    # tune2fs
 o  jfsutils               1.1.3                   # fsck.jfs -V
 o  reiserfsprogs          3.6.3                   # reiserfsck -V 2>&1|grep reiserfsprogs
 o  xfsprogs               2.6.0                   # xfs_db -V
+o  pcmciautils            004
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  quota-tools            3.09                    # quota -V
 o  PPP                    2.4.0                   # pppd --version
 o  isdn4k-utils           3.1pre1                 # isdnctrl 2>&1|grep version
 o  nfs-utils              1.0.5                   # showmount --version
 o  procps                 3.2.0                   # ps --version
-o  oprofile               0.5.3                   # oprofiled --version
+o  oprofile               0.9                     # oprofiled --version
 
 Kernel compilation
 ==================
@@ -186,13 +187,20 @@ architecture independent and any version from 2.0.0 onward should
 work correctly with this version of the XFS kernel code (2.6.0 or
 later is recommended, due to some significant improvements).
 
+PCMCIAutils
+-----------
+
+PCMCIAutils replaces pcmcia-cs (see below). It properly sets up
+PCMCIA sockets at system startup and loads the appropriate modules
+for 16-bit PCMCIA devices if the kernel is modularized and the hotplug
+subsystem is used.
 
 Pcmcia-cs
 ---------
 
 PCMCIA (PC Card) support is now partially implemented in the main
-kernel source.  Pay attention when you recompile your kernel ;-).
-Also, be sure to upgrade to the latest pcmcia-cs release.
+kernel source. The "pcmciautils" package (see above) replaces pcmcia-cs
+for newest kernels.
 
 Quota-tools
 -----------
@@ -349,9 +357,13 @@ Xfsprogs
 --------
 o  <ftp://oss.sgi.com/projects/xfs/download/>
 
+Pcmciautils
+-----------
+o  <ftp://ftp.kernel.org/pub/linux/utils/kernel/pcmcia/>
+
 Pcmcia-cs
 ---------
-o  <ftp://pcmcia-cs.sourceforge.net/pub/pcmcia-cs/pcmcia-cs-3.1.21.tar.gz>
+o  <http://pcmcia-cs.sourceforge.net/>
 
 Quota-tools
 ----------
index 87da3478fada4298d0b2d9c396904e2e3e7fa8f0..fa3e29ad8a463855c48241fb49ebfd3fd8ba86bb 100644 (file)
@@ -49,7 +49,7 @@ installmandocs: mandocs
 KERNELDOC = scripts/kernel-doc
 DOCPROC   = scripts/basic/docproc
 
-XMLTOFLAGS = -m Documentation/DocBook/stylesheet.xsl
+XMLTOFLAGS = -m $(srctree)/Documentation/DocBook/stylesheet.xsl
 #XMLTOFLAGS += --skip-validation
 
 ###
index bb6a0106be1100951a7b99696f9e8176bd862e7e..d650ce36485fe9b84a3f070bd9b4d4f13b433988 100644 (file)
@@ -266,7 +266,7 @@ X!Ekernel/module.c
   <chapter id="hardware">
      <title>Hardware Interfaces</title>
      <sect1><title>Interrupt Handling</title>
-!Iarch/i386/kernel/irq.c
+!Ikernel/irq/manage.c
      </sect1>
 
      <sect1><title>Resources Management</title>
index 6df1dfd18b651fce1224fe0e127cf7e777981d34..375ae760dc1ed1112d47874adde4de738ba5079e 100644 (file)
@@ -84,6 +84,14 @@ void (*port_disable) (struct ata_port *);
        Called from ata_bus_probe() and ata_bus_reset() error paths,
        as well as when unregistering from the SCSI module (rmmod, hot
        unplug).
+       This function should do whatever needs to be done to take the
+       port out of use.  In most cases, ata_port_disable() can be used
+       as this hook.
+       </para>
+       <para>
+       Called from ata_bus_probe() on a failed probe.
+       Called from ata_bus_reset() on a failed bus reset.
+       Called from ata_scsi_release().
        </para>
 
        </sect2>
@@ -98,6 +106,13 @@ void (*dev_config) (struct ata_port *, struct ata_device *);
        found.  Typically used to apply device-specific fixups prior to
        issue of SET FEATURES - XFER MODE, and prior to operation.
        </para>
+       <para>
+       Called by ata_device_add() after ata_dev_identify() determines
+       a device is present.
+       </para>
+       <para>
+       This entry may be specified as NULL in ata_port_operations.
+       </para>
 
        </sect2>
 
@@ -135,6 +150,8 @@ void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
        registers / DMA buffers.  ->tf_read() is called to read the
        hardware registers / DMA buffers, to obtain the current set of
        taskfile register values.
+       Most drivers for taskfile-based hardware (PIO or MMIO) use
+       ata_tf_load() and ata_tf_read() for these hooks.
        </para>
 
        </sect2>
@@ -147,6 +164,8 @@ void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
        <para>
        causes an ATA command, previously loaded with
        ->tf_load(), to be initiated in hardware.
+       Most drivers for taskfile-based hardware use ata_exec_command()
+       for this hook.
        </para>
 
        </sect2>
@@ -161,6 +180,10 @@ Allow low-level driver to filter ATA PACKET commands, returning a status
 indicating whether or not it is OK to use DMA for the supplied PACKET
 command.
        </para>
+       <para>
+       This hook may be specified as NULL, in which case libata will
+       assume that atapi dma can be supported.
+       </para>
 
        </sect2>
 
@@ -175,6 +198,14 @@ u8   (*check_err)(struct ata_port *ap);
        Reads the Status/AltStatus/Error ATA shadow register from
        hardware.  On some hardware, reading the Status register has
        the side effect of clearing the interrupt condition.
+       Most drivers for taskfile-based hardware use
+       ata_check_status() for this hook.
+       </para>
+       <para>
+       Note that because this is called from ata_device_add(), at
+       least a dummy function that clears device interrupts must be
+       provided for all drivers, even if the controller doesn't
+       actually have a taskfile status register.
        </para>
 
        </sect2>
@@ -188,7 +219,13 @@ void (*dev_select)(struct ata_port *ap, unsigned int device);
        Issues the low-level hardware command(s) that causes one of N
        hardware devices to be considered 'selected' (active and
        available for use) on the ATA bus.  This generally has no
-meaning on FIS-based devices.
+       meaning on FIS-based devices.
+       </para>
+       <para>
+       Most drivers for taskfile-based hardware use
+       ata_std_dev_select() for this hook.  Controllers which do not
+       support second drives on a port (such as SATA contollers) will
+       use ata_noop_dev_select().
        </para>
 
        </sect2>
@@ -204,6 +241,8 @@ void (*phy_reset) (struct ata_port *ap);
        for device presence (PATA and SATA), typically a soft reset
        (SRST) will be performed.  Drivers typically use the helper
        functions ata_bus_reset() or sata_phy_reset() for this hook.
+       Many SATA drivers use sata_phy_reset() or call it from within
+       their own phy_reset() functions.
        </para>
 
        </sect2>
@@ -227,6 +266,25 @@ PCI IDE DMA Status register.
 These hooks are typically either no-ops, or simply not implemented, in
 FIS-based drivers.
        </para>
+       <para>
+Most legacy IDE drivers use ata_bmdma_setup() for the bmdma_setup()
+hook.  ata_bmdma_setup() will write the pointer to the PRD table to
+the IDE PRD Table Address register, enable DMA in the DMA Command
+register, and call exec_command() to begin the transfer.
+       </para>
+       <para>
+Most legacy IDE drivers use ata_bmdma_start() for the bmdma_start()
+hook.  ata_bmdma_start() will write the ATA_DMA_START flag to the DMA
+Command register.
+       </para>
+       <para>
+Many legacy IDE drivers use ata_bmdma_stop() for the bmdma_stop()
+hook.  ata_bmdma_stop() clears the ATA_DMA_START flag in the DMA
+command register.
+       </para>
+       <para>
+Many legacy IDE drivers use ata_bmdma_status() as the bmdma_status() hook.
+       </para>
 
        </sect2>
 
@@ -250,6 +308,10 @@ int (*qc_issue) (struct ata_queued_cmd *qc);
        helper function ata_qc_issue_prot() for taskfile protocol-based
        dispatch.  More advanced drivers implement their own ->qc_issue.
        </para>
+       <para>
+       ata_qc_issue_prot() calls ->tf_load(), ->bmdma_setup(), and
+       ->bmdma_start() as necessary to initiate a transfer.
+       </para>
 
        </sect2>
 
@@ -279,6 +341,21 @@ void (*irq_clear) (struct ata_port *);
        before the interrupt handler is registered, to be sure hardware
        is quiet.
        </para>
+       <para>
+       The second argument, dev_instance, should be cast to a pointer
+       to struct ata_host_set.
+       </para>
+       <para>
+       Most legacy IDE drivers use ata_interrupt() for the
+       irq_handler hook, which scans all ports in the host_set,
+       determines which queued command was active (if any), and calls
+       ata_host_intr(ap,qc).
+       </para>
+       <para>
+       Most legacy IDE drivers use ata_bmdma_irq_clear() for the
+       irq_clear() hook, which simply clears the interrupt and error
+       flags in the DMA status register.
+       </para>
 
        </sect2>
 
@@ -292,6 +369,7 @@ void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
        <para>
        Read and write standard SATA phy registers.  Currently only used
        if ->phy_reset hook called the sata_phy_reset() helper function.
+       sc_reg is one of SCR_STATUS, SCR_CONTROL, SCR_ERROR, or SCR_ACTIVE.
        </para>
 
        </sect2>
@@ -307,17 +385,29 @@ void (*host_stop) (struct ata_host_set *host_set);
        ->port_start() is called just after the data structures for each
        port are initialized.  Typically this is used to alloc per-port
        DMA buffers / tables / rings, enable DMA engines, and similar
-       tasks.  
+       tasks.  Some drivers also use this entry point as a chance to
+       allocate driver-private memory for ap->private_data.
+       </para>
+       <para>
+       Many drivers use ata_port_start() as this hook or call
+       it from their own port_start() hooks.  ata_port_start()
+       allocates space for a legacy IDE PRD table and returns.
        </para>
        <para>
        ->port_stop() is called after ->host_stop().  It's sole function
        is to release DMA/memory resources, now that they are no longer
-       actively being used.
+       actively being used.  Many drivers also free driver-private
+       data from port at this time.
+       </para>
+       <para>
+       Many drivers use ata_port_stop() as this hook, which frees the
+       PRD table.
        </para>
        <para>
        ->host_stop() is called after all ->port_stop() calls
 have completed.  The hook must finalize hardware shutdown, release DMA
 and other resources, etc.
+       This hook may be specified as NULL, in which case it is not called.
        </para>
 
        </sect2>
index e14c21dda403dc19cdd272a468dcc7e2433c507d..64be9f7ee3bba74a415d10c0f9508c7c4105e176 100644 (file)
@@ -2,4 +2,5 @@
 <stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
 <param name="chunk.quietly">1</param>
 <param name="funcsynopsis.style">ansi</param>
+<param name="funcsynopsis.tabular.threshold">80</param>
 </stylesheet>
index 90d10e708ca3fba4afdad8cdf4609bd5b02d8842..84d3d4d10c175943a86f12bd735694be19529eb7 100644 (file)
@@ -25,9 +25,10 @@ subject and I can't cover it all here!
 Configuration
 -------------
 
-The LinuxIPMI driver is modular, which means you have to pick several
+The Linux IPMI driver is modular, which means you have to pick several
 things to have it work right depending on your hardware.  Most of
-these are available in the 'Character Devices' menu.
+these are available in the 'Character Devices' menu then the IPMI
+menu.
 
 No matter what, you must pick 'IPMI top-level message handler' to use
 IPMI.  What you do beyond that depends on your needs and hardware.
@@ -35,33 +36,30 @@ IPMI.  What you do beyond that depends on your needs and hardware.
 The message handler does not provide any user-level interfaces.
 Kernel code (like the watchdog) can still use it.  If you need access
 from userland, you need to select 'Device interface for IPMI' if you
-want access through a device driver.  Another interface is also
-available, you may select 'IPMI sockets' in the 'Networking Support'
-main menu.  This provides a socket interface to IPMI.  You may select
-both of these at the same time, they will both work together.
-
-The driver interface depends on your hardware.  If you have a board
-with a standard interface (These will generally be either "KCS",
-"SMIC", or "BT", consult your hardware manual), choose the 'IPMI SI
-handler' option.  A driver also exists for direct I2C access to the
-IPMI management controller.  Some boards support this, but it is
-unknown if it will work on every board.  For this, choose 'IPMI SMBus
-handler', but be ready to try to do some figuring to see if it will
-work.
-
-There is also a KCS-only driver interface supplied, but it is
-depracated in favor of the SI interface.
+want access through a device driver.
+
+The driver interface depends on your hardware.  If your system
+properly provides the SMBIOS info for IPMI, the driver will detect it
+and just work.  If you have a board with a standard interface (These
+will generally be either "KCS", "SMIC", or "BT", consult your hardware
+manual), choose the 'IPMI SI handler' option.  A driver also exists
+for direct I2C access to the IPMI management controller.  Some boards
+support this, but it is unknown if it will work on every board.  For
+this, choose 'IPMI SMBus handler', but be ready to try to do some
+figuring to see if it will work on your system if the SMBIOS/APCI
+information is wrong or not present.  It is fairly safe to have both
+these enabled and let the drivers auto-detect what is present.
 
 You should generally enable ACPI on your system, as systems with IPMI
-should have ACPI tables describing them.
+can have ACPI tables describing them.
 
 If you have a standard interface and the board manufacturer has done
 their job correctly, the IPMI controller should be automatically
-detect (via ACPI or SMBIOS tables) and should just work.  Sadly, many
-boards do not have this information.  The driver attempts standard
-defaults, but they may not work.  If you fall into this situation, you
-need to read the section below named 'The SI Driver' on how to
-hand-configure your system.
+detected (via ACPI or SMBIOS tables) and should just work.  Sadly,
+many boards do not have this information.  The driver attempts
+standard defaults, but they may not work.  If you fall into this
+situation, you need to read the section below named 'The SI Driver' or
+"The SMBus Driver" on how to hand-configure your system.
 
 IPMI defines a standard watchdog timer.  You can enable this with the
 'IPMI Watchdog Timer' config option.  If you compile the driver into
@@ -73,6 +71,18 @@ closed (by default it is disabled on close).  Go into the 'Watchdog
 Cards' menu, enable 'Watchdog Timer Support', and enable the option
 'Disable watchdog shutdown on close'.
 
+IPMI systems can often be powered off using IPMI commands.  Select
+'IPMI Poweroff' to do this.  The driver will auto-detect if the system
+can be powered off by IPMI.  It is safe to enable this even if your
+system doesn't support this option.  This works on ATCA systems, the
+Radisys CPI1 card, and any IPMI system that supports standard chassis
+management commands.
+
+If you want the driver to put an event into the event log on a panic,
+enable the 'Generate a panic event to all BMCs on a panic' option.  If
+you want the whole panic string put into the event log using OEM
+events, enable the 'Generate OEM events containing the panic string'
+option.
 
 Basic Design
 ------------
@@ -80,7 +90,7 @@ Basic Design
 The Linux IPMI driver is designed to be very modular and flexible, you
 only need to take the pieces you need and you can use it in many
 different ways.  Because of that, it's broken into many chunks of
-code.  These chunks are:
+code.  These chunks (by module name) are:
 
 ipmi_msghandler - This is the central piece of software for the IPMI
 system.  It handles all messages, message timing, and responses.  The
@@ -93,18 +103,26 @@ ipmi_devintf - This provides a userland IOCTL interface for the IPMI
 driver, each open file for this device ties in to the message handler
 as an IPMI user.
 
-ipmi_si - A driver for various system interfaces.  This supports
-KCS, SMIC, and may support BT in the future.  Unless you have your own
-custom interface, you probably need to use this.
+ipmi_si - A driver for various system interfaces.  This supports KCS,
+SMIC, and BT interfaces.  Unless you have an SMBus interface or your
+own custom interface, you probably need to use this.
 
 ipmi_smb - A driver for accessing BMCs on the SMBus. It uses the
 I2C kernel driver's SMBus interfaces to send and receive IPMI messages
 over the SMBus.
 
-af_ipmi - A network socket interface to IPMI.  This doesn't take up
-a character device in your system.
+ipmi_watchdog - IPMI requires systems to have a very capable watchdog
+timer.  This driver implements the standard Linux watchdog timer
+interface on top of the IPMI message handler.
+
+ipmi_poweroff - Some systems support the ability to be turned off via
+IPMI commands.
 
-Note that the KCS-only interface ahs been removed.
+These are all individually selectable via configuration options.
+
+Note that the KCS-only interface has been removed.  The af_ipmi driver
+is no longer supported and has been removed because it was impossible
+to do 32 bit emulation on 64-bit kernels with it.
 
 Much documentation for the interface is in the include files.  The
 IPMI include files are:
@@ -424,7 +442,7 @@ at module load time (for a module) with:
   modprobe ipmi_smb.o
        addr=<adapter1>,<i2caddr1>[,<adapter2>,<i2caddr2>[,...]]
        dbg=<flags1>,<flags2>...
-       [defaultprobe=0] [dbg_probe=1]
+       [defaultprobe=1] [dbg_probe=1]
 
 The addresses are specified in pairs, the first is the adapter ID and the
 second is the I2C address on that adapter.
@@ -532,3 +550,67 @@ Once you open the watchdog timer, you must write a 'V' character to the
 device to close it, or the timer will not stop.  This is a new semantic
 for the driver, but makes it consistent with the rest of the watchdog
 drivers in Linux.
+
+
+Panic Timeouts
+--------------
+
+The OpenIPMI driver supports the ability to put semi-custom and custom
+events in the system event log if a panic occurs.  if you enable the
+'Generate a panic event to all BMCs on a panic' option, you will get
+one event on a panic in a standard IPMI event format.  If you enable
+the 'Generate OEM events containing the panic string' option, you will
+also get a bunch of OEM events holding the panic string.
+
+
+The field settings of the events are:
+* Generator ID: 0x21 (kernel)
+* EvM Rev: 0x03 (this event is formatting in IPMI 1.0 format)
+* Sensor Type: 0x20 (OS critical stop sensor)
+* Sensor #: The first byte of the panic string (0 if no panic string)
+* Event Dir | Event Type: 0x6f (Assertion, sensor-specific event info)
+* Event Data 1: 0xa1 (Runtime stop in OEM bytes 2 and 3)
+* Event data 2: second byte of panic string
+* Event data 3: third byte of panic string
+See the IPMI spec for the details of the event layout.  This event is
+always sent to the local management controller.  It will handle routing
+the message to the right place
+
+Other OEM events have the following format:
+Record ID (bytes 0-1): Set by the SEL.
+Record type (byte 2): 0xf0 (OEM non-timestamped)
+byte 3: The slave address of the card saving the panic
+byte 4: A sequence number (starting at zero)
+The rest of the bytes (11 bytes) are the panic string.  If the panic string
+is longer than 11 bytes, multiple messages will be sent with increasing
+sequence numbers.
+
+Because you cannot send OEM events using the standard interface, this
+function will attempt to find an SEL and add the events there.  It
+will first query the capabilities of the local management controller.
+If it has an SEL, then they will be stored in the SEL of the local
+management controller.  If not, and the local management controller is
+an event generator, the event receiver from the local management
+controller will be queried and the events sent to the SEL on that
+device.  Otherwise, the events go nowhere since there is nowhere to
+send them.
+
+
+Poweroff
+--------
+
+If the poweroff capability is selected, the IPMI driver will install
+a shutdown function into the standard poweroff function pointer.  This
+is in the ipmi_poweroff module.  When the system requests a powerdown,
+it will send the proper IPMI commands to do this.  This is supported on
+several platforms.
+
+There is a module parameter named "poweroff_control" that may either be zero
+(do a power down) or 2 (do a power cycle, power the system off, then power
+it on in a few seconds).  Setting ipmi_poweroff.poweroff_control=x will do
+the same thing on the kernel command line.  The parameter is also available
+via the proc filesystem in /proc/ipmi/poweroff_control.  Note that if the
+system does not support power cycling, it will always to the power off.
+
+Note that if you have ACPI enabled, the system will prefer using ACPI to
+power off.
index de3b252e717d0f0f10c4259cb1cbf7624073de6f..c3cca924e94b4accf6848e9338d12c1ca863bb36 100644 (file)
@@ -13,13 +13,14 @@ Allocating Device Numbers
 -------------------------
 
 Major and minor numbers for block and character devices are allocated
-by the Linux assigned name and number authority (currently better
-known as H Peter Anvin). The site is http://www.lanana.org/. This
+by the Linux assigned name and number authority (currently this is
+Torben Mathiasen). The site is http://www.lanana.org/. This
 also deals with allocating numbers for devices that are not going to
 be submitted to the mainstream kernel.
+See Documentation/devices.txt for more information on this.
 
-If you don't use assigned numbers then when you device is submitted it will
-get given an assigned number even if that is different from values you may
+If you don't use assigned numbers then when your device is submitted it will
+be given an assigned number even if that is different from values you may
 have shipped to customers before.
 
 Who To Submit Drivers To
@@ -32,7 +33,8 @@ Linux 2.2:
        If the code area has a general maintainer then please submit it to
        the maintainer listed in MAINTAINERS in the kernel file. If the
        maintainer does not respond or you cannot find the appropriate
-       maintainer then please contact Alan Cox <alan@lxorguk.ukuu.org.uk>
+       maintainer then please contact the 2.2 kernel maintainer:
+       Marc-Christian Petersen <m.c.p@wolk-project.de>.
 
 Linux 2.4:
        The same rules apply as 2.2. The final contact point for Linux 2.4
@@ -48,7 +50,7 @@ What Criteria Determine Acceptance
 
 Licensing:     The code must be released to us under the
                GNU General Public License. We don't insist on any kind
-               of exclusively GPL licensing, and if you wish the driver
+               of exclusive GPL licensing, and if you wish the driver
                to be useful to other communities such as BSD you may well
                wish to release under multiple licenses.
 
index 4d35562b1cf976d7f63f7f555440686e44ae5db4..6761a7b241a5fafbe77c69d09e23b1dd56781f06 100644 (file)
@@ -35,7 +35,7 @@ not in any lower subdirectory.
 
 To create a patch for a single file, it is often sufficient to do:
 
-       SRCTREE= linux-2.4
+       SRCTREE= linux-2.6
        MYFILE=  drivers/net/mydriver.c
 
        cd $SRCTREE
@@ -48,17 +48,18 @@ To create a patch for multiple files, you should unpack a "vanilla",
 or unmodified kernel source tree, and generate a diff against your
 own source tree.  For example:
 
-       MYSRC= /devel/linux-2.4
+       MYSRC= /devel/linux-2.6
 
-       tar xvfz linux-2.4.0-test11.tar.gz
-       mv linux linux-vanilla
-       wget http://www.moses.uklinux.net/patches/dontdiff
-       diff -uprN -X dontdiff linux-vanilla $MYSRC > /tmp/patch
-       rm -f dontdiff
+       tar xvfz linux-2.6.12.tar.gz
+       mv linux-2.6.12 linux-2.6.12-vanilla
+       diff -uprN -X linux-2.6.12-vanilla/Documentation/dontdiff \
+               linux-2.6.12-vanilla $MYSRC > /tmp/patch
 
 "dontdiff" is a list of files which are generated by the kernel during
 the build process, and should be ignored in any diff(1)-generated
-patch.  dontdiff is maintained by Tigran Aivazian <tigran@veritas.com>
+patch.  The "dontdiff" file is included in the kernel tree in
+2.6.12 and later.  For earlier kernel versions, you can get it
+from <http://www.xenotime.net/linux/doc/dontdiff>.
 
 Make sure your patch does not include any extra files which do not
 belong in a patch submission.  Make sure to review your patch -after-
@@ -66,18 +67,20 @@ generated it with diff(1), to ensure accuracy.
 
 If your changes produce a lot of deltas, you may want to look into
 splitting them into individual patches which modify things in
-logical stages, this will facilitate easier reviewing by other
+logical stages.  This will facilitate easier reviewing by other
 kernel developers, very important if you want your patch accepted.
-There are a number of scripts which can aid in this;
+There are a number of scripts which can aid in this:
 
 Quilt:
 http://savannah.nongnu.org/projects/quilt
 
 Randy Dunlap's patch scripts:
-http://developer.osdl.org/rddunlap/scripts/patching-scripts.tgz
+http://www.xenotime.net/linux/scripts/patching-scripts-002.tar.gz
 
 Andrew Morton's patch scripts:
-http://www.zip.com.au/~akpm/linux/patches/patch-scripts-0.16
+http://www.zip.com.au/~akpm/linux/patches/patch-scripts-0.20
+
+
 
 2) Describe your changes.
 
@@ -132,21 +135,6 @@ which require discussion or do not have a clear advantage should
 usually be sent first to linux-kernel.  Only after the patch is
 discussed should the patch then be submitted to Linus.
 
-For small patches you may want to CC the Trivial Patch Monkey
-trivial@rustcorp.com.au set up by Rusty Russell; which collects "trivial"
-patches. Trivial patches must qualify for one of the following rules:
- Spelling fixes in documentation
- Spelling fixes which could break grep(1).
- Warning fixes (cluttering with useless warnings is bad)
- Compilation fixes (only if they are actually correct)
- Runtime fixes (only if they actually fix things)
- Removing use of deprecated functions/macros (eg. check_region).
- Contact detail and documentation fixes
- Non-portable code replaced by portable code (even in arch-specific,
- since people copy, as long as it's trivial)
- Any fix by the author/maintainer of the file. (ie. patch monkey
- in re-transmission mode)
-
 
 
 5) Select your CC (e-mail carbon copy) list.
@@ -178,6 +166,8 @@ patches. Trivial patches must qualify for one of the following rules:
  since people copy, as long as it's trivial)
  Any fix by the author/maintainer of the file. (ie. patch monkey
  in re-transmission mode)
+URL: <http://www.kernel.org/pub/linux/kernel/people/rusty/trivial/>
+
 
 
 
@@ -299,13 +289,24 @@ can certify the below:
 
 then you just add a line saying
 
-       Signed-off-by: Random J Developer <random@developer.org>
+       Signed-off-by: Random J Developer <random@developer.example.org>
 
 Some people also put extra tags at the end.  They'll just be ignored for
 now, but you can do this to mark internal company procedures or just
 point out some special detail about the sign-off. 
 
 
+
+12) More references for submitting patches
+
+Andrew Morton, "The perfect patch" (tpp).
+  <http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt>
+
+Jeff Garzik, "Linux kernel patch submission format."
+  <http://linux.yyz.us/patch-format.html>
+
+
+
 -----------------------------------
 SECTION 2 - HINTS, TIPS, AND TRICKS
 -----------------------------------
@@ -374,7 +375,5 @@ and 'extern __inline__'.
 4) Don't over-design.
 
 Don't try to anticipate nebulous future cases which may or may not
-be useful:  "Make it as simple as you can, and no simpler"
-
-
+be useful:  "Make it as simple as you can, and no simpler."
 
index 65e3dc2d4437a460fa68d5b52c87d52e401e2825..8764e9f70821e4f894551f1fb1b98a881f3d3e9d 100644 (file)
@@ -27,9 +27,13 @@ dump output  readprofile -m /boot/System.map > captured_profile
 
 Oprofile
 --------
-Get the source (I use 0.8) from http://oprofile.sourceforge.net/
-and add "idle=poll" to the kernel command line
+
+Get the source (see Changes for required version) from
+http://oprofile.sourceforge.net/ and add "idle=poll" to the kernel command
+line.
+
 Configure with CONFIG_PROFILING=y and CONFIG_OPROFILE=y & reboot on new kernel
+
 ./configure --with-kernel-support
 make install
 
@@ -46,7 +50,7 @@ start         opcontrol --start
 stop           opcontrol --stop
 dump output    opreport >  output_file
 
-To only report on the kernel, run opreport /boot/vmlinux > output_file
+To only report on the kernel, run opreport -l /boot/vmlinux > output_file
 
 A reset is needed to clear old statistics, which survive a reboot.
 
diff --git a/Documentation/block/ioprio.txt b/Documentation/block/ioprio.txt
new file mode 100644 (file)
index 0000000..96ccf68
--- /dev/null
@@ -0,0 +1,176 @@
+Block io priorities
+===================
+
+
+Intro
+-----
+
+With the introduction of cfq v3 (aka cfq-ts or time sliced cfq), basic io
+priorities is supported for reads on files. This enables users to io nice
+processes or process groups, similar to what has been possible to cpu
+scheduling for ages. This document mainly details the current possibilites
+with cfq, other io schedulers do not support io priorities so far.
+
+Scheduling classes
+------------------
+
+CFQ implements three generic scheduling classes that determine how io is
+served for a process.
+
+IOPRIO_CLASS_RT: This is the realtime io class. This scheduling class is given
+higher priority than any other in the system, processes from this class are
+given first access to the disk every time. Thus it needs to be used with some
+care, one io RT process can starve the entire system. Within the RT class,
+there are 8 levels of class data that determine exactly how much time this
+process needs the disk for on each service. In the future this might change
+to be more directly mappable to performance, by passing in a wanted data
+rate instead.
+
+IOPRIO_CLASS_BE: This is the best-effort scheduling class, which is the default
+for any process that hasn't set a specific io priority. The class data
+determines how much io bandwidth the process will get, it's directly mappable
+to the cpu nice levels just more coarsely implemented. 0 is the highest
+BE prio level, 7 is the lowest. The mapping between cpu nice level and io
+nice level is determined as: io_nice = (cpu_nice + 20) / 5.
+
+IOPRIO_CLASS_IDLE: This is the idle scheduling class, processes running at this
+level only get io time when no one else needs the disk. The idle class has no
+class data, since it doesn't really apply here.
+
+Tools
+-----
+
+See below for a sample ionice tool. Usage:
+
+# ionice -c<class> -n<level> -p<pid>
+
+If pid isn't given, the current process is assumed. IO priority settings
+are inherited on fork, so you can use ionice to start the process at a given
+level:
+
+# ionice -c2 -n0 /bin/ls
+
+will run ls at the best-effort scheduling class at the highest priority.
+For a running process, you can give the pid instead:
+
+# ionice -c1 -n2 -p100
+
+will change pid 100 to run at the realtime scheduling class, at priority 2.
+
+---> snip ionice.c tool <---
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/ptrace.h>
+#include <asm/unistd.h>
+
+extern int sys_ioprio_set(int, int, int);
+extern int sys_ioprio_get(int, int);
+
+#if defined(__i386__)
+#define __NR_ioprio_set                289
+#define __NR_ioprio_get                290
+#elif defined(__ppc__)
+#define __NR_ioprio_set                273
+#define __NR_ioprio_get                274
+#elif defined(__x86_64__)
+#define __NR_ioprio_set                251
+#define __NR_ioprio_get                252
+#elif defined(__ia64__)
+#define __NR_ioprio_set                1274
+#define __NR_ioprio_get                1275
+#else
+#error "Unsupported arch"
+#endif
+
+_syscall3(int, ioprio_set, int, which, int, who, int, ioprio);
+_syscall2(int, ioprio_get, int, which, int, who);
+
+enum {
+       IOPRIO_CLASS_NONE,
+       IOPRIO_CLASS_RT,
+       IOPRIO_CLASS_BE,
+       IOPRIO_CLASS_IDLE,
+};
+
+enum {
+       IOPRIO_WHO_PROCESS = 1,
+       IOPRIO_WHO_PGRP,
+       IOPRIO_WHO_USER,
+};
+
+#define IOPRIO_CLASS_SHIFT     13
+
+const char *to_prio[] = { "none", "realtime", "best-effort", "idle", };
+
+int main(int argc, char *argv[])
+{
+       int ioprio = 4, set = 0, ioprio_class = IOPRIO_CLASS_BE;
+       int c, pid = 0;
+
+       while ((c = getopt(argc, argv, "+n:c:p:")) != EOF) {
+               switch (c) {
+               case 'n':
+                       ioprio = strtol(optarg, NULL, 10);
+                       set = 1;
+                       break;
+               case 'c':
+                       ioprio_class = strtol(optarg, NULL, 10);
+                       set = 1;
+                       break;
+               case 'p':
+                       pid = strtol(optarg, NULL, 10);
+                       break;
+               }
+       }
+
+       switch (ioprio_class) {
+               case IOPRIO_CLASS_NONE:
+                       ioprio_class = IOPRIO_CLASS_BE;
+                       break;
+               case IOPRIO_CLASS_RT:
+               case IOPRIO_CLASS_BE:
+                       break;
+               case IOPRIO_CLASS_IDLE:
+                       ioprio = 7;
+                       break;
+               default:
+                       printf("bad prio class %d\n", ioprio_class);
+                       return 1;
+       }
+
+       if (!set) {
+               if (!pid && argv[optind])
+                       pid = strtol(argv[optind], NULL, 10);
+
+               ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
+
+               printf("pid=%d, %d\n", pid, ioprio);
+
+               if (ioprio == -1)
+                       perror("ioprio_get");
+               else {
+                       ioprio_class = ioprio >> IOPRIO_CLASS_SHIFT;
+                       ioprio = ioprio & 0xff;
+                       printf("%s: prio %d\n", to_prio[ioprio_class], ioprio);
+               }
+       } else {
+               if (ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio | ioprio_class << IOPRIO_CLASS_SHIFT) == -1) {
+                       perror("ioprio_set");
+                       return 1;
+               }
+
+               if (argv[optind])
+                       execvp(argv[optind], &argv[optind]);
+       }
+
+       return 0;
+}
+
+---> snip ionice.c tool <---
+
+
+March 11 2005, Jens Axboe <axboe@suse.de>
index d599beb9df8a7594ff5c1ee177945f45a0f33601..c8f9a73111da8371d5ff4b49b68116ffb3353e48 100644 (file)
@@ -17,6 +17,7 @@ This driver is known to work with the following cards:
        * SA P600
        * SA P800
        * SA E400
+       * SA E300
 
 If nodes are not already created in the /dev/cciss directory, run as root:
 
index d1825dffca34ed600b7a1b216355b3bbca60eca6..b3ba63f4ce3e9cf00f41fd38a17fae94ba05d046 100644 (file)
@@ -419,6 +419,7 @@ into the file "track01":
  */
 #include <stdio.h>
 #include <sys/ioctl.h>
+#include <sys/types.h>
 #include <linux/cdrom.h>
 
 static struct cdrom_tochdr hdr;
@@ -429,7 +430,7 @@ static int datafile, drive;
 static int i, j, limit, track, err;
 static char filename[32];
 
-main(int argc, char *argv[])
+int main(int argc, char *argv[])
 {
 /*
  * open /dev/cdrom
@@ -516,6 +517,7 @@ entry[track+1].cdte_addr.lba=entry[track].cdte_addr.lba+300;
        }
       arg.addr.lba++;
     }
+    return 0;
 }
 /*===================== end program ========================================*/
 
@@ -564,15 +566,16 @@ Appendix -- the "cdtester" utility:
 #include <stdio.h>
 #include <malloc.h>
 #include <sys/ioctl.h>
+#include <sys/types.h>
 #include <linux/cdrom.h>
 
 #ifdef AZT_PRIVATE_IOCTLS
 #include <linux/../../drivers/cdrom/aztcd.h>
-#endif AZT_PRIVATE_IOCTLS
+#endif /* AZT_PRIVATE_IOCTLS */
 #ifdef SBP_PRIVATE_IOCTLS
 #include <linux/../../drivers/cdrom/sbpcd.h>
 #include <linux/fs.h>
-#endif SBP_PRIVATE_IOCTLS
+#endif /* SBP_PRIVATE_IOCTLS */
 
 struct cdrom_tochdr hdr;
 struct cdrom_tochdr tocHdr;
@@ -590,7 +593,7 @@ union
        struct cdrom_msf msf;
        unsigned char buf[CD_FRAMESIZE_RAW];
 } azt;
-#endif AZT_PRIVATE_IOCTLS
+#endif /* AZT_PRIVATE_IOCTLS */
 int i, i1, i2, i3, j, k;
 unsigned char sequence=0;
 unsigned char command[80];
@@ -738,7 +741,7 @@ void display(int size,unsigned char *buffer)
        } 
 } 
 
-main(int argc, char *argv[])
+int main(int argc, char *argv[])
 {
        printf("\nTesting tool for a CDROM driver's audio functions V0.1\n");
        printf("(C) 1995 Eberhard Moenkeberg <emoenke@gwdg.de>\n");
@@ -1046,12 +1049,13 @@ main(int argc, char *argv[])
                        rc=ioctl(drive,CDROMAUDIOBUFSIZ,j);
                        printf("%d frames granted.\n",rc);
                        break;
-#endif SBP_PRIVATE_IOCTLS
+#endif /* SBP_PRIVATE_IOCTLS */
                default:
                        printf("unknown command: \"%s\".\n",command);
                        break;
                }
        }
+       return 0;
 }
 /*==========================================================================*/
 
index b85481acd0ca49fdb6625faaae44293cc213d3ea..933fae74c3379cba1fd7d066a2ab7f6daead76a3 100644 (file)
@@ -9,6 +9,7 @@
 
 
                    Dominik Brodowski  <linux@brodo.de>
+            some additions and corrections by Nico Golde <nico@ngolde.de>
 
 
 
@@ -25,6 +26,7 @@ Contents:
 2.1  Performance
 2.2  Powersave
 2.3  Userspace
+2.4  Ondemand
 
 3.   The Governor Interface in the CPUfreq Core
 
@@ -86,7 +88,7 @@ highest frequency within the borders of scaling_min_freq and
 scaling_max_freq.
 
 
-2.1 Powersave
+2.2 Powersave
 -------------
 
 The CPUfreq governor "powersave" sets the CPU statically to the
@@ -94,7 +96,7 @@ lowest frequency within the borders of scaling_min_freq and
 scaling_max_freq.
 
 
-2.2 Userspace
+2.3 Userspace
 -------------
 
 The CPUfreq governor "userspace" allows the user, or any userspace
@@ -103,6 +105,14 @@ by making a sysfs file "scaling_setspeed" available in the CPU-device
 directory.
 
 
+2.4 Ondemand
+------------
+
+The CPUfreq govenor "ondemand" sets the CPU depending on the
+current usage. To do this the CPU must have the capability to
+switch the frequency very fast.
+
+
 
 3. The Governor Interface in the CPUfreq Core
 =============================================
index 2f8f24eaefd9ac746f8a1e98b6e2c99abcc23b58..ad944c06031294cc35265d82ecf2a8fcc12586de 100644 (file)
@@ -51,6 +51,14 @@ mems_allowed vector.
 
 If a cpuset is cpu or mem exclusive, no other cpuset, other than a direct
 ancestor or descendent, may share any of the same CPUs or Memory Nodes.
+A cpuset that is cpu exclusive has a sched domain associated with it.
+The sched domain consists of all cpus in the current cpuset that are not
+part of any exclusive child cpusets.
+This ensures that the scheduler load balacing code only balances
+against the cpus that are in the sched domain as defined above and not
+all of the cpus in the system. This removes any overhead due to
+load balancing code trying to pull tasks outside of the cpu exclusive
+cpuset only to be prevented by the tasks' cpus_allowed mask.
 
 User level code may create and destroy cpusets by name in the cpuset
 virtual file system, manage the attributes and permissions of these
@@ -84,6 +92,9 @@ This can be especially valuable on:
       and a database), or
     * NUMA systems running large HPC applications with demanding
       performance characteristics.
+    * Also cpu_exclusive cpusets are useful for servers running orthogonal
+      workloads such as RT applications requiring low latency and HPC
+      applications that are throughput sensitive
 
 These subsets, or "soft partitions" must be able to be dynamically
 adjusted, as the job mix changes, without impacting other concurrently
@@ -125,6 +136,8 @@ Cpusets extends these two mechanisms as follows:
  - A cpuset may be marked exclusive, which ensures that no other
    cpuset (except direct ancestors and descendents) may contain
    any overlapping CPUs or Memory Nodes.
+   Also a cpu_exclusive cpuset would be associated with a sched
+   domain.
  - You can list all the tasks (by pid) attached to any cpuset.
 
 The implementation of cpusets requires a few, simple hooks
@@ -136,6 +149,9 @@ into the rest of the kernel, none in performance critical paths:
    allowed in that tasks cpuset.
  - in sched.c migrate_all_tasks(), to keep migrating tasks within
    the CPUs allowed by their cpuset, if possible.
+ - in sched.c, a new API partition_sched_domains for handling
+   sched domain changes associated with cpu_exclusive cpusets
+   and related changes in both sched.c and arch/ia64/kernel/domain.c
  - in the mbind and set_mempolicy system calls, to mask the requested
    Memory Nodes by what's allowed in that tasks cpuset.
  - in page_alloc, to restrict memory to allowed nodes.
index bb67cf25010ed4ceb64b2157f3db4b299bf597c9..0f515175c72a889959ad5258379a602f31495767 100644 (file)
@@ -94,6 +94,7 @@ Your cooperation is appreciated.
                  9 = /dev/urandom      Faster, less secure random number gen.
                 10 = /dev/aio          Asyncronous I/O notification interface
                 11 = /dev/kmsg         Writes to this come out as printk's
+                12 = /dev/oldmem       Access to crash dump from kexec kernel
   1 block      RAM disk
                  0 = /dev/ram0         First RAM disk
                  1 = /dev/ram1         Second RAM disk
diff --git a/Documentation/dvb/README.dibusb b/Documentation/dvb/README.dibusb
deleted file mode 100644 (file)
index 7a9e958..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-Documentation for dib3000* frontend drivers and dibusb device driver
-====================================================================
-
-Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de),
-
-dibusb and dib3000mb/mc drivers based on GPL code, which has
-
-Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation, version 2.
-
-
-Supported devices USB1.1
-========================
-
-Produced and reselled by Twinhan:
----------------------------------
-- TwinhanDTV USB-Ter DVB-T Device (VP7041)
-       http://www.twinhan.com/product_terrestrial_3.asp
-
-- TwinhanDTV Magic Box (VP7041e)
-       http://www.twinhan.com/product_terrestrial_4.asp
-
-- HAMA DVB-T USB device
-       http://www.hama.de/portal/articleId*110620/action*2598
-
-- CTS Portable (Chinese Television System) (2)
-       http://www.2cts.tv/ctsportable/
-
-- Unknown USB DVB-T device with vendor ID Hyper-Paltek
-
-
-Produced and reselled by KWorld:
---------------------------------
-- KWorld V-Stream XPERT DTV DVB-T USB
-       http://www.kworld.com.tw/en/product/DVBT-USB/DVBT-USB.html
-
-- JetWay DTV DVB-T USB
-       http://www.jetway.com.tw/evisn/product/lcd-tv/DVT-USB/dtv-usb.htm
-
-- ADSTech Instant TV DVB-T USB
-       http://www.adstech.com/products/PTV-333/intro/PTV-333_intro.asp?pid=PTV-333
-
-
-Others:
--------
-- Ultima Electronic/Artec T1 USB TVBOX (AN2135, AN2235, AN2235 with Panasonic Tuner)
-       http://82.161.246.249/products-tvbox.html
-
-- Compro Videomate DVB-U2000 - DVB-T USB (2)
-       http://www.comprousa.com/products/vmu2000.htm
-
-- Grandtec USB DVB-T
-       http://www.grand.com.tw/
-
-- Avermedia AverTV DVBT USB (2)
-       http://www.avermedia.com/
-
-- DiBcom USB DVB-T reference device (non-public)
-
-
-Supported devices USB2.0
-========================
-- Twinhan MagicBox II (2)
-       http://www.twinhan.com/product_terrestrial_7.asp
-
-- Hanftek UMT-010 (1)
-       http://www.globalsources.com/si/6008819757082/ProductDetail/Digital-TV/product_id-100046529
-
-- Typhoon/Yakumo/HAMA DVB-T mobile USB2.0 (1)
-       http://www.yakumo.de/produkte/index.php?pid=1&ag=DVB-T
-
-- Artec T1 USB TVBOX (FX2) (2)
-
-- Hauppauge WinTV NOVA-T USB2
-       http://www.hauppauge.com/
-
-- KWorld/ADSTech Instant DVB-T USB2.0 (DiB3000M-B)
-
-- DiBcom USB2.0 DVB-T reference device (non-public)
-
-1) It is working almost.
-2) No test reports received yet.
-
-
-0. NEWS:
-  2005-02-11 - added support for the KWorld/ADSTech Instant DVB-T USB2.0. Thanks a lot to Joachim von Caron
-  2005-02-02 - added support for the Hauppauge Win-TV Nova-T USB2
-  2005-01-31 - distorted streaming is finally gone for USB1.1 devices
-  2005-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb
-             - first almost working version for HanfTek UMT-010
-             - found out, that Yakumo/HAMA/Typhoon are predessors of the HanfTek UMT-010
-  2005-01-10 - refactoring completed, now everything is very delightful
-             - tuner quirks for some weird devices (Artec T1 AN2235 device has sometimes a
-               Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich.
-  2004-12-29 - after several days of struggling around bug of no returning URBs fixed.
-  2004-12-26 - refactored the dibusb-driver, splitted into separate files
-             - i2c-probing enabled
-  2004-12-06 - possibility for demod i2c-address probing
-             - new usb IDs (Compro,Artec)
-  2004-11-23 - merged changes from DiB3000MC_ver2.1
-             - revised the debugging
-             - possibility to deliver the complete TS for USB2.0
-  2004-11-21 - first working version of the dib3000mc/p frontend driver.
-  2004-11-12 - added additional remote control keys. Thanks to Uwe Hanke.
-  2004-11-07 - added remote control support. Thanks to David Matthews.
-  2004-11-05 - added support for a new devices (Grandtec/Avermedia/Artec)
-             - merged my changes (for dib3000mb/dibusb) to the FE_REFACTORING, because it became HEAD
-             - moved transfer control (pid filter, fifo control) from usb driver to frontend, it seems
-               better settled there (added xfer_ops-struct)
-             - created a common files for frontends (mc/p/mb)
-  2004-09-28 - added support for a new device (Unkown, vendor ID is Hyper-Paltek)
-  2004-09-20 - added support for a new device (Compro DVB-U2000), thanks
-               to Amaury Demol for reporting
-             - changed usb TS transfer method (several urbs, stopping transfer
-               before setting a new pid)
-  2004-09-13 - added support for a new device (Artec T1 USB TVBOX), thanks
-               to Christian Motschke for reporting
-  2004-09-05 - released the dibusb device and dib3000mb-frontend driver
-
-  (old news for vp7041.c)
-  2004-07-15 - found out, by accident, that the device has a TUA6010XS for
-               PLL
-  2004-07-12 - figured out, that the driver should also work with the
-               CTS Portable (Chinese Television System)
-  2004-07-08 - firmware-extraction-2.422-problem solved, driver is now working
-               properly with firmware extracted from 2.422
-                        - #if for 2.6.4 (dvb), compile issue
-                        - changed firmware handling, see vp7041.txt sec 1.1
-  2004-07-02 - some tuner modifications, v0.1, cleanups, first public
-  2004-06-28 - now using the dvb_dmx_swfilter_packets, everything
-               runs fine now
-  2004-06-27 - able to watch and switching channels (pre-alpha)
-             - no section filtering yet
-  2004-06-06 - first TS received, but kernel oops :/
-  2004-05-14 - firmware loader is working
-  2004-05-11 - start writing the driver
-
-1. How to use?
-NOTE: This driver was developed using Linux 2.6.6.,
-it is working with 2.6.7 and above.
-
-Linux 2.4.x support is not planned, but patches are very welcome.
-
-NOTE: I'm using Debian testing, so the following explaination (especially
-the hotplug-path) needn't match your system, but probably it will :).
-
-The driver is included in the kernel since Linux 2.6.10.
-
-1.1. Firmware
-
-The USB driver needs to download a firmware to start working.
-
-You can either use "get_dvb_firmware dibusb" to download the firmware or you
-can get it directly via
-
-for USB1.1 (AN2135)
-http://www.linuxtv.org/downloads/firmware/dvb-dibusb-5.0.0.11.fw
-
-for USB1.1 (AN2235) (a few Artec T1 devices)
-http://www.linuxtv.org/downloads/firmware/dvb-dibusb-an2235-1.fw
-
-for USB2.0 (FX2) Hauppauge, DiBcom
-http://www.linuxtv.org/downloads/firmware/dvb-dibusb-6.0.0.5.fw
-
-for USB2.0 ADSTech/Kworld USB2.0
-http://www.linuxtv.org/downloads/firmware/dvb-dibusb-adstech-usb2-1.fw
-
-for USB2.0 HanfTek
-http://www.linuxtv.org/downloads/firmware/dvb-dibusb-an2235-1.fw
-
-
-1.2. Compiling
-
-Since the driver is in the linux kernel, activating the driver in
-your favorite config-environment should sufficient. I recommend
-to compile the driver as module. Hotplug does the rest.
-
-1.3. Loading the drivers
-
-Hotplug is able to load the driver, when it is needed (because you plugged
-in the device).
-
-If you want to enable debug output, you have to load the driver manually and
-from withing the dvb-kernel cvs repository.
-
-first have a look, which debug level are available:
-
-modinfo dib3000mb
-modinfo dib3000-common
-modinfo dib3000mc
-modinfo dvb-dibusb
-
-modprobe dib3000-common debug=<level>
-modprobe dib3000mb debug=<level>
-modprobe dib3000mc debug=<level>
-modprobe dvb-dibusb debug=<level>
-
-should do the trick.
-
-When the driver is loaded successfully, the firmware file was in
-the right place and the device is connected, the "Power"-LED should be
-turned on.
-
-At this point you should be able to start a dvb-capable application. For myself
-I used mplayer, dvbscan, tzap and kaxtv, they are working. Using the device
-in vdr is working now also.
-
-2. Known problems and bugs
-
-- Don't remove the USB device while running an DVB application, your system will die.
-
-2.1. Adding support for devices
-
-It is not possible to determine the range of devices based on the DiBcom
-reference designs. This is because the reference design of DiBcom can be sold
-to thirds, without telling DiBcom (so done with the Twinhan VP7041 and
-the HAMA device).
-
-When you think you have a device like this and the driver does not recognizes it,
-please send the ****load*.inf and the ****cap*.inf of the Windows driver to me.
-
-Sometimes the Vendor or Product ID is identical to the ones of Twinhan, even
-though it is not a Twinhan device (e.g. HAMA), then please send me the name
-of the device. I will add it to this list in order to make this clear to
-others.
-
-If you are familar with C you can also add the VID and PID of the device to
-the dvb-dibusb-core.c-file and create a patch and send it over to me or to
-the linux-dvb mailing list, _after_ you have tried compiling and modprobing
-it.
-
-2.2. USB1.1 Bandwidth limitation
-
-Most of the currently supported devices are USB1.1 and thus they have a
-maximum bandwidth of about 5-6 MBit/s when connected to a USB2.0 hub.
-This is not enough for receiving the complete transport stream of a
-DVB-T channel (which can be about 16 MBit/s). Normally this is not a
-problem, if you only want to watch TV (this does not apply for HDTV),
-but watching a channel while recording another channel on the same
-frequency simply does not work very well. This applies to all USB1.1
-DVB-T devices, not just dibusb)
-
-Update: For the USB1.1 and VDR some work has been done (patches and comments
-are still very welcome). Maybe the problem is solved in the meantime because I
-now use the dmx_sw_filter function instead of dmx_sw_filter_packet. I hope the
-linux-dvb software filter is able to get the best of the garbled TS.
-
-The bug, where the TS is distorted by a heavy usage of the device is gone
-definitely. All dibusb-devices I was using (Twinhan, Kworld, DiBcom) are
-working like charm now with VDR. Sometimes I even was able to record a channel
-and watch another one.
-
-2.3. Comments
-
-Patches, comments and suggestions are very very welcome.
-
-3. Acknowledgements
-       Amaury Demol (ademol@dibcom.fr) and Francois Kanounnikoff from DiBcom for
-    providing specs, code and help, on which the dvb-dibusb, dib3000mb and
-    dib3000mc are based.
-
-   David Matthews for identifying a new device type (Artec T1 with AN2235)
-    and for extending dibusb with remote control event handling. Thank you.
-
-   Alex Woods for frequently answering question about usb and dvb
-    stuff, a big thank you.
-
-   Bernd Wagner for helping with huge bug reports and discussions.
-
-   Gunnar Wittich and Joachim von Caron for their trust for giving me
-    root-shells on their machines to implement support for new devices.
-
-   Some guys on the linux-dvb mailing list for encouraging me
-
-   Peter Schildmann >peter.schildmann-nospam-at-web.de< for his
-    user-level firmware loader, which saves a lot of time
-    (when writing the vp7041 driver)
-
-   Ulf Hermenau for helping me out with traditional chinese.
-
-   André Smoktun and Christian Frömmel for supporting me with
-    hardware and listening to my problems very patient
diff --git a/Documentation/dvb/README.dvb-usb b/Documentation/dvb/README.dvb-usb
new file mode 100644 (file)
index 0000000..c7ed01b
--- /dev/null
@@ -0,0 +1,308 @@
+Documentation for dvb-usb-framework module and its devices
+
+Idea behind the dvb-usb-framework
+=================================
+
+In March 2005 I got the new Twinhan USB2.0 DVB-T device. They provided specs and a firmware.
+
+Quite keen I wanted to put the driver (with some quirks of course) into dibusb.
+After reading some specs and doing some USB snooping, it realized, that the
+dibusb-driver would be a complete mess afterwards. So I decided to do it in a
+different way: With the help of a dvb-usb-framework.
+
+The framework provides generic functions (mostly kernel API calls), such as:
+
+- Transport Stream URB handling in conjunction with dvb-demux-feed-control
+  (bulk and isoc (TODO) are supported)
+- registering the device for the DVB-API
+- registering an I2C-adapter if applicable
+- remote-control/input-device handling
+- firmware requesting and loading (currently just for the Cypress USB
+  controller)
+- other functions/methods which can be shared by several drivers (such as
+  functions for bulk-control-commands)
+
+The source code of the particular DVB USB devices does just the communication
+with the device via the bus. The connection between the DVB-API-functionality
+is done via callbacks, assigned in a static device-description (struct
+dvb_usb_device) each device-driver has to have.
+
+For an example have a look in drivers/media/dvb/dvb-usb/vp7045*.
+
+Objective is to migrate all the usb-devices (dibusb, cinergyT2, maybe the
+ttusb; flexcop-usb already benefits from the generic flexcop-device) to use
+the dvb-usb-lib.
+
+TODO: dynamic enabling and disabling of the pid-filter in regard to number of
+feeds requested.
+
+Supported devices USB1.1
+========================
+
+Produced and reselled by Twinhan:
+---------------------------------
+- TwinhanDTV USB-Ter DVB-T Device (VP7041)
+       http://www.twinhan.com/product_terrestrial_3.asp
+
+- TwinhanDTV Magic Box (VP7041e)
+       http://www.twinhan.com/product_terrestrial_4.asp
+
+- HAMA DVB-T USB device
+       http://www.hama.de/portal/articleId*110620/action*2598
+
+- CTS Portable (Chinese Television System) (2)
+       http://www.2cts.tv/ctsportable/
+
+- Unknown USB DVB-T device with vendor ID Hyper-Paltek
+
+
+Produced and reselled by KWorld:
+--------------------------------
+- KWorld V-Stream XPERT DTV DVB-T USB
+       http://www.kworld.com.tw/en/product/DVBT-USB/DVBT-USB.html
+
+- JetWay DTV DVB-T USB
+       http://www.jetway.com.tw/evisn/product/lcd-tv/DVT-USB/dtv-usb.htm
+
+- ADSTech Instant TV DVB-T USB
+       http://www.adstech.com/products/PTV-333/intro/PTV-333_intro.asp?pid=PTV-333
+
+
+Others:
+-------
+- Ultima Electronic/Artec T1 USB TVBOX (AN2135, AN2235, AN2235 with Panasonic Tuner)
+       http://82.161.246.249/products-tvbox.html
+
+- Compro Videomate DVB-U2000 - DVB-T USB (2)
+       http://www.comprousa.com/products/vmu2000.htm
+
+- Grandtec USB DVB-T
+       http://www.grand.com.tw/
+
+- AVerMedia AverTV DVBT USB
+       http://www.avermedia.com/
+
+- DiBcom USB DVB-T reference device (non-public)
+
+
+Supported devices USB2.0-only
+=============================
+- Twinhan MagicBox II
+       http://www.twinhan.com/product_terrestrial_7.asp
+
+- TwinhanDTV Alpha
+       http://www.twinhan.com/product_terrestrial_8.asp
+
+- DigitalNow TinyUSB 2 DVB-t Receiver
+       http://www.digitalnow.com.au/DigitalNow%20tinyUSB2%20Specifications.html
+
+- Hanftek UMT-010
+       http://www.globalsources.com/si/6008819757082/ProductDetail/Digital-TV/product_id-100046529
+
+
+Supported devices USB2.0 and USB1.1
+=============================
+- Typhoon/Yakumo/HAMA/Yuan DVB-T mobile USB2.0
+       http://www.yakumo.de/produkte/index.php?pid=1&ag=DVB-T
+       http://www.yuan.com.tw/en/products/vdo_ub300.html
+       http://www.hama.de/portal/articleId*114663/action*2563
+       http://www.anubisline.com/english/articlec.asp?id=50502&catid=002
+
+- Artec T1 USB TVBOX (FX2) (2)
+
+- Hauppauge WinTV NOVA-T USB2
+       http://www.hauppauge.com/
+
+- KWorld/ADSTech Instant DVB-T USB2.0 (DiB3000M-B)
+
+- DiBcom USB2.0 DVB-T reference device (non-public)
+
+- AVerMedia AverTV A800 DVB-T USB2.0
+
+1) It is working almost - work-in-progress.
+2) No test reports received yet.
+
+0. History & News:
+  2005-04-17 - all dibusb devices ported to make use of the dvb-usb-framework
+  2005-04-02 - re-enabled and improved remote control code.
+  2005-03-31 - ported the Yakumo/Hama/Typhoon DVB-T USB2.0 device to dvb-usb.
+  2005-03-30 - first commit of the dvb-usb-module based on the dibusb-source. First device is a new driver for the
+               TwinhanDTV Alpha / MagicBox II USB2.0-only DVB-T device.
+
+  (change from dvb-dibusb to dvb-usb)
+  2005-03-28 - added support for the AVerMedia AverTV DVB-T USB2.0 device (Thanks to Glen Harris and Jiun-Kuei Jung, AVerMedia)
+  2005-03-14 - added support for the Typhoon/Yakumo/HAMA DVB-T mobile USB2.0
+  2005-02-11 - added support for the KWorld/ADSTech Instant DVB-T USB2.0. Thanks a lot to Joachim von Caron
+  2005-02-02 - added support for the Hauppauge Win-TV Nova-T USB2
+  2005-01-31 - distorted streaming is gone for USB1.1 devices
+  2005-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb
+             - first almost working version for HanfTek UMT-010
+             - found out, that Yakumo/HAMA/Typhoon are predessors of the HanfTek UMT-010
+  2005-01-10 - refactoring completed, now everything is very delightful
+             - tuner quirks for some weird devices (Artec T1 AN2235 device has sometimes a
+               Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich.
+  2004-12-29 - after several days of struggling around bug of no returning URBs fixed.
+  2004-12-26 - refactored the dibusb-driver, splitted into separate files
+             - i2c-probing enabled
+  2004-12-06 - possibility for demod i2c-address probing
+             - new usb IDs (Compro, Artec)
+  2004-11-23 - merged changes from DiB3000MC_ver2.1
+             - revised the debugging
+             - possibility to deliver the complete TS for USB2.0
+  2004-11-21 - first working version of the dib3000mc/p frontend driver.
+  2004-11-12 - added additional remote control keys. Thanks to Uwe Hanke.
+  2004-11-07 - added remote control support. Thanks to David Matthews.
+  2004-11-05 - added support for a new devices (Grandtec/Avermedia/Artec)
+             - merged my changes (for dib3000mb/dibusb) to the FE_REFACTORING, because it became HEAD
+             - moved transfer control (pid filter, fifo control) from usb driver to frontend, it seems
+               better settled there (added xfer_ops-struct)
+             - created a common files for frontends (mc/p/mb)
+  2004-09-28 - added support for a new device (Unkown, vendor ID is Hyper-Paltek)
+  2004-09-20 - added support for a new device (Compro DVB-U2000), thanks
+               to Amaury Demol for reporting
+             - changed usb TS transfer method (several urbs, stopping transfer
+               before setting a new pid)
+  2004-09-13 - added support for a new device (Artec T1 USB TVBOX), thanks
+               to Christian Motschke for reporting
+  2004-09-05 - released the dibusb device and dib3000mb-frontend driver
+
+  (old news for vp7041.c)
+  2004-07-15 - found out, by accident, that the device has a TUA6010XS for
+               PLL
+  2004-07-12 - figured out, that the driver should also work with the
+               CTS Portable (Chinese Television System)
+  2004-07-08 - firmware-extraction-2.422-problem solved, driver is now working
+               properly with firmware extracted from 2.422
+             - #if for 2.6.4 (dvb), compile issue
+             - changed firmware handling, see vp7041.txt sec 1.1
+  2004-07-02 - some tuner modifications, v0.1, cleanups, first public
+  2004-06-28 - now using the dvb_dmx_swfilter_packets, everything
+               runs fine now
+  2004-06-27 - able to watch and switching channels (pre-alpha)
+             - no section filtering yet
+  2004-06-06 - first TS received, but kernel oops :/
+  2004-05-14 - firmware loader is working
+  2004-05-11 - start writing the driver
+
+1. How to use?
+1.1. Firmware
+
+Most of the USB drivers need to download a firmware to start working.
+
+for USB1.1 (AN2135) you need: dvb-usb-dibusb-5.0.0.11.fw
+for USB2.0 HanfTek: dvb-usb-umt-010-02.fw
+for USB2.0 DiBcom: dvb-usb-dibusb-6.0.0.8.fw
+for USB2.0 AVerMedia AverTV DVB-T USB2: dvb-usb-avertv-a800-01.fw
+for USB2.0 TwinhanDTV Alpha/MagicBox II: dvb-usb-vp7045-01.fw
+
+The files can be found on http://www.linuxtv.org/download/firmware/ .
+
+We do not have the permission (yet) to publish the following firmware-files.
+You'll need to extract them from the windows drivers.
+
+You should be able to use "get_dvb_firmware dvb-usb" to get the firmware:
+
+for USB1.1 (AN2235) (a few Artec T1 devices): dvb-usb-dibusb-an2235-01.fw
+for USB2.0 Hauppauge: dvb-usb-nova-t-usb2-01.fw
+for USB2.0 ADSTech/Kworld USB2.0: dvb-usb-adstech-usb2-01.fw
+for USB2.0 Yakumo/Typhoon/Hama: dvb-usb-dtt200u-01.fw
+
+1.2. Compiling
+
+Since the driver is in the linux kernel, activating the driver in
+your favorite config-environment should sufficient. I recommend
+to compile the driver as module. Hotplug does the rest.
+
+If you use dvb-kernel enter the build-2.6 directory run 'make' and 'insmod.sh
+load' afterwards.
+
+1.3. Loading the drivers
+
+Hotplug is able to load the driver, when it is needed (because you plugged
+in the device).
+
+If you want to enable debug output, you have to load the driver manually and
+from withing the dvb-kernel cvs repository.
+
+first have a look, which debug level are available:
+
+modinfo dvb-usb
+modinfo dvb-usb-vp7045
+etc.
+
+modprobe dvb-usb debug=<level>
+modprobe dvb-usb-vp7045 debug=<level>
+etc.
+
+should do the trick.
+
+When the driver is loaded successfully, the firmware file was in
+the right place and the device is connected, the "Power"-LED should be
+turned on.
+
+At this point you should be able to start a dvb-capable application. I'm use
+(t|s)zap, mplayer and dvbscan to test the basics. VDR-xine provides the
+long-term test scenario.
+
+2. Known problems and bugs
+
+- Don't remove the USB device while running an DVB application, your system
+  will go crazy or die most likely.
+
+2.1. Adding support for devices
+
+TODO
+
+2.2. USB1.1 Bandwidth limitation
+
+A lot of the currently supported devices are USB1.1 and thus they have a
+maximum bandwidth of about 5-6 MBit/s when connected to a USB2.0 hub.
+This is not enough for receiving the complete transport stream of a
+DVB-T channel (which is about 16 MBit/s). Normally this is not a
+problem, if you only want to watch TV (this does not apply for HDTV),
+but watching a channel while recording another channel on the same
+frequency simply does not work very well. This applies to all USB1.1
+DVB-T devices, not just the dvb-usb-devices)
+
+The bug, where the TS is distorted by a heavy usage of the device is gone
+definitely. All dvb-usb-devices I was using (Twinhan, Kworld, DiBcom) are
+working like charm now with VDR. Sometimes I even was able to record a channel
+and watch another one.
+
+2.3. Comments
+
+Patches, comments and suggestions are very very welcome.
+
+3. Acknowledgements
+   Amaury Demol (ademol@dibcom.fr) and Francois Kanounnikoff from DiBcom for
+    providing specs, code and help, on which the dvb-dibusb, dib3000mb and
+    dib3000mc are based.
+
+   David Matthews for identifying a new device type (Artec T1 with AN2235)
+    and for extending dibusb with remote control event handling. Thank you.
+
+   Alex Woods for frequently answering question about usb and dvb
+    stuff, a big thank you.
+
+   Bernd Wagner for helping with huge bug reports and discussions.
+
+   Gunnar Wittich and Joachim von Caron for their trust for providing
+    root-shells on their machines to implement support for new devices.
+
+   Glen Harris for bringing up, that there is a new dibusb-device and Jiun-Kuei
+    Jung from AVerMedia who kindly provided a special firmware to get the device
+    up and running in Linux.
+
+   Jennifer Chen, Jeff and Jack from Twinhan for kindly supporting by
+       writing the vp7045-driver.
+
+   Some guys on the linux-dvb mailing list for encouraging me
+
+   Peter Schildmann >peter.schildmann-nospam-at-web.de< for his
+    user-level firmware loader, which saves a lot of time
+    (when writing the vp7041 driver)
+
+   Ulf Hermenau for helping me out with traditional chinese.
+
+   André Smoktun and Christian Frömmel for supporting me with
+    hardware and listening to my problems very patient.
index d64430bf4bb6ec5d681c2f7c30cc71905a72bd67..3a326079475864fa8637ab7e998fbbec89fd9416 100644 (file)
@@ -44,26 +44,23 @@ TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver.
    $ modprobe dst
 
 The value 0x71 will override the PCI type detection for dvb-bt8xx,
-which  is necessary for TwinHan cards.
+which is necessary for TwinHan cards.
 
 If you're having an older card (blue color circuit) and card=0x71 locks
 your machine, try using 0x68, too. If that does not work, ask on the
 mailing list.
 
-The DST module takes a couple of useful parameters.
+The DST module takes a couple of useful parameters:
 
-verbose takes values 0 to 5. These values control the verbosity level.
-
-debug takes values 0 and 1. You can either disable or enable debugging.
-
-dst_addons takes values 0 and 0x20. A value of 0 means it is a FTA card.
-0x20 means it has a Conditional Access slot.
-
-The autodected values are determined bythe cards 'response
-string' which you can see in your logs e.g.
-
-dst_get_device_id: Recognise [DSTMCI]
+a. verbose takes values 0 to 5. These values control the verbosity level.
+b. debug takes values 0 and 1. You can either disable or enable debugging.
+c. dst_addons takes values 0 and 0x20:
+- A value of 0 means it is a FTA card.
+- A value of 0x20 means it has a Conditional Access slot.
 
+The autodetected values are determined by the "response string"
+of the card, which you can see in your logs:
+e.g.: dst_get_device_id: Recognize [DSTMCI]
 
 --
-Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham
+Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham, Uwe Bugla
index 77511af453625bb959c132f5723f718b8e94c41c..1d227ee3792a1f704c7b505486e50985cf7fd8b5 100644 (file)
@@ -43,6 +43,14 @@ Who: Randy Dunlap <rddunlap@osdl.org>
 
 ---------------------------
 
+What:  RAW driver (CONFIG_RAW_DRIVER)
+When:  December 2005
+Why:   declared obsolete since kernel 2.6.3
+       O_DIRECT can be used instead
+Who:   Adrian Bunk <bunk@stusta.de>
+
+---------------------------
+
 What:  register_ioctl32_conversion() / unregister_ioctl32_conversion()
 When:  April 2005
 Why:   Replaced by ->compat_ioctl in file_operations and other method
index b5cb9110cc6b9d8d9db01c69d66a1f78ce4f0d89..d16334ec48ba02cc719d9072dd800f12d9ed17cb 100644 (file)
@@ -58,6 +58,8 @@ noacl                         Don't support POSIX ACLs.
 
 nobh                           Do not attach buffer_heads to file pagecache.
 
+xip                            Use execute in place (no caching) if possible
+
 grpquota,noquota,quota,usrquota        Quota options are silently ignored by ext2.
 
 
diff --git a/Documentation/filesystems/xip.txt b/Documentation/filesystems/xip.txt
new file mode 100644 (file)
index 0000000..6c0cef1
--- /dev/null
@@ -0,0 +1,67 @@
+Execute-in-place for file mappings
+----------------------------------
+
+Motivation
+----------
+File mappings are performed by mapping page cache pages to userspace. In
+addition, read&write type file operations also transfer data from/to the page
+cache.
+
+For memory backed storage devices that use the block device interface, the page
+cache pages are in fact copies of the original storage. Various approaches
+exist to work around the need for an extra copy. The ramdisk driver for example
+does read the data into the page cache, keeps a reference, and discards the
+original data behind later on.
+
+Execute-in-place solves this issue the other way around: instead of keeping
+data in the page cache, the need to have a page cache copy is eliminated
+completely. With execute-in-place, read&write type operations are performed
+directly from/to the memory backed storage device. For file mappings, the
+storage device itself is mapped directly into userspace.
+
+This implementation was initialy written for shared memory segments between
+different virtual machines on s390 hardware to allow multiple machines to
+share the same binaries and libraries.
+
+Implementation
+--------------
+Execute-in-place is implemented in three steps: block device operation,
+address space operation, and file operations.
+
+A block device operation named direct_access is used to retrieve a
+reference (pointer) to a block on-disk. The reference is supposed to be
+cpu-addressable, physical address and remain valid until the release operation
+is performed. A struct block_device reference is used to address the device,
+and a sector_t argument is used to identify the individual block. As an
+alternative, memory technology devices can be used for this.
+
+The block device operation is optional, these block devices support it as of
+today:
+- dcssblk: s390 dcss block device driver
+
+An address space operation named get_xip_page is used to retrieve reference
+to a struct page. To address the target page, a reference to an address_space,
+and a sector number is provided. A 3rd argument indicates whether the
+function should allocate blocks if needed.
+
+This address space operation is mutually exclusive with readpage&writepage that
+do page cache read/write operations.
+The following filesystems support it as of today:
+- ext2: the second extended filesystem, see Documentation/filesystems/ext2.txt
+
+A set of file operations that do utilize get_xip_page can be found in
+mm/filemap_xip.c . The following file operation implementations are provided:
+- aio_read/aio_write
+- readv/writev
+- sendfile
+
+The generic file operations do_sync_read/do_sync_write can be used to implement
+classic synchronous IO calls.
+
+Shortcomings
+------------
+This implementation is limited to storage devices that are cpu addressable at
+all times (no highmem or such). It works well on rom/ram, but enhancements are
+needed to make it work with flash in read+write mode.
+Putting the Linux kernel and/or its modules on a xip filesystem does not mean
+they are not copied.
diff --git a/Documentation/kdump/gdbmacros.txt b/Documentation/kdump/gdbmacros.txt
new file mode 100644 (file)
index 0000000..bc1b9eb
--- /dev/null
@@ -0,0 +1,179 @@
+#
+# This file contains a few gdb macros (user defined commands) to extract
+# useful information from kernel crashdump (kdump) like stack traces of
+# all the processes or a particular process and trapinfo.
+#
+# These macros can be used by copying this file in .gdbinit (put in home
+# directory or current directory) or by invoking gdb command with
+# --command=<command-file-name> option
+#
+# Credits:
+# Alexander Nyberg <alexn@telia.com>
+# V Srivatsa <vatsa@in.ibm.com>
+# Maneesh Soni <maneesh@in.ibm.com>
+#
+
+define bttnobp
+       set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
+       set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next)
+       set $init_t=&init_task
+       set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
+       while ($next_t != $init_t)
+               set $next_t=(struct task_struct *)$next_t
+               printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
+               printf "===================\n"
+               set var $stackp = $next_t.thread.esp
+               set var $stack_top = ($stackp & ~4095) + 4096
+
+               while ($stackp < $stack_top)
+                       if (*($stackp) > _stext && *($stackp) < _sinittext)
+                               info symbol *($stackp)
+                       end
+                       set $stackp += 4
+               end
+               set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off)
+               while ($next_th != $next_t)
+                       set $next_th=(struct task_struct *)$next_th
+                       printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
+                       printf "===================\n"
+                       set var $stackp = $next_t.thread.esp
+                       set var $stack_top = ($stackp & ~4095) + 4096
+
+                       while ($stackp < $stack_top)
+                               if (*($stackp) > _stext && *($stackp) < _sinittext)
+                                       info symbol *($stackp)
+                               end
+                               set $stackp += 4
+                       end
+                       set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off)
+               end
+               set $next_t=(char *)($next_t->tasks.next) - $tasks_off
+       end
+end
+document bttnobp
+       dump all thread stack traces on a kernel compiled with !CONFIG_FRAME_POINTER
+end
+
+define btt
+       set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
+       set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next)
+       set $init_t=&init_task
+       set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
+       while ($next_t != $init_t)
+               set $next_t=(struct task_struct *)$next_t
+               printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
+               printf "===================\n"
+               set var $stackp = $next_t.thread.esp
+               set var $stack_top = ($stackp & ~4095) + 4096
+               set var $stack_bot = ($stackp & ~4095)
+
+               set $stackp = *($stackp)
+               while (($stackp < $stack_top) && ($stackp > $stack_bot))
+                       set var $addr = *($stackp + 4)
+                       info symbol $addr
+                       set $stackp = *($stackp)
+               end
+
+               set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off)
+               while ($next_th != $next_t)
+                       set $next_th=(struct task_struct *)$next_th
+                       printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
+                       printf "===================\n"
+                       set var $stackp = $next_t.thread.esp
+                       set var $stack_top = ($stackp & ~4095) + 4096
+                       set var $stack_bot = ($stackp & ~4095)
+
+                       set $stackp = *($stackp)
+                       while (($stackp < $stack_top) && ($stackp > $stack_bot))
+                               set var $addr = *($stackp + 4)
+                               info symbol $addr
+                               set $stackp = *($stackp)
+                       end
+                       set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off)
+               end
+               set $next_t=(char *)($next_t->tasks.next) - $tasks_off
+       end
+end
+document btt
+       dump all thread stack traces on a kernel compiled with CONFIG_FRAME_POINTER
+end
+
+define btpid
+       set var $pid = $arg0
+       set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
+       set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next)
+       set $init_t=&init_task
+       set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
+       set var $pid_task = 0
+
+       while ($next_t != $init_t)
+               set $next_t=(struct task_struct *)$next_t
+
+               if ($next_t.pid == $pid)
+                       set $pid_task = $next_t
+               end
+
+               set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off)
+               while ($next_th != $next_t)
+                       set $next_th=(struct task_struct *)$next_th
+                       if ($next_th.pid == $pid)
+                               set $pid_task = $next_th
+                       end
+                       set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off)
+               end
+               set $next_t=(char *)($next_t->tasks.next) - $tasks_off
+       end
+
+       printf "\npid %d; comm %s:\n", $pid_task.pid, $pid_task.comm
+       printf "===================\n"
+       set var $stackp = $pid_task.thread.esp
+       set var $stack_top = ($stackp & ~4095) + 4096
+       set var $stack_bot = ($stackp & ~4095)
+
+       set $stackp = *($stackp)
+       while (($stackp < $stack_top) && ($stackp > $stack_bot))
+               set var $addr = *($stackp + 4)
+               info symbol $addr
+               set $stackp = *($stackp)
+       end
+end
+document btpid
+       backtrace of pid
+end
+
+
+define trapinfo
+       set var $pid = $arg0
+       set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
+       set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next)
+       set $init_t=&init_task
+       set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
+       set var $pid_task = 0
+
+       while ($next_t != $init_t)
+               set $next_t=(struct task_struct *)$next_t
+
+               if ($next_t.pid == $pid)
+                       set $pid_task = $next_t
+               end
+
+               set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off)
+               while ($next_th != $next_t)
+                       set $next_th=(struct task_struct *)$next_th
+                       if ($next_th.pid == $pid)
+                               set $pid_task = $next_th
+                       end
+                       set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off)
+               end
+               set $next_t=(char *)($next_t->tasks.next) - $tasks_off
+       end
+
+       printf "Trapno %ld, cr2 0x%lx, error_code %ld\n", $pid_task.thread.trap_no, \
+                               $pid_task.thread.cr2, $pid_task.thread.error_code
+
+end
+document trapinfo
+       Run info threads and lookup pid of thread #1
+       'trapinfo <pid>' will tell you by which trap & possibly
+       addresthe kernel paniced.
+end
diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt
new file mode 100644 (file)
index 0000000..7ff213f
--- /dev/null
@@ -0,0 +1,141 @@
+Documentation for kdump - the kexec-based crash dumping solution
+================================================================
+
+DESIGN
+======
+
+Kdump uses kexec to reboot to a second kernel whenever a dump needs to be taken.
+This second kernel is booted with very little memory. The first kernel reserves
+the section of memory that the second kernel uses. This ensures that on-going
+DMA from the first kernel does not corrupt the second kernel.
+
+All the necessary information about Core image is encoded in ELF format and
+stored in reserved area of memory before crash. Physical address of start of
+ELF header is passed to new kernel through command line parameter elfcorehdr=.
+
+On i386, the first 640 KB of physical memory is needed to boot, irrespective
+of where the kernel loads. Hence, this region is backed up by kexec just before
+rebooting into the new kernel.
+
+In the second kernel, "old memory" can be accessed in two ways.
+
+- The first one is through a /dev/oldmem device interface. A capture utility
+  can read the device file and write out the memory in raw format. This is raw
+  dump of memory and analysis/capture tool should be intelligent enough to
+  determine where to look for the right information. ELF headers (elfcorehdr=)
+  can become handy here.
+
+- The second interface is through /proc/vmcore. This exports the dump as an ELF
+  format file which can be written out using any file copy command
+  (cp, scp, etc). Further, gdb can be used to perform limited debugging on
+  the dump file. This method ensures methods ensure that there is correct
+  ordering of the dump pages (corresponding to the first 640 KB that has been
+  relocated).
+
+SETUP
+=====
+
+1) Download http://www.xmission.com/~ebiederm/files/kexec/kexec-tools-1.101.tar.gz
+   and apply http://lse.sourceforge.net/kdump/patches/kexec-tools-1.101-kdump.patch
+   and after that build the source.
+
+2) Download and build the appropriate (latest) kexec/kdump (-mm) kernel
+   patchset and apply it to the vanilla kernel tree.
+
+   Two kernels need to be built in order to get this feature working.
+
+  A) First kernel:
+   a) Enable "kexec system call" feature (in Processor type and features).
+       CONFIG_KEXEC=y
+   b) This kernel's physical load address should be the default value of
+      0x100000 (0x100000, 1 MB) (in Processor type and features).
+       CONFIG_PHYSICAL_START=0x100000
+   c) Enable "sysfs file system support" (in Pseudo filesystems).
+       CONFIG_SYSFS=y
+   d) Boot into first kernel with the command line parameter "crashkernel=Y@X".
+      Use appropriate values for X and Y. Y denotes how much memory to reserve
+      for the second kernel, and X denotes at what physical address the reserved
+      memory section starts. For example: "crashkernel=64M@16M".
+
+  B) Second kernel:
+   a) Enable "kernel crash dumps" feature (in Processor type and features).
+       CONFIG_CRASH_DUMP=y
+   b) Specify a suitable value for "Physical address where the kernel is
+      loaded" (in Processor type and features). Typically this value
+      should be same as X (See option d) above, e.g., 16 MB or 0x1000000.
+       CONFIG_PHYSICAL_START=0x1000000
+   c) Enable "/proc/vmcore support" (Optional, in Pseudo filesystems).
+       CONFIG_PROC_VMCORE=y
+   d) Disable SMP support and build a UP kernel (Until it is fixed).
+       CONFIG_SMP=n
+   e) Enable "Local APIC support on uniprocessors".
+       CONFIG_X86_UP_APIC=y
+   f) Enable "IO-APIC support on uniprocessors"
+       CONFIG_X86_UP_IOAPIC=y
+
+  Note:   i) Options a) and b) depend upon "Configure standard kernel features
+            (for small systems)" (under General setup).
+        ii) Option a) also depends on CONFIG_HIGHMEM (under Processor
+               type and features).
+       iii) Both option a) and b) are under "Processor type and features".
+
+3) Boot into the first kernel. You are now ready to try out kexec-based crash
+   dumps.
+
+4) Load the second kernel to be booted using:
+
+   kexec -p <second-kernel> --crash-dump --args-linux --append="root=<root-dev>
+   init 1 irqpoll"
+
+   Note: i) <second-kernel> has to be a vmlinux image. bzImage will not work,
+           as of now.
+       ii) By default ELF headers are stored in ELF32 format (for i386). This
+           is sufficient to represent the physical memory up to 4GB. To store
+           headers in ELF64 format, specifiy "--elf64-core-headers" on the
+           kexec command line additionally.
+       iii) Specify "irqpoll" as command line parameter. This reduces driver
+            initialization failures in second kernel due to shared interrupts.
+
+5) System reboots into the second kernel when a panic occurs. A module can be
+   written to force the panic or "ALT-SysRq-c" can be used initiate a crash
+   dump for testing purposes.
+
+6) Write out the dump file using
+
+   cp /proc/vmcore <dump-file>
+
+   Dump memory can also be accessed as a /dev/oldmem device for a linear/raw
+   view.  To create the device, type:
+
+   mknod /dev/oldmem c 1 12
+
+   Use "dd" with suitable options for count, bs and skip to access specific
+   portions of the dump.
+
+   Entire memory:  dd if=/dev/oldmem of=oldmem.001
+
+ANALYSIS
+========
+
+Limited analysis can be done using gdb on the dump file copied out of
+/proc/vmcore. Use vmlinux built with -g and run
+
+  gdb vmlinux <dump-file>
+
+Stack trace for the task on processor 0, register display, memory display
+work fine.
+
+Note: gdb cannot analyse core files generated in ELF64 format for i386.
+
+TODO
+====
+
+1) Provide a kernel pages filtering mechanism so that core file size is not
+   insane on systems having huge memory banks.
+2) Modify "crash" tool to make it recognize this dump.
+
+CONTACT
+=======
+
+Vivek Goyal (vgoyal@in.ibm.com)
+Maneesh Soni (maneesh@in.ibm.com)
index 4924d387a6573223e9877b56d4d28219f9f650b2..4ec75c06bca4b0945b856582ebcd9d84f4c368f8 100644 (file)
@@ -358,6 +358,10 @@ running once the system is up.
        cpia_pp=        [HW,PPT]
                        Format: { parport<nr> | auto | none }
 
+       crashkernel=nn[KMG]@ss[KMG]
+                       [KNL] Reserve a chunk of physical memory to
+                       hold a kernel to switch to with kexec on panic.
+
        cs4232=         [HW,OSS]
                        Format: <io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>
 
@@ -447,6 +451,10 @@ running once the system is up.
                        Format: {"as"|"cfq"|"deadline"|"noop"}
                        See Documentation/block/as-iosched.txt
                        and Documentation/block/deadline-iosched.txt for details.
+       elfcorehdr=     [IA-32]
+                       Specifies physical address of start of kernel core image
+                       elf header.
+                       See Documentation/kdump.txt for details.
 
        enforcing       [SELINUX] Set initial enforcing status.
                        Format: {"0" | "1"}
@@ -548,6 +556,9 @@ running once the system is up.
 
        i810=           [HW,DRM]
 
+       i8k.ignore_dmi  [HW] Continue probing hardware even if DMI data
+                       indicates that the driver is running on unsupported
+                       hardware.
        i8k.force       [HW] Activate i8k driver even if SMM BIOS signature
                        does not match list of supported models.
        i8k.power_status
@@ -611,6 +622,17 @@ running once the system is up.
        ips=            [HW,SCSI] Adaptec / IBM ServeRAID controller
                        See header of drivers/scsi/ips.c.
 
+       irqfixup        [HW]
+                       When an interrupt is not handled search all handlers
+                       for it. Intended to get systems with badly broken
+                       firmware running.
+
+       irqpoll         [HW]
+                       When an interrupt is not handled search all handlers
+                       for it. Also check all handlers each timer
+                       interrupt. Intended to get systems with badly broken
+                       firmware running.
+
        isapnp=         [ISAPNP]
                        Format: <RDP>, <reset>, <pci_scan>, <verbosity>
 
@@ -1019,6 +1041,10 @@ running once the system is up.
                irqmask=0xMMMM          [IA-32] Set a bit mask of IRQs allowed to be assigned
                                        automatically to PCI devices. You can make the kernel
                                        exclude IRQs of your ISA cards this way.
+               pirqaddr=0xAAAAA        [IA-32] Specify the physical address
+                                       of the PIRQ table (normally generated
+                                       by the BIOS) if it is outside the
+                                       F0000h-100000h range.
                lastbus=N               [IA-32] Scan all buses till bus #N. Can be useful
                                        if the kernel is unable to find your secondary buses
                                        and you want to tell it explicitly which ones they are.
@@ -1104,7 +1130,7 @@ running once the system is up.
                        See Documentation/ramdisk.txt.
 
        psmouse.proto=  [HW,MOUSE] Highest PS2 mouse protocol extension to
-                       probe for (bare|imps|exps).
+                       probe for (bare|imps|exps|lifebook|any).
        psmouse.rate=   [HW,MOUSE] Set desired mouse report rate, in reports
                        per second.
        psmouse.resetafter=
index 36d80aeeaf28ca763584bb92240198abe1b5b44e..0321ded4b9ae2df9b8dc469f8e8aa1dd5c216da8 100644 (file)
@@ -22,6 +22,7 @@ This document has the following sections:
        - New procfs files
        - Userspace system call interface
        - Kernel services
+       - Notes on accessing payload contents
        - Defining a key type
        - Request-key callback service
        - Key access filesystem
@@ -45,27 +46,26 @@ Each key has a number of attributes:
        - State.
 
 
- (*) Each key is issued a serial number of type key_serial_t that is unique
-     for the lifetime of that key. All serial numbers are positive non-zero
-     32-bit integers.
+ (*) Each key is issued a serial number of type key_serial_t that is unique for
+     the lifetime of that key. All serial numbers are positive non-zero 32-bit
+     integers.
 
      Userspace programs can use a key's serial numbers as a way to gain access
      to it, subject to permission checking.
 
  (*) Each key is of a defined "type". Types must be registered inside the
-     kernel by a kernel service (such as a filesystem) before keys of that
-     type can be added or used. Userspace programs cannot define new types
-     directly.
+     kernel by a kernel service (such as a filesystem) before keys of that type
+     can be added or used. Userspace programs cannot define new types directly.
 
-     Key types are represented in the kernel by struct key_type. This defines
-     number of operations that can be performed on a key of that type.
+     Key types are represented in the kernel by struct key_type. This defines a
+     number of operations that can be performed on a key of that type.
 
      Should a type be removed from the system, all the keys of that type will
      be invalidated.
 
  (*) Each key has a description. This should be a printable string. The key
-     type provides an operation to perform a match between the description on
-     key and a criterion string.
+     type provides an operation to perform a match between the description on a
+     key and a criterion string.
 
  (*) Each key has an owner user ID, a group ID and a permissions mask. These
      are used to control what a process may do to a key from userspace, and
@@ -74,10 +74,10 @@ Each key has a number of attributes:
  (*) Each key can be set to expire at a specific time by the key type's
      instantiation function. Keys can also be immortal.
 
- (*) Each key can have a payload. This is a quantity of data that represent
-     the actual "key". In the case of a keyring, this is a list of keys to
-     which the keyring links; in the case of a user-defined key, it's an
-     arbitrary blob of data.
+ (*) Each key can have a payload. This is a quantity of data that represent the
+     actual "key". In the case of a keyring, this is a list of keys to which
+     the keyring links; in the case of a user-defined key, it's an arbitrary
+     blob of data.
 
      Having a payload is not required; and the payload can, in fact, just be a
      value stored in the struct key itself.
@@ -92,8 +92,8 @@ Each key has a number of attributes:
 
  (*) Each key can be in one of a number of basic states:
 
-     (*) Uninstantiated. The key exists, but does not have any data
-        attached. Keys being requested from userspace will be in this state.
+     (*) Uninstantiated. The key exists, but does not have any data attached.
+        Keys being requested from userspace will be in this state.
 
      (*) Instantiated. This is the normal state. The key is fully formed, and
         has data attached.
@@ -140,10 +140,10 @@ The key service provides a number of features besides keys:
      clone, fork, vfork or execve occurs. A new keyring is created only when
      required.
 
-     The process-specific keyring is replaced with an empty one in the child
-     on clone, fork, vfork unless CLONE_THREAD is supplied, in which case it
-     is shared. execve also discards the process's process keyring and creates
-     new one.
+     The process-specific keyring is replaced with an empty one in the child on
+     clone, fork, vfork unless CLONE_THREAD is supplied, in which case it is
+     shared. execve also discards the process's process keyring and creates a
+     new one.
 
      The session-specific keyring is persistent across clone, fork, vfork and
      execve, even when the latter executes a set-UID or set-GID binary. A
@@ -177,11 +177,11 @@ The key service provides a number of features besides keys:
      If a system call that modifies a key or keyring in some way would put the
      user over quota, the operation is refused and error EDQUOT is returned.
 
- (*) There's a system call interface by which userspace programs can create
-     and manipulate keys and keyrings.
+ (*) There's a system call interface by which userspace programs can create and
+     manipulate keys and keyrings.
 
- (*) There's a kernel interface by which services can register types and
-     search for keys.
+ (*) There's a kernel interface by which services can register types and search
+     for keys.
 
  (*) There's a way for the a search done from the kernel to call back to
      userspace to request a key that can't be found in a process's keyrings.
@@ -194,9 +194,9 @@ The key service provides a number of features besides keys:
 KEY ACCESS PERMISSIONS
 ======================
 
-Keys have an owner user ID, a group access ID, and a permissions mask. The
-mask has up to eight bits each for user, group and other access. Only five of
-each set of eight bits are defined. These permissions granted are:
+Keys have an owner user ID, a group access ID, and a permissions mask. The mask
+has up to eight bits each for user, group and other access. Only five of each
+set of eight bits are defined. These permissions granted are:
 
  (*) View
 
@@ -210,8 +210,8 @@ each set of eight bits are defined. These permissions granted are:
 
  (*) Write
 
-     This permits a key's payload to be instantiated or updated, or it allows
-     link to be added to or removed from a keyring.
+     This permits a key's payload to be instantiated or updated, or it allows a
+     link to be added to or removed from a keyring.
 
  (*) Search
 
@@ -238,8 +238,8 @@ about the status of the key service:
  (*) /proc/keys
 
      This lists all the keys on the system, giving information about their
-     type, description and permissions. The payload of the key is not
-     available this way:
+     type, description and permissions. The payload of the key is not available
+     this way:
 
        SERIAL   FLAGS  USAGE EXPY PERM   UID   GID   TYPE      DESCRIPTION: SUMMARY
        00000001 I-----    39 perm 1f0000     0     0 keyring   _uid_ses.0: 1/4
@@ -318,21 +318,21 @@ The main syscalls are:
      If a key of the same type and description as that proposed already exists
      in the keyring, this will try to update it with the given payload, or it
      will return error EEXIST if that function is not supported by the key
-     type. The process must also have permission to write to the key to be
-     able to update it. The new key will have all user permissions granted and
-     no group or third party permissions.
+     type. The process must also have permission to write to the key to be able
+     to update it. The new key will have all user permissions granted and no
+     group or third party permissions.
 
-     Otherwise, this will attempt to create a new key of the specified type
-     and description, and to instantiate it with the supplied payload and
-     attach it to the keyring. In this case, an error will be generated if the
-     process does not have permission to write to the keyring.
+     Otherwise, this will attempt to create a new key of the specified type and
+     description, and to instantiate it with the supplied payload and attach it
+     to the keyring. In this case, an error will be generated if the process
+     does not have permission to write to the keyring.
 
      The payload is optional, and the pointer can be NULL if not required by
      the type. The payload is plen in size, and plen can be zero for an empty
      payload.
 
-     A new keyring can be generated by setting type "keyring", the keyring
-     name as the description (or NULL) and setting the payload to NULL.
+     A new keyring can be generated by setting type "keyring", the keyring name
+     as the description (or NULL) and setting the payload to NULL.
 
      User defined keys can be created by specifying type "user". It is
      recommended that a user defined key's description by prefixed with a type
@@ -369,9 +369,9 @@ The keyctl syscall functions are:
        key_serial_t keyctl(KEYCTL_GET_KEYRING_ID, key_serial_t id,
                            int create);
 
-     The special key specified by "id" is looked up (with the key being
-     created if necessary) and the ID of the key or keyring thus found is
-     returned if it exists.
+     The special key specified by "id" is looked up (with the key being created
+     if necessary) and the ID of the key or keyring thus found is returned if
+     it exists.
 
      If the key does not yet exist, the key will be created if "create" is
      non-zero; and the error ENOKEY will be returned if "create" is zero.
@@ -402,8 +402,8 @@ The keyctl syscall functions are:
 
      This will try to update the specified key with the given payload, or it
      will return error EOPNOTSUPP if that function is not supported by the key
-     type. The process must also have permission to write to the key to be
-     able to update it.
+     type. The process must also have permission to write to the key to be able
+     to update it.
 
      The payload is of length plen, and may be absent or empty as for
      add_key().
@@ -422,8 +422,8 @@ The keyctl syscall functions are:
 
        long keyctl(KEYCTL_CHOWN, key_serial_t key, uid_t uid, gid_t gid);
 
-     This function permits a key's owner and group ID to be changed. Either
-     one of uid or gid can be set to -1 to suppress that change.
+     This function permits a key's owner and group ID to be changed. Either one
+     of uid or gid can be set to -1 to suppress that change.
 
      Only the superuser can change a key's owner to something other than the
      key's current owner. Similarly, only the superuser can change a key's
@@ -484,12 +484,12 @@ The keyctl syscall functions are:
 
        long keyctl(KEYCTL_LINK, key_serial_t keyring, key_serial_t key);
 
-     This function creates a link from the keyring to the key. The process
-     must have write permission on the keyring and must have link permission
-     on the key.
+     This function creates a link from the keyring to the key. The process must
+     have write permission on the keyring and must have link permission on the
+     key.
 
-     Should the keyring not be a keyring, error ENOTDIR will result; and if
-     the keyring is full, error ENFILE will result.
+     Should the keyring not be a keyring, error ENOTDIR will result; and if the
+     keyring is full, error ENFILE will result.
 
      The link procedure checks the nesting of the keyrings, returning ELOOP if
      it appears to deep or EDEADLK if the link would introduce a cycle.
@@ -503,8 +503,8 @@ The keyctl syscall functions are:
      specified key, and removes it if found. Subsequent links to that key are
      ignored. The process must have write permission on the keyring.
 
-     If the keyring is not a keyring, error ENOTDIR will result; and if the
-     key is not present, error ENOENT will be the result.
+     If the keyring is not a keyring, error ENOTDIR will result; and if the key
+     is not present, error ENOENT will be the result.
 
 
  (*) Search a keyring tree for a key:
@@ -513,9 +513,9 @@ The keyctl syscall functions are:
                            const char *type, const char *description,
                            key_serial_t dest_keyring);
 
-     This searches the keyring tree headed by the specified keyring until a
-     key is found that matches the type and description criteria. Each keyring
-     is checked for keys before recursion into its children occurs.
+     This searches the keyring tree headed by the specified keyring until a key
+     is found that matches the type and description criteria. Each keyring is
+     checked for keys before recursion into its children occurs.
 
      The process must have search permission on the top level keyring, or else
      error EACCES will result. Only keyrings that the process has search
@@ -549,8 +549,8 @@ The keyctl syscall functions are:
      As much of the data as can be fitted into the buffer will be copied to
      userspace if the buffer pointer is not NULL.
 
-     On a successful return, the function will always return the amount of
-     data available rather than the amount copied.
+     On a successful return, the function will always return the amount of data
+     available rather than the amount copied.
 
 
  (*) Instantiate a partially constructed key.
@@ -568,8 +568,8 @@ The keyctl syscall functions are:
      it, and the key must be uninstantiated.
 
      If a keyring is specified (non-zero), the key will also be linked into
-     that keyring, however all the constraints applying in KEYCTL_LINK apply
-     in this case too.
+     that keyring, however all the constraints applying in KEYCTL_LINK apply in
+     this case too.
 
      The payload and plen arguments describe the payload data as for add_key().
 
@@ -587,8 +587,39 @@ The keyctl syscall functions are:
      it, and the key must be uninstantiated.
 
      If a keyring is specified (non-zero), the key will also be linked into
-     that keyring, however all the constraints applying in KEYCTL_LINK apply
-     in this case too.
+     that keyring, however all the constraints applying in KEYCTL_LINK apply in
+     this case too.
+
+
+ (*) Set the default request-key destination keyring.
+
+       long keyctl(KEYCTL_SET_REQKEY_KEYRING, int reqkey_defl);
+
+     This sets the default keyring to which implicitly requested keys will be
+     attached for this thread. reqkey_defl should be one of these constants:
+
+       CONSTANT                                VALUE   NEW DEFAULT KEYRING
+       ======================================  ======  =======================
+       KEY_REQKEY_DEFL_NO_CHANGE               -1      No change
+       KEY_REQKEY_DEFL_DEFAULT                 0       Default[1]
+       KEY_REQKEY_DEFL_THREAD_KEYRING          1       Thread keyring
+       KEY_REQKEY_DEFL_PROCESS_KEYRING         2       Process keyring
+       KEY_REQKEY_DEFL_SESSION_KEYRING         3       Session keyring
+       KEY_REQKEY_DEFL_USER_KEYRING            4       User keyring
+       KEY_REQKEY_DEFL_USER_SESSION_KEYRING    5       User session keyring
+       KEY_REQKEY_DEFL_GROUP_KEYRING           6       Group keyring
+
+     The old default will be returned if successful and error EINVAL will be
+     returned if reqkey_defl is not one of the above values.
+
+     The default keyring can be overridden by the keyring indicated to the
+     request_key() system call.
+
+     Note that this setting is inherited across fork/exec.
+
+     [1] The default default is: the thread keyring if there is one, otherwise
+     the process keyring if there is one, otherwise the session keyring if
+     there is one, otherwise the user default session keyring.
 
 
 ===============
@@ -601,17 +632,14 @@ be broken down into two areas: keys and key types.
 Dealing with keys is fairly straightforward. Firstly, the kernel service
 registers its type, then it searches for a key of that type. It should retain
 the key as long as it has need of it, and then it should release it. For a
-filesystem or device file, a search would probably be performed during the
-open call, and the key released upon close. How to deal with conflicting keys
-due to two different users opening the same file is left to the filesystem
-author to solve.
-
-When accessing a key's payload data, key->lock should be at least read locked,
-or else the data may be changed by an update being performed from userspace
-whilst the driver or filesystem is trying to access it. If no update method is
-supplied, then the key's payload may be accessed without holding a lock as
-there is no way to change it, provided it can be guaranteed that the key's
-type definition won't go away.
+filesystem or device file, a search would probably be performed during the open
+call, and the key released upon close. How to deal with conflicting keys due to
+two different users opening the same file is left to the filesystem author to
+solve.
+
+When accessing a key's payload contents, certain precautions must be taken to
+prevent access vs modification races. See the section "Notes on accessing
+payload contents" for more information.
 
 (*) To search for a key, call:
 
@@ -629,6 +657,9 @@ type definition won't go away.
     Should the function fail error ENOKEY, EKEYEXPIRED or EKEYREVOKED will be
     returned.
 
+    If successful, the key will have been attached to the default keyring for
+    implicitly obtained request-key keys, as set by KEYCTL_SET_REQKEY_KEYRING.
+
 
 (*) When it is no longer required, the key should be released using:
 
@@ -690,6 +721,54 @@ type definition won't go away.
        void unregister_key_type(struct key_type *type);
 
 
+===================================
+NOTES ON ACCESSING PAYLOAD CONTENTS
+===================================
+
+The simplest payload is just a number in key->payload.value. In this case,
+there's no need to indulge in RCU or locking when accessing the payload.
+
+More complex payload contents must be allocated and a pointer to them set in
+key->payload.data. One of the following ways must be selected to access the
+data:
+
+ (1) Unmodifyable key type.
+
+     If the key type does not have a modify method, then the key's payload can
+     be accessed without any form of locking, provided that it's known to be
+     instantiated (uninstantiated keys cannot be "found").
+
+ (2) The key's semaphore.
+
+     The semaphore could be used to govern access to the payload and to control
+     the payload pointer. It must be write-locked for modifications and would
+     have to be read-locked for general access. The disadvantage of doing this
+     is that the accessor may be required to sleep.
+
+ (3) RCU.
+
+     RCU must be used when the semaphore isn't already held; if the semaphore
+     is held then the contents can't change under you unexpectedly as the
+     semaphore must still be used to serialise modifications to the key. The
+     key management code takes care of this for the key type.
+
+     However, this means using:
+
+       rcu_read_lock() ... rcu_dereference() ... rcu_read_unlock()
+
+     to read the pointer, and:
+
+       rcu_dereference() ... rcu_assign_pointer() ... call_rcu()
+
+     to set the pointer and dispose of the old contents after a grace period.
+     Note that only the key type should ever modify a key's payload.
+
+     Furthermore, an RCU controlled payload must hold a struct rcu_head for the
+     use of call_rcu() and, if the payload is of variable size, the length of
+     the payload. key->datalen cannot be relied upon to be consistent with the
+     payload just dereferenced if the key's semaphore is not held.
+
+
 ===================
 DEFINING A KEY TYPE
 ===================
@@ -717,15 +796,15 @@ The structure has a number of fields, some of which are mandatory:
 
        int key_payload_reserve(struct key *key, size_t datalen);
 
-     With the revised data length. Error EDQUOT will be returned if this is
-     not viable.
+     With the revised data length. Error EDQUOT will be returned if this is not
+     viable.
 
 
  (*) int (*instantiate)(struct key *key, const void *data, size_t datalen);
 
      This method is called to attach a payload to a key during construction.
-     The payload attached need not bear any relation to the data passed to
-     this function.
+     The payload attached need not bear any relation to the data passed to this
+     function.
 
      If the amount of data attached to the key differs from the size in
      keytype->def_datalen, then key_payload_reserve() should be called.
@@ -734,38 +813,47 @@ The structure has a number of fields, some of which are mandatory:
      The fact that KEY_FLAG_INSTANTIATED is not set in key->flags prevents
      anything else from gaining access to the key.
 
-     This method may sleep if it wishes.
+     It is safe to sleep in this method.
 
 
  (*) int (*duplicate)(struct key *key, const struct key *source);
 
      If this type of key can be duplicated, then this method should be
-     provided. It is called to copy the payload attached to the source into
-     the new key. The data length on the new key will have been updated and
-     the quota adjusted already.
+     provided. It is called to copy the payload attached to the source into the
+     new key. The data length on the new key will have been updated and the
+     quota adjusted already.
 
      This method will be called with the source key's semaphore read-locked to
-     prevent its payload from being changed. It is safe to sleep here.
+     prevent its payload from being changed, thus RCU constraints need not be
+     applied to the source key.
+
+     This method does not have to lock the destination key in order to attach a
+     payload. The fact that KEY_FLAG_INSTANTIATED is not set in key->flags
+     prevents anything else from gaining access to the key.
+
+     It is safe to sleep in this method.
 
 
  (*) int (*update)(struct key *key, const void *data, size_t datalen);
 
-     If this type of key can be updated, then this method should be
-     provided. It is called to update a key's payload from the blob of data
-     provided.
+     If this type of key can be updated, then this method should be provided.
+     It is called to update a key's payload from the blob of data provided.
 
      key_payload_reserve() should be called if the data length might change
-     before any changes are actually made. Note that if this succeeds, the
-     type is committed to changing the key because it's already been altered,
-     so all memory allocation must be done first.
+     before any changes are actually made. Note that if this succeeds, the type
+     is committed to changing the key because it's already been altered, so all
+     memory allocation must be done first.
+
+     The key will have its semaphore write-locked before this method is called,
+     but this only deters other writers; any changes to the key's payload must
+     be made under RCU conditions, and call_rcu() must be used to dispose of
+     the old payload.
 
-     key_payload_reserve() should be called with the key->lock write locked,
-     and the changes to the key's attached payload should be made before the
-     key is locked.
+     key_payload_reserve() should be called before the changes are made, but
+     after all allocations and other potentially failing function calls are
+     made.
 
-     The key will have its semaphore write-locked before this method is
-     called. Any changes to the key should be made with the key's rwlock
-     write-locked also. It is safe to sleep here.
+     It is safe to sleep in this method.
 
 
  (*) int (*match)(const struct key *key, const void *desc);
@@ -782,12 +870,12 @@ The structure has a number of fields, some of which are mandatory:
 
  (*) void (*destroy)(struct key *key);
 
-     This method is optional. It is called to discard the payload data on a
-     key when it is being destroyed.
+     This method is optional. It is called to discard the payload data on a key
+     when it is being destroyed.
 
-     This method does not need to lock the key; it can consider the key as
-     being inaccessible. Note that the key's type may have changed before this
-     function is called.
+     This method does not need to lock the key to access the payload; it can
+     consider the key as being inaccessible at this time. Note that the key's
+     type may have been changed before this function is called.
 
      It is not safe to sleep in this method; the caller may hold spinlocks.
 
@@ -797,26 +885,31 @@ The structure has a number of fields, some of which are mandatory:
      This method is optional. It is called during /proc/keys reading to
      summarise a key's description and payload in text form.
 
-     This method will be called with the key's rwlock read-locked. This will
-     prevent the key's payload and state changing; also the description should
-     not change. This also means it is not safe to sleep in this method.
+     This method will be called with the RCU read lock held. rcu_dereference()
+     should be used to read the payload pointer if the payload is to be
+     accessed. key->datalen cannot be trusted to stay consistent with the
+     contents of the payload.
+
+     The description will not change, though the key's state may.
+
+     It is not safe to sleep in this method; the RCU read lock is held by the
+     caller.
 
 
  (*) long (*read)(const struct key *key, char __user *buffer, size_t buflen);
 
      This method is optional. It is called by KEYCTL_READ to translate the
-     key's payload into something a blob of data for userspace to deal
-     with. Ideally, the blob should be in the same format as that passed in to
-     the instantiate and update methods.
+     key's payload into something a blob of data for userspace to deal with.
+     Ideally, the blob should be in the same format as that passed in to the
+     instantiate and update methods.
 
      If successful, the blob size that could be produced should be returned
      rather than the size copied.
 
-     This method will be called with the key's semaphore read-locked. This
-     will prevent the key's payload changing. It is not necessary to also
-     read-lock key->lock when accessing the key's payload. It is safe to sleep
-     in this method, such as might happen when the userspace buffer is
-     accessed.
+     This method will be called with the key's semaphore read-locked. This will
+     prevent the key's payload changing. It is not necessary to use RCU locking
+     when accessing the key's payload. It is safe to sleep in this method, such
+     as might happen when the userspace buffer is accessed.
 
 
 ============================
@@ -853,8 +946,8 @@ If it returns with the key remaining in the unconstructed state, the key will
 be marked as being negative, it will be added to the session keyring, and an
 error will be returned to the key requestor.
 
-Supplementary information may be provided from whoever or whatever invoked
-this service. This will be passed as the <callout_info> parameter. If no such
+Supplementary information may be provided from whoever or whatever invoked this
+service. This will be passed as the <callout_info> parameter. If no such
 information was made available, then "-" will be passed as this parameter
 instead.
 
index 834993d267303d30e53817aafb0ffe4894afb608..5b01d5cc4e95b8d2087d3dc1039094bfab34f56f 100644 (file)
@@ -114,9 +114,7 @@ tuntap.txt
 vortex.txt
        - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards.
 wan-router.txt
-       - Wan router documentation
-wanpipe.txt
-       - WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router
+       - WAN router documentation
 wavelan.txt
        - AT&T GIS (nee NCR) WaveLAN card: An Ethernet-like radio transceiver
 x25.txt
index c0e8398674eff5c5d026ed774a8fb01b23ad6c2b..046363552d09605937c1a23fc481db0cdbc9af21 100644 (file)
@@ -1,59 +1,65 @@
-  dmfe.c: Version 1.28        01/18/2000
+Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver for Linux.
 
-        A Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver for Linux. 
-        Copyright (C) 1997  Sten Wang
+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 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.
 
-        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.
 
+This driver provides kernel support for Davicom DM9102(A)/DM9132/DM9801 ethernet cards ( CNET
+10/100 ethernet cards uses Davicom chipset too, so this driver supports CNET cards too ).If you
+didn't compile this driver as a module, it will automatically load itself on boot and print a
+line similar to :
 
-  A. Compiler command:
+       dmfe: Davicom DM9xxx net driver, version 1.36.4 (2002-01-17)
 
-     A-1: For normal single or multiple processor kernel
-          "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall 
-            -Wstrict-prototypes -O6 -c dmfe.c"
+If you compiled this driver as a module, you have to load it on boot.You can load it with command :
 
-     A-2: For single or multiple processor with kernel module version function
-          "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -I/usr/src/linux/net/inet 
-            -Wall -Wstrict-prototypes -O6 -c dmfe.c"
+       insmod dmfe
 
+This way it will autodetect the device mode.This is the suggested way to load the module.Or you can pass
+a mode= setting to module while loading, like :
 
-  B. The following steps teach you how to activate a DM9102 board:
+       insmod dmfe mode=0 # Force 10M Half Duplex
+       insmod dmfe mode=1 # Force 100M Half Duplex
+       insmod dmfe mode=4 # Force 10M Full Duplex
+       insmod dmfe mode=5 # Force 100M Full Duplex
 
-        1. Used the upper compiler command to compile dmfe.c
+Next you should configure your network interface with a command similar to :
 
-        2. Insert dmfe module into kernel
-           "insmod dmfe"        ;;Auto Detection Mode (Suggest)
-           "insmod dmfe mode=0" ;;Force 10M Half Duplex
-           "insmod dmfe mode=1" ;;Force 100M Half Duplex
-           "insmod dmfe mode=4" ;;Force 10M Full Duplex
-           "insmod dmfe mode=5" ;;Force 100M Full Duplex
+       ifconfig eth0 172.22.3.18
+                      ^^^^^^^^^^^
+                    Your IP Adress
 
-        3. Config a dm9102 network interface
-           "ifconfig eth0 172.22.3.18"
-                          ^^^^^^^^^^^ Your IP address
+Then you may have to modify the default routing table with command :
 
-        4. Activate the IP routing table. For some distributions, it is not
-           necessary. You can type "route" to check.
+       route add default eth0
 
-           "route add default eth0"
 
+Now your ethernet card should be up and running.
 
-        5. Well done. Your DM9102 adapter is now activated.
 
+TODO:
 
-   C. Object files description:
-        1. dmfe_rh61.o:        For Redhat 6.1
+Implement pci_driver::suspend() and pci_driver::resume() power management methods.
+Check on 64 bit boxes.
+Check and fix on big endian boxes.
+Test and make sure PCI latency is now correct for all cases.
 
-        If you can make sure your kernel version, you can rename
-        to dmfe.o and directly use it without re-compiling.
 
+Authors:
 
-  Author: Sten Wang, 886-3-5798797-8517, E-mail: sten_wang@davicom.com.tw
+Sten Wang <sten_wang@davicom.com.tw >   : Original Author
+Tobias Ringstrom <tori@unhappy.mine.nu> : Current Maintainer
+
+Contributors:
+
+Marcelo Tosatti <marcelo@conectiva.com.br>
+Alan Cox <alan@redhat.com>
+Jeff Garzik <jgarzik@pobox.com>
+Vojtech Pavlik <vojtech@suse.cz>
diff --git a/Documentation/networking/wanpipe.txt b/Documentation/networking/wanpipe.txt
deleted file mode 100644 (file)
index aea20cd..0000000
+++ /dev/null
@@ -1,622 +0,0 @@
-------------------------------------------------------------------------------
-Linux WAN Router Utilities Package
-------------------------------------------------------------------------------
-Version 2.2.1 
-Mar 28, 2001
-Author: Nenad Corbic <ncorbic@sangoma.com>
-Copyright (c) 1995-2001 Sangoma Technologies Inc.
-------------------------------------------------------------------------------
-
-INTRODUCTION
-
-Wide Area Networks (WANs) are used to interconnect Local Area Networks (LANs)
-and/or stand-alone hosts over vast distances with data transfer rates
-significantly higher than those achievable with commonly used dial-up
-connections.
-
-Usually an external device called `WAN router' sitting on your local network
-or connected to your machine's serial port provides physical connection to
-WAN.  Although router's job may be as simple as taking your local network
-traffic, converting it to WAN format and piping it through the WAN link, these
-devices are notoriously expensive, with prices as much as 2 - 5 times higher
-then the price of a typical PC box.
-
-Alternatively, considering robustness and multitasking capabilities of Linux,
-an internal router can be built (most routers use some sort of stripped down
-Unix-like operating system anyway). With a number of relatively inexpensive WAN
-interface cards available on the market, a perfectly usable router can be
-built for less than half a price of an external router.  Yet a Linux box
-acting as a router can still be used for other purposes, such as fire-walling,
-running FTP, WWW or DNS server, etc.
-
-This kernel module introduces the notion of a WAN Link Driver (WLD) to Linux
-operating system and provides generic hardware-independent services for such
-drivers.  Why can existing Linux network device interface not be used for
-this purpose?  Well, it can.  However, there are a few key differences between
-a typical network interface (e.g. Ethernet) and a WAN link.
-
-Many WAN protocols, such as X.25 and frame relay, allow for multiple logical
-connections (known as `virtual circuits' in X.25 terminology) over a single
-physical link.  Each such virtual circuit may (and almost always does) lead
-to a different geographical location and, therefore, different network.  As a
-result, it is the virtual circuit, not the physical link, that represents a
-route and, therefore, a network interface in Linux terms.
-
-To further complicate things, virtual circuits are usually volatile in nature
-(excluding so called `permanent' virtual circuits or PVCs).  With almost no
-time required to set up and tear down a virtual circuit, it is highly desirable
-to implement on-demand connections in order to minimize network charges.  So
-unlike a typical network driver, the WAN driver must be able to handle multiple
-network interfaces and cope as multiple virtual circuits come into existence
-and go away dynamically.
-Last, but not least, WAN configuration is much more complex than that of say
-Ethernet and may well amount to several dozens of parameters.  Some of them
-are "link-wide"  while others are virtual circuit-specific.  The same holds
-true for WAN statistics which is by far more extensive and extremely useful
-when troubleshooting WAN connections.  Extending the ifconfig utility to suit
-these needs may be possible, but does not seem quite reasonable.  Therefore, a
-WAN configuration utility and corresponding application programmer's interface
-is needed for this purpose.
-
-Most of these problems are taken care of by this module.  Its goal is to
-provide a user with more-or-less standard look and feel for all WAN devices and
-assist a WAN device driver writer by providing common services, such as:
-
- o User-level interface via /proc file system
- o Centralized configuration
- o Device management (setup, shutdown, etc.)
- o Network interface management (dynamic creation/destruction)
- o Protocol encapsulation/decapsulation
-
-To ba able to use the Linux WAN Router you will also need a WAN Tools package
-available from
-
-       ftp.sangoma.com/pub/linux/current_wanpipe/wanpipe-X.Y.Z.tgz
-
-where vX.Y.Z represent the wanpipe version number.
-
-For technical questions and/or comments please e-mail to ncorbic@sangoma.com.
-For general inquiries please contact Sangoma Technologies Inc. by
-
-       Hotline:        1-800-388-2475  (USA and Canada, toll free)
-       Phone:          (905) 474-1990  ext: 106
-       Fax:            (905) 474-9223
-       E-mail:         dm@sangoma.com  (David Mandelstam)
-       WWW:            http://www.sangoma.com
-
-
-INSTALLATION
-
-Please read the WanpipeForLinux.pdf manual on how to 
-install the WANPIPE tools and drivers properly. 
-
-
-After installing wanpipe package: /usr/local/wanrouter/doc. 
-On the ftp.sangoma.com : /linux/current_wanpipe/doc
-
-
-COPYRIGHT AND LICENSING INFORMATION
-
-This program is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free Software
-Foundation; either version 2, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along with
-this program; if not, write to the Free Software Foundation, Inc., 675 Mass
-Ave, Cambridge, MA 02139, USA.
-
-
-
-ACKNOWLEDGEMENTS
-
-This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed
-by Sangoma Technologies Inc. for Linux 2.0.x and 2.2.x.  Success of the WANPIPE
-together with the next major release of Linux kernel in summer 1996 commanded
-adequate changes to the WANPIPE code to take full advantage of new Linux
-features.
-
-Instead of continuing developing proprietary interface tied to Sangoma WAN
-cards, we decided to separate all hardware-independent code into a separate
-module and defined two levels of interfaces - one for user-level applications
-and another for kernel-level WAN drivers.  WANPIPE is now implemented as a
-WAN driver compliant with the WAN Link Driver interface.  Also a general
-purpose WAN configuration utility and a set of shell scripts was developed to 
-support WAN router at the user level.
-
-Many useful ideas concerning hardware-independent interface implementation
-were given by Mike McLagan <mike.mclagan@linux.org> and his implementation
-of the Frame Relay router and drivers for Sangoma cards (dlci/sdla).
-
-With the new implementation of the APIs being incorporated into the WANPIPE,
-a special thank goes to Alan Cox in providing insight into BSD sockets.
-
-Special thanks to all the WANPIPE users who performed field-testing, reported
-bugs and made valuable comments and suggestions that help us to improve this
-product.
-
-
-
-NEW IN THIS RELEASE
-
-       o Updated the WANCFG utility
-               Calls the pppconfig to configure the PPPD
-               for async connections.
-
-       o Added the PPPCONFIG utility
-               Used to configure the PPPD dameon for the
-               WANPIPE Async PPP and standard serial port.
-               The wancfg calls the pppconfig to configure
-               the pppd.
-
-       o Fixed the PCI autodetect feature.  
-               The SLOT 0 was used as an autodetect option
-               however, some high end PC's slot numbers start
-               from 0. 
-
-       o This release has been tested with the new backupd
-         daemon release.
-       
-
-PRODUCT COMPONENTS AND RELATED FILES
-
-/etc: (or user defined)
-       wanpipe1.conf   default router configuration file
-
-/lib/modules/X.Y.Z/misc:
-       wanrouter.o     router kernel loadable module
-       af_wanpipe.o    wanpipe api socket module
-
-/lib/modules/X.Y.Z/net:
-       sdladrv.o       Sangoma SDLA support module
-       wanpipe.o       Sangoma WANPIPE(tm) driver module
-
-/proc/net/wanrouter
-       Config          reads current router configuration
-       Status          reads current router status
-       {name}          reads WAN driver statistics
-
-/usr/sbin:
-       wanrouter       wanrouter start-up script
-       wanconfig       wanrouter configuration utility
-       sdladump        WANPIPE adapter memory dump utility
-        fpipemon        Monitor for Frame Relay
-        cpipemon        Monitor for Cisco HDLC
-       ppipemon        Monitor for PPP
-       xpipemon        Monitor for X25
-       wpkbdmon        WANPIPE keyboard led monitor/debugger
-
-/usr/local/wanrouter:
-       README          this file
-       COPYING         GNU General Public License
-       Setup           installation script
-       Filelist        distribution definition file
-       wanrouter.rc    meta-configuration file 
-                       (used by the Setup and wanrouter script)
-
-/usr/local/wanrouter/doc:
-       wanpipeForLinux.pdf     WAN Router User's Manual
-
-/usr/local/wanrouter/patches:
-       wanrouter-v2213.gz      patch for Linux kernels 2.2.11 up to 2.2.13.
-       wanrouter-v2214.gz      patch for Linux kernel 2.2.14. 
-       wanrouter-v2215.gz      patch for Linux kernels 2.2.15 to 2.2.17.
-       wanrouter-v2218.gz      patch for Linux kernels 2.2.18 and up.
-       wanrouter-v240.gz       patch for Linux kernel 2.4.0.  
-       wanrouter-v242.gz       patch for Linux kernel 2.4.2 and up.
-       wanrouter-v2034.gz      patch for Linux kernel 2.0.34
-       wanrouter-v2036.gz      patch for Linux kernel 2.0.36 and up. 
-
-/usr/local/wanrouter/patches/kdrivers:
-       Sources of the latest WANPIPE device drivers.
-       These are used to UPGRADE the linux kernel to the newest
-       version if the kernel source has already been pathced with
-       WANPIPE drivers.
-
-/usr/local/wanrouter/samples:
-       interface       sample interface configuration file
-       wanpipe1.cpri   CHDLC primary port
-       wanpipe2.csec   CHDLC secondary port
-       wanpipe1.fr     Frame Relay protocol
-       wanpipe1.ppp    PPP protocol ) 
-       wanpipe1.asy    CHDLC ASYNC protocol
-       wanpipe1.x25    X25 protocol
-       wanpipe1.stty   Sync TTY driver (Used by Kernel PPPD daemon)
-       wanpipe1.atty   Async TTY driver (Used by Kernel PPPD daemon)
-       wanrouter.rc    sample meta-configuration file
-
-/usr/local/wanrouter/util:
-       *               wan-tools utilities source code
-
-/usr/local/wanrouter/api/x25:
-       *               x25 api sample programs.
-/usr/local/wanrouter/api/chdlc:
-       *               chdlc api sample programs.
-/usr/local/wanrouter/api/fr:
-       *               fr api sample programs.
-/usr/local/wanrouter/config/wancfg:
-       wancfg          WANPIPE GUI configuration program.
-                        Creates wanpipe#.conf files. 
-/usr/local/wanrouter/config/cfgft1:
-       cfgft1          GUI CSU/DSU configuration program.
-
-/usr/include/linux:
-       wanrouter.h     router API definitions
-       wanpipe.h       WANPIPE API definitions
-       sdladrv.h       SDLA support module API definitions
-       sdlasfm.h       SDLA firmware module definitions
-       if_wanpipe.h    WANPIPE Socket definitions
-       if_wanpipe_common.h     WANPIPE Socket/Driver common definitions.
-       sdlapci.h       WANPIPE PCI definitions
-       
-
-/usr/src/linux/net/wanrouter:
-       *               wanrouter source code
-
-/var/log:
-       wanrouter       wanrouter start-up log (created by the Setup script)
-
-/var/lock:  (or /var/lock/subsys for RedHat)
-       wanrouter       wanrouter lock file (created by the Setup script)
-
-/usr/local/wanrouter/firmware:
-       fr514.sfm       Frame relay firmware for Sangoma S508/S514 card
-       cdual514.sfm    Dual Port Cisco HDLC firmware for Sangoma S508/S514 card
-       ppp514.sfm      PPP Firmware for Sangoma S508 and S514 cards
-       x25_508.sfm     X25 Firmware for Sangoma S508 card.
-
-
-REVISION HISTORY
-
-1.0.0  December 31, 1996       Initial version
-
-1.0.1  January 30, 1997        Status and statistics can be read via /proc
-                               filesystem entries.
-
-1.0.2   April 30, 1997          Added UDP management via monitors.
-
-1.0.3  June 3, 1997            UDP management for multiple boards using Frame
-                               Relay and PPP
-                               Enabled continuous transmission of Configure 
-                               Request Packet for PPP (for 508 only)
-                               Connection Timeout for PPP changed from 900 to 0
-                               Flow Control Problem fixed for Frame Relay
-
-1.0.4  July 10, 1997           S508/FT1 monitoring capability in fpipemon and
-                               ppipemon utilities.
-                               Configurable TTL for UDP packets.
-                               Multicast and Broadcast IP source addresses are
-                               silently discarded.
-
-1.0.5  July 28, 1997           Configurable T391,T392,N391,N392,N393 for Frame
-                               Relay in router.conf.
-                               Configurable Memory Address through router.conf 
-                               for Frame Relay, PPP and X.25. (commenting this
-                               out enables auto-detection).
-                               Fixed freeing up received buffers using kfree()
-                               for Frame Relay and X.25.
-                               Protect sdla_peek() by calling save_flags(),
-                               cli() and restore_flags().
-                               Changed number of Trace elements from 32 to 20
-                               Added DLCI specific data monitoring in FPIPEMON. 
-2.0.0  Nov 07, 1997            Implemented protection of RACE conditions by 
-                               critical flags for FRAME RELAY and PPP.
-                               DLCI List interrupt mode implemented.
-                               IPX support in FRAME RELAY and PPP.
-                               IPX Server Support (MARS)
-                               More driver specific stats included in FPIPEMON
-                               and PIPEMON.
-
-2.0.1  Nov 28, 1997            Bug Fixes for version 2.0.0.
-                               Protection of "enable_irq()" while 
-                               "disable_irq()" has been enabled from any other
-                               routine (for Frame Relay, PPP and X25).
-                               Added additional Stats for Fpipemon and Ppipemon
-                               Improved Load Sharing for multiple boards
-
-2.0.2  Dec 09, 1997            Support for PAP and CHAP for ppp has been
-                               implemented.
-
-2.0.3  Aug 15, 1998            New release supporting Cisco HDLC, CIR for Frame
-                               relay, Dynamic IP assignment for PPP and Inverse
-                               Arp support for Frame-relay.  Man Pages are 
-                               included for better support and a new utility
-                               for configuring FT1 cards.
-
-2.0.4  Dec 09, 1998            Dual Port support for Cisco HDLC.
-                               Support for HDLC (LAPB) API.
-                               Supports BiSync Streaming code for S502E 
-                               and S503 cards.
-                               Support for Streaming HDLC API.
-                               Provides a BSD socket interface for 
-                               creating applications using BiSync
-                               streaming.        
-
-2.0.5   Aug 04, 1999           CHDLC initializatin bug fix.
-                               PPP interrupt driven driver: 
-                               Fix to the PPP line hangup problem.
-                               New PPP firmware
-                               Added comments to the startup SYSTEM ERROR messages
-                               Xpipemon debugging application for the X25 protocol
-                               New USER_MANUAL.txt
-                               Fixed the odd boundary 4byte writes to the board.
-                               BiSync Streaming code has been taken out.  
-                                Available as a patch.
-                               Streaming HDLC API has been taken out.  
-                                Available as a patch.                 
-
-2.0.6   Aug 17, 1999           Increased debugging in statup scripts
-                               Fixed insallation bugs from 2.0.5
-                               Kernel patch works for both 2.2.10 and 2.2.11 kernels.
-                               There is no functional difference between the two packages         
-
-2.0.7   Aug 26, 1999           o  Merged X25API code into WANPIPE.
-                               o  Fixed a memeory leak for X25API
-                               o  Updated the X25API code for 2.2.X kernels.
-                               o  Improved NEM handling.   
-
-2.1.0  Oct 25, 1999            o New code for S514 PCI Card
-                               o New CHDLC and Frame Relay drivers
-                               o PPP and X25 are not supported in this release    
-
-2.1.1  Nov 30, 1999            o PPP support for S514 PCI Cards
-
-2.1.3   Apr 06, 2000           o Socket based x25api 
-                               o Socket based chdlc api
-                               o Socket based fr api
-                               o Dual Port Receive only CHDLC support.
-                               o Asynchronous CHDLC support (Secondary Port)
-                               o cfgft1 GUI csu/dsu configurator
-                               o wancfg GUI configuration file 
-                                 configurator.
-                               o Architectual directory changes.
-
-beta-2.1.4 Jul 2000            o Dynamic interface configuration:
-                                       Network interfaces reflect the state
-                                       of protocol layer.  If the protocol becomes
-                                       disconnected, driver will bring down
-                                       the interface.  Once the protocol reconnects
-                                       the interface will be brought up. 
-                                       
-                                       Note: This option is turned off by default.
-
-                               o Dynamic wanrouter setup using 'wanconfig':
-                                       wanconfig utility can be used to
-                                       shutdown,restart,start or reconfigure 
-                                       a virtual circuit dynamically.
-                                    
-                                       Frame Relay:  Each DLCI can be: 
-                                                     created,stopped,restarted and reconfigured
-                                                     dynamically using wanconfig.
-                                       
-                                                     ex: wanconfig card wanpipe1 dev wp1_fr16 up
-                                 
-                               o Wanrouter startup via command line arguments:
-                                       wanconfig also supports wanrouter startup via command line
-                                       arguments.  Thus, there is no need to create a wanpipe#.conf
-                                       configuration file.  
-
-                               o Socket based x25api update/bug fixes.
-                                       Added support for LCN numbers greater than 255.
-                                       Option to pass up modem messages.
-                                       Provided a PCI IRQ check, so a single S514
-                                       card is guaranteed to have a non-sharing interrupt.
-
-                               o Fixes to the wancfg utility.
-                               o New FT1 debugging support via *pipemon utilities.
-                               o Frame Relay ARP support Enabled.
-
-beta3-2.1.4 Jul 2000           o X25 M_BIT Problem fix.
-                               o Added the Multi-Port PPP
-                                 Updated utilites for the Multi-Port PPP.
-
-2.1.4  Aut 2000
-                               o In X25API:
-                                       Maximum packet an application can send
-                                       to the driver has been extended to 4096 bytes.
-
-                                       Fixed the x25 startup bug. Enable 
-                                       communications only after all interfaces
-                                       come up.  HIGH SVC/PVC is used to calculate
-                                       the number of channels.
-                                       Enable protocol only after all interfaces
-                                       are enabled.
-
-                               o Added an extra state to the FT1 config, kernel module.
-                               o Updated the pipemon debuggers.
-
-                               o Blocked the Multi-Port PPP from running on kernels
-                                 2.2.16 or greater, due to syncppp kernel module
-                                 change. 
-         
-beta1-2.1.5    Nov 15 2000
-                               o Fixed the MulitPort PPP Support for kernels 2.2.16 and above.
-                                 2.2.X kernels only
-
-                               o Secured the driver UDP debugging calls
-                                       - All illegal netowrk debugging calls are reported to
-                                         the log.
-                                       - Defined a set of allowed commands, all other denied.
-                                       
-                               o Cpipemon
-                                       - Added set FT1 commands to the cpipemon. Thus CSU/DSU
-                                         configuraiton can be performed using cpipemon.
-                                         All systems that cannot run cfgft1 GUI utility should
-                                         use cpipemon to configure the on board CSU/DSU.
-
-
-                               o Keyboard Led Monitor/Debugger
-                                       - A new utilty /usr/sbin/wpkbdmon uses keyboard leds
-                                         to convey operatinal statistic information of the 
-                                         Sangoma WANPIPE cards.
-                                       NUM_LOCK    = Line State  (On=connected,    Off=disconnected)
-                                       CAPS_LOCK   = Tx data     (On=transmitting, Off=no tx data)
-                                       SCROLL_LOCK = Rx data     (On=receiving,    Off=no rx data
-                                       
-                               o Hardware probe on module load and dynamic device allocation
-                                       - During WANPIPE module load, all Sangoma cards are probed
-                                         and found information is printed in the /var/log/messages.
-                                       - If no cards are found, the module load fails.
-                                       - Appropriate number of devices are dynamically loaded 
-                                         based on the number of Sangoma cards found.
-
-                                         Note: The kernel configuraiton option 
-                                               CONFIG_WANPIPE_CARDS has been taken out.
-                                       
-                               o Fixed the Frame Relay and Chdlc network interfaces so they are
-                                 compatible with libpcap libraries.  Meaning, tcpdump, snort,
-                                 ethereal, and all other packet sniffers and debuggers work on
-                                 all WANPIPE netowrk interfaces.
-                                       - Set the network interface encoding type to ARPHRD_PPP.
-                                         This tell the sniffers that data obtained from the
-                                         network interface is in pure IP format.
-                                 Fix for 2.2.X kernels only.
-                               
-                               o True interface encoding option for Frame Relay and CHDLC
-                                       - The above fix sets the network interface encoding
-                                         type to ARPHRD_PPP, however some customers use
-                                         the encoding interface type to determine the
-                                         protocol running.  Therefore, the TURE ENCODING
-                                         option will set the interface type back to the
-                                         original value.  
-
-                                         NOTE: If this option is used with Frame Relay and CHDLC
-                                               libpcap library support will be broken.  
-                                               i.e. tcpdump will not work.
-                                       Fix for 2.2.x Kernels only.
-                                               
-                               o Ethernet Bridgind over Frame Relay
-                                       - The Frame Relay bridging has been developed by 
-                                         Kristian Hoffmann and Mark Wells.  
-                                       - The Linux kernel bridge is used to send ethernet 
-                                         data over the frame relay links.
-                                       For 2.2.X Kernels only.
-
-                               o Added extensive 2.0.X support. Most new features of
-                                 2.1.5 for protocols Frame Relay, PPP and CHDLC are
-                                 supported under 2.0.X kernels. 
-
-beta1-2.2.0    Dec 30 2000
-                               o Updated drivers for 2.4.X kernels.
-                               o Updated drivers for SMP support.
-                               o X25API is now able to share PCI interrupts.
-                               o Took out a general polling routine that was used
-                                 only by X25API. 
-                               o Added appropriate locks to the dynamic reconfiguration
-                                 code.
-                               o Fixed a bug in the keyboard debug monitor.
-
-beta2-2.2.0    Jan 8 2001
-                               o Patches for 2.4.0 kernel
-                               o Patches for 2.2.18 kernel
-                               o Minor updates to PPP and CHLDC drivers.
-                                 Note: No functinal difference. 
-
-beta3-2.2.9    Jan 10 2001
-                               o I missed the 2.2.18 kernel patches in beta2-2.2.0
-                                 release.  They are included in this release.
-
-Stable Release
-2.2.0          Feb 01 2001
-                               o Bug fix in wancfg GUI configurator.
-                                       The edit function didn't work properly.
-
-
-bata1-2.2.1    Feb 09 2001
-                       o WANPIPE TTY Driver emulation. 
-                         Two modes of operation Sync and Async.
-                               Sync: Using the PPPD daemon, kernel SyncPPP layer
-                                     and the Wanpipe sync TTY driver: a PPP protocol 
-                                     connection can be established via Sangoma adapter, over
-                                     a T1 leased line.
-                       
-                                     The 2.4.0 kernel PPP layer supports MULTILINK
-                                     protocol, that can be used to bundle any number of Sangoma
-                                     adapters (T1 lines) into one, under a single IP address.
-                                     Thus, efficiently obtaining multiple T1 throughput. 
-
-                                     NOTE: The remote side must also implement MULTILINK PPP
-                                           protocol.
-
-                               Async:Using the PPPD daemon, kernel AsyncPPP layer
-                                     and the WANPIPE async TTY driver: a PPP protocol
-                                     connection can be established via Sangoma adapter and
-                                     a modem, over a telephone line.
-
-                                     Thus, the WANPIPE async TTY driver simulates a serial
-                                     TTY driver that would normally be used to interface the 
-                                     MODEM to the linux kernel.
-                               
-                       o WANPIPE PPP Backup Utility
-                               This utility will monitor the state of the PPP T1 line.
-                               In case of failure, a dial up connection will be established
-                               via pppd daemon, ether via a serial tty driver (serial port), 
-                               or a WANPIPE async TTY driver (in case serial port is unavailable).
-                               
-                               Furthermore, while in dial up mode, the primary PPP T1 link
-                               will be monitored for signs of life.  
-
-                               If the PPP T1 link comes back to life, the dial up connection
-                               will be shutdown and T1 line re-established.
-                       
-
-                       o New Setup installation script.
-                               Option to UPGRADE device drivers if the kernel source has
-                               already been patched with WANPIPE.
-
-                               Option to COMPILE WANPIPE modules against the currently 
-                               running kernel, thus no need for manual kernel and module
-                               re-compilatin.
-                       
-                       o Updates and Bug Fixes to wancfg utility.
-
-bata2-2.2.1    Feb 20 2001
-
-                       o Bug fixes to the CHDLC device drivers.
-                               The driver had compilation problems under kernels
-                               2.2.14 or lower.
-
-                       o Bug fixes to the Setup installation script.
-                               The device drivers compilation options didn't work
-                               properly.
-
-                       o Update to the wpbackupd daemon.  
-                               Optimized the cross-over times, between the primary
-                               link and the backup dialup.
-
-beta3-2.2.1    Mar 02 2001
-                       o Patches for 2.4.2 kernel.
-
-                       o Bug fixes to util/ make files.
-                       o Bug fixes to the Setup installation script.
-
-                       o Took out the backupd support and made it into
-                         as separate package.
-                         
-beta4-2.2.1     Mar 12 2001
-
-               o Fix to the Frame Relay Device driver.
-                       IPSAC sends a packet of zero length
-                       header to the frame relay driver.  The
-                       driver tries to push its own 2 byte header
-                       into the packet, which causes the driver to
-                       crash.
-
-               o Fix the WANPIPE re-configuration code.
-                       Bug was found by trying to run  the cfgft1 while the
-                       interface was already running.  
-
-               o Updates to cfgft1.
-                       Writes a wanpipe#.cfgft1 configuration file
-                       once the CSU/DSU is configured. This file can
-                       holds the current CSU/DSU configuration.
-
-
-
->>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-
-
diff --git a/Documentation/pcmcia/devicetable.txt b/Documentation/pcmcia/devicetable.txt
new file mode 100644 (file)
index 0000000..3351c03
--- /dev/null
@@ -0,0 +1,63 @@
+Matching of PCMCIA devices to drivers is done using one or more of the
+following criteria:
+
+- manufactor ID
+- card ID
+- product ID strings _and_ hashes of these strings
+- function ID
+- device function (actual and pseudo)
+
+You should use the helpers in include/pcmcia/device_id.h for generating the
+struct pcmcia_device_id[] entries which match devices to drivers.
+
+If you want to match product ID strings, you also need to pass the crc32
+hashes of the string to the macro, e.g. if you want to match the product ID
+string 1, you need to use
+
+PCMCIA_DEVICE_PROD_ID1("some_string", 0x(hash_of_some_string)),
+
+If the hash is incorrect, the kernel will inform you about this in "dmesg"
+upon module initialization, and tell you of the correct hash.
+
+You can determine the hash of the product ID strings by catting the file
+"modalias" in the sysfs directory of the PCMCIA device. It generates a string
+in the following form:
+pcmcia:m0149cC1ABf06pfn00fn00pa725B842DpbF1EFEE84pc0877B627pd00000000
+
+The hex value after "pa" is the hash of product ID string 1, after "pb" for
+string 2 and so on.
+
+Alternatively, you can use this small tool to determine the crc32 hash.
+simply pass the string you want to evaluate as argument to this program,
+e.g.
+$ ./crc32hash "Dual Speed"
+
+-------------------------------------------------------------------------
+/* crc32hash.c - derived from linux/lib/crc32.c, GNU GPL v2 */
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+unsigned int crc32(unsigned char const *p, unsigned int len)
+{
+       int i;
+       unsigned int crc = 0;
+       while (len--) {
+               crc ^= *p++;
+               for (i = 0; i < 8; i++)
+                       crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
+       }
+       return crc;
+}
+
+int main(int argc, char **argv) {
+       unsigned int result;
+       if (argc != 2) {
+               printf("no string passed as argument\n");
+               return -1;
+       }
+       result = crc32(argv[1], strlen(argv[1]));
+       printf("0x%x\n", result);
+       return 0;
+}
diff --git a/Documentation/pcmcia/driver-changes.txt b/Documentation/pcmcia/driver-changes.txt
new file mode 100644 (file)
index 0000000..9c315ab
--- /dev/null
@@ -0,0 +1,51 @@
+This file details changes in 2.6 which affect PCMCIA card driver authors:
+
+* in-kernel device<->driver matching
+   PCMCIA devices and their correct drivers can now be matched in
+   kernelspace. See 'devicetable.txt' for details.
+
+* Device model integration (as of 2.6.11)
+   A struct pcmcia_device is registered with the device model core,
+   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.
+
+* irq_mask and irq_list parameters (as of 2.6.11)
+   The irq_mask and irq_list parameters should no longer be used in
+   PCMCIA card drivers. Instead, it is the job of the PCMCIA core to
+   determine which IRQ should be used. Therefore, link->irq.IRQInfo2
+   is ignored.
+
+* client->PendingEvents is gone (as of 2.6.11)
+   client->PendingEvents is no longer available.
+
+* client->Attributes are gone (as of 2.6.11)
+   client->Attributes is unused, therefore it is removed from all
+   PCMCIA card drivers
+
+* core functions no longer available (as of 2.6.11)
+   The following functions have been removed from the kernel source
+   because they are unused by all in-kernel drivers, and no external
+   driver was reported to rely on them:
+       pcmcia_get_first_region()
+       pcmcia_get_next_region()
+       pcmcia_modify_window()
+       pcmcia_set_event_mask()
+       pcmcia_get_first_window()
+       pcmcia_get_next_window()
+
+* device list iteration upon module removal (as of 2.6.10)
+   It is no longer necessary to iterate on the driver's internal
+   client list and call the ->detach() function upon module removal.
+
+* Resource management. (as of 2.6.8)
+   Although the PCMCIA subsystem will allocate resources for cards,
+   it no longer marks these resources busy. This means that driver
+   authors are now responsible for claiming your resources as per
+   other drivers in Linux. You should use request_region() to mark
+   your IO regions in-use, and request_mem_region() to mark your
+   memory regions in-use. The name argument should be a pointer to
+   your driver name. Eg, for pcnet_cs, name should point to the
+   string "pcnet_cs".
index 60b548105edf7052501fa43ab299dbbc44208fd8..fb57784986b1fcdee6b76048fb9c9703939bc849 100644 (file)
@@ -12,8 +12,7 @@ refrigerator. Code to do this looks like this:
        do {
                hub_events();
                wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list));
-               if (current->flags & PF_FREEZE)
-                       refrigerator(PF_FREEZE);
+               try_to_freeze();
        } while (!signal_pending(current));
 
 from drivers/usb/core/hub.c::hub_thread()
index 35b1a7dae34253751ade84ca7f0eda948fac11dd..6fc9d511fc39ef01af4b88492b4b2edea5ffb623 100644 (file)
@@ -291,6 +291,44 @@ a request to enable wake events from D3, two calls should be made to
 pci_enable_wake (one for both D3hot and D3cold).
 
 
+A reference implementation
+-------------------------
+.suspend()
+{
+       /* driver specific operations */
+
+       /* Disable IRQ */
+       free_irq();
+       /* If using MSI */
+       pci_disable_msi();
+
+       pci_save_state();
+       pci_enable_wake();
+       /* Disable IO/bus master/irq router */
+       pci_disable_device();
+       pci_set_power_state(pci_choose_state());
+}
+
+.resume()
+{
+       pci_set_power_state(PCI_D0);
+       pci_restore_state();
+       /* device's irq possibly is changed, driver should take care */
+       pci_enable_device();
+       pci_set_master();
+
+       /* if using MSI, device's vector possibly is changed */
+       pci_enable_msi();
+
+       request_irq();
+       /* driver specific operations; */
+}
+
+This is a typical implementation. Drivers can slightly change the order
+of the operations in the implementation, ignore some operations or add
+more deriver specific operations in it, but drivers should do something like
+this on the whole.
+
 5. Resources
 ~~~~~~~~~~~~
 
index c7c3459fde4343fa3823db8ce21acb8830638df7..7a6b7896645942d69815ee3b37594618367a9069 100644 (file)
@@ -164,11 +164,11 @@ place where the thread is safe to be frozen (no kernel semaphores
 should be held at that point and it must be safe to sleep there), and
 add:
 
-            if (current->flags & PF_FREEZE)
-                    refrigerator(PF_FREEZE);
+       try_to_freeze();
 
 If the thread is needed for writing the image to storage, you should
-instead set the PF_NOFREEZE process flag when creating the thread.
+instead set the PF_NOFREEZE process flag when creating the thread (and
+be very carefull).
 
 
 Q: What is the difference between between "platform", "shutdown" and
@@ -233,3 +233,81 @@ A: Try running
 cat `cat /proc/[0-9]*/maps | grep / | sed 's:.* /:/:' | sort -u` > /dev/null
 
 after resume. swapoff -a; swapon -a may also be usefull.
+
+Q: What happens to devices during swsusp? They seem to be resumed
+during system suspend?
+
+A: That's correct. We need to resume them if we want to write image to
+disk. Whole sequence goes like
+
+      Suspend part
+      ~~~~~~~~~~~~
+      running system, user asks for suspend-to-disk
+
+      user processes are stopped
+
+      suspend(PMSG_FREEZE): devices are frozen so that they don't interfere
+                     with state snapshot
+
+      state snapshot: copy of whole used memory is taken with interrupts disabled
+
+      resume(): devices are woken up so that we can write image to swap
+
+      write image to swap
+
+      suspend(PMSG_SUSPEND): suspend devices so that we can power off
+
+      turn the power off
+
+      Resume part
+      ~~~~~~~~~~~
+      (is actually pretty similar)
+
+      running system, user asks for suspend-to-disk
+
+      user processes are stopped (in common case there are none, but with resume-from-initrd, noone knows)
+
+      read image from disk
+
+      suspend(PMSG_FREEZE): devices are frozen so that they don't interfere
+                     with image restoration
+
+      image restoration: rewrite memory with image
+
+      resume(): devices are woken up so that system can continue
+
+      thaw all user processes
+
+Q: What is this 'Encrypt suspend image' for?
+
+A: First of all: it is not a replacement for dm-crypt encrypted swap.
+It cannot protect your computer while it is suspended. Instead it does
+protect from leaking sensitive data after resume from suspend.
+
+Think of the following: you suspend while an application is running
+that keeps sensitive data in memory. The application itself prevents
+the data from being swapped out. Suspend, however, must write these
+data to swap to be able to resume later on. Without suspend encryption
+your sensitive data are then stored in plaintext on disk.  This means
+that after resume your sensitive data are accessible to all
+applications having direct access to the swap device which was used
+for suspend. If you don't need swap after resume these data can remain
+on disk virtually forever. Thus it can happen that your system gets
+broken in weeks later and sensitive data which you thought were
+encrypted and protected are retrieved and stolen from the swap device.
+To prevent this situation you should use 'Encrypt suspend image'.
+
+During suspend a temporary key is created and this key is used to
+encrypt the data written to disk. When, during resume, the data was
+read back into memory the temporary key is destroyed which simply
+means that all data written to disk during suspend are then
+inaccessible so they can't be stolen later on.  The only thing that
+you must then take care of is that you call 'mkswap' for the swap
+partition used for suspend as early as possible during regular
+boot. This asserts that any temporary key from an oopsed suspend or
+from a failed or aborted resume is erased from the swap device.
+
+As a rule of thumb use encrypted swap to protect your data while your
+system is shut down or suspended. Additionally use the encrypted
+suspend image to prevent sensitive data from being stolen after
+resume.
index 68734355d7cffccdac1071e733c419fef525f9b4..881a37e3eeb0a8cd36194453c3c728c9e3720fc1 100644 (file)
@@ -83,8 +83,10 @@ Compaq Armada E500 - P3-700     none (1) (S1 also works OK)
 Compaq Evo N620c               vga=normal, s3_bios (2)
 Dell 600m, ATI R250 Lf         none (1), but needs xorg-x11-6.8.1.902-1
 Dell D600, ATI RV250            vga=normal and X, or try vbestate (6)
+Dell D610                      vga=normal and X (possibly vbestate (6) too, but not tested)
 Dell Inspiron 4000             ??? (*)
 Dell Inspiron 500m             ??? (*)
+Dell Inspiron 510m             ???
 Dell Inspiron 600m             ??? (*)
 Dell Inspiron 8200             ??? (*)
 Dell Inspiron 8500             ??? (*)
@@ -123,6 +125,7 @@ Toshiba Satellite 4030CDT   s3_mode (3)
 Toshiba Satellite 4080XCDT      s3_mode (3)
 Toshiba Satellite 4090XCDT      ??? (*)
 Toshiba Satellite P10-554       s3_bios,s3_mode (4)(****)
+Toshiba M30                     (2) xor X with nvidia driver using internal AGP
 Uniwill 244IIO                 ??? (*)
 
 
index 8e33d7c82c49c05e53c7a45e29fd8de5af9e9bdf..b2f9b1598ac21c5df72b5327226db1891713cf24 100644 (file)
@@ -1,13 +1,16 @@
-This driver implement the ACPI Extensions For Display Adapters
-for integrated graphics devices on motherboard, as specified in
-ACPI 2.0 Specification, Appendix B, allowing to perform some basic
-control like defining the video POST device, retrieving EDID information
-or to setup a video output, etc.  Note that this is an ref. implementation only.
-It may or may not work for your integrated video device.
+ACPI video extensions
+~~~~~~~~~~~~~~~~~~~~~
+
+This driver implement the ACPI Extensions For Display Adapters for
+integrated graphics devices on motherboard, as specified in ACPI 2.0
+Specification, Appendix B, allowing to perform some basic control like
+defining the video POST device, retrieving EDID information or to
+setup a video output, etc.  Note that this is an ref. implementation
+only.  It may or may not work for your integrated video device.
 
 Interfaces exposed to userland through /proc/acpi/video:
 
-VGA/info : display the supported video bus device capability like ,Video ROM, CRT/LCD/TV.
+VGA/info : display the supported video bus device capability like Video ROM, CRT/LCD/TV.
 VGA/ROM :  Used to get a copy of the display devices' ROM data (up to 4k).
 VGA/POST_info : Used to determine what options are implemented.
 VGA/POST : Used to get/set POST device.
@@ -15,7 +18,7 @@ VGA/DOS : Used to get/set ownership of output switching:
        Please refer ACPI spec B.4.1 _DOS
 VGA/CRT : CRT output
 VGA/LCD : LCD output
-VGA/TV : TV output 
+VGA/TVO : TV output
 VGA/*/brightness : Used to get/set brightness of output device
 
 Notify event through /proc/acpi/event:
index 2d1cd939b4df784d3644c6572d54693ff70b6b96..e24fdeada9705e3e9a14cc4195592e832d169c00 100644 (file)
@@ -12,8 +12,8 @@ where log records can be stored efficiently in memory, where each component
 One purpose of this is to inspect the debug logs after a production system crash
 in order to analyze the reason for the crash.
 If the system still runs but only a subcomponent which uses dbf failes,
-it is possible to look at the debug logs on a live system via the Linux proc
-filesystem.
+it is possible to look at the debug logs on a live system via the Linux
+debugfs filesystem.
 The debug feature may also very useful for kernel and driver development.
 
 Design:
@@ -52,16 +52,18 @@ Each debug entry contains the following data:
 - Flag, if entry is an exception or not
 
 The debug logs can be inspected in a live system through entries in
-the proc-filesystem. Under the path /proc/s390dbf there is 
+the debugfs-filesystem. Under the toplevel directory "s390dbf" there is
 a directory for each registered component, which is named like the
-corresponding component.
+corresponding component. The debugfs normally should be mounted to
+/sys/kernel/debug therefore the debug feature can be accessed unter
+/sys/kernel/debug/s390dbf.
 
 The content of the directories are files which represent different views
 to the debug log. Each component can decide which views should be
 used through registering them with the function debug_register_view().
 Predefined views for hex/ascii, sprintf and raw binary data are provided.
 It is also possible to define other views. The content of
-a view can be inspected simply by reading the corresponding proc file.
+a view can be inspected simply by reading the corresponding debugfs file.
 
 All debug logs have an an actual debug level (range from 0 to 6).
 The default level is 3. Event and Exception functions have a 'level'
@@ -69,14 +71,14 @@ parameter. Only debug entries with a level that is lower or equal
 than the actual level are written to the log. This means, when
 writing events, high priority log entries should have a low level
 value whereas low priority entries should have a high one.
-The actual debug level can be changed with the help of the proc-filesystem 
-through writing a number string "x" to the 'level' proc file which is
+The actual debug level can be changed with the help of the debugfs-filesystem
+through writing a number string "x" to the 'level' debugfs file which is
 provided for every debug log. Debugging can be switched off completely
-by using "-" on the 'level' proc file.
+by using "-" on the 'level' debugfs file.
 
 Example:
 
-> echo "-" > /proc/s390dbf/dasd/level
+> echo "-" > /sys/kernel/debug/s390dbf/dasd/level
 
 It is also possible to deactivate the debug feature globally for every
 debug log. You can change the behavior using  2 sysctl parameters in
@@ -99,11 +101,11 @@ Kernel Interfaces:
 ------------------
 
 ----------------------------------------------------------------------------
-debug_info_t *debug_register(char *name, int pages_index, int nr_areas,
+debug_info_t *debug_register(char *name, int pages, int nr_areas,
                              int buf_size);
 
-Parameter:    name:        Name of debug log (e.g. used for proc entry) 
-              pages_index: 2^pages_index pages will be allocated per area
+Parameter:    name:        Name of debug log (e.g. used for debugfs entry)
+              pages:       number of pages, which will be allocated per area
               nr_areas:    number of debug areas
               buf_size:    size of data area in each debug entry
 
@@ -134,7 +136,7 @@ Return Value:  none
 Description:   Sets new actual debug level if new_level is valid. 
 
 ---------------------------------------------------------------------------
-+void debug_stop_all(void);
+void debug_stop_all(void);
 
 Parameter:     none
 
@@ -270,7 +272,7 @@ Parameter:     id:    handle for debug log
 Return Value:  0  : ok 
                < 0: Error 
 
-Description:   registers new debug view and creates proc dir entry 
+Description:   registers new debug view and creates debugfs dir entry
 
 ---------------------------------------------------------------------------
 int debug_unregister_view (debug_info_t * id, struct debug_view *view); 
@@ -281,7 +283,7 @@ Parameter:     id:    handle for debug log
 Return Value:  0  : ok 
                < 0: Error 
 
-Description:   unregisters debug view and removes proc dir entry 
+Description:   unregisters debug view and removes debugfs dir entry
 
 
 
@@ -308,7 +310,7 @@ static int init(void)
 {
     /* register 4 debug areas with one page each and 4 byte data field */
 
-    debug_info = debug_register ("test", 0, 4, 4 );
+    debug_info = debug_register ("test", 1, 4, 4 );
     debug_register_view(debug_info,&debug_hex_ascii_view);
     debug_register_view(debug_info,&debug_raw_view);
 
@@ -343,7 +345,7 @@ static int init(void)
     /* register 4 debug areas with one page each and data field for */
     /* format string pointer + 2 varargs (= 3 * sizeof(long))       */
 
-    debug_info = debug_register ("test", 0, 4, sizeof(long) * 3);
+    debug_info = debug_register ("test", 1, 4, sizeof(long) * 3);
     debug_register_view(debug_info,&debug_sprintf_view);
 
     debug_sprintf_event(debug_info, 2 , "first event in %s:%i\n",__FILE__,__LINE__);
@@ -362,16 +364,16 @@ module_exit(cleanup);
 
 
 
-ProcFS Interface
+Debugfs Interface
 ----------------
 Views to the debug logs can be investigated through reading the corresponding 
-proc-files:
+debugfs-files:
 
 Example:
 
-> ls /proc/s390dbf/dasd
-flush  hex_ascii  level      raw 
-> cat /proc/s390dbf/dasd/hex_ascii | sort +1
+> ls /sys/kernel/debug/s390dbf/dasd
+flush  hex_ascii  level pages raw
+> cat /sys/kernel/debug/s390dbf/dasd/hex_ascii | sort +1
 00 00974733272:680099 2 - 02 0006ad7e  07 ea 4a 90 | ....
 00 00974733272:682210 2 - 02 0006ade6  46 52 45 45 | FREE
 00 00974733272:682213 2 - 02 0006adf6  07 ea 4a 90 | ....
@@ -391,25 +393,36 @@ Changing the debug level
 Example:
 
 
-> cat /proc/s390dbf/dasd/level
+> cat /sys/kernel/debug/s390dbf/dasd/level
 3
-> echo "5" > /proc/s390dbf/dasd/level
-> cat /proc/s390dbf/dasd/level
+> echo "5" > /sys/kernel/debug/s390dbf/dasd/level
+> cat /sys/kernel/debug/s390dbf/dasd/level
 5
 
 Flushing debug areas
 --------------------
 Debug areas can be flushed with piping the number of the desired
-area (0...n) to the proc file "flush". When using "-" all debug areas
+area (0...n) to the debugfs file "flush". When using "-" all debug areas
 are flushed.
 
 Examples:
 
 1. Flush debug area 0:
-> echo "0" > /proc/s390dbf/dasd/flush  
+> echo "0" > /sys/kernel/debug/s390dbf/dasd/flush
 
 2. Flush all debug areas:
-> echo "-" > /proc/s390dbf/dasd/flush
+> echo "-" > /sys/kernel/debug/s390dbf/dasd/flush
+
+Changing the size of debug areas
+------------------------------------
+It is possible the change the size of debug areas through piping
+the number of pages to the debugfs file "pages". The resize request will
+also flush the debug areas.
+
+Example:
+
+Define 4 pages for the debug areas of debug feature "dasd":
+> echo "4" > /sys/kernel/debug/s390dbf/dasd/pages
 
 Stooping the debug feature
 --------------------------
@@ -491,7 +504,7 @@ Defining views
 --------------
 
 Views are specified with the 'debug_view' structure. There are defined
-callback functions which are used for reading and writing the proc files:
+callback functions which are used for reading and writing the debugfs files:
 
 struct debug_view {
         char name[DEBUG_MAX_PROCF_LEN];  
@@ -525,7 +538,7 @@ typedef int (debug_input_proc_t) (debug_info_t* id,
 The "private_data" member can be used as pointer to view specific data.
 It is not used by the debug feature itself.
 
-The output when reading a debug-proc file is structured like this:
+The output when reading a debugfs file is structured like this:
 
 "prolog_proc output"
 
@@ -534,13 +547,13 @@ The output when reading a debug-proc file is structured like this:
 "header_proc output 3"  "format_proc output 3"
 ...
 
-When a view is read from the proc fs, the Debug Feature calls the 
+When a view is read from the debugfs, the Debug Feature calls the
 'prolog_proc' once for writing the prolog.
 Then 'header_proc' and 'format_proc' are called for each 
 existing debug entry.
 
 The input_proc can be used to implement functionality when it is written to 
-the view (e.g. like with 'echo "0" > /proc/s390dbf/dasd/level).
+the view (e.g. like with 'echo "0" > /sys/kernel/debug/s390dbf/dasd/level).
 
 For header_proc there can be used the default function
 debug_dflt_header_fn() which is defined in in debug.h.
@@ -602,7 +615,7 @@ debug_info = debug_register ("test", 0, 4, 4 ));
 debug_register_view(debug_info, &debug_test_view);
 for(i = 0; i < 10; i ++) debug_int_event(debug_info, 1, i);
 
-> cat /proc/s390dbf/test/myview
+> cat /sys/kernel/debug/s390dbf/test/myview
 00 00964419734:611402 1 - 00 88042ca   This error...........
 00 00964419734:611405 1 - 00 88042ca   That error...........
 00 00964419734:611408 1 - 00 88042ca   Problem..............
index e9c0178cd202dafa7097e545152afe49a11b6628..ac7eabbf662aaf9d83814debb4f39d0c79043faf 100644 (file)
@@ -107,8 +107,8 @@ hardware.
        indicate that the signal is permanently active.  If RI is
        not available, the signal should not be indicated as active.
 
-       Locking: none.
-       Interrupts: caller dependent.
+       Locking: port->lock taken.
+       Interrupts: locally disabled.
        This call must not sleep
 
   stop_tx(port,tty_stop)
index f98c2e31c143e6a114f61feaef725f4422e3b028..136d817c01babb51fc8e80ba5917544a7204c5ab 100644 (file)
@@ -72,6 +72,8 @@ On all -  write a character to /proc/sysrq-trigger.  eg:
 'b'     - Will immediately reboot the system without syncing or unmounting
           your disks.
 
+'c'    - Will perform a kexec reboot in order to take a crashdump.
+
 'o'     - Will shut your system off (if configured and supported).
 
 's'     - Will attempt to sync all mounted filesystems.
@@ -122,6 +124,9 @@ useful when you want to exit a program that will not let you switch consoles.
 re'B'oot is good when you're unable to shut down. But you should also 'S'ync
 and 'U'mount first.
 
+'C'rashdump can be used to manually trigger a crashdump when the system is hung.
+The kernel needs to have been built with CONFIG_KEXEC enabled.
+
 'S'ync is great when your system is locked up, it allows you to sync your
 disks and will certainly lessen the chance of data loss and fscking. Note
 that the sync hasn't taken place until you see the "OK" and "Done" appear
index 4b3d8f640a4a37a308788234f1506e755607e8fc..441407b12a9f49563f9132a44dbf830739041428 100644 (file)
-<HTML><HEAD>
-<TITLE>Video4Linux Kernel API Reference v0.1:19990430</TITLE>
-</HEAD>
-<! Revision History: >
-<!   4/30/1999 - Fred Gleason (fredg@wava.com)>
-<! Documented extensions for the Radio Data System (RDS) extensions >
-<BODY bgcolor="#ffffff">
-<H3>Devices</H3>
-Video4Linux provides the following sets of device files. These live on the
-character device formerly known as "/dev/bttv". /dev/bttv should be a
-symlink to /dev/video0 for most people. 
-<P>
-<TABLE>
-<TR><TH>Device Name</TH><TH>Minor Range</TH><TH>Function</TH>
-<TR><TD>/dev/video</TD><TD>0-63</TD><TD>Video Capture Interface</TD>
-<TR><TD>/dev/radio</TD><TD>64-127</TD><TD>AM/FM Radio Devices</TD>
-<TR><TD>/dev/vtx</TD><TD>192-223</TD><TD>Teletext Interface Chips</TD>
-<TR><TD>/dev/vbi</TD><TD>224-239</TD><TD>Raw VBI Data (Intercast/teletext)</TD>
-</TABLE>
-<P>
-Video4Linux programs open and scan the devices to find what they are looking
-for. Capability queries define what each interface supports. The 
-described API is only defined for video capture cards. The relevant subset
-applies to radio cards. Teletext interfaces talk the existing VTX API.
-<P>
-<H3>Capability Query Ioctl</H3>
-The <B>VIDIOCGCAP</B> ioctl call is used to obtain the capability
-information for a video device. The <b>struct video_capability</b> object
-passed to the ioctl is completed and returned. It contains the following
-information
-<P>
-<TABLE>
-<TR><TD><b>name[32]</b><TD>Canonical name for this interface</TD>
-<TR><TD><b>type</b><TD>Type of interface</TD>
-<TR><TD><b>channels</b><TD>Number of radio/tv channels if appropriate</TD>
-<TR><TD><b>audios</b><TD>Number of audio devices if appropriate</TD>
-<TR><TD><b>maxwidth</b><TD>Maximum capture width in pixels</TD>
-<TR><TD><b>maxheight</b><TD>Maximum capture height in pixels</TD>
-<TR><TD><b>minwidth</b><TD>Minimum capture width in pixels</TD>
-<TR><TD><b>minheight</b><TD>Minimum capture height in pixels</TD>
-</TABLE>
-<P>
-The type field lists the capability flags for the device. These are
-as follows
-<P>
-<TABLE>
-<TR><TH>Name</TH><TH>Description</TH>
-<TR><TD><b>VID_TYPE_CAPTURE</b><TD>Can capture to memory</TD>
-<TR><TD><b>VID_TYPE_TUNER</b><TD>Has a tuner of some form</TD>
-<TR><TD><b>VID_TYPE_TELETEXT</b><TD>Has teletext capability</TD>
-<TR><TD><b>VID_TYPE_OVERLAY</b><TD>Can overlay its image onto the frame buffer</TD>
-<TR><TD><b>VID_TYPE_CHROMAKEY</b><TD>Overlay is Chromakeyed</TD>
-<TR><TD><b>VID_TYPE_CLIPPING</b><TD>Overlay clipping is supported</TD>
-<TR><TD><b>VID_TYPE_FRAMERAM</b><TD>Overlay overwrites frame buffer memory</TD>
-<TR><TD><b>VID_TYPE_SCALES</b><TD>The hardware supports image scaling</TD>
-<TR><TD><b>VID_TYPE_MONOCHROME</b><TD>Image capture is grey scale only</TD>
-<TR><TD><b>VID_TYPE_SUBCAPTURE</b><TD>Capture can be of only part of the image</TD>
-</TABLE>
-<P>
-The minimum and maximum sizes listed for a capture device do not imply all
-that all height/width ratios or sizes within the range are possible. A
-request to set a size will be honoured by the largest available capture
-size whose capture is no large than the requested rectangle in either
-direction. For example the quickcam has 3 fixed settings. 
-<P>
-<H3>Frame Buffer</H3>
-Capture cards that drop data directly onto the frame buffer must be told the
-base address of the frame buffer, its size and organisation. This is a 
-privileged ioctl and one that eventually X itself should set.
-<P>
-The <b>VIDIOCSFBUF</b> ioctl sets the frame buffer parameters for a capture
-card. If the card does not do direct writes to the frame buffer then this
-ioctl will be unsupported. The <b>VIDIOCGFBUF</b> ioctl returns the
-currently used parameters. The structure used in both cases is a 
-<b>struct video_buffer</b>.
-<P>
-<TABLE>
-<TR><TD><b>void *base</b></TD><TD>Base physical address of the buffer</TD>
-<TR><TD><b>int height</b></TD><TD>Height of the frame buffer</TD>
-<TR><TD><b>int width</b></TD><TD>Width of the frame buffer</TD>
-<TR><TD><b>int depth</b></TD><TD>Depth of the frame buffer</TD>
-<TR><TD><b>int bytesperline</b></TD><TD>Number of bytes of memory between the start of two adjacent lines</TD>
-</TABLE>
-<P>
-Note that these values reflect the physical layout of the frame buffer. 
-The visible area may be smaller. In fact under XFree86 this is commonly the
-case. XFree86 DGA can provide the parameters required to set up this ioctl.
-Setting the base address to NULL indicates there is no physical frame buffer
-access.
-<P>
-<H3>Capture Windows</H3>
-The capture area is described by a <b>struct video_window</b>. This defines
-a capture area and the clipping information if relevant. The 
-<b>VIDIOCGWIN</b> ioctl recovers the current settings and the 
-<b>VIDIOCSWIN</b> sets new values. A successful call to <b>VIDIOCSWIN</b> 
-indicates that a suitable set of parameters have been chosen. They do not
-indicate that exactly what was requested was granted. The program should
-call <b>VIDIOCGWIN</b> to check if the nearest match was suitable. The
-<b>struct video_window</b> contains the following fields.
-<P>
-<TABLE>
-<TR><TD><b>x</b><TD>The X co-ordinate specified in X windows format.</TD>
-<TR><TD><b>y</b><TD>The Y co-ordinate specified in X windows format.</TD>
-<TR><TD><b>width</b><TD>The width of the image capture.</TD>
-<TR><TD><b>height</b><TD>The height of the image capture.</TD>
-<TR><TD><b>chromakey</b><TD>A host order RGB32 value for the chroma key.</TD>
-<TR><TD><b>flags</b><TD>Additional capture flags.</TD>
-<TR><TD><b>clips</b><TD>A list of clipping rectangles. <em>(Set only)</em></TD>
-<TR><TD><b>clipcount</b><TD>The number of clipping rectangles. <em>(Set only)</em></TD>
-</TABLE>
-<P>
-Clipping rectangles are passed as an array. Each clip consists of the following
-fields available to the user.
-<P>
-<TABLE>
-<TR><TD><b>x</b></TD><TD>X co-ordinate of rectangle to skip</TD>
-<TR><TD><b>y</b></TD><TD>Y co-ordinate of rectangle to skip</TD>
-<TR><TD><b>width</b></TD><TD>Width of rectangle to skip</TD>
-<TR><TD><b>height</b></TD><TD>Height of rectangle to skip</TD>
-</TABLE>
-<P>
-Merely setting the window does not enable capturing. Overlay capturing
-(i.e. PCI-PCI transfer to the frame buffer of the video card)
-is activated by passing the <b>VIDIOCCAPTURE</b> ioctl a value of 1, and
-disabled by passing it a value of 0. 
-<P>
-Some capture devices can capture a subfield of the image they actually see.
-This is indicated when VIDEO_TYPE_SUBCAPTURE is defined.
-The video_capture describes the time and special subfields to capture.
-The video_capture structure contains the following fields.
-<P>
-<TABLE>
-<TR><TD><b>x</b></TD><TD>X co-ordinate of source rectangle to grab</TD>
-<TR><TD><b>y</b></TD><TD>Y co-ordinate of source rectangle to grab</TD>
-<TR><TD><b>width</b></TD><TD>Width of source rectangle to grab</TD>
-<TR><TD><b>height</b></TD><TD>Height of source rectangle to grab</TD>
-<TR><TD><b>decimation</b></TD><TD>Decimation to apply</TD>
-<TR><TD><b>flags</b></TD><TD>Flag settings for grabbing</TD>
-</TABLE>
-The available flags are
-<P>
-<TABLE>
-<TR><TH>Name</TH><TH>Description</TH>
-<TR><TD><b>VIDEO_CAPTURE_ODD</b><TD>Capture only odd frames</TD>
-<TR><TD><b>VIDEO_CAPTURE_EVEN</b><TD>Capture only even frames</TD>
-</TABLE>
-<P>
-<H3>Video Sources</H3>
-Each video4linux video or audio device captures from one or more 
-source <b>channels</b>. Each channel can be queries with the 
-<b>VDIOCGCHAN</b> ioctl call. Before invoking this function the caller
-must set the channel field to the channel that is being queried. On return
-the <b>struct video_channel</b> is filled in with information about the
-nature of the channel itself.
-<P>
-The <b>VIDIOCSCHAN</b> ioctl takes an integer argument and switches the
-capture to this input. It is not defined whether parameters such as colour
-settings or tuning are maintained across a channel switch. The caller should
-maintain settings as desired for each channel. (This is reasonable as 
-different video inputs may have different properties).
-<P>
-The <b>struct video_channel</b> consists of the following
-<P>
-<TABLE>
-<TR><TD><b>channel</b></TD><TD>The channel number</TD>
-<TR><TD><b>name</b></TD><TD>The input name - preferably reflecting the label
-on the card input itself</TD>
-<TR><TD><b>tuners</b></TD><TD>Number of tuners for this input</TD>
-<TR><TD><b>flags</b></TD><TD>Properties the tuner has</TD>
-<TR><TD><b>type</b></TD><TD>Input type (if known)</TD>
-<TR><TD><b>norm</b><TD>The norm for this channel</TD>
-</TABLE>
-<P>
-The flags defined are
-<P>
-<TABLE>
-<TR><TD><b>VIDEO_VC_TUNER</b><TD>Channel has tuners.</TD>
-<TR><TD><b>VIDEO_VC_AUDIO</b><TD>Channel has audio.</TD>
-<TR><TD><b>VIDEO_VC_NORM</b><TD>Channel has norm setting.</TD>
-</TABLE>
-<P>
-The types defined are
-<P>
-<TABLE>
-<TR><TD><b>VIDEO_TYPE_TV</b><TD>The input is a TV input.</TD>
-<TR><TD><b>VIDEO_TYPE_CAMERA</b><TD>The input is a camera.</TD>
-</TABLE>
-<P>
-<H3>Image Properties</H3>
-The image properties of the picture can be queried with the <b>VIDIOCGPICT</b>
-ioctl which fills in a <b>struct video_picture</b>. The <b>VIDIOCSPICT</b> 
-ioctl allows values to be changed. All values except for the palette type
-are scaled between 0-65535. 
-<P>
-The <b>struct video_picture</b> consists of the following fields
-<P>
-<TABLE>
-<TR><TD><b>brightness</b><TD>Picture brightness</TD>
-<TR><TD><b>hue</b><TD>Picture hue (colour only)</TD>
-<TR><TD><b>colour</b><TD>Picture colour (colour only)</TD>
-<TR><TD><b>contrast</b><TD>Picture contrast</TD>
-<TR><TD><b>whiteness</b><TD>The whiteness (greyscale only)</TD>
-<TR><TD><b>depth</b><TD>The capture depth (may need to match the frame buffer depth)</TD>
-<TR><TD><b>palette</b><TD>Reports the palette that should be used for this image</TD>
-</TABLE>
-<P>
-The following palettes are defined
-<P>
-<TABLE>
-<TR><TD><b>VIDEO_PALETTE_GREY</b><TD>Linear intensity grey scale (255 is brightest).</TD>
-<TR><TD><b>VIDEO_PALETTE_HI240</b><TD>The BT848 8bit colour cube.</TD>
-<TR><TD><b>VIDEO_PALETTE_RGB565</b><TD>RGB565 packed into 16 bit words.</TD>
-<TR><TD><b>VIDEO_PALETTE_RGB555</b><TD>RGV555 packed into 16 bit words, top bit undefined.</TD>
-<TR><TD><b>VIDEO_PALETTE_RGB24</b><TD>RGB888 packed into 24bit words.</TD>
-<TR><TD><b>VIDEO_PALETTE_RGB32</b><TD>RGB888 packed into the low 3 bytes of 32bit words. The top 8bits are undefined.</TD>
-<TR><TD><b>VIDEO_PALETTE_YUV422</b><TD>Video style YUV422 - 8bits packed 4bits Y 2bits U 2bits V</TD>
-<TR><TD><b>VIDEO_PALETTE_YUYV</b><TD>Describe me</TD>
-<TR><TD><b>VIDEO_PALETTE_UYVY</b><TD>Describe me</TD>
-<TR><TD><b>VIDEO_PALETTE_YUV420</b><TD>YUV420 capture</TD>
-<TR><TD><b>VIDEO_PALETTE_YUV411</b><TD>YUV411 capture</TD>
-<TR><TD><b>VIDEO_PALETTE_RAW</b><TD>RAW capture (BT848)</TD>
-<TR><TD><b>VIDEO_PALETTE_YUV422P</b><TD>YUV 4:2:2 Planar</TD>
-<TR><TD><b>VIDEO_PALETTE_YUV411P</b><TD>YUV 4:1:1 Planar</TD>
-</TABLE>
-<P>
-<H3>Tuning</H3>
-Each video input channel can have one or more tuners associated with it. Many
-devices will not have tuners. TV cards and radio cards will have one or more
-tuners attached.
-<P>
-Tuners are described by a <b>struct video_tuner</b> which can be obtained by
-the <b>VIDIOCGTUNER</b> ioctl. Fill in the tuner number in the structure
-then pass the structure to the ioctl to have the data filled in. The 
-tuner can be switched using <b>VIDIOCSTUNER</b> which takes an integer argument
-giving the tuner to use. A struct tuner has the following fields
-<P>
-<TABLE>
-<TR><TD><b>tuner</b><TD>Number of the tuner</TD>
-<TR><TD><b>name</b><TD>Canonical name for this tuner (eg FM/AM/TV)</TD>
-<TR><TD><b>rangelow</b><TD>Lowest tunable frequency</TD>
-<TR><TD><b>rangehigh</b><TD>Highest tunable frequency</TD>
-<TR><TD><b>flags</b><TD>Flags describing the tuner</TD>
-<TR><TD><b>mode</b><TD>The video signal mode if relevant</TD>
-<TR><TD><b>signal</b><TD>Signal strength if known - between 0-65535</TD>
-</TABLE>
-<P>
-The following flags exist
-<P>
-<TABLE>
-<TR><TD><b>VIDEO_TUNER_PAL</b><TD>PAL tuning is supported</TD>
-<TR><TD><b>VIDEO_TUNER_NTSC</b><TD>NTSC tuning is supported</TD>
-<TR><TD><b>VIDEO_TUNER_SECAM</b><TD>SECAM tuning is supported</TD>
-<TR><TD><b>VIDEO_TUNER_LOW</b><TD>Frequency is in a lower range</TD>
-<TR><TD><b>VIDEO_TUNER_NORM</b><TD>The norm for this tuner is settable</TD>
-<TR><TD><b>VIDEO_TUNER_STEREO_ON</b><TD>The tuner is seeing stereo audio</TD>
-<TR><TD><b>VIDEO_TUNER_RDS_ON</b><TD>The tuner is seeing a RDS datastream</TD>
-<TR><TD><b>VIDEO_TUNER_MBS_ON</b><TD>The tuner is seeing a MBS datastream</TD>
-</TABLE>
-<P>
-The following modes are defined
-<P>
-<TABLE>
-<TR><TD><b>VIDEO_MODE_PAL</b><TD>The tuner is in PAL mode</TD>
-<TR><TD><b>VIDEO_MODE_NTSC</b><TD>The tuner is in NTSC mode</TD>
-<TR><TD><b>VIDEO_MODE_SECAM</b><TD>The tuner is in SECAM mode</TD>
-<TR><TD><b>VIDEO_MODE_AUTO</b><TD>The tuner auto switches, or mode does not apply</TD>
-</TABLE>
-<P>
-Tuning frequencies are an unsigned 32bit value in 1/16th MHz or if the
-<b>VIDEO_TUNER_LOW</b> flag is set they are in 1/16th KHz. The current
-frequency is obtained as an unsigned long via the <b>VIDIOCGFREQ</b> ioctl and
-set by the <b>VIDIOCSFREQ</b> ioctl.
-<P>
-<H3>Audio</H3>
-TV and Radio devices have one or more audio inputs that may be selected. 
-The audio properties are queried by passing a <b>struct video_audio</b> to <b>VIDIOCGAUDIO</b> ioctl. The
-<b>VIDIOCSAUDIO</b> ioctl sets audio properties.
-<P>
-The structure contains the following fields
-<P>
-<TABLE>
-<TR><TD><b>audio</b><TD>The channel number</TD>
-<TR><TD><b>volume</b><TD>The volume level</TD>
-<TR><TD><b>bass</b><TD>The bass level</TD>
-<TR><TD><b>treble</b><TD>The treble level</TD>
-<TR><TD><b>flags</b><TD>Flags describing the audio channel</TD>
-<TR><TD><b>name</b><TD>Canonical name for the audio input</TD>
-<TR><TD><b>mode</b><TD>The mode the audio input is in</TD>
-<TR><TD><b>balance</b><TD>The left/right balance</TD>
-<TR><TD><b>step</b><TD>Actual step used by the hardware</TD>
-</TABLE>
-<P>
-The following flags are defined
-<P>
-<TABLE>
-<TR><TD><b>VIDEO_AUDIO_MUTE</b><TD>The audio is muted</TD>
-<TR><TD><b>VIDEO_AUDIO_MUTABLE</b><TD>Audio muting is supported</TD>
-<TR><TD><b>VIDEO_AUDIO_VOLUME</b><TD>The volume is controllable</TD>
-<TR><TD><b>VIDEO_AUDIO_BASS</b><TD>The bass is controllable</TD>
-<TR><TD><b>VIDEO_AUDIO_TREBLE</b><TD>The treble is controllable</TD>
-<TR><TD><b>VIDEO_AUDIO_BALANCE</b><TD>The balance is controllable</TD>
-</TABLE>
-<P>
-The following decoding modes are defined
-<P>
-<TABLE>
-<TR><TD><b>VIDEO_SOUND_MONO</b><TD>Mono signal</TD>
-<TR><TD><b>VIDEO_SOUND_STEREO</b><TD>Stereo signal (NICAM for TV)</TD>
-<TR><TD><b>VIDEO_SOUND_LANG1</b><TD>European TV alternate language 1</TD>
-<TR><TD><b>VIDEO_SOUND_LANG2</b><TD>European TV alternate language 2</TD>
-</TABLE>
-<P>
-<H3>Reading Images</H3>
-Each call to the <b>read</b> syscall returns the next available image
-from the device. It is up to the caller to set format and size (using
-the VIDIOCSPICT and VIDIOCSWIN ioctls) and then to pass a suitable
-size buffer and length to the function. Not all devices will support
-read operations.
-<P>
-A second way to handle image capture is via the mmap interface if supported.
-To use the mmap interface a user first sets the desired image size and depth
-properties. Next the VIDIOCGMBUF ioctl is issued. This reports the size
-of buffer to mmap and the offset within the buffer for each frame. The
-number of frames supported is device dependent and may only be one. 
-<P>
-The video_mbuf structure contains the following fields
-<P>
-<TABLE>
-<TR><TD><b>size</b><TD>The number of bytes to map</TD>
-<TR><TD><b>frames</b><TD>The number of frames</TD>
-<TR><TD><b>offsets</b><TD>The offset of each frame</TD>
-</TABLE>
-<P>
-Once the mmap has been made the VIDIOCMCAPTURE ioctl starts the
-capture to a frame using the format and image size specified in the
-video_mmap (which should match or be below the initial query size).
-When the VIDIOCMCAPTURE ioctl returns the frame is <em>not</em>
-captured yet, the driver just instructed the hardware to start the
-capture.  The application has to use the VIDIOCSYNC ioctl to wait
-until the capture of a frame is finished.  VIDIOCSYNC takes the frame
-number you want to wait for as argument.
-<p>
-It is allowed to call VIDIOCMCAPTURE multiple times (with different
-frame numbers in video_mmap->frame of course) and thus have multiple
-outstanding capture requests.  A simple way do to double-buffering
-using this feature looks like this:
-<pre>
-/* setup everything */
-VIDIOCMCAPTURE(0)
-while (whatever) {
-   VIDIOCMCAPTURE(1)
-   VIDIOCSYNC(0)
-   /* process frame 0 while the hardware captures frame 1 */
-   VIDIOCMCAPTURE(0)
-   VIDIOCSYNC(1)
-   /* process frame 1 while the hardware captures frame 0 */
-}
-</pre>
-Note that you are <em>not</em> limited to only two frames.  The API
-allows up to 32 frames, the VIDIOCGMBUF ioctl returns the number of
-frames the driver granted.  Thus it is possible to build deeper queues
-to avoid loosing frames on load peaks.
-<p>
-While capturing to memory the driver will make a "best effort" attempt
-to capture to screen as well if requested. This normally means all
-frames that "miss" memory mapped capture will go to the display.
-<P>
-A final ioctl exists to allow a device to obtain related devices if a
-driver has multiple components (for example video0 may not be associated
-with vbi0 which would cause an intercast display program to make a bad
-mistake). The VIDIOCGUNIT ioctl reports the unit numbers of the associated
-devices if any exist. The video_unit structure has the following fields.
-<P>
-<TABLE>
-<TR><TD><b>video</b><TD>Video capture device</TD>
-<TR><TD><b>vbi</b><TD>VBI capture device</TD>
-<TR><TD><b>radio</b><TD>Radio device</TD>
-<TR><TD><b>audio</b><TD>Audio mixer</TD>
-<TR><TD><b>teletext</b><TD>Teletext device</TD>
-</TABLE>
-<P>
-<H3>RDS Datastreams</H3>
-For radio devices that support it, it is possible to receive Radio Data
-System (RDS) data by means of a read() on the device.  The data is packed in
-groups of three, as follows:
-<TABLE>
-<TR><TD>First Octet</TD><TD>Least Significant Byte of RDS Block</TD></TR>
-<TR><TD>Second Octet</TD><TD>Most Significant Byte of RDS Block
-<TR><TD>Third Octet</TD><TD>Bit 7:</TD><TD>Error bit.  Indicates that
-an uncorrectable error occurred during reception of this block.</TD></TR>
-<TR><TD>&nbsp;</TD><TD>Bit 6:</TD><TD>Corrected bit.  Indicates that  
-an error was corrected for this data block.</TD></TR>
-<TR><TD>&nbsp;</TD><TD>Bits 5-3:</TD><TD>Received Offset.  Indicates the  
-offset received by the sync system.</TD></TR>
-<TR><TD>&nbsp;</TD><TD>Bits 2-0:</TD><TD>Offset Name.  Indicates the  
-offset applied to this data.</TD></TR>
-</TABLE>
-</BODY>
-</HTML>
+<TITLE>V4L API</TITLE>
+<H1>Video For Linux APIs</H1>
+<table border=0>
+<tr>
+<td>
+<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L1_API.html>
+V4L original API</a>
+</td><td>
+Obsoleted by V4L2 API
+</td></tr><tr><td>
+<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L2_API.html>
+V4L2 API</a>
+</td><td>
+Should be used for new projects
+</td></tr>
+</table>
index e46761c39e3f81a622491bdec2fb00ad61992dd7..aeeafec0594cda9d5176f67ed8eb839e33c5fca0 100644 (file)
@@ -119,3 +119,17 @@ card=117 - NGS NGSTV+
 card=118 - LMLBT4
 card=119 - Tekram M205 PRO
 card=120 - Conceptronic CONTVFMi
+card=121 - Euresys Picolo Tetra
+card=122 - Spirit TV Tuner
+card=123 - AVerMedia AVerTV DVB-T 771
+card=124 - AverMedia AverTV DVB-T 761
+card=125 - MATRIX Vision Sigma-SQ
+card=126 - MATRIX Vision Sigma-SLC
+card=127 - APAC Viewcomp 878(AMAX)
+card=128 - DVICO FusionHDTV DVB-T Lite
+card=129 - V-Gear MyVCD
+card=130 - Super TV Tuner
+card=131 - Tibet Systems 'Progress DVR' CS16
+card=132 - Kodicom 4400R (master)
+card=133 - Kodicom 4400R (slave)
+card=134 - Adlink RTV24
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
new file mode 100644 (file)
index 0000000..4377aa1
--- /dev/null
@@ -0,0 +1,29 @@
+card=0 - UNKNOWN/GENERIC
+card=1 - Hauppauge WinTV 34xxx models
+card=2 - GDI Black Gold
+card=3 - PixelView
+card=4 - ATI TV Wonder Pro
+card=5 - Leadtek Winfast 2000XP Expert
+card=6 - AverTV Studio 303 (M126)
+card=7 - MSI TV-@nywhere Master
+card=8 - Leadtek Winfast DV2000
+card=9 - Leadtek PVR 2000
+card=10 - IODATA GV-VCP3/PCI
+card=11 - Prolink PlayTV PVR
+card=12 - ASUS PVR-416
+card=13 - MSI TV-@nywhere
+card=14 - KWorld/VStream XPert DVB-T
+card=15 - DViCO FusionHDTV DVB-T1
+card=16 - KWorld LTV883RF
+card=17 - DViCO FusionHDTV 3 Gold-Q
+card=18 - Hauppauge Nova-T DVB-T
+card=19 - Conexant DVB-T reference design
+card=20 - Provideo PV259
+card=21 - DViCO FusionHDTV DVB-T Plus
+card=22 - digitalnow DNTV Live! DVB-T
+card=23 - pcHDTV HD3000 HDTV
+card=24 - Hauppauge WinTV 28xxx (Roslyn) models
+card=25 - Digital-Logic MICROSPACE Entertainment Center (MEC)
+card=26 - IODATA GV/BCTV7E
+card=27 - PixelView PlayTV Ultra Pro (Stereo)
+card=28 - DViCO FusionHDTV 3 Gold-T
index a6c82fa4de025e20337376a56ff07b3b265c5250..735e8ba02d9fe42650c22ea05a3df45a432104f1 100644 (file)
  19 -> Compro VideoMate TV                      [185b:c100]
  20 -> Matrox CronosPlus                        [102B:48d0]
  21 -> 10MOONS PCI TV CAPTURE CARD              [1131:2001]
- 22 -> Medion 2819/ AverMedia M156              [1461:a70b,1461:2115]
+ 22 -> AverMedia M156 / Medion 2819             [1461:a70b]
  23 -> BMK MPEX Tuner
  24 -> KNC One TV-Station DVR                   [1894:a006]
  25 -> ASUS TV-FM 7133                          [1043:4843]
  26 -> Pinnacle PCTV Stereo (saa7134)           [11bd:002b]
- 27 -> Manli MuchTV M-TV002
- 28 -> Manli MuchTV M-TV001
+ 27 -> Manli MuchTV M-TV002/Behold TV 403 FM
+ 28 -> Manli MuchTV M-TV001/Behold TV 401
  29 -> Nagase Sangyo TransGear 3000TV           [1461:050c]
  30 -> Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM)  [1019:4cb4]
  31 -> Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM) [1019:4cb5]
  32 -> AVACS SmartTV
  33 -> AVerMedia DVD EZMaker                    [1461:10ff]
- 34 -> LifeView FlyTV Platinum33 mini           [5168:0212]
+ 34 -> Noval Prime TV 7133
+ 35 -> AverMedia AverTV Studio 305              [1461:2115]
+ 37 -> Items MuchTV Plus / IT-005
+ 38 -> Terratec Cinergy 200 TV                  [153B:1152]
+ 39 -> LifeView FlyTV Platinum Mini             [5168:0212]
+ 40 -> Compro VideoMate TV PVR/FM               [185b:c100]
+ 41 -> Compro VideoMate TV Gold+                [185b:c100]
+ 42 -> Sabrent SBT-TVFM (saa7130)
+ 43 -> :Zolid Xpert TV7134
+ 44 -> Empire PCI TV-Radio LE
+ 45 -> Avermedia AVerTV Studio 307              [1461:9715]
+ 46 -> AVerMedia Cardbus TV/Radio               [1461:d6ee]
+ 47 -> Terratec Cinergy 400 mobile              [153b:1162]
+ 48 -> Terratec Cinergy 600 TV MK3              [153B:1158]
+ 49 -> Compro VideoMate Gold+ Pal               [185b:c200]
+ 50 -> Pinnacle PCTV 300i DVB-T + PAL           [11bd:002d]
+ 51 -> ProVideo PV952                           [1540:9524]
+ 52 -> AverMedia AverTV/305                     [1461:2108]
+ 54 -> LifeView FlyTV Platinum FM               [5168:0214,1489:0214]
+ 55 -> LifeView FlyDVB-T DUO                    [5168:0306]
+ 56 -> Avermedia AVerTV 307                     [1461:a70a]
+ 57 -> Avermedia AVerTV GO 007 FM               [1461:f31f]
+ 58 -> ADS Tech Instant TV (saa7135)            [1421:0350,1421:0370]
+ 59 -> Kworld/Tevion V-Stream Xpert TV PVR7134
+ 60 -> Typhoon DVB-T Duo Digital/Analog Cardbus
+ 61 -> Philips TOUGH DVB-T reference design
+ 62 -> Compro VideoMate TV Gold+II
+ 63 -> Kworld Xpert TV PVR7134
index f7bafe862ba01c96b78a2fdba05fb99cb584b185..e78020f68b2e5ffb8382d4f309cf3b48187f4821 100644 (file)
@@ -44,3 +44,21 @@ tuner=42 - Philips 1236D ATSC/NTSC daul in
 tuner=43 - Philips NTSC MK3 (FM1236MK3 or FM1236/F)
 tuner=44 - Philips 4 in 1 (ATI TV Wonder Pro/Conexant)
 tuner=45 - Microtune 4049 FM5
+tuner=46 - Panasonic VP27s/ENGE4324D
+tuner=47 - LG NTSC (TAPE series)
+tuner=48 - Tenna TNF 8831 BGFF)
+tuner=49 - Microtune 4042 FI5 ATSC/NTSC dual in
+tuner=50 - TCL 2002N
+tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3)
+tuner=52 - Thomson DDT 7610 (ATSC/NTSC)
+tuner=53 - Philips FQ1286
+tuner=54 - tda8290+75
+tuner=55 - LG PAL (TAPE series)
+tuner=56 - Philips PAL/SECAM multi (FQ1216AME MK4)
+tuner=57 - Philips FQ1236A MK4
+tuner=58 - Ymec TVision TVF-8531MF
+tuner=59 - Ymec TVision TVF-5533MF
+tuner=60 - Thomson DDT 7611 (ATSC/NTSC)
+tuner=61 - Tena TNF9533-D/IF
+tuner=62 - Philips TEA5767HN FM Radio
+tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
index 1a446c65365e8792a6c496ff2216b8416fa0d426..1f788e498effe392cd48d0a907a88a6601bdea72 100644 (file)
@@ -57,6 +57,15 @@ Cards can use either of these two crystals (xtal):
  - 24.576MHz -> .audio_clock=0x200000
 (xtal * .audio_clock = 51539600)
 
+Some details about 30/34/35:
+
+ - saa7130 - low-price chip, doesn't have mute, that is why all those
+ cards should have .mute field defined in their tuner structure.
+
+ - saa7134 - usual chip
+
+ - saa7133/35 - saa7135 is probably a marketing decision, since all those
+ chips identifies itself as 33 on pci.
 
 Credits
 =======
diff --git a/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt b/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt
new file mode 100644 (file)
index 0000000..93fec32
--- /dev/null
@@ -0,0 +1,54 @@
+The controls for the mux are GPIO [0,1] for source, and GPIO 2 for muting.
+
+GPIO0  GPIO1
+  0        0    TV Audio
+  1        0    FM radio
+  0        1    Line-In
+  1        1    Mono tuner bypass or CD passthru (tuner specific)
+
+GPIO 16(i believe) is tied to the IR port (if present).
+
+------------------------------------------------------------------------------------
+
+>From the data sheet:
+ Register 24'h20004  PCI Interrupt Status
+  bit [18]  IR_SMP_INT Set when 32 input samples have been collected over
+  gpio[16] pin into GP_SAMPLE register.
+
+What's missing from the data sheet:
+
+Setup 4KHz sampling rate (roughly 2x oversampled; good enough for our RC5
+compat remote)
+set register 0x35C050 to  0xa80a80
+
+enable sampling
+set register 0x35C054 to 0x5
+
+Of course, enable the IRQ bit 18 in the interrupt mask register .(and
+provide for a handler)
+
+GP_SAMPLE register is at 0x35C058
+
+Bits are then right shifted into the GP_SAMPLE register at the specified
+rate; you get an interrupt when a full DWORD is recieved.
+You need to recover the actual RC5 bits out of the (oversampled) IR sensor
+bits. (Hint: look for the 0/1and 1/0 crossings of the RC5 bi-phase data)  An
+actual raw RC5 code will span 2-3 DWORDS, depending on the actual alignment.
+
+I'm pretty sure when no IR signal is present the receiver is always in a
+marking state(1); but stray light, etc can cause intermittent noise values
+as well.  Remember, this is a free running sample of the IR receiver state
+over time, so don't assume any sample starts at any particular place.
+
+http://www.atmel.com/dyn/resources/prod_documents/doc2817.pdf
+This data sheet (google search) seems to have a lovely description of the
+RC5 basics
+
+http://users.pandora.be/nenya/electronics/rc5/  and more data
+
+http://www.ee.washington.edu/circuit_archive/text/ir_decode.txt
+and even a reference to how to decode a bi-phase data stream.
+
+http://www.xs4all.nl/~sbp/knowledge/ir/rc5.htm
+still more info
+
diff --git a/Documentation/video4linux/lifeview.txt b/Documentation/video4linux/lifeview.txt
new file mode 100644 (file)
index 0000000..b07ea79
--- /dev/null
@@ -0,0 +1,42 @@
+collecting data about the lifeview models and the config coding on
+gpio pins 0-9 ...
+==================================================================
+
+bt878:
+ LR50 rev. Q ("PARTS: 7031505116), Tuner wurde als Nr. 5 erkannt, Eingänge
+ SVideo, TV, Composite, Audio, Remote. CP9..1=100001001 (1: 0-Ohm-Widerstand
+ gegen GND unbestückt; 0: bestückt)
+
+------------------------------------------------------------------------------
+
+saa7134:
+                /* LifeView FlyTV Platinum FM (LR214WF) */
+                /* "Peter Missel <peter.missel@onlinehome.de> */
+                .name           = "LifeView FlyTV Platinum FM",
+                /*      GP27    MDT2005 PB4 pin 10 */
+                /*      GP26    MDT2005 PB3 pin 9 */
+                /*      GP25    MDT2005 PB2 pin 8 */
+                /*      GP23    MDT2005 PB1 pin 7 */
+                /*      GP22    MDT2005 PB0 pin 6 */
+                /*      GP21    MDT2005 PB5 pin 11 */
+                /*      GP20    MDT2005 PB6 pin 12 */
+                /*      GP19    MDT2005 PB7 pin 13 */
+                /*      nc      MDT2005 PA3 pin 2 */
+                /*      Remote  MDT2005 PA2 pin 1 */
+                /*      GP18    MDT2005 PA1 pin 18 */
+                /*      nc      MDT2005 PA0 pin 17 strap low */
+
+                /*      GP17    Strap "GP7"=High */
+                /*      GP16    Strap "GP6"=High
+                                0=Radio 1=TV
+                                Drives SA630D ENCH1 and HEF4052 A1 pins
+                                to do FM radio through SIF input */
+                /*      GP15    nc */
+                /*      GP14    nc */
+                /*      GP13    nc */
+                /*      GP12    Strap "GP5" = High */
+                /*      GP11    Strap "GP4" = High */
+                /*      GP10    Strap "GP3" = High */
+                /*      GP09    Strap "GP2" = Low */
+                /*      GP08    Strap "GP1" = Low */
+                /*      GP07.00 nc */
diff --git a/Documentation/video4linux/not-in-cx2388x-datasheet.txt b/Documentation/video4linux/not-in-cx2388x-datasheet.txt
new file mode 100644 (file)
index 0000000..96b638b
--- /dev/null
@@ -0,0 +1,37 @@
+=================================================================================
+MO_OUTPUT_FORMAT (0x310164)
+
+  Previous default from DScaler: 0x1c1f0008
+  Digit 8: 31-28
+  28: PREVREMOD = 1
+
+  Digit 7: 27-24 (0xc = 12 = b1100 )
+  27: COMBALT = 1
+  26: PAL_INV_PHASE
+    (DScaler apparently set this to 1, resulted in sucky picture)
+
+  Digits 6,5: 23-16
+  25-16: COMB_RANGE = 0x1f [default] (9 bits -> max 512)
+
+  Digit 4: 15-12
+  15: DISIFX = 0
+  14: INVCBF = 0
+  13: DISADAPT = 0
+  12: NARROWADAPT = 0
+
+  Digit 3: 11-8
+  11: FORCE2H
+  10: FORCEREMD
+  9: NCHROMAEN
+  8: NREMODEN
+
+  Digit 2: 7-4
+  7-6: YCORE
+  5-4: CCORE
+
+  Digit 1: 3-0
+  3: RANGE = 1
+  2: HACTEXT
+  1: HSFMT
+
+=================================================================================
index 651af5012c981d4b877f3119d965830855620faf..19a9a1c530371a9328af010d96d2544e88289378 100644 (file)
@@ -512,11 +512,11 @@ W:        http://linuxppc64.org
 S:     Supported
 
 BTTV VIDEO4LINUX DRIVER
-P:     Gerd Knorr
-M:     kraxel@bytesex.org
+P:     Mauro Carvalho Chehab
+M:     mchehab@brturbo.com.br
 L:     video4linux-list@redhat.com
-W:     http://bytesex.org/bttv/
-S:     Orphan
+W:     http://linuxtv.org
+S:     Maintained
 
 BUSLOGIC SCSI DRIVER
 P:     Leonard N. Zubkoff
@@ -576,10 +576,9 @@ S: Supported
 
 COMPUTONE INTELLIPORT MULTIPORT CARD
 P:     Michael H. Warfield
-M:     Michael H. Warfield <mhw@wittsend.com>
+M:     mhw@wittsend.com
 W:     http://www.wittsend.com/computone.html
-L:     linux-computone@lazuli.wittsend.com
-S:     Orphaned
+S:     Maintained
 
 COSA/SRP SYNC SERIAL DRIVER
 P:     Jan "Yenya" Kasprzak
@@ -1150,7 +1149,7 @@ S:        Maintained
 
 INFINIBAND SUBSYSTEM
 P:     Roland Dreier
-M:     roland@topspin.com
+M:     rolandd@cisco.com
 P:     Sean Hefty
 M:     mshefty@ichips.intel.com
 P:     Hal Rosenstock
@@ -1330,6 +1329,16 @@ M:       rml@novell.com
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
+KEXEC
+P:     Eric Biederman
+P:     Randy Dunlap
+M:     ebiederm@xmission.com
+M:     rddunlap@osdl.org
+W:     http://www.xmission.com/~ebiederm/files/kexec/
+L:     linux-kernel@vger.kernel.org
+L:     fastboot@osdl.org
+S:     Maintained
+
 LANMEDIA WAN CARD DRIVER
 P:     Andrew Stanley-Jones
 M:     asj@lanmedia.com
@@ -2115,9 +2124,7 @@ S:        Maintained
 SOFTWARE SUSPEND:
 P:     Pavel Machek
 M:     pavel@suse.cz
-M:     pavel@ucw.cz
-L:     http://lister.fornax.hu/mailman/listinfo/swsusp
-W:     http://swsusp.sf.net/
+L:     linux-pm@osdl.org
 S:     Maintained
 
 SONIC NETWORK DRIVER
@@ -2145,6 +2152,11 @@ W:       http://tpmdd.sourceforge.net
 L:     tpmdd-devel@lists.sourceforge.net
 S:     Maintained
 
+TENSILICA XTENSA PORT (xtensa):
+P:     Chris Zankel
+M:     chris@zankel.net
+S:     Maintained
+
 UltraSPARC (sparc64):
 P:     David S. Miller
 M:     davem@davemloft.net
@@ -2589,7 +2601,7 @@ M:        davidm@snapgear.com
 P:     D. Jeff Dionne (created first uClinux port)
 M:     jeff@uclinux.org
 W:     http://www.uclinux.org/
-L:     uclinux-dev@uclinux.org
+L:     uclinux-dev@uclinux.org  (subscribers-only)
 S:     Maintained
 
 UCLINUX FOR NEC V850
@@ -2613,10 +2625,11 @@ W:      http://rio500.sourceforge.net
 S:     Maintained
 
 VIDEO FOR LINUX
-P:     Gerd Knorr
-M:     kraxel@bytesex.org
+P:     Mauro Carvalho Chehab
+M:     mchehab@brturbo.com.br
 L:     video4linux-list@redhat.com
-S:     Orphan
+W:     http://linuxtv.org
+S:     Maintained
 
 W1 DALLAS'S 1-WIRE BUS
 P:     Evgeniy Polyakov
index fad349724e993f6a297ca019aab9b4d0a2455d35..77aab7bdde01cb3b61440b164d937e4372536a34 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
-SUBLEVEL = 12
-EXTRAVERSION =
+SUBLEVEL = 13
+EXTRAVERSION =-rc1
 NAME=Woozy Numbat
 
 # *DOCUMENTATION*
@@ -281,7 +281,7 @@ export quiet Q KBUILD_VERBOSE
 # See documentation in Documentation/kbuild/makefiles.txt
 
 # cc-option
-# Usage: cflags-y += $(call gcc-option, -march=winchip-c6, -march=i586)
+# Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586)
 
 cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
              > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
index 07ba77c19f6c9172771c91f697ad0d2217439fdc..620f2ca94ed27390640abe911f0ab4a4bca20a1e 100644 (file)
@@ -157,7 +157,7 @@ config ARCH_RPC
 config ARCH_SA1100
        bool "SA1100-based"
        select ISA
-       select DISCONTIGMEM
+       select ARCH_DISCONTIGMEM_ENABLE
 
 config ARCH_S3C2410
        bool "Samsung S3C2410"
@@ -346,6 +346,26 @@ config PREEMPT
          Say Y here if you are building a kernel for a desktop, embedded
          or real-time system.  Say N if you are unsure.
 
+config NO_IDLE_HZ
+       bool "Dynamic tick timer"
+       help
+         Select this option if you want to disable continuous timer ticks
+         and have them programmed to occur as required. This option saves
+         power as the system can remain in idle state for longer.
+
+         By default dynamic tick is disabled during the boot, and can be
+         manually enabled with:
+
+           echo 1 > /sys/devices/system/timer/timer0/dyn_tick
+
+         Alternatively, if you want dynamic tick automatically enabled
+         during boot, pass "dyntick=enable" via the kernel command string.
+
+         Please note that dynamic tick may affect the accuracy of
+         timekeeping on some platforms depending on the implementation.
+         Currently at least OMAP platform is known to have accurate
+         timekeeping with dynamic tick.
+
 config ARCH_DISCONTIGMEM_ENABLE
        bool
        default (ARCH_LH7A40X && !LH7A40X_CONTIGMEM)
index 06fae4b62774659a1b6389db4a1a5d56f5a088c2..b8c51ee7f1bb05e530bdb252e5db4b55c8bfe405 100644 (file)
@@ -1,14 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 22:08:24 2005
+# Linux kernel version: 2.6.12-git6
+# Sat Jun 25 00:57:29 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
@@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y
 # CONFIG_ARCH_VERSATILE 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
 
 #
@@ -96,6 +99,7 @@ CONFIG_ARCH_ENP2611=y
 # CONFIG_ARCH_IXDP2800 is not set
 # CONFIG_ARCH_IXDP2401 is not set
 # CONFIG_ARCH_IXDP2801 is not set
+# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set
 
 #
 # Processor Type
@@ -106,7 +110,6 @@ CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
 
 #
 # Processor Features
@@ -118,9 +121,11 @@ CONFIG_XSCALE_PMU=y
 #
 # Bus support
 #
+CONFIG_ISA_DMA_API=y
 CONFIG_PCI=y
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
 
 #
 # PCCARD (PCMCIA/CardBus) support
@@ -130,7 +135,15 @@ CONFIG_PCI_NAMES=y
 #
 # Kernel Features
 #
+# CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -269,7 +282,6 @@ CONFIG_MTD_IXP2000=y
 #
 # Block devices
 #
-# CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -308,6 +320,7 @@ CONFIG_IOSCHED_CFQ=y
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -329,10 +342,11 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
 CONFIG_IP_PNP=y
@@ -349,6 +363,17 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_TUNNEL is not set
 # CONFIG_IP_TCPDIAG is not set
 # CONFIG_IP_TCPDIAG_IPV6 is not set
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -404,6 +429,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM 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
@@ -440,9 +466,11 @@ CONFIG_EEPRO100=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SKGE 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)
@@ -464,6 +492,7 @@ CONFIG_EEPRO100=y
 # Wan interfaces
 #
 CONFIG_WAN=y
+# CONFIG_DSCC4 is not set
 # CONFIG_LANMEDIA is not set
 # CONFIG_SYNCLINK_SYNCPPP is not set
 CONFIG_HDLC=y
@@ -526,7 +555,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 #
 # CONFIG_SERIO is not set
 # CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
 
 #
 # Character devices
@@ -547,6 +575,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -613,17 +642,18 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
 # CONFIG_I2C_IXP2000 is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
 # CONFIG_SCx200_ACB is not set
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
@@ -637,7 +667,9 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 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
@@ -653,6 +685,7 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_LM85 is not set
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
@@ -662,14 +695,19 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 
 #
 # Other I2C Chip support
 #
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 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_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
@@ -723,6 +761,7 @@ CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
 # CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
@@ -763,7 +802,6 @@ CONFIG_DNOTIFY=y
 #
 CONFIG_PROC_FS=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_XATTR is not set
@@ -801,12 +839,14 @@ CONFIG_JFFS2_RTIME=y
 #
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -891,3 +931,4 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+# CONFIG_TEXTSEARCH is not set
index 810a450a55d22a4c1dbcc139688f937aafab9db8..3cfbe2ec29ca6baeba87a066e486da5b259bb7dc 100644 (file)
@@ -1,14 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 21:13:38 2005
+# Linux kernel version: 2.6.12-git6
+# Sat Jun 25 00:58:38 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
@@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y
 # CONFIG_ARCH_VERSATILE 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
 
 #
@@ -97,6 +100,7 @@ CONFIG_ARCH_IXDP2400=y
 CONFIG_ARCH_IXDP2X00=y
 # CONFIG_ARCH_IXDP2401 is not set
 # CONFIG_ARCH_IXDP2801 is not set
+# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set
 
 #
 # Processor Type
@@ -107,7 +111,6 @@ CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
 
 #
 # Processor Features
@@ -119,9 +122,11 @@ CONFIG_XSCALE_PMU=y
 #
 # Bus support
 #
+CONFIG_ISA_DMA_API=y
 CONFIG_PCI=y
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
 
 #
 # PCCARD (PCMCIA/CardBus) support
@@ -131,7 +136,15 @@ CONFIG_PCI_NAMES=y
 #
 # Kernel Features
 #
+# CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -270,7 +283,6 @@ CONFIG_MTD_IXP2000=y
 #
 # Block devices
 #
-# CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -309,6 +321,7 @@ CONFIG_IOSCHED_CFQ=y
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -330,10 +343,11 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
 CONFIG_IP_PNP=y
@@ -350,6 +364,17 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_TUNNEL is not set
 # CONFIG_IP_TCPDIAG is not set
 # CONFIG_IP_TCPDIAG_IPV6 is not set
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -405,6 +430,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM 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
@@ -441,9 +467,11 @@ CONFIG_EEPRO100=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SKGE 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)
@@ -465,6 +493,7 @@ CONFIG_EEPRO100=y
 # Wan interfaces
 #
 CONFIG_WAN=y
+# CONFIG_DSCC4 is not set
 # CONFIG_LANMEDIA is not set
 # CONFIG_SYNCLINK_SYNCPPP is not set
 CONFIG_HDLC=y
@@ -527,7 +556,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 #
 # CONFIG_SERIO is not set
 # CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
 
 #
 # Character devices
@@ -548,6 +576,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -614,17 +643,18 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
 # CONFIG_I2C_IXP2000 is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
 # CONFIG_SCx200_ACB is not set
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
@@ -638,7 +668,9 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 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
@@ -654,6 +686,7 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_LM85 is not set
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
@@ -663,14 +696,19 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 
 #
 # Other I2C Chip support
 #
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 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_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
@@ -724,6 +762,7 @@ CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
 # CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
@@ -764,7 +803,6 @@ CONFIG_DNOTIFY=y
 #
 CONFIG_PROC_FS=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_XATTR is not set
@@ -802,12 +840,14 @@ CONFIG_JFFS2_RTIME=y
 #
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -892,3 +932,4 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+# CONFIG_TEXTSEARCH is not set
index 72e1b940e975b858769ac25ce0556dee0b0d0c62..5c87e8e6969b1cb828158c853344d844a0071da7 100644 (file)
@@ -1,14 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 21:53:55 2005
+# Linux kernel version: 2.6.12-git6
+# Sat Jun 25 00:59:35 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
@@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y
 # CONFIG_ARCH_VERSATILE 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
 
 #
@@ -97,6 +100,7 @@ CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
 CONFIG_ARCH_IXDP2401=y
 # CONFIG_ARCH_IXDP2801 is not set
 CONFIG_ARCH_IXDP2X01=y
+# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set
 
 #
 # Processor Type
@@ -107,7 +111,6 @@ CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
 
 #
 # Processor Features
@@ -119,9 +122,11 @@ CONFIG_XSCALE_PMU=y
 #
 # Bus support
 #
+CONFIG_ISA_DMA_API=y
 CONFIG_PCI=y
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
 
 #
 # PCCARD (PCMCIA/CardBus) support
@@ -131,7 +136,15 @@ CONFIG_PCI_NAMES=y
 #
 # Kernel Features
 #
+# CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -270,7 +283,6 @@ CONFIG_MTD_IXP2000=y
 #
 # Block devices
 #
-# CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -309,6 +321,7 @@ CONFIG_IOSCHED_CFQ=y
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -330,10 +343,11 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
 CONFIG_IP_PNP=y
@@ -350,6 +364,17 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_TUNNEL is not set
 CONFIG_IP_TCPDIAG=y
 # CONFIG_IP_TCPDIAG_IPV6 is not set
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -405,6 +430,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM 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
@@ -442,9 +468,11 @@ CONFIG_EEPRO100=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SKGE 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)
@@ -466,6 +494,7 @@ CONFIG_EEPRO100=y
 # Wan interfaces
 #
 CONFIG_WAN=y
+# CONFIG_DSCC4 is not set
 # CONFIG_LANMEDIA is not set
 # CONFIG_SYNCLINK_SYNCPPP is not set
 CONFIG_HDLC=y
@@ -528,7 +557,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 #
 # CONFIG_SERIO is not set
 # CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
 
 #
 # Character devices
@@ -549,6 +577,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -615,17 +644,18 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
 # CONFIG_I2C_IXP2000 is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
 # CONFIG_SCx200_ACB is not set
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
@@ -639,7 +669,9 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 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
@@ -655,6 +687,7 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_LM85 is not set
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
@@ -664,14 +697,19 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 
 #
 # Other I2C Chip support
 #
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 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_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
@@ -725,6 +763,7 @@ CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
 # CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
@@ -765,7 +804,6 @@ CONFIG_DNOTIFY=y
 #
 CONFIG_PROC_FS=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_XATTR is not set
@@ -803,12 +841,14 @@ CONFIG_JFFS2_RTIME=y
 #
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -893,3 +933,4 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+# CONFIG_TEXTSEARCH is not set
index 1592e45f027839e7967ef26c17e79bdc44bd1f64..3cb561a551cb598c5fe13033b7d8dffd4c2f886e 100644 (file)
@@ -1,14 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 22:15:23 2005
+# Linux kernel version: 2.6.12-git6
+# Sat Jun 25 01:00:27 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
@@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y
 # CONFIG_ARCH_VERSATILE 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
 
 #
@@ -97,6 +100,7 @@ CONFIG_ARCH_IXDP2800=y
 CONFIG_ARCH_IXDP2X00=y
 # CONFIG_ARCH_IXDP2401 is not set
 # CONFIG_ARCH_IXDP2801 is not set
+# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set
 
 #
 # Processor Type
@@ -107,7 +111,6 @@ CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
 
 #
 # Processor Features
@@ -119,9 +122,11 @@ CONFIG_XSCALE_PMU=y
 #
 # Bus support
 #
+CONFIG_ISA_DMA_API=y
 CONFIG_PCI=y
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
 
 #
 # PCCARD (PCMCIA/CardBus) support
@@ -131,7 +136,15 @@ CONFIG_PCI_NAMES=y
 #
 # Kernel Features
 #
+# CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -270,7 +283,6 @@ CONFIG_MTD_IXP2000=y
 #
 # Block devices
 #
-# CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -309,6 +321,7 @@ CONFIG_IOSCHED_CFQ=y
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -330,10 +343,11 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
 CONFIG_IP_PNP=y
@@ -350,6 +364,17 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_TUNNEL is not set
 # CONFIG_IP_TCPDIAG is not set
 # CONFIG_IP_TCPDIAG_IPV6 is not set
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -405,6 +430,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM 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
@@ -441,9 +467,11 @@ CONFIG_EEPRO100=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SKGE 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)
@@ -465,6 +493,7 @@ CONFIG_EEPRO100=y
 # Wan interfaces
 #
 CONFIG_WAN=y
+# CONFIG_DSCC4 is not set
 # CONFIG_LANMEDIA is not set
 # CONFIG_SYNCLINK_SYNCPPP is not set
 CONFIG_HDLC=y
@@ -527,7 +556,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 #
 # CONFIG_SERIO is not set
 # CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
 
 #
 # Character devices
@@ -548,6 +576,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -614,17 +643,18 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
 # CONFIG_I2C_IXP2000 is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
 # CONFIG_SCx200_ACB is not set
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
@@ -638,7 +668,9 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 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
@@ -654,6 +686,7 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_LM85 is not set
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
@@ -663,14 +696,19 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 
 #
 # Other I2C Chip support
 #
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 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_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
@@ -724,6 +762,7 @@ CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
 # CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
@@ -764,7 +803,6 @@ CONFIG_DNOTIFY=y
 #
 CONFIG_PROC_FS=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_XATTR is not set
@@ -802,12 +840,14 @@ CONFIG_JFFS2_RTIME=y
 #
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -892,3 +932,4 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+# CONFIG_TEXTSEARCH is not set
index f1afe3d09ec66c5797ed553f1de4d1c1138396ed..b1e162f29cb9490b64b59c0cd04d6973369e9c52 100644 (file)
@@ -1,14 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 22:39:19 2005
+# Linux kernel version: 2.6.12-git6
+# Sat Jun 25 01:01:18 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
@@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y
 # CONFIG_ARCH_VERSATILE 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
 
 #
@@ -97,6 +100,7 @@ CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
 # CONFIG_ARCH_IXDP2401 is not set
 CONFIG_ARCH_IXDP2801=y
 CONFIG_ARCH_IXDP2X01=y
+# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set
 
 #
 # Processor Type
@@ -107,7 +111,6 @@ CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
 
 #
 # Processor Features
@@ -119,9 +122,11 @@ CONFIG_XSCALE_PMU=y
 #
 # Bus support
 #
+CONFIG_ISA_DMA_API=y
 CONFIG_PCI=y
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
 
 #
 # PCCARD (PCMCIA/CardBus) support
@@ -131,7 +136,15 @@ CONFIG_PCI_NAMES=y
 #
 # Kernel Features
 #
+# CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -270,7 +283,6 @@ CONFIG_MTD_IXP2000=y
 #
 # Block devices
 #
-# CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -309,6 +321,7 @@ CONFIG_IOSCHED_CFQ=y
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -330,10 +343,11 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
 CONFIG_IP_PNP=y
@@ -350,6 +364,17 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_TUNNEL is not set
 # CONFIG_IP_TCPDIAG is not set
 # CONFIG_IP_TCPDIAG_IPV6 is not set
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -405,6 +430,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM 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
@@ -442,9 +468,11 @@ CONFIG_EEPRO100=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SKGE 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)
@@ -466,6 +494,7 @@ CONFIG_EEPRO100=y
 # Wan interfaces
 #
 CONFIG_WAN=y
+# CONFIG_DSCC4 is not set
 # CONFIG_LANMEDIA is not set
 # CONFIG_SYNCLINK_SYNCPPP is not set
 CONFIG_HDLC=y
@@ -528,7 +557,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 #
 # CONFIG_SERIO is not set
 # CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
 
 #
 # Character devices
@@ -549,6 +577,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -615,17 +644,18 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
 # CONFIG_I2C_IXP2000 is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
 # CONFIG_SCx200_ACB is not set
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
@@ -639,7 +669,9 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 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
@@ -655,6 +687,7 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_LM85 is not set
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
@@ -664,14 +697,19 @@ CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 
 #
 # Other I2C Chip support
 #
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 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_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
@@ -725,6 +763,7 @@ CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
 # CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
@@ -765,7 +804,6 @@ CONFIG_DNOTIFY=y
 #
 CONFIG_PROC_FS=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_XATTR is not set
@@ -803,12 +841,14 @@ CONFIG_JFFS2_RTIME=y
 #
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -893,3 +933,4 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+# CONFIG_TEXTSEARCH is not set
index 4c38bd8bc298c3a4ecd64ea3a31d2ced999d2e48..b713c44c6fb429c8da7bdfab8a4399a906df1050 100644 (file)
@@ -30,9 +30,6 @@ extern void __lshrdi3(void);
 extern void __modsi3(void);
 extern void __muldi3(void);
 extern void __ucmpdi2(void);
-extern void __udivdi3(void);
-extern void __umoddi3(void);
-extern void __udivmoddi4(void);
 extern void __udivsi3(void);
 extern void __umodsi3(void);
 extern void __do_div64(void);
@@ -134,9 +131,6 @@ EXPORT_SYMBOL(__lshrdi3);
 EXPORT_SYMBOL(__modsi3);
 EXPORT_SYMBOL(__muldi3);
 EXPORT_SYMBOL(__ucmpdi2);
-EXPORT_SYMBOL(__udivdi3);
-EXPORT_SYMBOL(__umoddi3);
-EXPORT_SYMBOL(__udivmoddi4);
 EXPORT_SYMBOL(__udivsi3);
 EXPORT_SYMBOL(__umodsi3);
 EXPORT_SYMBOL(__do_div64);
index ff187f4308f01ec786056f07b82299d8adf90cb2..395137a8fad276ce20cb250d58920f7c12fac501 100644 (file)
@@ -4,6 +4,10 @@
  *  Copyright (C) 1992 Linus Torvalds
  *  Modifications for ARM processor Copyright (C) 1995-2000 Russell King.
  *
+ *  Support for Dynamic Tick Timer Copyright (C) 2004-2005 Nokia Corporation.
+ *  Dynamic Tick Timer written by Tony Lindgren <tony@atomide.com> and
+ *  Tuukka Tikkanen <tuukka.tikkanen@elektrobit.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.
@@ -37,6 +41,7 @@
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/mach/irq.h>
+#include <asm/mach/time.h>
 
 /*
  * Maximum IRQ count.  Currently, this is arbitary.  However, it should
@@ -329,6 +334,15 @@ __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs)
 
        spin_unlock(&irq_controller_lock);
 
+#ifdef CONFIG_NO_IDLE_HZ
+       if (!(action->flags & SA_TIMER) && system_timer->dyn_tick != NULL) {
+               write_seqlock(&xtime_lock);
+               if (system_timer->dyn_tick->state & DYN_TICK_ENABLED)
+                       system_timer->dyn_tick->handler(irq, 0, regs);
+               write_sequnlock(&xtime_lock);
+       }
+#endif
+
        if (!(action->flags & SA_INTERRUPT))
                local_irq_enable();
 
index 8f146a4b4752665013bc33c510f1df5adb53a739..bbea636ff687a57feb1e2a5f240e5f0726485b7a 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/leds.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
+#include <asm/mach/time.h>
 
 extern const char *processor_modes[];
 extern void setup_mm_for_reboot(char mode);
@@ -85,8 +86,10 @@ EXPORT_SYMBOL(pm_power_off);
 void default_idle(void)
 {
        local_irq_disable();
-       if (!need_resched() && !hlt_counter)
+       if (!need_resched() && !hlt_counter) {
+               timer_dyn_reprogram();
                arch_idle();
+       }
        local_irq_enable();
 }
 
index 8cf733daa8008f70090587f42be4d77c7acfc1a5..35b7273cfdb4252cb6b886b306870924f5abb38a 100644 (file)
@@ -359,7 +359,8 @@ void cpu_init(void)
              "I" (offsetof(struct stack, abt[0])),
              "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
              "I" (offsetof(struct stack, und[0])),
-             "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE));
+             "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
+           : "r14");
 }
 
 static struct machine_desc * __init setup_machine(unsigned int nr)
index 07ddeed61766559c1a6d12b1fb70f92608f31c8c..5e435e42dacdef45d87173527d60759aa7af083f 100644 (file)
@@ -697,7 +697,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
        if (!user_mode(regs))
                return 0;
 
-       if (try_to_freeze(0))
+       if (try_to_freeze())
                goto no_signal;
 
        if (current->ptrace & PT_SINGLESTEP)
index 34892758f098c485f0b47e97083daf699a399878..a931409c8fe405340cab9205ad1d5af156583d9c 100644 (file)
@@ -502,3 +502,126 @@ int __init setup_profiling_timer(unsigned int multiplier)
 {
        return -EINVAL;
 }
+
+static int
+on_each_cpu_mask(void (*func)(void *), void *info, int retry, int wait,
+                cpumask_t mask)
+{
+       int ret = 0;
+
+       preempt_disable();
+
+       ret = smp_call_function_on_cpu(func, info, retry, wait, mask);
+       if (cpu_isset(smp_processor_id(), mask))
+               func(info);
+
+       preempt_enable();
+
+       return ret;
+}
+
+/**********************************************************************/
+
+/*
+ * TLB operations
+ */
+struct tlb_args {
+       struct vm_area_struct *ta_vma;
+       unsigned long ta_start;
+       unsigned long ta_end;
+};
+
+static inline void ipi_flush_tlb_all(void *ignored)
+{
+       local_flush_tlb_all();
+}
+
+static inline void ipi_flush_tlb_mm(void *arg)
+{
+       struct mm_struct *mm = (struct mm_struct *)arg;
+
+       local_flush_tlb_mm(mm);
+}
+
+static inline void ipi_flush_tlb_page(void *arg)
+{
+       struct tlb_args *ta = (struct tlb_args *)arg;
+
+       local_flush_tlb_page(ta->ta_vma, ta->ta_start);
+}
+
+static inline void ipi_flush_tlb_kernel_page(void *arg)
+{
+       struct tlb_args *ta = (struct tlb_args *)arg;
+
+       local_flush_tlb_kernel_page(ta->ta_start);
+}
+
+static inline void ipi_flush_tlb_range(void *arg)
+{
+       struct tlb_args *ta = (struct tlb_args *)arg;
+
+       local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end);
+}
+
+static inline void ipi_flush_tlb_kernel_range(void *arg)
+{
+       struct tlb_args *ta = (struct tlb_args *)arg;
+
+       local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end);
+}
+
+void flush_tlb_all(void)
+{
+       on_each_cpu(ipi_flush_tlb_all, NULL, 1, 1);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+       cpumask_t mask = mm->cpu_vm_mask;
+
+       on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, 1, mask);
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
+{
+       cpumask_t mask = vma->vm_mm->cpu_vm_mask;
+       struct tlb_args ta;
+
+       ta.ta_vma = vma;
+       ta.ta_start = uaddr;
+
+       on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, 1, mask);
+}
+
+void flush_tlb_kernel_page(unsigned long kaddr)
+{
+       struct tlb_args ta;
+
+       ta.ta_start = kaddr;
+
+       on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1, 1);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma,
+                     unsigned long start, unsigned long end)
+{
+       cpumask_t mask = vma->vm_mm->cpu_vm_mask;
+       struct tlb_args ta;
+
+       ta.ta_vma = vma;
+       ta.ta_start = start;
+       ta.ta_end = end;
+
+       on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, 1, mask);
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+       struct tlb_args ta;
+
+       ta.ta_start = start;
+       ta.ta_end = end;
+
+       on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1, 1);
+}
index c232f24f4a60042806958f8e74e685af473e3196..1b7fcd50c3e25c8a208bc3347dc55dc7d0605e1e 100644 (file)
@@ -381,6 +381,99 @@ static struct sysdev_class timer_sysclass = {
        .resume         = timer_resume,
 };
 
+#ifdef CONFIG_NO_IDLE_HZ
+static int timer_dyn_tick_enable(void)
+{
+       struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
+       unsigned long flags;
+       int ret = -ENODEV;
+
+       if (dyn_tick) {
+               write_seqlock_irqsave(&xtime_lock, flags);
+               ret = 0;
+               if (!(dyn_tick->state & DYN_TICK_ENABLED)) {
+                       ret = dyn_tick->enable();
+
+                       if (ret == 0)
+                               dyn_tick->state |= DYN_TICK_ENABLED;
+               }
+               write_sequnlock_irqrestore(&xtime_lock, flags);
+       }
+
+       return ret;
+}
+
+static int timer_dyn_tick_disable(void)
+{
+       struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
+       unsigned long flags;
+       int ret = -ENODEV;
+
+       if (dyn_tick) {
+               write_seqlock_irqsave(&xtime_lock, flags);
+               ret = 0;
+               if (dyn_tick->state & DYN_TICK_ENABLED) {
+                       ret = dyn_tick->disable();
+
+                       if (ret == 0)
+                               dyn_tick->state &= ~DYN_TICK_ENABLED;
+               }
+               write_sequnlock_irqrestore(&xtime_lock, flags);
+       }
+
+       return ret;
+}
+
+/*
+ * Reprogram the system timer for at least the calculated time interval.
+ * This function should be called from the idle thread with IRQs disabled,
+ * immediately before sleeping.
+ */
+void timer_dyn_reprogram(void)
+{
+       struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
+
+       write_seqlock(&xtime_lock);
+       if (dyn_tick->state & DYN_TICK_ENABLED)
+               dyn_tick->reprogram(next_timer_interrupt() - jiffies);
+       write_sequnlock(&xtime_lock);
+}
+
+static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
+{
+       return sprintf(buf, "%i\n",
+                      (system_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1);
+}
+
+static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf,
+                                 size_t count)
+{
+       unsigned int enable = simple_strtoul(buf, NULL, 2);
+
+       if (enable)
+               timer_dyn_tick_enable();
+       else
+               timer_dyn_tick_disable();
+
+       return count;
+}
+static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick);
+
+/*
+ * dyntick=enable|disable
+ */
+static char dyntick_str[4] __initdata = "";
+
+static int __init dyntick_setup(char *str)
+{
+       if (str)
+               strlcpy(dyntick_str, str, sizeof(dyntick_str));
+       return 1;
+}
+
+__setup("dyntick=", dyntick_setup);
+#endif
+
 static int __init timer_init_sysfs(void)
 {
        int ret = sysdev_class_register(&timer_sysclass);
@@ -388,6 +481,20 @@ static int __init timer_init_sysfs(void)
                system_timer->dev.cls = &timer_sysclass;
                ret = sysdev_register(&system_timer->dev);
        }
+
+#ifdef CONFIG_NO_IDLE_HZ
+       if (ret == 0 && system_timer->dyn_tick) {
+               ret = sysdev_create_file(&system_timer->dev, &attr_dyn_tick);
+
+               /*
+                * Turn on dynamic tick after calibrate delay
+                * for correct bogomips
+                */
+               if (ret == 0 && dyntick_str[0] == 'e')
+                       ret = timer_dyn_tick_enable();
+       }
+#endif
+
        return ret;
 }
 
index c0e65833ffc41895840c0b0bbaa86ad065b39e65..8725d63e4219801eadf0b4c7704b5384d4077af4 100644 (file)
@@ -11,7 +11,7 @@ lib-y         := backtrace.o changebit.o csumipv6.o csumpartial.o   \
                   strnlen_user.o strchr.o strrchr.o testchangebit.o  \
                   testclearbit.o testsetbit.o uaccess.o getuser.o    \
                   putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o   \
-                  ucmpdi2.o udivdi3.o lib1funcs.o div64.o            \
+                  ucmpdi2.o lib1funcs.o div64.o                      \
                   io-readsb.o io-writesb.o io-readsl.o io-writesl.o
 
 ifeq ($(CONFIG_CPU_32v3),y)
diff --git a/arch/arm/lib/longlong.h b/arch/arm/lib/longlong.h
deleted file mode 100644 (file)
index 90ae647..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/* longlong.h -- based on code from gcc-2.95.3
-
-   definitions for mixed size 32/64 bit arithmetic.
-   Copyright (C) 1991, 92, 94, 95, 96, 1997, 1998 Free Software Foundation, Inc.
-
-   This definition file 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 definition file 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.  */
-
-/* Borrowed from GCC 2.95.3, I Molton 29/07/01 */
-
-#ifndef SI_TYPE_SIZE
-#define SI_TYPE_SIZE 32
-#endif
-
-#define __BITS4 (SI_TYPE_SIZE / 4)
-#define __ll_B (1L << (SI_TYPE_SIZE / 2))
-#define __ll_lowpart(t) ((u32) (t) % __ll_B)
-#define __ll_highpart(t) ((u32) (t) / __ll_B)
-
-/* Define auxiliary asm macros.
-
-   1) umul_ppmm(high_prod, low_prod, multipler, multiplicand)
-   multiplies two u32 integers MULTIPLER and MULTIPLICAND,
-   and generates a two-part u32 product in HIGH_PROD and
-   LOW_PROD.
-
-   2) __umulsidi3(a,b) multiplies two u32 integers A and B,
-   and returns a u64 product.  This is just a variant of umul_ppmm.
-
-   3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
-   denominator) divides a two-word unsigned integer, composed by the
-   integers HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and
-   places the quotient in QUOTIENT and the remainder in REMAINDER.
-   HIGH_NUMERATOR must be less than DENOMINATOR for correct operation.
-   If, in addition, the most significant bit of DENOMINATOR must be 1,
-   then the pre-processor symbol UDIV_NEEDS_NORMALIZATION is defined to 1.
-
-   4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
-   denominator).  Like udiv_qrnnd but the numbers are signed.  The
-   quotient is rounded towards 0.
-
-   5) count_leading_zeros(count, x) counts the number of zero-bits from
-   the msb to the first non-zero bit.  This is the number of steps X
-   needs to be shifted left to set the msb.  Undefined for X == 0.
-
-   6) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
-   high_addend_2, low_addend_2) adds two two-word unsigned integers,
-   composed by HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and
-   LOW_ADDEND_2 respectively.  The result is placed in HIGH_SUM and
-   LOW_SUM.  Overflow (i.e. carry out) is not stored anywhere, and is
-   lost.
-
-   7) sub_ddmmss(high_difference, low_difference, high_minuend,
-   low_minuend, high_subtrahend, low_subtrahend) subtracts two
-   two-word unsigned integers, composed by HIGH_MINUEND_1 and
-   LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and LOW_SUBTRAHEND_2
-   respectively.  The result is placed in HIGH_DIFFERENCE and
-   LOW_DIFFERENCE.  Overflow (i.e. carry out) is not stored anywhere,
-   and is lost.
-
-   If any of these macros are left undefined for a particular CPU,
-   C macros are used.  */
-
-#if defined (__arm__)
-#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
-  __asm__ ("adds       %1, %4, %5                                      \n\
-       adc     %0, %2, %3"                                             \
-          : "=r" ((u32) (sh)),                                 \
-            "=&r" ((u32) (sl))                                 \
-          : "%r" ((u32) (ah)),                                 \
-            "rI" ((u32) (bh)),                                 \
-            "%r" ((u32) (al)),                                 \
-            "rI" ((u32) (bl)))
-#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
-  __asm__ ("subs       %1, %4, %5                                      \n\
-       sbc     %0, %2, %3"                                             \
-          : "=r" ((u32) (sh)),                                 \
-            "=&r" ((u32) (sl))                                 \
-          : "r" ((u32) (ah)),                                  \
-            "rI" ((u32) (bh)),                                 \
-            "r" ((u32) (al)),                                  \
-            "rI" ((u32) (bl)))
-#define umul_ppmm(xh, xl, a, b) \
-{register u32 __t0, __t1, __t2;                                        \
-  __asm__ ("%@ Inlined umul_ppmm                                       \n\
-       mov     %2, %5, lsr #16                                         \n\
-       mov     %0, %6, lsr #16                                         \n\
-       bic     %3, %5, %2, lsl #16                                     \n\
-       bic     %4, %6, %0, lsl #16                                     \n\
-       mul     %1, %3, %4                                              \n\
-       mul     %4, %2, %4                                              \n\
-       mul     %3, %0, %3                                              \n\
-       mul     %0, %2, %0                                              \n\
-       adds    %3, %4, %3                                              \n\
-       addcs   %0, %0, #65536                                          \n\
-       adds    %1, %1, %3, lsl #16                                     \n\
-       adc     %0, %0, %3, lsr #16"                                    \
-          : "=&r" ((u32) (xh)),                                        \
-            "=r" ((u32) (xl)),                                 \
-            "=&r" (__t0), "=&r" (__t1), "=r" (__t2)                    \
-          : "r" ((u32) (a)),                                   \
-            "r" ((u32) (b)));}
-#define UMUL_TIME 20
-#define UDIV_TIME 100
-#endif                         /* __arm__ */
-
-#define __umulsidi3(u, v) \
-  ({DIunion __w;                                                       \
-    umul_ppmm (__w.s.high, __w.s.low, u, v);                           \
-    __w.ll; })
-
-#define __udiv_qrnnd_c(q, r, n1, n0, d) \
-  do {                                                                 \
-    u32 __d1, __d0, __q1, __q0;                                        \
-    u32 __r1, __r0, __m;                                               \
-    __d1 = __ll_highpart (d);                                          \
-    __d0 = __ll_lowpart (d);                                           \
-                                                                       \
-    __r1 = (n1) % __d1;                                                        \
-    __q1 = (n1) / __d1;                                                        \
-    __m = (u32) __q1 * __d0;                                   \
-    __r1 = __r1 * __ll_B | __ll_highpart (n0);                         \
-    if (__r1 < __m)                                                    \
-      {                                                                        \
-       __q1--, __r1 += (d);                                            \
-       if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
-         if (__r1 < __m)                                               \
-           __q1--, __r1 += (d);                                        \
-      }                                                                        \
-    __r1 -= __m;                                                       \
-                                                                       \
-    __r0 = __r1 % __d1;                                                        \
-    __q0 = __r1 / __d1;                                                        \
-    __m = (u32) __q0 * __d0;                                   \
-    __r0 = __r0 * __ll_B | __ll_lowpart (n0);                          \
-    if (__r0 < __m)                                                    \
-      {                                                                        \
-       __q0--, __r0 += (d);                                            \
-       if (__r0 >= (d))                                                \
-         if (__r0 < __m)                                               \
-           __q0--, __r0 += (d);                                        \
-      }                                                                        \
-    __r0 -= __m;                                                       \
-                                                                       \
-    (q) = (u32) __q1 * __ll_B | __q0;                          \
-    (r) = __r0;                                                                \
-  } while (0)
-
-#define UDIV_NEEDS_NORMALIZATION 1
-#define udiv_qrnnd __udiv_qrnnd_c
-
-#define count_leading_zeros(count, x) \
-  do {                                                                 \
-    u32 __xr = (x);                                                    \
-    u32 __a;                                                   \
-                                                                       \
-    if (SI_TYPE_SIZE <= 32)                                            \
-      {                                                                        \
-       __a = __xr < ((u32)1<<2*__BITS4)                                \
-         ? (__xr < ((u32)1<<__BITS4) ? 0 : __BITS4)            \
-         : (__xr < ((u32)1<<3*__BITS4) ?  2*__BITS4 : 3*__BITS4);      \
-      }                                                                        \
-    else                                                               \
-      {                                                                        \
-       for (__a = SI_TYPE_SIZE - 8; __a > 0; __a -= 8)                 \
-         if (((__xr >> __a) & 0xff) != 0)                              \
-           break;                                                      \
-      }                                                                        \
-                                                                       \
-    (count) = SI_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a);           \
-  } while (0)
diff --git a/arch/arm/lib/udivdi3.c b/arch/arm/lib/udivdi3.c
deleted file mode 100644 (file)
index e343be4..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-/* More subroutines needed by GCC output code on some machines.  */
-/* Compile this one with gcc.  */
-/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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.
-
-GNU CC 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 GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-/* As a special exception, if you link this library with other files,
-   some of which are compiled with GCC, to produce an executable,
-   this library does not by itself cause the resulting executable
-   to be covered by the GNU General Public License.
-   This exception does not however invalidate any other reasons why
-   the executable file might be covered by the GNU General Public License.
- */
-/* support functions required by the kernel. based on code from gcc-2.95.3 */
-/* I Molton     29/07/01 */
-
-#include "gcclib.h"
-#include "longlong.h"
-
-static const u8 __clz_tab[] = {
-       0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
-           5, 5, 5, 5, 5, 5, 5, 5,
-       6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-           6, 6, 6, 6, 6, 6, 6, 6,
-       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-           7, 7, 7, 7, 7, 7, 7, 7,
-       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-           7, 7, 7, 7, 7, 7, 7, 7,
-       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-           8, 8, 8, 8, 8, 8, 8, 8,
-       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-           8, 8, 8, 8, 8, 8, 8, 8,
-       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-           8, 8, 8, 8, 8, 8, 8, 8,
-       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-           8, 8, 8, 8, 8, 8, 8, 8,
-};
-
-u64 __udivmoddi4(u64 n, u64 d, u64 * rp)
-{
-       DIunion ww;
-       DIunion nn, dd;
-       DIunion rr;
-       u32 d0, d1, n0, n1, n2;
-       u32 q0, q1;
-       u32 b, bm;
-
-       nn.ll = n;
-       dd.ll = d;
-
-       d0 = dd.s.low;
-       d1 = dd.s.high;
-       n0 = nn.s.low;
-       n1 = nn.s.high;
-
-       if (d1 == 0) {
-               if (d0 > n1) {
-                       /* 0q = nn / 0D */
-
-                       count_leading_zeros(bm, d0);
-
-                       if (bm != 0) {
-                               /* Normalize, i.e. make the most significant bit of the
-                                  denominator set.  */
-
-                               d0 = d0 << bm;
-                               n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm));
-                               n0 = n0 << bm;
-                       }
-
-                       udiv_qrnnd(q0, n0, n1, n0, d0);
-                       q1 = 0;
-
-                       /* Remainder in n0 >> bm.  */
-               } else {
-                       /* qq = NN / 0d */
-
-                       if (d0 == 0)
-                               d0 = 1 / d0;    /* Divide intentionally by zero.  */
-
-                       count_leading_zeros(bm, d0);
-
-                       if (bm == 0) {
-                               /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
-                                  conclude (the most significant bit of n1 is set) /\ (the
-                                  leading quotient digit q1 = 1).
-
-                                  This special case is necessary, not an optimization.
-                                  (Shifts counts of SI_TYPE_SIZE are undefined.)  */
-
-                               n1 -= d0;
-                               q1 = 1;
-                       } else {
-                               /* Normalize.  */
-
-                               b = SI_TYPE_SIZE - bm;
-
-                               d0 = d0 << bm;
-                               n2 = n1 >> b;
-                               n1 = (n1 << bm) | (n0 >> b);
-                               n0 = n0 << bm;
-
-                               udiv_qrnnd(q1, n1, n2, n1, d0);
-                       }
-
-                       /* n1 != d0...  */
-
-                       udiv_qrnnd(q0, n0, n1, n0, d0);
-
-                       /* Remainder in n0 >> bm.  */
-               }
-
-               if (rp != 0) {
-                       rr.s.low = n0 >> bm;
-                       rr.s.high = 0;
-                       *rp = rr.ll;
-               }
-       } else {
-               if (d1 > n1) {
-                       /* 00 = nn / DD */
-
-                       q0 = 0;
-                       q1 = 0;
-
-                       /* Remainder in n1n0.  */
-                       if (rp != 0) {
-                               rr.s.low = n0;
-                               rr.s.high = n1;
-                               *rp = rr.ll;
-                       }
-               } else {
-                       /* 0q = NN / dd */
-
-                       count_leading_zeros(bm, d1);
-                       if (bm == 0) {
-                               /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
-                                  conclude (the most significant bit of n1 is set) /\ (the
-                                  quotient digit q0 = 0 or 1).
-
-                                  This special case is necessary, not an optimization.  */
-
-                               /* The condition on the next line takes advantage of that
-                                  n1 >= d1 (true due to program flow).  */
-                               if (n1 > d1 || n0 >= d0) {
-                                       q0 = 1;
-                                       sub_ddmmss(n1, n0, n1, n0, d1, d0);
-                               } else
-                                       q0 = 0;
-
-                               q1 = 0;
-
-                               if (rp != 0) {
-                                       rr.s.low = n0;
-                                       rr.s.high = n1;
-                                       *rp = rr.ll;
-                               }
-                       } else {
-                               u32 m1, m0;
-                               /* Normalize.  */
-
-                               b = SI_TYPE_SIZE - bm;
-
-                               d1 = (d1 << bm) | (d0 >> b);
-                               d0 = d0 << bm;
-                               n2 = n1 >> b;
-                               n1 = (n1 << bm) | (n0 >> b);
-                               n0 = n0 << bm;
-
-                               udiv_qrnnd(q0, n1, n2, n1, d1);
-                               umul_ppmm(m1, m0, q0, d0);
-
-                               if (m1 > n1 || (m1 == n1 && m0 > n0)) {
-                                       q0--;
-                                       sub_ddmmss(m1, m0, m1, m0, d1, d0);
-                               }
-
-                               q1 = 0;
-
-                               /* Remainder in (n1n0 - m1m0) >> bm.  */
-                               if (rp != 0) {
-                                       sub_ddmmss(n1, n0, n1, n0, m1, m0);
-                                       rr.s.low = (n1 << b) | (n0 >> bm);
-                                       rr.s.high = n1 >> bm;
-                                       *rp = rr.ll;
-                               }
-                       }
-               }
-       }
-
-       ww.s.low = q0;
-       ww.s.high = q1;
-       return ww.ll;
-}
-
-u64 __udivdi3(u64 n, u64 d)
-{
-       return __udivmoddi4(n, d, (u64 *) 0);
-}
-
-u64 __umoddi3(u64 u, u64 v)
-{
-       u64 w;
-
-       (void)__udivmoddi4(u, v, &w);
-
-       return w;
-}
diff --git a/arch/arm/mach-aaec2000/Makefile.boot b/arch/arm/mach-aaec2000/Makefile.boot
new file mode 100644 (file)
index 0000000..8f5a8b7
--- /dev/null
@@ -0,0 +1 @@
+       zreladdr-y := 0xf0008000
index fc145b3768fab5a4431f59ec45ac57536456c420..aece0cd4f0a3f324cb203476db3d0bc9921794a1 100644 (file)
@@ -128,8 +128,8 @@ aaec2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction aaec2000_timer_irq = {
        .name           = "AAEC-2000 Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = aaec2000_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = aaec2000_timer_interrupt,
 };
 
 static void __init aaec2000_timer_init(void)
index 45c930ccd064802ec3195e342ed57476db6ca43d..0793dcf54f2e51dd30be757962db1483824a1d9d 100644 (file)
@@ -28,7 +28,7 @@ config ARCH_CLEP7312
 config ARCH_EDB7211
        bool "EDB7211"
        select ISA
-       select DISCONTIGMEM
+       select ARCH_DISCONTIGMEM_ENABLE
        help
          Say Y here if you intend to run this kernel on a Cirrus Logic EDB-7211
          evaluation board.
index 383d4e0c6e35a4d7f1d0f0633259507ca8988e81..1a23f0dcd4b89cee7e8b6b3afedbaeb80aab9ed3 100644 (file)
@@ -57,8 +57,8 @@ p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction clps711x_timer_irq = {
        .name           = "CLPS711x Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = p720t_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = p720t_timer_interrupt,
 };
 
 static void __init clps711x_timer_init(void)
index 0bc7da488612ade33be256f5b0ee973b5f49ca29..90e85f434f6ff56d365381912f03d198f52dd70f 100644 (file)
@@ -298,8 +298,8 @@ clps7500_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction clps7500_timer_irq = {
        .name           = "CLPS7500 Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = clps7500_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = clps7500_timer_interrupt,
 };
 
 /*
index ef362d44949d41d678128f3c713f8e43acc81c51..86ffdbb5626e23046d89f5a48ebf656f8916a49d 100644 (file)
@@ -173,8 +173,8 @@ ebsa110_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction ebsa110_timer_irq = {
        .name           = "EBSA110 Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = ebsa110_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = ebsa110_timer_interrupt,
 };
 
 /*
index 1b991f3cc3c6a51adee517c270e6cca55ff0ce2f..4b1084dde8ddfa2dd024412e23af421a5bfe7125 100644 (file)
@@ -56,8 +56,8 @@ epxa10db_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction epxa10db_timer_irq = {
        .name           = "Excalibur Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = epxa10db_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = epxa10db_timer_interrupt,
 };
 
 /*
index da5b9b7623ca9fb6537bc22d26f45aceb4986d24..14a62d6008fe2f6165001d34ebc5c0d894f2084b 100644 (file)
@@ -43,7 +43,7 @@ timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 static struct irqaction footbridge_timer_irq = {
        .name           = "Timer1 timer tick",
        .handler        = timer1_interrupt,
-       .flags          = SA_INTERRUPT,
+       .flags          = SA_INTERRUPT | SA_TIMER,
 };
 
 /*
index a4fefa0bb5a1e9d10819feacc100d34e536159e4..c1d74f7ab669f76948663796e6de753131fa64aa 100644 (file)
@@ -72,7 +72,7 @@ isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 static struct irqaction isa_timer_irq = {
        .name           = "ISA timer tick",
        .handler        = isa_timer_interrupt,
-       .flags          = SA_INTERRUPT,
+       .flags          = SA_INTERRUPT | SA_TIMER,
 };
 
 static void __init isa_timer_init(void)
index 743656881ed6f8a9baca6ede567ff3112abfe162..af9e4a5d5ea7fcd97c9fe5e714b516391426ba36 100644 (file)
@@ -41,8 +41,8 @@ h7201_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction h7201_timer_irq = {
        .name           = "h7201 Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = h7201_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = h7201_timer_interrupt,
 };
 
 /*
index 21b8fb6122cd2582c7713e6390b02de7acd87819..593b6a2a30e1d5e8c2aa05ded41c8cbf1bd1284b 100644 (file)
@@ -171,8 +171,8 @@ static struct irqchip h7202_timerx_chip = {
 
 static struct irqaction h7202_timer_irq = {
        .name           = "h7202 Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = h7202_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = h7202_timer_interrupt,
 };
 
 /*
index 11f1e56c36bc041154e995b00650c0fcb34c4eb0..ea805bfa5e5401f01455f47d586fde14ecfb5b2d 100644 (file)
@@ -72,8 +72,8 @@ imx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction imx_timer_irq = {
        .name           = "i.MX Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = imx_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = imx_timer_interrupt,
 };
 
 /*
index bd1e5e3c9d34b2e055f6d12763e2735b3994daf4..dacbf504dae277e57cb4bd00eb1044022e3f26ff 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/hardware/amba.h>
+#include <asm/hardware/arm_timer.h>
 #include <asm/arch/cm.h>
 #include <asm/system.h>
 #include <asm/leds.h>
@@ -156,16 +157,6 @@ EXPORT_SYMBOL(cm_control);
 #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
 #endif
 
-/*
- * What does it look like?
- */
-typedef struct TimerStruct {
-       unsigned long TimerLoad;
-       unsigned long TimerValue;
-       unsigned long TimerControl;
-       unsigned long TimerClear;
-} TimerStruct_t;
-
 static unsigned long timer_reload;
 
 /*
@@ -174,7 +165,6 @@ static unsigned long timer_reload;
  */
 unsigned long integrator_gettimeoffset(void)
 {
-       volatile TimerStruct_t *timer1 = (TimerStruct_t *)TIMER1_VA_BASE;
        unsigned long ticks1, ticks2, status;
 
        /*
@@ -183,11 +173,11 @@ unsigned long integrator_gettimeoffset(void)
         * an interrupt.  We get around this by ensuring that the
         * counter has not reloaded between our two reads.
         */
-       ticks2 = timer1->TimerValue & 0xffff;
+       ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
        do {
                ticks1 = ticks2;
                status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS);
-               ticks2 = timer1->TimerValue & 0xffff;
+               ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
        } while (ticks2 > ticks1);
 
        /*
@@ -213,14 +203,12 @@ unsigned long integrator_gettimeoffset(void)
 static irqreturn_t
 integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-       volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
-
        write_seqlock(&xtime_lock);
 
        /*
         * clear the interrupt
         */
-       timer1->TimerClear = 1;
+       writel(1, TIMER1_VA_BASE + TIMER_INTCLR);
 
        /*
         * the clock tick routines are only processed on the
@@ -247,8 +235,8 @@ integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction integrator_timer_irq = {
        .name           = "Integrator Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = integrator_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = integrator_timer_interrupt,
 };
 
 /*
@@ -256,32 +244,29 @@ static struct irqaction integrator_timer_irq = {
  */
 void __init integrator_time_init(unsigned long reload, unsigned int ctrl)
 {
-       volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
-       volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
-       volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE;
-       unsigned int timer_ctrl = 0x80 | 0x40;  /* periodic */
+       unsigned int timer_ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
 
        timer_reload = reload;
        timer_ctrl |= ctrl;
 
        if (timer_reload > 0x100000) {
                timer_reload >>= 8;
-               timer_ctrl |= 0x08; /* /256 */
+               timer_ctrl |= TIMER_CTRL_DIV256;
        } else if (timer_reload > 0x010000) {
                timer_reload >>= 4;
-               timer_ctrl |= 0x04; /* /16 */
+               timer_ctrl |= TIMER_CTRL_DIV16;
        }
 
        /*
         * Initialise to a known state (all timers off)
         */
-       timer0->TimerControl = 0;
-       timer1->TimerControl = 0;
-       timer2->TimerControl = 0;
+       writel(0, TIMER0_VA_BASE + TIMER_CTRL);
+       writel(0, TIMER1_VA_BASE + TIMER_CTRL);
+       writel(0, TIMER2_VA_BASE + TIMER_CTRL);
 
-       timer1->TimerLoad    = timer_reload;
-       timer1->TimerValue   = timer_reload;
-       timer1->TimerControl = timer_ctrl;
+       writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD);
+       writel(timer_reload, TIMER1_VA_BASE + TIMER_VALUE);
+       writel(timer_ctrl, TIMER1_VA_BASE + TIMER_CTRL);
 
        /*
         * Make irqs happen for the system timer
index 9b7dd64d1b8fea01fcd4cbe9493a39a22fbf69d7..d53af16695023d16f7867b74c35b56c2dfa952cc 100644 (file)
@@ -86,7 +86,7 @@ iop321_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 static struct irqaction iop321_timer_irq = {
        .name           = "IOP321 Timer Tick",
        .handler        = iop321_timer_interrupt,
-       .flags          = SA_INTERRUPT
+       .flags          = SA_INTERRUPT | SA_TIMER,
 };
 
 static void __init iop321_timer_init(void)
index e01696769263c1bf275254fa792dd2015d72bbbb..1a6d9d661e4b8ee851ef0867be104309eebe917f 100644 (file)
@@ -83,7 +83,7 @@ iop331_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 static struct irqaction iop331_timer_irq = {
        .name           = "IOP331 Timer Tick",
        .handler        = iop331_timer_interrupt,
-       .flags          = SA_INTERRUPT
+       .flags          = SA_INTERRUPT | SA_TIMER,
 };
 
 static void __init iop331_timer_init(void)
index 9361e05f6fa39e5519608c6e13fd806bbffd250c..ecb58d83478e32e511a77937328cfd79ef5f290a 100644 (file)
@@ -54,6 +54,14 @@ config ARCH_IXDP2X01
        depends on ARCH_IXDP2401 || ARCH_IXDP2801
        default y       
 
+config IXP2000_SUPPORT_BROKEN_PCI_IO
+       bool "Support broken PCI I/O on older IXP2000s"
+       default y
+       help
+         Say 'N' here if you only intend to run your kernel on an
+         IXP2000 B0 or later model and do not need the PCI I/O
+         byteswap workaround.  Say 'Y' otherwise.
+
 endmenu
 
 endif
index fc0555596d6d70c82a0c3cefb603efc9e574d2e7..4b9d841e04c15395a50488c52b1f1ca86daa9bd7 100644 (file)
@@ -40,6 +40,8 @@
 #include <asm/mach/time.h>
 #include <asm/mach/irq.h>
 
+#include <asm/arch/gpio.h>
+
 static DEFINE_SPINLOCK(ixp2000_slowport_lock);
 static unsigned long ixp2000_slowport_irq_flags;
 
@@ -100,6 +102,11 @@ static struct map_desc ixp2000_io_desc[] __initdata = {
                .physical       = IXP2000_PCI_CSR_PHYS_BASE,
                .length         = IXP2000_PCI_CSR_SIZE,
                .type           = MT_DEVICE
+       }, {
+               .virtual        = IXP2000_MSF_VIRT_BASE,
+               .physical       = IXP2000_MSF_PHYS_BASE,
+               .length         = IXP2000_MSF_SIZE,
+               .type           = MT_DEVICE
        }, {
                .virtual        = IXP2000_PCI_IO_VIRT_BASE,
                .physical       = IXP2000_PCI_IO_PHYS_BASE,
@@ -179,7 +186,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        /* clear timer 1 */
        ixp2000_reg_write(IXP2000_T1_CLR, 1);
-       
+
        while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) {
                timer_tick(regs);
                next_jiffy_time -= ticks_per_jiffy;
@@ -192,8 +199,8 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction ixp2000_timer_irq = {
        .name           = "IXP2000 Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = ixp2000_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = ixp2000_timer_interrupt,
 };
 
 void __init ixp2000_init_time(unsigned long tick_rate)
@@ -238,35 +245,40 @@ void __init ixp2000_init_time(unsigned long tick_rate)
 /*************************************************************************
  * GPIO helpers
  *************************************************************************/
-static unsigned long GPIO_IRQ_rising_edge;
 static unsigned long GPIO_IRQ_falling_edge;
+static unsigned long GPIO_IRQ_rising_edge;
 static unsigned long GPIO_IRQ_level_low;
 static unsigned long GPIO_IRQ_level_high;
 
-void gpio_line_config(int line, int style)
+static void update_gpio_int_csrs(void)
+{
+       ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge);
+       ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge);
+       ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low);
+       ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high);
+}
+
+void gpio_line_config(int line, int direction)
 {
        unsigned long flags;
 
        local_irq_save(flags);
+       if (direction == GPIO_OUT) {
+               irq_desc[line + IRQ_IXP2000_GPIO0].valid = 0;
 
-       if(style == GPIO_OUT) {
                /* if it's an output, it ain't an interrupt anymore */
-               ixp2000_reg_write(IXP2000_GPIO_PDSR, (1 << line));
                GPIO_IRQ_falling_edge &= ~(1 << line);
                GPIO_IRQ_rising_edge &= ~(1 << line);
                GPIO_IRQ_level_low &= ~(1 << line);
                GPIO_IRQ_level_high &= ~(1 << line);
-               ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge);
-               ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge);
-               ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high);
-               ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low);
-               irq_desc[line+IRQ_IXP2000_GPIO0].valid = 0;
-       } else if(style == GPIO_IN) {
-               ixp2000_reg_write(IXP2000_GPIO_PDCR, (1 << line));
+               update_gpio_int_csrs();
+
+               ixp2000_reg_write(IXP2000_GPIO_PDSR, 1 << line);
+       } else if (direction == GPIO_IN) {
+               ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line);
        }
-               
        local_irq_restore(flags);
-}      
+}
 
 
 /*************************************************************************
@@ -285,9 +297,50 @@ static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, str
        }
 }
 
+static int ixp2000_GPIO_irq_type(unsigned int irq, unsigned int type)
+{
+       int line = irq - IRQ_IXP2000_GPIO0;
+
+       /*
+        * First, configure this GPIO line as an input.
+        */
+       ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line);
+
+       /*
+        * Then, set the proper trigger type.
+        */
+       if (type & IRQT_FALLING)
+               GPIO_IRQ_falling_edge |= 1 << line;
+       else
+               GPIO_IRQ_falling_edge &= ~(1 << line);
+       if (type & IRQT_RISING)
+               GPIO_IRQ_rising_edge |= 1 << line;
+       else
+               GPIO_IRQ_rising_edge &= ~(1 << line);
+       if (type & IRQT_LOW)
+               GPIO_IRQ_level_low |= 1 << line;
+       else
+               GPIO_IRQ_level_low &= ~(1 << line);
+       if (type & IRQT_HIGH)
+               GPIO_IRQ_level_high |= 1 << line;
+       else
+               GPIO_IRQ_level_high &= ~(1 << line);
+       update_gpio_int_csrs();
+
+       /*
+        * Finally, mark the corresponding IRQ as valid.
+        */
+       irq_desc[irq].valid = 1;
+
+       return 0;
+}
+
 static void ixp2000_GPIO_irq_mask_ack(unsigned int irq)
 {
        ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
+
+       ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
+       ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
        ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0)));
 }
 
@@ -302,6 +355,7 @@ static void ixp2000_GPIO_irq_unmask(unsigned int irq)
 }
 
 static struct irqchip ixp2000_GPIO_irq_chip = {
+       .type   = ixp2000_GPIO_irq_type,
        .ack    = ixp2000_GPIO_irq_mask_ack,
        .mask   = ixp2000_GPIO_irq_mask,
        .unmask = ixp2000_GPIO_irq_unmask
@@ -338,7 +392,7 @@ static void ixp2000_irq_mask(unsigned int irq)
 
 static void ixp2000_irq_unmask(unsigned int irq)
 {
-       ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET,  (1 << irq));
+       ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << irq));
 }
 
 static struct irqchip ixp2000_irq_chip = {
@@ -375,16 +429,16 @@ void __init ixp2000_init_irq(void)
         * our mask/unmask code much simpler.
         */
        for (irq = IRQ_IXP2000_SOFT_INT; irq <= IRQ_IXP2000_THDB3; irq++) {
-               if((1 << irq) & IXP2000_VALID_IRQ_MASK) {
+               if ((1 << irq) & IXP2000_VALID_IRQ_MASK) {
                        set_irq_chip(irq, &ixp2000_irq_chip);
                        set_irq_handler(irq, do_level_IRQ);
                        set_irq_flags(irq, IRQF_VALID);
                } else set_irq_flags(irq, 0);
        }
-       
+
        /*
         * GPIO IRQs are invalid until someone sets the interrupt mode
-        * by calling gpio_line_set();
+        * by calling set_irq_type().
         */
        for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) {
                set_irq_chip(irq, &ixp2000_GPIO_irq_chip);
index 04b38bcf9aace6deb405720e2d554594242ffc49..f3a291b6a9fb7b72d7eeece51e4739cabef45794 100644 (file)
@@ -197,8 +197,23 @@ static struct platform_device enp2611_flash = {
        .resource       = &enp2611_flash_resource,
 };
 
+static struct ixp2000_i2c_pins enp2611_i2c_gpio_pins = {
+       .sda_pin        = ENP2611_GPIO_SDA,
+       .scl_pin        = ENP2611_GPIO_SCL,
+};
+
+static struct platform_device enp2611_i2c_controller = {
+       .name           = "IXP2000-I2C",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &enp2611_i2c_gpio_pins
+       },
+       .num_resources  = 0
+};
+
 static struct platform_device *enp2611_devices[] __initdata = {
-       &enp2611_flash
+       &enp2611_flash,
+       &enp2611_i2c_controller
 };
 
 static void __init enp2611_init_machine(void)
index aec13c7108a9e94272e5c20e04b18fe817518f3c..468a4bbfb724a84a23a0f44d2d604ffefa84a484 100644 (file)
 #include <asm/mach/flash.h>
 #include <asm/mach/arch.h>
 
-
-void ixdp2400_init_irq(void)
-{
-       ixdp2x00_init_irq(IXDP2800_CPLD_INT_STAT, IXDP2800_CPLD_INT_MASK, IXDP2400_NR_IRQS);
-}
-
 /*************************************************************************
  * IXDP2800 timer tick
  *************************************************************************/
index 21c41fe15b99cacd2493ba5d2d22f472944eb1c0..5e4380747b53d1bb2b105b35ec71f890ba4440c1 100644 (file)
@@ -42,6 +42,9 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/arch.h>
 
+#include <asm/arch/gpio.h>
+
+
 /*************************************************************************
  * IXDP2x00 IRQ Initialization
  *************************************************************************/
index 5ff2f2718c58c0762cfca0f3173cc74f80f09794..0788fb2b5c10e6ae6e2023649930205cc3afb016 100644 (file)
@@ -198,6 +198,19 @@ clear_master_aborts(void)
 void __init
 ixp2000_pci_preinit(void)
 {
+#ifndef CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO
+       /*
+        * Configure the PCI unit to properly byteswap I/O transactions,
+        * and verify that it worked.
+        */
+       ixp2000_reg_write(IXP2000_PCI_CONTROL,
+                         (*IXP2000_PCI_CONTROL | PCI_CONTROL_IEE));
+
+       if ((*IXP2000_PCI_CONTROL & PCI_CONTROL_IEE) == 0)
+               panic("IXP2000: PCI I/O is broken on this ixp model, and "
+                       "the needed workaround has not been configured in");
+#endif
+
        hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS,
                                "PCI config cycle to non-existent device");
 }
index 267ba02d77dc770a5ec82d5783d42321bc4e25fb..04490a9f8f6ecfc2158d8b21ec3aa096b888e1f2 100644 (file)
@@ -141,7 +141,15 @@ static struct map_desc ixp4xx_io_desc[] __initdata = {
                .physical       = IXP4XX_PCI_CFG_BASE_PHYS,
                .length         = IXP4XX_PCI_CFG_REGION_SIZE,
                .type           = MT_DEVICE
+       },
+#ifdef CONFIG_DEBUG_LL
+       {       /* Debug UART mapping */
+               .virtual        = IXP4XX_DEBUG_UART_BASE_VIRT,
+               .physical       = IXP4XX_DEBUG_UART_BASE_PHYS,
+               .length         = IXP4XX_DEBUG_UART_REGION_SIZE,
+               .type           = MT_DEVICE
        }
+#endif
 };
 
 void __init ixp4xx_map_io(void)
@@ -290,8 +298,8 @@ static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs
 
 static struct irqaction ixp4xx_timer_irq = {
        .name           = "IXP4xx Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = ixp4xx_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = ixp4xx_timer_interrupt,
 };
 
 static void __init ixp4xx_timer_init(void)
index 51e1c814b40058972ad49b4571a13cf9f8b694a0..be377e331f255baeceb7530f41dfbd00b8694c9c 100644 (file)
@@ -53,8 +53,8 @@ lh7a40x_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction lh7a40x_timer_irq = {
        .name           = "LHA740x Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = lh7a40x_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = lh7a40x_timer_interrupt,
 };
 
 static void __init lh7a40x_timer_init(void)
index 00fac155df2a6fb45ee37106bac4d21c7f5056ea..6b03ccdc1e926a127ace7f7bcdfbc29ac2cd8534 100644 (file)
@@ -41,7 +41,9 @@
 #include <linux/pm.h>
 
 #include <asm/io.h>
+#include <asm/mach/time.h>
 #include <asm/mach-types.h>
+
 #include <asm/arch/omap16xx.h>
 #include <asm/arch/pm.h>
 #include <asm/arch/mux.h>
@@ -80,13 +82,13 @@ void omap_pm_idle(void)
                return;
        }
        mask32 = omap_readl(ARM_SYSST);
-       local_fiq_enable();
-       local_irq_enable();
 
-#if defined(CONFIG_OMAP_32K_TIMER) && defined(CONFIG_NO_IDLE_HZ)
-       /* Override timer to use VST for the next cycle */
-       omap_32k_timer_next_vst_interrupt();
-#endif
+       /*
+        * Since an interrupt may set up a timer, we don't want to
+        * reprogram the hardware timer with interrupts enabled.
+        * Re-enable interrupts only after returning from idle.
+        */
+       timer_dyn_reprogram();
 
        if ((mask32 & DSP_IDLE) == 0) {
                __asm__ volatile ("mcr  p15, 0, r0, c7, c0, 4");
@@ -102,6 +104,8 @@ void omap_pm_idle(void)
 
                func_ptr();
        }
+       local_fiq_enable();
+       local_irq_enable();
 }
 
 /*
index 4205fdcb632c238fd173df7ffc51b0bedfeed45b..dd34e9f4c4139cebd68da923e1b839e8164c762a 100644 (file)
@@ -4,7 +4,7 @@
  * OMAP Timers
  *
  * Copyright (C) 2004 Nokia Corporation
- * Partial timer rewrite and additional VST timer support by
+ * Partial timer rewrite and additional dynamic tick timer support by
  * Tony Lindgen <tony@atomide.com> and
  * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
  *
@@ -188,8 +188,8 @@ static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id,
 
 static struct irqaction omap_mpu_timer_irq = {
        .name           = "mpu timer",
-       .flags          = SA_INTERRUPT,
-       .handler        = omap_mpu_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = omap_mpu_timer_interrupt,
 };
 
 static unsigned long omap_mpu_timer1_overflows;
@@ -203,7 +203,7 @@ static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id,
 static struct irqaction omap_mpu_timer1_irq = {
        .name           = "mpu timer1 overflow",
        .flags          = SA_INTERRUPT,
-       .handler        = omap_mpu_timer1_interrupt
+       .handler        = omap_mpu_timer1_interrupt,
 };
 
 static __init void omap_init_mpu_timer(void)
@@ -261,7 +261,6 @@ unsigned long long sched_clock(void)
  * so with HZ = 100, TVR = 327.68.
  */
 #define OMAP_32K_TIMER_TICK_PERIOD     ((32768 / HZ) - 1)
-#define MAX_SKIP_JIFFIES               25
 #define TIMER_32K_SYNCHRONIZED         0xfffbc410
 
 #define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate)                    \
@@ -347,14 +346,55 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_NO_IDLE_HZ
+/*
+ * Programs the next timer interrupt needed. Called when dynamic tick is
+ * enabled, and to reprogram the ticks to skip from pm_idle. Note that
+ * we can keep the timer continuous, and don't need to set it to run in
+ * one-shot mode. This is because the timer will get reprogrammed again
+ * after next interrupt.
+ */
+void omap_32k_timer_reprogram(unsigned long next_tick)
+{
+       omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1);
+}
+
+static struct irqaction omap_32k_timer_irq;
+extern struct timer_update_handler timer_update;
+
+static int omap_32k_timer_enable_dyn_tick(void)
+{
+       /* No need to reprogram timer, just use the next interrupt */
+       return 0;
+}
+
+static int omap_32k_timer_disable_dyn_tick(void)
+{
+       omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
+       return 0;
+}
+
+static struct dyn_tick_timer omap_dyn_tick_timer = {
+       .enable         = omap_32k_timer_enable_dyn_tick,
+       .disable        = omap_32k_timer_disable_dyn_tick,
+       .reprogram      = omap_32k_timer_reprogram,
+       .handler        = omap_32k_timer_interrupt,
+};
+#endif /* CONFIG_NO_IDLE_HZ */
+
 static struct irqaction omap_32k_timer_irq = {
        .name           = "32KHz timer",
-       .flags          = SA_INTERRUPT,
-       .handler        = omap_32k_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = omap_32k_timer_interrupt,
 };
 
 static __init void omap_init_32k_timer(void)
 {
+
+#ifdef CONFIG_NO_IDLE_HZ
+       omap_timer.dyn_tick = &omap_dyn_tick_timer;
+#endif
+
        setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
        omap_timer.offset  = omap_32k_timer_gettimeoffset;
        omap_32k_last_tick = omap_32k_sync_timer_read();
index 6e805d451d0e7b69a461e32f6b468e8a9fc347a6..7f37857b1a28fe0eb08a1aa520a271e14dd5d295 100644 (file)
@@ -288,8 +288,8 @@ static void usb_release(struct device *dev)
 static struct resource udc_resources[] = {
        /* order is significant! */
        {               /* registers */
-               .start          = IO_ADDRESS(UDC_BASE),
-               .end            = IO_ADDRESS(UDC_BASE + 0xff),
+               .start          = UDC_BASE,
+               .end            = UDC_BASE + 0xff,
                .flags          = IORESOURCE_MEM,
        }, {            /* general IRQ */
                .start          = IH2_BASE + 20,
@@ -355,8 +355,8 @@ static struct platform_device ohci_device = {
 static struct resource otg_resources[] = {
        /* order is significant! */
        {
-               .start          = IO_ADDRESS(OTG_BASE),
-               .end            = IO_ADDRESS(OTG_BASE + 0xff),
+               .start          = OTG_BASE,
+               .end            = OTG_BASE + 0xff,
                .flags          = IORESOURCE_MEM,
        }, {
                .start          = IH2_BASE + 8,
index 473fb6173f7210a3ac7561983f05a437c8b8f910..6e5202154f911321a82e53e0b93d716726b57d5e 100644 (file)
@@ -105,8 +105,8 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction pxa_timer_irq = {
        .name           = "PXA Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = pxa_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = pxa_timer_interrupt,
 };
 
 static void __init pxa_timer_init(void)
index 534df0c6c77051cdcee965b1a30f72817c1a6b75..d4d03d0daaecdecc053b0cb04c033a20f5189d2d 100644 (file)
@@ -154,6 +154,11 @@ config S3C2410_PM_CHECK_CHUNKSIZE
          the CRC data block will take more memory, but wil identify any
          faults with better precision.
 
+config PM_SIMTEC
+       bool
+       depends on PM && (ARCH_BAST || MACH_VR1000)
+       default y
+
 config S3C2410_LOWLEVEL_UART_PORT
        int "S3C2410 UART to use for low-level messages"
        default 0
index 7c379aad5d62929d3b24b70aa840b37b673a4559..f99b689e4392ec5c8d8ba7240a599fa83bb41c40 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_S3C2410_DMA)  += dma.o
 # Power Management support
 
 obj-$(CONFIG_PM)          += pm.o sleep.o
+obj-$(CONFIG_PM_SIMTEC)           += pm-simtec.o
 
 # S3C2440 support
 
index 64792f6786688e3d47aa0ee7a908b6733f1ac1c2..4664bd11adc1eb45931431ea38d895c819936b8a 100644 (file)
@@ -96,8 +96,8 @@ struct platform_device s3c_device_lcd = {
        .num_resources    = ARRAY_SIZE(s3c_lcd_resource),
        .resource         = s3c_lcd_resource,
        .dev              = {
-               .dma_mask = &s3c_device_lcd_dmamask,
-               .coherent_dma_mask = 0xffffffffUL
+               .dma_mask               = &s3c_device_lcd_dmamask,
+               .coherent_dma_mask      = 0xffffffffUL
        }
 };
 
index b668c48f43990f3648f248f8c17399f884568b4f..cf9f46d88061819432925c4097673b8d458a9350 100644 (file)
  *   04-Nov-2004  Ben Dooks
  *               Fix standard IRQ wake for EINT0..4 and RTC
  *
- *   22-Feb-2004  Ben Dooks
+ *   22-Feb-2005  Ben Dooks
  *               Fixed edge-triggering on ADC IRQ
+ *
+ *   28-Jun-2005  Ben Dooks
+ *               Mark IRQ_LCD valid
 */
 
 #include <linux/init.h>
@@ -366,7 +369,6 @@ static struct irqchip s3c_irq_eint0t4 = {
 #define INTMSK_UART1    (1UL << (IRQ_UART1 - IRQ_EINT0))
 #define INTMSK_UART2    (1UL << (IRQ_UART2 - IRQ_EINT0))
 #define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0))
-#define INTMSK_LCD      (1UL << (IRQ_LCD - IRQ_EINT0))
 
 static inline void
 s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit,
@@ -716,7 +718,6 @@ void __init s3c24xx_init_irq(void)
                case IRQ_UART0:
                case IRQ_UART1:
                case IRQ_UART2:
-               case IRQ_LCD:
                case IRQ_ADCPARENT:
                        set_irq_chip(irqno, &s3c_irq_level_chip);
                        set_irq_handler(irqno, do_level_IRQ);
index f3e970039b65b407fdee9d95901b36bf1e39ceab..549bcb1f32c050160e656c6a9d8ca1d383cd0469 100644 (file)
@@ -27,6 +27,7 @@
  *     10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
  *     14-Mar-2006 BJD  Updated for __iomem changes
  *     22-Jun-2006 BJD  Added DM9000 platform information
+ *     28-Jun-2006 BJD  Moved pm functionality out to common code
 */
 
 #include <linux/kernel.h>
@@ -67,7 +68,6 @@
 #include "devs.h"
 #include "cpu.h"
 #include "usb-simtec.h"
-#include "pm.h"
 
 #define COPYRIGHT ", (c) 2004-2005 Simtec Electronics"
 
@@ -405,44 +405,13 @@ void __init bast_map_io(void)
        usb_simtec_init();
 }
 
-void __init bast_init_irq(void)
-{
-       s3c24xx_init_irq();
-}
-
-#ifdef CONFIG_PM
-
-/* bast_init_machine
- *
- * enable the power management functions for the EB2410ITX
-*/
-
-static __init void bast_init_machine(void)
-{
-       unsigned long gstatus4;
-
-       printk(KERN_INFO "BAST Power Manangement" COPYRIGHT "\n");
-
-       gstatus4  = (__raw_readl(S3C2410_BANKCON7) & 0x3) << 30;
-       gstatus4 |= (__raw_readl(S3C2410_BANKCON6) & 0x3) << 28;
-       gstatus4 |= (__raw_readl(S3C2410_BANKSIZE) & S3C2410_BANKSIZE_MASK);
-
-       __raw_writel(gstatus4, S3C2410_GSTATUS4);
-
-       s3c2410_pm_init();
-}
-
-#else
-#define bast_init_machine NULL
-#endif
-
 
 MACHINE_START(BAST, "Simtec-BAST")
      MAINTAINER("Ben Dooks <ben@simtec.co.uk>")
      BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
      BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
-     MAPIO(bast_map_io)
-     INITIRQ(bast_init_irq)
-       .init_machine   = bast_init_machine,
+
+       .map_io         = bast_map_io,
+       .init_irq       = s3c24xx_init_irq,
        .timer          = &s3c24xx_timer,
 MACHINE_END
index 76be074944a0827e81354e09244459a51dd3d18b..1db2855e3e561ae62eaae6d7ee98bee37aaf72f0 100644 (file)
@@ -371,16 +371,12 @@ void __init vr1000_map_io(void)
        usb_simtec_init();
 }
 
-void __init vr1000_init_irq(void)
-{
-       s3c24xx_init_irq();
-}
 
 MACHINE_START(VR1000, "Thorcom-VR1000")
      MAINTAINER("Ben Dooks <ben@simtec.co.uk>")
      BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
      BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
-     MAPIO(vr1000_map_io)
-     INITIRQ(vr1000_init_irq)
+       .map_io         = vr1000_map_io,
+       .init_irq       = s3c24xx_init_irq,
        .timer          = &s3c24xx_timer,
 MACHINE_END
diff --git a/arch/arm/mach-s3c2410/pm-simtec.c b/arch/arm/mach-s3c2410/pm-simtec.c
new file mode 100644 (file)
index 0000000..2cb7988
--- /dev/null
@@ -0,0 +1,65 @@
+/* linux/arch/arm/mach-s3c2410/pm-simtec.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * Power Management helpers for Simtec S3C24XX implementations
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include <asm/arch/map.h>
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-mem.h>
+
+#include <asm/mach-types.h>
+
+#include "pm.h"
+
+#define COPYRIGHT ", (c) 2005 Simtec Electronics"
+
+/* pm_simtec_init
+ *
+ * enable the power management functions
+*/
+
+static __init int pm_simtec_init(void)
+{
+       unsigned long gstatus4;
+
+       /* check which machine we are running on */
+
+       if (!machine_is_bast() && !machine_is_vr1000())
+               return 0;
+
+       printk(KERN_INFO "Simtec Board Power Manangement" COPYRIGHT "\n");
+
+       gstatus4  = (__raw_readl(S3C2410_BANKCON7) & 0x3) << 30;
+       gstatus4 |= (__raw_readl(S3C2410_BANKCON6) & 0x3) << 28;
+       gstatus4 |= (__raw_readl(S3C2410_BANKSIZE) & S3C2410_BANKSIZE_MASK);
+
+       __raw_writel(gstatus4, S3C2410_GSTATUS4);
+
+       return s3c2410_pm_init();
+}
+
+arch_initcall(pm_simtec_init);
index 179f0e031af4824bc5bb99b814862efe23cccd1d..765a3a9ae032581b7f6c97217807fb8bc9cdc014 100644 (file)
@@ -137,8 +137,8 @@ s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction s3c2410_timer_irq = {
        .name           = "S3C2410 Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = s3c2410_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = s3c2410_timer_interrupt,
 };
 
 /*
index 84c86543501a7831ca7286fd373bdc959e367ce0..65dbe991426dda1bd5993a608ef66b572a337064 100644 (file)
@@ -727,7 +727,7 @@ static void h3800_IRQ_demux(unsigned int irq, struct irqdesc *desc, struct pt_re
 static struct irqaction h3800_irq = {
        .name           = "h3800_asic",
        .handler        = h3800_IRQ_demux,
-       .flags          = SA_INTERRUPT,
+       .flags          = SA_INTERRUPT | SA_TIMER,
 };
 
 u32 kpio_int_shadow = 0;
index 19b0c0fd63772085cf37e3ae51232e2e32fa9324..0eeb3616ffea739652f8221504da7a1548374171 100644 (file)
@@ -99,8 +99,8 @@ sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction sa1100_timer_irq = {
        .name           = "SA11xx Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = sa1100_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = sa1100_timer_interrupt,
 };
 
 static void __init sa1100_timer_init(void)
index a9bc5d0dbd85515c5694c04a3a21f8d0c706b35b..aa0e2f6e02f6df52da2a31755107340f289eeae8 100644 (file)
@@ -84,8 +84,8 @@ shark_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction shark_timer_irq = {
        .name           = "Shark Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = shark_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = shark_timer_interrupt,
 };
 
 /*
index 6a7cbea5e098d4acf62a3966217a643656848a3b..f01c0f8a2bb369ccb7dfb47dc5ea75c13443d0b9 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/mach-types.h>
 #include <asm/hardware/amba.h>
 #include <asm/hardware/amba_clcd.h>
+#include <asm/hardware/arm_timer.h>
 #include <asm/hardware/icst307.h>
 
 #include <asm/mach/arch.h>
@@ -788,38 +789,25 @@ void __init versatile_init(void)
  */
 #define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
 #if TIMER_INTERVAL >= 0x100000
-#define TIMER_RELOAD   (TIMER_INTERVAL >> 8)           /* Divide by 256 */
-#define TIMER_CTRL     0x88                            /* Enable, Clock / 256 */
+#define TIMER_RELOAD   (TIMER_INTERVAL >> 8)
+#define TIMER_DIVISOR  (TIMER_CTRL_DIV256)
 #define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
 #elif TIMER_INTERVAL >= 0x10000
 #define TIMER_RELOAD   (TIMER_INTERVAL >> 4)           /* Divide by 16 */
-#define TIMER_CTRL     0x84                            /* Enable, Clock / 16 */
+#define TIMER_DIVISOR  (TIMER_CTRL_DIV16)
 #define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
 #else
 #define TIMER_RELOAD   (TIMER_INTERVAL)
-#define TIMER_CTRL     0x80                            /* Enable */
+#define TIMER_DIVISOR  (TIMER_CTRL_DIV1)
 #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
 #endif
 
-#define TIMER_CTRL_IE  (1 << 5)        /* Interrupt Enable */
-
-/*
- * What does it look like?
- */
-typedef struct TimerStruct {
-       unsigned long TimerLoad;
-       unsigned long TimerValue;
-       unsigned long TimerControl;
-       unsigned long TimerClear;
-} TimerStruct_t;
-
 /*
  * Returns number of ms since last clock interrupt.  Note that interrupts
  * will have been disabled by do_gettimeoffset()
  */
 static unsigned long versatile_gettimeoffset(void)
 {
-       volatile TimerStruct_t *timer0 = (TimerStruct_t *)TIMER0_VA_BASE;
        unsigned long ticks1, ticks2, status;
 
        /*
@@ -828,11 +816,11 @@ static unsigned long versatile_gettimeoffset(void)
         * an interrupt.  We get around this by ensuring that the
         * counter has not reloaded between our two reads.
         */
-       ticks2 = timer0->TimerValue & 0xffff;
+       ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
        do {
                ticks1 = ticks2;
                status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS);
-               ticks2 = timer0->TimerValue & 0xffff;
+               ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
        } while (ticks2 > ticks1);
 
        /*
@@ -859,12 +847,10 @@ static unsigned long versatile_gettimeoffset(void)
  */
 static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-       volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
-
        write_seqlock(&xtime_lock);
 
        // ...clear the interrupt
-       timer0->TimerClear = 1;
+       writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
 
        timer_tick(regs);
 
@@ -875,8 +861,8 @@ static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_re
 
 static struct irqaction versatile_timer_irq = {
        .name           = "Versatile Timer Tick",
-       .flags          = SA_INTERRUPT,
-       .handler        = versatile_timer_interrupt
+       .flags          = SA_INTERRUPT | SA_TIMER,
+       .handler        = versatile_timer_interrupt,
 };
 
 /*
@@ -884,31 +870,32 @@ static struct irqaction versatile_timer_irq = {
  */
 static void __init versatile_timer_init(void)
 {
-       volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
-       volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
-       volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE;
-       volatile TimerStruct_t *timer3 = (volatile TimerStruct_t *)TIMER3_VA_BASE;
+       u32 val;
 
        /* 
         * set clock frequency: 
         *      VERSATILE_REFCLK is 32KHz
         *      VERSATILE_TIMCLK is 1MHz
         */
-       *(volatile unsigned int *)IO_ADDRESS(VERSATILE_SCTL_BASE) |= 
-         ((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | 
-          (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel));
+       val = readl(IO_ADDRESS(VERSATILE_SCTL_BASE));
+       writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
+              (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | 
+              (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
+              (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
+              IO_ADDRESS(VERSATILE_SCTL_BASE));
 
        /*
         * Initialise to a known state (all timers off)
         */
-       timer0->TimerControl = 0;
-       timer1->TimerControl = 0;
-       timer2->TimerControl = 0;
-       timer3->TimerControl = 0;
-
-       timer0->TimerLoad    = TIMER_RELOAD;
-       timer0->TimerValue   = TIMER_RELOAD;
-       timer0->TimerControl = TIMER_CTRL | 0x40 | TIMER_CTRL_IE;  /* periodic + IE */
+       writel(0, TIMER0_VA_BASE + TIMER_CTRL);
+       writel(0, TIMER1_VA_BASE + TIMER_CTRL);
+       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
index c08710b1ff02689bce10b2bdd8baac8eb10b12e3..edffa47a4b2aab8b3e05f42f65bf20e496fc96d5 100644 (file)
@@ -437,7 +437,7 @@ void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
        memtable_init(mi);
        if (mdesc->map_io)
                mdesc->map_io();
-       flush_tlb_all();
+       local_flush_tlb_all();
 
        /*
         * initialise the zones within each node
@@ -522,6 +522,69 @@ static inline void free_area(unsigned long addr, unsigned long end, char *s)
                printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
 }
 
+static inline void
+free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
+{
+       struct page *start_pg, *end_pg;
+       unsigned long pg, pgend;
+
+       /*
+        * Convert start_pfn/end_pfn to a struct page pointer.
+        */
+       start_pg = pfn_to_page(start_pfn);
+       end_pg = pfn_to_page(end_pfn);
+
+       /*
+        * Convert to physical addresses, and
+        * round start upwards and end downwards.
+        */
+       pg = PAGE_ALIGN(__pa(start_pg));
+       pgend = __pa(end_pg) & PAGE_MASK;
+
+       /*
+        * If there are free pages between these,
+        * free the section of the memmap array.
+        */
+       if (pg < pgend)
+               free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
+}
+
+/*
+ * The mem_map array can get very big.  Free the unused area of the memory map.
+ */
+static void __init free_unused_memmap_node(int node, struct meminfo *mi)
+{
+       unsigned long bank_start, prev_bank_end = 0;
+       unsigned int i;
+
+       /*
+        * [FIXME] This relies on each bank being in address order.  This
+        * may not be the case, especially if the user has provided the
+        * information on the command line.
+        */
+       for (i = 0; i < mi->nr_banks; i++) {
+               if (mi->bank[i].size == 0 || mi->bank[i].node != node)
+                       continue;
+
+               bank_start = mi->bank[i].start >> PAGE_SHIFT;
+               if (bank_start < prev_bank_end) {
+                       printk(KERN_ERR "MEM: unordered memory banks.  "
+                               "Not freeing memmap.\n");
+                       break;
+               }
+
+               /*
+                * If we had a previous bank, and there is a space
+                * between the current bank and the previous, free it.
+                */
+               if (prev_bank_end && prev_bank_end != bank_start)
+                       free_memmap(node, prev_bank_end, bank_start);
+
+               prev_bank_end = (mi->bank[i].start +
+                                mi->bank[i].size) >> PAGE_SHIFT;
+       }
+}
+
 /*
  * mem_init() marks the free areas in the mem_map and tells us how much
  * memory is free.  This is done after various parts of the system have
@@ -540,16 +603,12 @@ void __init mem_init(void)
        max_mapnr   = virt_to_page(high_memory) - mem_map;
 #endif
 
-       /*
-        * We may have non-contiguous memory.
-        */
-       if (meminfo.nr_banks != 1)
-               create_memmap_holes(&meminfo);
-
        /* this will put all unused low memory onto the freelists */
        for_each_online_node(node) {
                pg_data_t *pgdat = NODE_DATA(node);
 
+               free_unused_memmap_node(node, &meminfo);
+
                if (pgdat->node_spanned_pages != 0)
                        totalram_pages += free_all_bootmem_node(pgdat);
        }
index 2c2b93d77d433248dba64b6a1dd525eae51277fc..c3bd503b43a2aa0ca50ce3ec23d405641c5fcd69 100644 (file)
@@ -169,7 +169,14 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
 
        memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
 
+       /*
+        * Copy over the kernel and IO PGD entries
+        */
        init_pgd = pgd_offset_k(0);
+       memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
+                      (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
+
+       clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
 
        if (!vectors_high()) {
                /*
@@ -198,14 +205,6 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
                spin_unlock(&mm->page_table_lock);
        }
 
-       /*
-        * Copy over the kernel and IO PGD entries
-        */
-       memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
-                      (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
-
-       clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
-
        return new_pgd;
 
 no_pte:
@@ -683,7 +682,7 @@ void __init memtable_init(struct meminfo *mi)
        }
 
        flush_cache_all();
-       flush_tlb_all();
+       local_flush_tlb_all();
 
        top_pmd = pmd_off_k(0xffff0000);
 }
@@ -698,75 +697,3 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
        for (i = 0; i < nr; i++)
                create_mapping(io_desc + i);
 }
-
-static inline void
-free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
-{
-       struct page *start_pg, *end_pg;
-       unsigned long pg, pgend;
-
-       /*
-        * Convert start_pfn/end_pfn to a struct page pointer.
-        */
-       start_pg = pfn_to_page(start_pfn);
-       end_pg = pfn_to_page(end_pfn);
-
-       /*
-        * Convert to physical addresses, and
-        * round start upwards and end downwards.
-        */
-       pg = PAGE_ALIGN(__pa(start_pg));
-       pgend = __pa(end_pg) & PAGE_MASK;
-
-       /*
-        * If there are free pages between these,
-        * free the section of the memmap array.
-        */
-       if (pg < pgend)
-               free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
-}
-
-static inline void free_unused_memmap_node(int node, struct meminfo *mi)
-{
-       unsigned long bank_start, prev_bank_end = 0;
-       unsigned int i;
-
-       /*
-        * [FIXME] This relies on each bank being in address order.  This
-        * may not be the case, especially if the user has provided the
-        * information on the command line.
-        */
-       for (i = 0; i < mi->nr_banks; i++) {
-               if (mi->bank[i].size == 0 || mi->bank[i].node != node)
-                       continue;
-
-               bank_start = mi->bank[i].start >> PAGE_SHIFT;
-               if (bank_start < prev_bank_end) {
-                       printk(KERN_ERR "MEM: unordered memory banks.  "
-                               "Not freeing memmap.\n");
-                       break;
-               }
-
-               /*
-                * If we had a previous bank, and there is a space
-                * between the current bank and the previous, free it.
-                */
-               if (prev_bank_end && prev_bank_end != bank_start)
-                       free_memmap(node, prev_bank_end, bank_start);
-
-               prev_bank_end = PAGE_ALIGN(mi->bank[i].start +
-                                          mi->bank[i].size) >> PAGE_SHIFT;
-       }
-}
-
-/*
- * The mem_map array can get very big.  Free
- * the unused area of the memory map.
- */
-void __init create_memmap_holes(struct meminfo *mi)
-{
-       int node;
-
-       for_each_online_node(node)
-               free_unused_memmap_node(node, mi);
-}
index 0aa73d4147838b07f41cac3f09ed0011efa03bd5..e3d8510f43400b9c66b85bf8f7995b5653050409 100644 (file)
@@ -132,8 +132,8 @@ ENTRY(cpu_v6_switch_mm)
  *       100x   1   0   1      r/o     no acc
  *       10x0   1   0   1      r/o     no acc
  *       1011   0   0   1      r/w     no acc
- *       110x   1   1   0      r/o     r/o
- *       11x0   1   1   0      r/o     r/o
+ *       110x   0   1   0      r/w     r/o
+ *       11x0   0   1   0      r/w     r/o
  *       1111   0   1   1      r/w     r/w
  */
 ENTRY(cpu_v6_set_pte)
@@ -150,7 +150,7 @@ ENTRY(cpu_v6_set_pte)
        tst     r1, #L_PTE_USER
        orrne   r2, r2, #AP1 | nG
        tstne   r2, #APX
-       eorne   r2, r2, #AP0
+       bicne   r2, r2, #APX | AP0
 
        tst     r1, #L_PTE_YOUNG
        biceq   r2, r2, #APX | AP1 | AP0
index ba1a6e9f2b28a2f7315a707c975e03f6a38ccdc9..8ffb523e6c77345c097da32221aa5fdf3f34a58e 100644 (file)
@@ -6,6 +6,6 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
                oprofilefs.o oprofile_stats.o \
                timer_int.o )
 
-oprofile-y                             := $(DRIVER_OBJS) init.o
+oprofile-y                             := $(DRIVER_OBJS) init.o backtrace.o
 oprofile-$(CONFIG_CPU_XSCALE)          += common.o op_model_xscale.o
 
diff --git a/arch/arm/oprofile/backtrace.c b/arch/arm/oprofile/backtrace.c
new file mode 100644 (file)
index 0000000..ec58d3e
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Arm specific backtracing code for oprofile
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * Based on i386 oprofile backtrace code by John Levon, David Smith
+ *
+ * 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/oprofile.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+
+
+/*
+ * The registers we're interested in are at the end of the variable
+ * length saved register structure. The fp points at the end of this
+ * structure so the address of this struct is:
+ * (struct frame_tail *)(xxx->fp)-1
+ */
+struct frame_tail {
+       struct frame_tail *fp;
+       unsigned long sp;
+       unsigned long lr;
+} __attribute__((packed));
+
+
+#ifdef CONFIG_FRAME_POINTER
+static struct frame_tail* kernel_backtrace(struct frame_tail *tail)
+{
+       oprofile_add_trace(tail->lr);
+
+       /* frame pointers should strictly progress back up the stack
+        * (towards higher addresses) */
+       if (tail >= tail->fp)
+               return NULL;
+
+       return tail->fp-1;
+}
+#endif
+
+static struct frame_tail* user_backtrace(struct frame_tail *tail)
+{
+       struct frame_tail buftail;
+
+       /* hardware pte might not be valid due to dirty/accessed bit emulation
+        * so we use copy_from_user and benefit from exception fixups */
+       if (copy_from_user(&buftail, tail, sizeof(struct frame_tail)))
+               return NULL;
+
+       oprofile_add_trace(buftail.lr);
+
+       /* frame pointers should strictly progress back up the stack
+        * (towards higher addresses) */
+       if (tail >= buftail.fp)
+               return NULL;
+
+       return buftail.fp-1;
+}
+
+/* Compare two addresses and see if they're on the same page */
+#define CMP_ADDR_EQUAL(x,y,offset) ((((unsigned long) x) >> PAGE_SHIFT) \
+       == ((((unsigned long) y) + offset) >> PAGE_SHIFT))
+
+/* check that the page(s) containing the frame tail are present */
+static int pages_present(struct frame_tail *tail)
+{
+       struct mm_struct * mm = current->mm;
+
+       if (!check_user_page_readable(mm, (unsigned long)tail))
+               return 0;
+
+       if (CMP_ADDR_EQUAL(tail, tail, 8))
+               return 1;
+
+       if (!check_user_page_readable(mm, ((unsigned long)tail) + 8))
+               return 0;
+
+       return 1;
+}
+
+/*
+ * |             | /\ Higher addresses
+ * |             |
+ * --------------- stack base (address of current_thread_info)
+ * | thread info |
+ * .             .
+ * |    stack    |
+ * --------------- saved regs->ARM_fp value if valid (frame_tail address)
+ * .             .
+ * --------------- struct pt_regs stored on stack (struct pt_regs *)
+ * |             |
+ * .             .
+ * |             |
+ * --------------- %esp
+ * |             |
+ * |             | \/ Lower addresses
+ *
+ * Thus, &pt_regs <-> stack base restricts the valid(ish) fp values
+ */
+static int valid_kernel_stack(struct frame_tail *tail, struct pt_regs *regs)
+{
+       unsigned long tailaddr = (unsigned long)tail;
+       unsigned long stack = (unsigned long)regs;
+       unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
+
+       return (tailaddr > stack) && (tailaddr < stack_base);
+}
+
+void arm_backtrace(struct pt_regs const *regs, unsigned int depth)
+{
+       struct frame_tail *tail;
+       unsigned long last_address = 0;
+
+       tail = ((struct frame_tail *) regs->ARM_fp) - 1;
+
+       if (!user_mode(regs)) {
+
+#ifdef CONFIG_FRAME_POINTER
+               while (depth-- && tail && valid_kernel_stack(tail, regs)) {
+                       tail = kernel_backtrace(tail);
+               }
+#endif
+               return;
+       }
+
+       while (depth-- && tail && !((unsigned long) tail & 3)) {
+               if ((!CMP_ADDR_EQUAL(last_address, tail, 0)
+                       || !CMP_ADDR_EQUAL(last_address, tail, 8))
+                               && !pages_present(tail))
+                       return;
+               last_address = (unsigned long) tail;
+               tail = user_backtrace(tail);
+       }
+}
+
index cce3d3015eb7999d79143d72eaa061ff98337e29..d315a3a86c8635aebe60c2508dab60e44394e63b 100644 (file)
@@ -20,6 +20,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
        ret = pmu_init(ops, &op_xscale_spec);
 #endif
 
+       ops->backtrace = arm_backtrace;
+
        return ret;
 }
 
index 2d4caf4781ad466d0f539878bc1462ecb730630d..2148d07484b7b5999b7f5402bef5aa1a5d9e24c4 100644 (file)
@@ -24,6 +24,8 @@ struct op_arm_model_spec {
 extern struct op_arm_model_spec op_xscale_spec;
 #endif
 
+extern void arm_backtrace(struct pt_regs * const regs, unsigned int depth);
+
 extern int __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec);
 extern void pmu_exit(void);
 #endif /* OP_ARM_MODEL_H */
index 30c1dfbb052fc3413a8f7e7877f2f465db286c07..6d3a79e5fef8470a782d794c909fa20b21b8f27f 100644 (file)
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Thu Mar 24 14:34:50 2005
+# Last update: Thu Jun 23 20:19:33 2005
 #
 # machine_is_xxx       CONFIG_xxxx             MACH_TYPE_xxx           number
 #
@@ -243,7 +243,7 @@ yoho                        ARCH_YOHO               YOHO                    231
 jasper                 ARCH_JASPER             JASPER                  232
 dsc25                  ARCH_DSC25              DSC25                   233
 omap_innovator         MACH_OMAP_INNOVATOR     OMAP_INNOVATOR          234
-ramses                 ARCH_RAMSES             RAMSES                  235
+mnci                   ARCH_RAMSES             RAMSES                  235
 s28x                   ARCH_S28X               S28X                    236
 mport3                 ARCH_MPORT3             MPORT3                  237
 pxa_eagle250           ARCH_PXA_EAGLE250       PXA_EAGLE250            238
@@ -323,7 +323,7 @@ nimbra29x           ARCH_NIMBRA29X          NIMBRA29X               311
 nimbra210              ARCH_NIMBRA210          NIMBRA210               312
 hhp_d95xx              ARCH_HHP_D95XX          HHP_D95XX               313
 labarm                 ARCH_LABARM             LABARM                  314
-m825xx                 ARCH_M825XX             M825XX                  315
+comcerto               ARCH_M825XX             M825XX                  315
 m7100                  SA1100_M7100            M7100                   316
 nipc2                  ARCH_NIPC2              NIPC2                   317
 fu7202                 ARCH_FU7202             FU7202                  318
@@ -724,3 +724,66 @@ lpc22xx                    MACH_LPC22XX            LPC22XX                 715
 omap_comet3            MACH_COMET3             COMET3                  716
 omap_comet4            MACH_COMET4             COMET4                  717
 csb625                 MACH_CSB625             CSB625                  718
+fortunet2              MACH_FORTUNET2          FORTUNET2               719
+s5h2200                        MACH_S5H2200            S5H2200                 720
+optorm920              MACH_OPTORM920          OPTORM920               721
+adsbitsyxb             MACH_ADSBITSYXB         ADSBITSYXB              722
+adssphere              MACH_ADSSPHERE          ADSSPHERE               723
+adsportal              MACH_ADSPORTAL          ADSPORTAL               724
+ln2410sbc              MACH_LN2410SBC          LN2410SBC               725
+cb3rufc                        MACH_CB3RUFC            CB3RUFC                 726
+mp2usb                 MACH_MP2USB             MP2USB                  727
+ntnp425c               MACH_NTNP425C           NTNP425C                728
+colibri                        MACH_COLIBRI            COLIBRI                 729
+pcm7220                        MACH_PCM7220            PCM7220                 730
+gateway7001            MACH_GATEWAY7001        GATEWAY7001             731
+pcm027                 MACH_PCM027             PCM027                  732
+cmpxa                  MACH_CMPXA              CMPXA                   733
+anubis                 MACH_ANUBIS             ANUBIS                  734
+ite8152                        MACH_ITE8152            ITE8152                 735
+lpc3xxx                        MACH_LPC3XXX            LPC3XXX                 736
+puppeteer              MACH_PUPPETEER          PUPPETEER               737
+vt001                  MACH_MACH_VADATECH      MACH_VADATECH           738
+e570                   MACH_E570               E570                    739
+x50                    MACH_X50                X50                     740
+recon                  MACH_RECON              RECON                   741
+xboardgp8              MACH_XBOARDGP8          XBOARDGP8               742
+fpic2                  MACH_FPIC2              FPIC2                   743
+akita                  MACH_AKITA              AKITA                   744
+a81                    MACH_A81                A81                     745
+svm_sc25x              MACH_SVM_SC25X          SVM_SC25X               746
+vt020                  MACH_VADATECH020        VADATECH020             747
+tli                    MACH_TLI                TLI                     748
+edb9315lc              MACH_EDB9315LC          EDB9315LC               749
+passec                 MACH_PASSEC             PASSEC                  750
+ds_tiger               MACH_DS_TIGER           DS_TIGER                751
+e310                   MACH_E310               E310                    752
+e330                   MACH_E330               E330                    753
+rt3000                 MACH_RT3000             RT3000                  754
+nokia770               MACH_NOKIA770           NOKIA770                755
+pnx0106                        MACH_PNX0106            PNX0106                 756
+hx21xx                 MACH_HX21XX             HX21XX                  757
+faraday                        MACH_FARADAY            FARADAY                 758
+sbc9312                        MACH_SBC9312            SBC9312                 759
+batman                 MACH_BATMAN             BATMAN                  760
+jpd201                 MACH_JPD201             JPD201                  761
+mipsa                  MACH_MIPSA              MIPSA                   762
+kacom                  MACH_KACOM              KACOM                   763
+swarcocpu              MACH_SWARCOCPU          SWARCOCPU               764
+swarcodsl              MACH_SWARCODSL          SWARCODSL               765
+blueangel              MACH_BLUEANGEL          BLUEANGEL               766
+hairygrama             MACH_HAIRYGRAMA         HAIRYGRAMA              767
+banff                  MACH_BANFF              BANFF                   768
+carmeva                        MACH_CARMEVA            CARMEVA                 769
+sam255                 MACH_SAM255             SAM255                  770
+ppm10                  MACH_PPM10              PPM10                   771
+edb9315a               MACH_EDB9315A           EDB9315A                772
+sunset                 MACH_SUNSET             SUNSET                  773
+stargate2              MACH_STARGATE2          STARGATE2               774
+intelmote2             MACH_INTELMOTE2         INTELMOTE2              775
+trizeps4               MACH_TRIZEPS4           TRIZEPS4                776
+mainstone2             MACH_MAINSTONE2         MAINSTONE2              777
+ez_ixp42x              MACH_EZ_IXP42X          EZ_IXP42X               778
+tapwave_zodiac         MACH_TAPWAVE_ZODIAC     TAPWAVE_ZODIAC          779
+universalmeter         MACH_UNIVERSALMETER     UNIVERSALMETER          780
+hicoarm9               MACH_HICOARM9           HICOARM9                781
index 55a02bc994a320a25a9dce034d9ebc060d75e36e..4b97950984e9628c895bb83dda4a99ba8300bee9 100644 (file)
@@ -117,7 +117,13 @@ static inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m)
        if (nh >= m)
                return ~0ULL;
        mh = m >> 32;
-       z = (mh << 32 <= nh) ? 0xffffffff00000000ULL : (nh / mh) << 32;
+       if (mh << 32 <= nh) {
+               z = 0xffffffff00000000ULL;
+       } else {
+               z = nh;
+               do_div(z, mh);
+               z <<= 32;
+       }
        mul64to128(&termh, &terml, m, z);
        sub128(&remh, &reml, nh, nl, termh, terml);
        ml = m << 32;
@@ -126,7 +132,12 @@ static inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m)
                add128(&remh, &reml, remh, reml, mh, ml);
        }
        remh = (remh << 32) | (reml >> 32);
-       z |= (mh << 32 <= remh) ? 0xffffffff : remh / mh;
+       if (mh << 32 <= remh) {
+               z |= 0xffffffff;
+       } else {
+               do_div(remh, mh);
+               z |= remh;
+       }
        return z;
 }
 
index fa3053e84db56996701bad20b6f757c10f0ae9bb..b801cd66b6eadaed73befcd8da0363871340a90c 100644 (file)
@@ -32,6 +32,8 @@
  */
 #include <linux/kernel.h>
 #include <linux/bitops.h>
+
+#include <asm/div64.h>
 #include <asm/ptrace.h>
 #include <asm/vfp.h>
 
index 3aeedd2afc70fc3ac23e3832bcf9d513f2ace7e3..22f3da4e0829b3d80b94ed3bd3a0225e19fa3590 100644 (file)
@@ -89,7 +89,7 @@ void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs)
        current->thread.error_code = 0;
        current->thread.trap_no = 6;
 
-       force_sig_info(SIGFPE, &info, current);
+       send_sig_info(SIGFPE, &info, current);
 }
 
 static void vfp_panic(char *reason)
index 6849fe35cb2e7d59d3310d0c95807e3bdd28db08..14dd696ddeb1e98177cbc3b9a9883d3218ca592f 100644 (file)
@@ -32,6 +32,8 @@
  */
 #include <linux/kernel.h>
 #include <linux/bitops.h>
+
+#include <asm/div64.h>
 #include <asm/ptrace.h>
 #include <asm/vfp.h>
 
@@ -303,7 +305,11 @@ u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
                if (z <= a)
                        return (s32)a >> 1;
        }
-       return (u32)(((u64)a << 31) / z) + (z >> 1);
+       {
+               u64 v = (u64)a << 31;
+               do_div(v, z);
+               return v + (z >> 1);
+       }
 }
 
 static u32 vfp_single_fsqrt(int sd, int unused, s32 m, u32 fpscr)
@@ -1107,7 +1113,11 @@ static u32 vfp_single_fdiv(int sd, int sn, s32 m, u32 fpscr)
                vsn.significand >>= 1;
                vsd.exponent++;
        }
-       vsd.significand = ((u64)vsn.significand << 32) / vsm.significand;
+       {
+               u64 significand = (u64)vsn.significand << 32;
+               do_div(significand, vsm.significand);
+               vsd.significand = significand;
+       }
        if ((vsd.significand & 0x3f) == 0)
                vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32);
 
index ef6865f0b9792a1ac199127f73aba068d426b410..767ebb55bd83d7e763b38d719aee47728f037052 100644 (file)
@@ -790,12 +790,10 @@ void __init setup_arch(char **cmdline_p)
 #ifndef CONFIG_GDBSTUB_UART0
        __reg(UART0_BASE + UART_IER * 8) = 0;
        early_serial_setup(&__frv_uart0);
-//     register_serial(&__frv_uart0);
 #endif
 #ifndef CONFIG_GDBSTUB_UART1
        __reg(UART1_BASE + UART_IER * 8) = 0;
        early_serial_setup(&__frv_uart1);
-//     register_serial(&__frv_uart1);
 #endif
 
 #if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
index d8d8f3d4304d9c11387b09d892c032049e7f9f4f..36a2dffc8ebd953618a70a4f365b23ce3349ea3f 100644 (file)
@@ -536,10 +536,8 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
        if (!user_mode(regs))
                return 1;
 
-       if (current->flags & PF_FREEZE) {
-               refrigerator(0);
+       if (try_to_freeze())
                goto no_signal;
-       }
 
        if (!oldset)
                oldset = &current->blocked;
index a4799d633ef40e74a820bfef240a3e97be65c177..5aab87eae1f941f8373d8ea1db5882ced9b447d0 100644 (file)
@@ -517,10 +517,8 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset)
        if ((regs->ccr & 0x10))
                return 1;
 
-       if (current->flags & PF_FREEZE) {
-               refrigerator(0);
+       if (try_to_freeze())
                goto no_signal;
-       }
 
        current->thread.esp0 = (unsigned long) regs;
 
index d4ae5f9ceae6bb0a9375c53259d77fdaa70e16a4..6c02336fe2e4489b89a74632404cf8f5aec07b71 100644 (file)
@@ -510,28 +510,7 @@ config SCHED_SMT
          cost of slightly increased overhead in some places. If unsure say
          N here.
 
-config PREEMPT
-       bool "Preemptible Kernel"
-       help
-         This option reduces the latency of the kernel when reacting to
-         real-time or interactive events by allowing a low priority process to
-         be preempted even if it is in kernel mode executing a system call.
-         This allows applications to run more reliably even when the system is
-         under load.
-
-         Say Y here if you are building a kernel for a desktop, embedded
-         or real-time system.  Say N if you are unsure.
-
-config PREEMPT_BKL
-       bool "Preempt The Big Kernel Lock"
-       depends on PREEMPT
-       default y
-       help
-         This option reduces the latency of the kernel by making the
-         big kernel lock preemptible.
-
-         Say Y here if you are building a kernel for a desktop system.
-         Say N if you are unsure.
+source "kernel/Kconfig.preempt"
 
 config X86_UP_APIC
        bool "Local APIC support on uniprocessors"
@@ -963,6 +942,41 @@ config SECCOMP
 
 source kernel/Kconfig.hz
 
+config PHYSICAL_START
+       hex "Physical address where the kernel is loaded" if EMBEDDED
+       default "0x100000"
+       help
+         This gives the physical address where the kernel is loaded.
+         Primarily used in the case of kexec on panic where the
+         fail safe kernel needs to run at a different address than
+         the panic-ed kernel.
+
+         Don't change this unless you know what you are doing.
+
+config KEXEC
+       bool "kexec system call (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       help
+         kexec is a system call that implements the ability to shutdown your
+         current kernel, and to start another kernel.  It is like a reboot
+         but it is indepedent of the system firmware.   And like a reboot
+         you can start any kernel with it, not just Linux.
+
+         The name comes from the similiarity to the exec system call.
+
+         It is an ongoing process to be certain the hardware in a machine
+         is properly shutdown, so do not be surprised if this code does not
+         initially work for you.  It may help to enable device hotplugging
+         support.  As of this writing the exact hardware interface is
+         strongly in flux, so no good recommendation can be made.
+
+config CRASH_DUMP
+       bool "kernel crash dumps (EXPERIMENTAL)"
+       depends on EMBEDDED
+       depends on EXPERIMENTAL
+       depends on HIGHMEM
+       help
+         Generate crash dump after being started by kexec.
 endmenu
 
 
@@ -1250,6 +1264,15 @@ config SCx200
          This support is also available as a module.  If compiled as a
          module, it will be called scx200.
 
+config HOTPLUG_CPU
+       bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
+       depends on SMP && HOTPLUG && EXPERIMENTAL
+       ---help---
+         Say Y here to experiment with turning CPUs off and on.  CPUs
+         can be controlled through /sys/devices/system/cpu.
+
+         Say N.
+
 source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
index 43cd6220ee4905c2375cfb1cece6767c0d8fa28f..1e71382d413a99b40f3a1e759ee0254acff94539 100644 (file)
@@ -25,8 +25,8 @@ SVGA_MODE := -DSVGA_MODE=NORMAL_VGA
 
 #RAMDISK := -DRAMDISK=512
 
-targets                := vmlinux.bin bootsect bootsect.o setup setup.o \
-                  zImage bzImage
+targets                := vmlinux.bin bootsect bootsect.o \
+                  setup setup.o zImage bzImage
 subdir-        := compressed
 
 hostprogs-y    := tools/build
index c5e80b69e7d41d8ae580ae734553d2b9584b9760..b5893e4ecd376b54a3044c09e035ff82bf5e923c 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/linkage.h>
 #include <asm/segment.h>
+#include <asm/page.h>
 
        .globl startup_32
        
@@ -74,7 +75,7 @@ startup_32:
        popl %esi       # discard address
        popl %esi       # real mode pointer
        xorl %ebx,%ebx
-       ljmp $(__BOOT_CS), $0x100000
+       ljmp $(__BOOT_CS), $__PHYSICAL_START
 
 /*
  * We come here, if we were loaded high.
@@ -99,7 +100,7 @@ startup_32:
        popl %ecx       # lcount
        popl %edx       # high_buffer_start
        popl %eax       # hcount
-       movl $0x100000,%edi
+       movl $__PHYSICAL_START,%edi
        cli             # make sure we don't get interrupted
        ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine
 
@@ -124,5 +125,5 @@ move_routine_start:
        movsl
        movl %ebx,%esi  # Restore setup pointer
        xorl %ebx,%ebx
-       ljmp $(__BOOT_CS), $0x100000
+       ljmp $(__BOOT_CS), $__PHYSICAL_START
 move_routine_end:
index cedc55cc47de0756df6e77afc0e94fedba2439f5..82a807f9f5e64d8e9230705941e55186d5537ab7 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/vmalloc.h>
 #include <linux/tty.h>
 #include <asm/io.h>
+#include <asm/page.h>
 
 /*
  * gzip declarations
@@ -308,7 +309,7 @@ static void setup_normal_output_buffer(void)
 #else
        if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory");
 #endif
-       output_data = (char *)0x100000; /* Points to 1M */
+       output_data = (char *)__PHYSICAL_START; /* Normally Points to 1M */
        free_mem_end_ptr = (long)real_mode;
 }
 
@@ -333,8 +334,8 @@ static void setup_output_buffer_if_we_run_high(struct moveparams *mv)
        low_buffer_size = low_buffer_end - LOW_BUFFER_START;
        high_loaded = 1;
        free_mem_end_ptr = (long)high_buffer_start;
-       if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) {
-               high_buffer_start = (uch *)(0x100000 + low_buffer_size);
+       if ( (__PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) {
+               high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size);
                mv->hcount = 0; /* say: we need not to move high_buffer */
        }
        else mv->hcount = -1;
@@ -353,7 +354,6 @@ static void close_output_buffer_if_we_run_high(struct moveparams *mv)
        }
 }
 
-
 asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode)
 {
        real_mode = rmode;
index 027d6b354ffbee7a1e5cde1a0d43f471cf5b2d64..d8d69f2b911d62c909b651de0d9e61a7c7b3b461 100644 (file)
@@ -6,7 +6,7 @@
  *   projects 1572D, 1484D, 1386D, 1226DT
  * disk signature read by Matt Domsch <Matt_Domsch@dell.com>
  *     and Andrew Wilks <Andrew_Wilks@dell.com> September 2003, June 2004
- * legacy CHS retreival by Patrick J. LoPresti <patl@users.sourceforge.net>
+ * legacy CHS retrieval by Patrick J. LoPresti <patl@users.sourceforge.net>
  *      March 2004
  * Command line option parsing, Matt Domsch, November 2004
  */
index caa1fde6904edc89eccdf49e693d8576aa9feecc..8cb420f40c58f106972d5ec830e8cd382378470c 100644 (file)
@@ -33,7 +33,7 @@
  * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
  * <stiker@northlink.com>
  *
- * Fix to work around buggy BIOSes which dont use carry bit correctly
+ * Fix to work around buggy BIOSes which don't use carry bit correctly
  * and/or report extended memory in CX/DX for e801h memory size detection 
  * call.  As a result the kernel got wrong figures.  The int15/e801h docs
  * from Ralf Brown interrupt list seem to indicate AX/BX should be used
@@ -357,7 +357,7 @@ bail820:
 
 meme801:
        stc                                     # fix to work around buggy
-       xorw    %cx,%cx                         # BIOSes which dont clear/set
+       xorw    %cx,%cx                         # BIOSes which don't clear/set
        xorw    %dx,%dx                         # carry on pass/error of
                                                # e801h memory size call
                                                # or merely pass cx,dx though
@@ -847,7 +847,7 @@ flush_instr:
 #
 #      but we yet haven't reloaded the CS register, so the default size 
 #      of the target offset still is 16 bit.
-#       However, using an operand prefix (0x66), the CPU will properly
+#      However, using an operand prefix (0x66), the CPU will properly
 #      take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
 #      Manual, Mixing 16-bit and 32-bit code, page 16-6)
 
index 26509b826aeda0468ca6bc26897e13c650952a7b..6835f6d47c31e8f5913a670c6bd7bdd57f1e7b7c 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  $Id: build.c,v 1.5 1997/05/19 12:29:58 mj Exp $
- *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1997 Martin Mares
  */
@@ -8,7 +6,8 @@
 /*
  * This file builds a disk-image from three different files:
  *
- * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
+ * - bootsect: compatibility mbr which prints an error message if
+ *             someone tries to boot the kernel directly.
  * - setup: 8086 machine code, sets up system parm
  * - system: 80386 code for actual system
  *
@@ -71,7 +70,8 @@ void usage(void)
 
 int main(int argc, char ** argv)
 {
-       unsigned int i, c, sz, setup_sectors;
+       unsigned int i, sz, setup_sectors;
+       int c;
        u32 sys_size;
        byte major_root, minor_root;
        struct stat sb;
index 1019430fc1f11015128f2f22fdf44f7d24330ab3..88ee85c3b43be94868e0229286a6db51cc9229cf 100644 (file)
@@ -59,7 +59,7 @@ struct aes_ctx {
 };
 
 #define WPOLY 0x011b
-#define u32_in(x) le32_to_cpu(*(const u32 *)(x))
+#define u32_in(x) le32_to_cpup((const __le32 *)(x))
 #define bytes2word(b0, b1, b2, b3)  \
        (((u32)(b3) << 24) | ((u32)(b2) << 16) | ((u32)(b1) << 8) | (b0))
 
index 28e620383799a1a05ecf82fb11bd9bf275ff19f6..ca07b95c06b82e6eeffd79fd3649b4c3ca22b8b5 100644 (file)
@@ -126,7 +126,6 @@ CONFIG_HAVE_DEC_LOCK=y
 #
 CONFIG_PM=y
 CONFIG_SOFTWARE_SUSPEND=y
-# CONFIG_PM_DISK is not set
 
 #
 # ACPI (Advanced Configuration and Power Interface) Support
index 51ecd512603da25153cbf194dcda57d724a8edd8..4cc83b322b362dc85739cc42e8df6b955bc7da7e 100644 (file)
@@ -24,6 +24,7 @@ obj-$(CONFIG_X86_MPPARSE)     += mpparse.o
 obj-$(CONFIG_X86_LOCAL_APIC)   += apic.o nmi.o
 obj-$(CONFIG_X86_IO_APIC)      += io_apic.o
 obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o
+obj-$(CONFIG_KEXEC)            += machine_kexec.o relocate_kernel.o crash.o
 obj-$(CONFIG_X86_NUMAQ)                += numaq.o
 obj-$(CONFIG_X86_SUMMIT_NUMA)  += summit.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
index 848bb97af7ca316755f6e47e612ecc75717fb197..b7808a89d94507fd41abf6c24bd471d5d9099209 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/efi.h>
 #include <linux/irq.h>
 #include <linux/module.h>
+#include <linux/dmi.h>
 
 #include <asm/pgtable.h>
 #include <asm/io_apic.h>
@@ -158,9 +159,15 @@ char *__acpi_map_table(unsigned long phys, unsigned long size)
 #endif
 
 #ifdef CONFIG_PCI_MMCONFIG
-static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
+/* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
+struct acpi_table_mcfg_config *pci_mmcfg_config;
+int pci_mmcfg_config_num;
+
+int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
 {
        struct acpi_table_mcfg *mcfg;
+       unsigned long i;
+       int config_size;
 
        if (!phys_addr || !size)
                return -EINVAL;
@@ -171,18 +178,38 @@ static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
                return -ENODEV;
        }
 
-       if (mcfg->base_reserved) {
-               printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n");
+       /* how many config structures do we have */
+       pci_mmcfg_config_num = 0;
+       i = size - sizeof(struct acpi_table_mcfg);
+       while (i >= sizeof(struct acpi_table_mcfg_config)) {
+               ++pci_mmcfg_config_num;
+               i -= sizeof(struct acpi_table_mcfg_config);
+       };
+       if (pci_mmcfg_config_num == 0) {
+               printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
                return -ENODEV;
        }
 
-       pci_mmcfg_base_addr = mcfg->base_address;
+       config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config);
+       pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL);
+       if (!pci_mmcfg_config) {
+               printk(KERN_WARNING PREFIX
+                      "No memory for MCFG config tables\n");
+               return -ENOMEM;
+       }
+
+       memcpy(pci_mmcfg_config, &mcfg->config, config_size);
+       for (i = 0; i < pci_mmcfg_config_num; ++i) {
+               if (mcfg->config[i].base_reserved) {
+                       printk(KERN_ERR PREFIX
+                              "MMCONFIG not in low 4GB of memory\n");
+                       return -ENODEV;
+               }
+       }
 
        return 0;
 }
-#else
-#define        acpi_parse_mcfg NULL
-#endif /* !CONFIG_PCI_MMCONFIG */
+#endif /* CONFIG_PCI_MMCONFIG */
 
 #ifdef CONFIG_X86_LOCAL_APIC
 static int __init
@@ -506,6 +533,22 @@ acpi_unmap_lsapic(int cpu)
 EXPORT_SYMBOL(acpi_unmap_lsapic);
 #endif /* CONFIG_ACPI_HOTPLUG_CPU */
 
+int
+acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
+{
+       /* TBD */
+       return -EINVAL;
+}
+EXPORT_SYMBOL(acpi_register_ioapic);
+
+int
+acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
+{
+       /* TBD */
+       return -EINVAL;
+}
+EXPORT_SYMBOL(acpi_unregister_ioapic);
+
 static unsigned long __init
 acpi_scan_rsdp (
        unsigned long           start,
@@ -815,6 +858,219 @@ acpi_process_madt(void)
        return;
 }
 
+extern int acpi_force;
+
+#ifdef __i386__
+
+#ifdef CONFIG_ACPI_PCI
+static int __init disable_acpi_irq(struct dmi_system_id *d)
+{
+       if (!acpi_force) {
+               printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n",
+                      d->ident);
+               acpi_noirq_set();
+       }
+       return 0;
+}
+
+static int __init disable_acpi_pci(struct dmi_system_id *d)
+{
+       if (!acpi_force) {
+               printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n",
+                      d->ident);
+               acpi_disable_pci();
+       }
+       return 0;
+}
+#endif
+
+static int __init dmi_disable_acpi(struct dmi_system_id *d)
+{
+       if (!acpi_force) {
+               printk(KERN_NOTICE "%s detected: acpi off\n",d->ident);
+               disable_acpi();
+       } else {
+               printk(KERN_NOTICE
+                      "Warning: DMI blacklist says broken, but acpi forced\n");
+       }
+       return 0;
+}
+
+/*
+ * Limit ACPI to CPU enumeration for HT
+ */
+static int __init force_acpi_ht(struct dmi_system_id *d)
+{
+       if (!acpi_force) {
+               printk(KERN_NOTICE "%s detected: force use of acpi=ht\n", d->ident);
+               disable_acpi();
+               acpi_ht = 1;
+       } else {
+               printk(KERN_NOTICE
+                      "Warning: acpi=force overrules DMI blacklist: acpi=ht\n");
+       }
+       return 0;
+}
+
+/*
+ * If your system is blacklisted here, but you find that acpi=force
+ * works for you, please contact acpi-devel@sourceforge.net
+ */
+static struct dmi_system_id __initdata acpi_dmi_table[] = {
+       /*
+        * Boxes that need ACPI disabled
+        */
+       {
+               .callback = dmi_disable_acpi,
+               .ident = "IBM Thinkpad",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
+                       DMI_MATCH(DMI_BOARD_NAME, "2629H1G"),
+               },
+       },
+
+       /*
+        * Boxes that need acpi=ht
+        */
+       {
+               .callback = force_acpi_ht,
+               .ident = "FSC Primergy T850",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"),
+               },
+       },
+       {
+               .callback = force_acpi_ht,
+               .ident = "DELL GX240",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Dell Computer Corporation"),
+                       DMI_MATCH(DMI_BOARD_NAME, "OptiPlex GX240"),
+               },
+       },
+       {
+               .callback = force_acpi_ht,
+               .ident = "HP VISUALIZE NT Workstation",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "HP VISUALIZE NT Workstation"),
+               },
+       },
+       {
+               .callback = force_acpi_ht,
+               .ident = "Compaq Workstation W8000",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Workstation W8000"),
+               },
+       },
+       {
+               .callback = force_acpi_ht,
+               .ident = "ASUS P4B266",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "P4B266"),
+               },
+       },
+       {
+               .callback = force_acpi_ht,
+               .ident = "ASUS P2B-DS",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "P2B-DS"),
+               },
+       },
+       {
+               .callback = force_acpi_ht,
+               .ident = "ASUS CUR-DLS",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "CUR-DLS"),
+               },
+       },
+       {
+               .callback = force_acpi_ht,
+               .ident = "ABIT i440BX-W83977",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ABIT <http://www.abit.com>"),
+                       DMI_MATCH(DMI_BOARD_NAME, "i440BX-W83977 (BP6)"),
+               },
+       },
+       {
+               .callback = force_acpi_ht,
+               .ident = "IBM Bladecenter",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
+                       DMI_MATCH(DMI_BOARD_NAME, "IBM eServer BladeCenter HS20"),
+               },
+       },
+       {
+               .callback = force_acpi_ht,
+               .ident = "IBM eServer xSeries 360",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
+                       DMI_MATCH(DMI_BOARD_NAME, "eServer xSeries 360"),
+               },
+       },
+       {
+               .callback = force_acpi_ht,
+               .ident = "IBM eserver xSeries 330",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
+                       DMI_MATCH(DMI_BOARD_NAME, "eserver xSeries 330"),
+               },
+       },
+       {
+               .callback = force_acpi_ht,
+               .ident = "IBM eserver xSeries 440",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "eserver xSeries 440"),
+               },
+       },
+
+#ifdef CONFIG_ACPI_PCI
+       /*
+        * Boxes that need ACPI PCI IRQ routing disabled
+        */
+       {
+               .callback = disable_acpi_irq,
+               .ident = "ASUS A7V",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"),
+                       DMI_MATCH(DMI_BOARD_NAME, "<A7V>"),
+                       /* newer BIOS, Revision 1011, does work */
+                       DMI_MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1007"),
+               },
+       },
+
+       /*
+        * Boxes that need ACPI PCI IRQ routing and PCI scan disabled
+        */
+       {       /* _BBN 0 bug */
+               .callback = disable_acpi_pci,
+               .ident = "ASUS PR-DLS",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "PR-DLS"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "ASUS PR-DLS ACPI BIOS Revision 1010"),
+                       DMI_MATCH(DMI_BIOS_DATE, "03/21/2003")
+               },
+       },
+       {
+               .callback = disable_acpi_pci,
+               .ident = "Acer TravelMate 36x Laptop",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
+               },
+       },
+#endif
+       { }
+};
+
+#endif /* __i386__ */
+
 /*
  * acpi_boot_table_init() and acpi_boot_init()
  *  called from setup_arch(), always.
@@ -843,6 +1099,10 @@ acpi_boot_table_init(void)
 {
        int error;
 
+#ifdef __i386__
+       dmi_check_system(acpi_dmi_table);
+#endif
+
        /*
         * If acpi_disabled, bail out
         * One exception: acpi=ht continues far enough to enumerate LAPICs
@@ -870,8 +1130,6 @@ acpi_boot_table_init(void)
         */
        error = acpi_blacklisted();
        if (error) {
-               extern int acpi_force;
-
                if (acpi_force) {
                        printk(KERN_WARNING PREFIX "acpi=force override\n");
                } else {
@@ -907,7 +1165,6 @@ int __init acpi_boot_init(void)
        acpi_process_madt();
 
        acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
-       acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
 
        return 0;
 }
index 28bb0514bb6e1ce0a038b5945f3f0f9673a4a038..c1af93032ff32bc02df16891819159e473efb78e 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/acpi.h>
 #include <linux/bootmem.h>
+#include <linux/dmi.h>
 #include <asm/smp.h>
 #include <asm/tlbflush.h>
 
@@ -91,3 +92,29 @@ static int __init acpi_sleep_setup(char *str)
 
 
 __setup("acpi_sleep=", acpi_sleep_setup);
+
+
+static __init int reset_videomode_after_s3(struct dmi_system_id *d)
+{
+       acpi_video_flags |= 2;
+       return 0;
+}
+
+static __initdata struct dmi_system_id acpisleep_dmi_table[] = {
+       {       /* Reset video mode after returning from ACPI S3 sleep */
+               .callback = reset_videomode_after_s3,
+               .ident = "Toshiba Satellite 4030cdt",
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
+               },
+       },
+       { }
+};
+
+static int __init acpisleep_dmi_init(void)
+{
+       dmi_check_system(acpisleep_dmi_table);
+       return 0;
+}
+
+core_initcall(acpisleep_dmi_init);
index 8d993fa71754a50a800ea5fd05749017be643a96..bd1dbf3bd223cfd51021b7eec43d89b206a8bb95 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/kernel_stat.h>
 #include <linux/sysdev.h>
+#include <linux/cpu.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
 #include <asm/desc.h>
 #include <asm/arch_hooks.h>
 #include <asm/hpet.h>
+#include <asm/i8253.h>
 
 #include <mach_apic.h>
 
 #include "io_ports.h"
 
+/*
+ * Knob to control our willingness to enable the local APIC.
+ */
+int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */
+
 /*
  * Debug level
  */
@@ -205,7 +212,7 @@ void __init connect_bsp_APIC(void)
        enable_apic_mode();
 }
 
-void disconnect_bsp_APIC(void)
+void disconnect_bsp_APIC(int virt_wire_setup)
 {
        if (pic_mode) {
                /*
@@ -219,6 +226,42 @@ void disconnect_bsp_APIC(void)
                outb(0x70, 0x22);
                outb(0x00, 0x23);
        }
+       else {
+               /* Go back to Virtual Wire compatibility mode */
+               unsigned long value;
+
+               /* For the spurious interrupt use vector F, and enable it */
+               value = apic_read(APIC_SPIV);
+               value &= ~APIC_VECTOR_MASK;
+               value |= APIC_SPIV_APIC_ENABLED;
+               value |= 0xf;
+               apic_write_around(APIC_SPIV, value);
+
+               if (!virt_wire_setup) {
+                       /* For LVT0 make it edge triggered, active high, external and enabled */
+                       value = apic_read(APIC_LVT0);
+                       value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
+                               APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
+                               APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED );
+                       value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
+                       value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);
+                       apic_write_around(APIC_LVT0, value);
+               }
+               else {
+                       /* Disable LVT0 */
+                       apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
+               }
+
+               /* For LVT1 make it edge triggered, active high, nmi and enabled */
+               value = apic_read(APIC_LVT1);
+               value &= ~(
+                       APIC_MODE_MASK | APIC_SEND_PENDING |
+                       APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
+                       APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
+               value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
+               value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
+               apic_write_around(APIC_LVT1, value);
+       }
 }
 
 void disable_local_APIC(void)
@@ -363,7 +406,7 @@ void __init init_bsp_APIC(void)
        apic_write_around(APIC_LVT1, value);
 }
 
-void __init setup_local_APIC (void)
+void __devinit setup_local_APIC(void)
 {
        unsigned long oldvalue, value, ver, maxlvt;
 
@@ -634,7 +677,7 @@ static struct sys_device device_lapic = {
        .cls    = &lapic_sysclass,
 };
 
-static void __init apic_pm_activate(void)
+static void __devinit apic_pm_activate(void)
 {
        apic_pm_state.active = 1;
 }
@@ -665,26 +708,6 @@ static void apic_pm_activate(void) { }
  * Original code written by Keir Fraser.
  */
 
-/*
- * Knob to control our willingness to enable the local APIC.
- */
-int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */
-
-static int __init lapic_disable(char *str)
-{
-       enable_local_apic = -1;
-       clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
-       return 0;
-}
-__setup("nolapic", lapic_disable);
-
-static int __init lapic_enable(char *str)
-{
-       enable_local_apic = 1;
-       return 0;
-}
-__setup("lapic", lapic_enable);
-
 static int __init apic_set_verbosity(char *str)
 {
        if (strcmp("debug", str) == 0)
@@ -855,9 +878,8 @@ fake_ioapic_page:
  * but we do not accept timer interrupts yet. We only allow the BP
  * to calibrate.
  */
-static unsigned int __init get_8254_timer_count(void)
+static unsigned int __devinit get_8254_timer_count(void)
 {
-       extern spinlock_t i8253_lock;
        unsigned long flags;
 
        unsigned int count;
@@ -874,7 +896,7 @@ static unsigned int __init get_8254_timer_count(void)
 }
 
 /* next tick in 8254 can be caught by catching timer wraparound */
-static void __init wait_8254_wraparound(void)
+static void __devinit wait_8254_wraparound(void)
 {
        unsigned int curr_count, prev_count;
 
@@ -894,7 +916,7 @@ static void __init wait_8254_wraparound(void)
  * Default initialization for 8254 timers. If we use other timers like HPET,
  * we override this later
  */
-void (*wait_timer_tick)(void) __initdata = wait_8254_wraparound;
+void (*wait_timer_tick)(void) __devinitdata = wait_8254_wraparound;
 
 /*
  * This function sets up the local APIC timer, with a timeout of
@@ -930,7 +952,7 @@ static void __setup_APIC_LVTT(unsigned int clocks)
        apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);
 }
 
-static void __init setup_APIC_timer(unsigned int clocks)
+static void __devinit setup_APIC_timer(unsigned int clocks)
 {
        unsigned long flags;
 
@@ -1043,12 +1065,12 @@ void __init setup_boot_APIC_clock(void)
        local_irq_enable();
 }
 
-void __init setup_secondary_APIC_clock(void)
+void __devinit setup_secondary_APIC_clock(void)
 {
        setup_APIC_timer(calibration_result);
 }
 
-void __init disable_APIC_timer(void)
+void __devinit disable_APIC_timer(void)
 {
        if (using_apic_timer) {
                unsigned long v;
index 0ff65abcd56c3c1139b4849a80228f555785c655..064211d5f41b62a9d4c593e94aaa2e37862434a6 100644 (file)
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/desc.h>
+#include <asm/i8253.h>
 
 #include "io_ports.h"
 
-extern spinlock_t i8253_lock;
 extern unsigned long get_cmos_time(void);
 extern void machine_real_restart(unsigned char *, int);
 
@@ -346,10 +346,10 @@ extern int (*console_blank_hook)(int);
 struct apm_user {
        int             magic;
        struct apm_user *       next;
-       int             suser: 1;
-       int             writer: 1;
-       int             reader: 1;
-       int             suspend_wait: 1;
+       unsigned int    suser: 1;
+       unsigned int    writer: 1;
+       unsigned int    reader: 1;
+       unsigned int    suspend_wait: 1;
        int             suspend_result;
        int             suspends_pending;
        int             standbys_pending;
@@ -1168,8 +1168,7 @@ static void get_time_diff(void)
 static void reinit_timer(void)
 {
 #ifdef INIT_TIMER_AFTER_SUSPEND
-       unsigned long   flags;
-       extern spinlock_t i8253_lock;
+       unsigned long flags;
 
        spin_lock_irqsave(&i8253_lock, flags);
        /* set the clock to 100 Hz */
index b9954248d0aaf13f8861a87c7b55e1ab9314e8a6..2203a9d2021251a59776109064d10d558b898574 100644 (file)
@@ -24,9 +24,9 @@ EXPORT_PER_CPU_SYMBOL(cpu_gdt_table);
 DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]);
 EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack);
 
-static int cachesize_override __initdata = -1;
-static int disable_x86_fxsr __initdata = 0;
-static int disable_x86_serial_nr __initdata = 1;
+static int cachesize_override __devinitdata = -1;
+static int disable_x86_fxsr __devinitdata = 0;
+static int disable_x86_serial_nr __devinitdata = 1;
 
 struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {};
 
@@ -59,7 +59,7 @@ static int __init cachesize_setup(char *str)
 }
 __setup("cachesize=", cachesize_setup);
 
-int __init get_model_name(struct cpuinfo_x86 *c)
+int __devinit get_model_name(struct cpuinfo_x86 *c)
 {
        unsigned int *v;
        char *p, *q;
@@ -89,7 +89,7 @@ int __init get_model_name(struct cpuinfo_x86 *c)
 }
 
 
-void __init display_cacheinfo(struct cpuinfo_x86 *c)
+void __devinit display_cacheinfo(struct cpuinfo_x86 *c)
 {
        unsigned int n, dummy, ecx, edx, l2size;
 
@@ -130,7 +130,7 @@ void __init display_cacheinfo(struct cpuinfo_x86 *c)
 /* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */
 
 /* Look up CPU names by table lookup. */
-static char __init *table_lookup_model(struct cpuinfo_x86 *c)
+static char __devinit *table_lookup_model(struct cpuinfo_x86 *c)
 {
        struct cpu_model_info *info;
 
@@ -151,7 +151,7 @@ static char __init *table_lookup_model(struct cpuinfo_x86 *c)
 }
 
 
-void __init get_cpu_vendor(struct cpuinfo_x86 *c, int early)
+void __devinit get_cpu_vendor(struct cpuinfo_x86 *c, int early)
 {
        char *v = c->x86_vendor_id;
        int i;
@@ -202,7 +202,7 @@ static inline int flag_is_changeable_p(u32 flag)
 
 
 /* Probe for the CPUID instruction */
-static int __init have_cpuid_p(void)
+static int __devinit have_cpuid_p(void)
 {
        return flag_is_changeable_p(X86_EFLAGS_ID);
 }
@@ -249,7 +249,7 @@ static void __init early_cpu_detect(void)
 #endif
 }
 
-void __init generic_identify(struct cpuinfo_x86 * c)
+void __devinit generic_identify(struct cpuinfo_x86 * c)
 {
        u32 tfms, xlvl;
        int junk;
@@ -296,7 +296,7 @@ void __init generic_identify(struct cpuinfo_x86 * c)
        }
 }
 
-static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
+static void __devinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
 {
        if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr ) {
                /* Disable processor serial number */
@@ -324,7 +324,7 @@ __setup("serialnumber", x86_serial_nr_setup);
 /*
  * This does the hard work of actually picking apart the CPU stuff...
  */
-void __init identify_cpu(struct cpuinfo_x86 *c)
+void __devinit identify_cpu(struct cpuinfo_x86 *c)
 {
        int i;
 
@@ -432,10 +432,13 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
 #ifdef CONFIG_X86_MCE
        mcheck_init(c);
 #endif
+       if (c == &boot_cpu_data)
+               sysenter_setup();
+       enable_sep_cpu();
 }
 
 #ifdef CONFIG_X86_HT
-void __init detect_ht(struct cpuinfo_x86 *c)
+void __devinit detect_ht(struct cpuinfo_x86 *c)
 {
        u32     eax, ebx, ecx, edx;
        int     index_msb, tmp;
@@ -490,7 +493,7 @@ void __init detect_ht(struct cpuinfo_x86 *c)
 }
 #endif
 
-void __init print_cpu_info(struct cpuinfo_x86 *c)
+void __devinit print_cpu_info(struct cpuinfo_x86 *c)
 {
        char *vendor = NULL;
 
@@ -513,7 +516,7 @@ void __init print_cpu_info(struct cpuinfo_x86 *c)
                printk("\n");
 }
 
-cpumask_t cpu_initialized __initdata = CPU_MASK_NONE;
+cpumask_t cpu_initialized __devinitdata = CPU_MASK_NONE;
 
 /* This is hacky. :)
  * We're emulating future behavior.
@@ -560,7 +563,7 @@ void __init early_cpu_init(void)
  * and IDT. We reload them nevertheless, this function acts as a
  * 'CPU state barrier', nothing should get across.
  */
-void __init cpu_init (void)
+void __devinit cpu_init(void)
 {
        int cpu = smp_processor_id();
        struct tss_struct * t = &per_cpu(init_tss, cpu);
@@ -648,3 +651,15 @@ void __init cpu_init (void)
        clear_used_math();
        mxcsr_feature_mask_init();
 }
+
+#ifdef CONFIG_HOTPLUG_CPU
+void __devinit cpu_uninit(void)
+{
+       int cpu = raw_smp_processor_id();
+       cpu_clear(cpu, cpu_initialized);
+
+       /* lazy TLB state */
+       per_cpu(cpu_tlbstate, cpu).state = 0;
+       per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
+}
+#endif
index 5c530064eb74bf963a8f43ea4265b96d6042ac65..73a5dc5b26b8403493d099b6b22073561855fa58 100644 (file)
@@ -648,9 +648,7 @@ static int powernow_cpu_exit (struct cpufreq_policy *policy) {
        }
 #endif
 
-       if (powernow_table)
-               kfree(powernow_table);
-
+       kfree(powernow_table);
        return 0;
 }
 
index 121aa2176e694a34f1fd06f23e1d903230b2207a..96a75d0458350c67a4dc1f57d4414a5ffe227790 100644 (file)
@@ -28,7 +28,7 @@ extern int trap_init_f00f_bug(void);
 struct movsl_mask movsl_mask;
 #endif
 
-void __init early_intel_workaround(struct cpuinfo_x86 *c)
+void __devinit early_intel_workaround(struct cpuinfo_x86 *c)
 {
        if (c->x86_vendor != X86_VENDOR_INTEL)
                return;
@@ -43,7 +43,7 @@ void __init early_intel_workaround(struct cpuinfo_x86 *c)
  *     This is called before we do cpu ident work
  */
  
-int __init ppro_with_ram_bug(void)
+int __devinit ppro_with_ram_bug(void)
 {
        /* Uses data from early_cpu_detect now */
        if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
@@ -61,7 +61,7 @@ int __init ppro_with_ram_bug(void)
  * P4 Xeon errata 037 workaround.
  * Hardware prefetcher may cause stale data to be loaded into the cache.
  */
-static void __init Intel_errata_workarounds(struct cpuinfo_x86 *c)
+static void __devinit Intel_errata_workarounds(struct cpuinfo_x86 *c)
 {
        unsigned long lo, hi;
 
@@ -80,7 +80,7 @@ static void __init Intel_errata_workarounds(struct cpuinfo_x86 *c)
 /*
  * find out the number of processor cores on the die
  */
-static int __init num_cpu_cores(struct cpuinfo_x86 *c)
+static int __devinit num_cpu_cores(struct cpuinfo_x86 *c)
 {
        unsigned int eax;
 
@@ -98,7 +98,7 @@ static int __init num_cpu_cores(struct cpuinfo_x86 *c)
                return 1;
 }
 
-static void __init init_intel(struct cpuinfo_x86 *c)
+static void __devinit init_intel(struct cpuinfo_x86 *c)
 {
        unsigned int l2 = 0;
        char *p = NULL;
@@ -204,7 +204,7 @@ static unsigned int intel_size_cache(struct cpuinfo_x86 * c, unsigned int size)
        return size;
 }
 
-static struct cpu_dev intel_cpu_dev __initdata = {
+static struct cpu_dev intel_cpu_dev __devinitdata = {
        .c_vendor       = "Intel",
        .c_ident        = { "GenuineIntel" },
        .c_models = {
index a710dc4eb20e33354cc446f6a74549f0e6a6e895..1d768b263269b0d8b728e57f9675ea1950efb8c6 100644 (file)
@@ -28,7 +28,7 @@ struct _cache_table
 };
 
 /* all the cache descriptor types we care about (no TLB or trace cache entries) */
-static struct _cache_table cache_table[] __initdata =
+static struct _cache_table cache_table[] __devinitdata =
 {
        { 0x06, LVL_1_INST, 8 },        /* 4-way set assoc, 32 byte line size */
        { 0x08, LVL_1_INST, 16 },       /* 4-way set assoc, 32 byte line size */
@@ -160,7 +160,7 @@ static int __init find_num_cache_leaves(void)
        return retval;
 }
 
-unsigned int __init init_intel_cacheinfo(struct cpuinfo_x86 *c)
+unsigned int __devinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
 {
        unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
        unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */
index 8df52e86c4d2918bc3b109ff9e4dbf34df6276ef..c4abe76573978fff801b487ebee33f050fd1cb79 100644 (file)
@@ -69,7 +69,7 @@ static fastcall void k7_machine_check(struct pt_regs * regs, long error_code)
 
 
 /* AMD K7 machine check is Intel like */
-void __init amd_mcheck_init(struct cpuinfo_x86 *c)
+void __devinit amd_mcheck_init(struct cpuinfo_x86 *c)
 {
        u32 l, h;
        int i;
index bf6d1aefafc0275f195d980aed1dd659d0cd09dc..2cf25d2ba0f11ee1b4120841e30f5cd9cabe5b98 100644 (file)
@@ -16,7 +16,7 @@
 
 #include "mce.h"
 
-int mce_disabled __initdata = 0;
+int mce_disabled __devinitdata = 0;
 int nr_mce_banks;
 
 EXPORT_SYMBOL_GPL(nr_mce_banks);       /* non-fatal.o */
@@ -31,7 +31,7 @@ static fastcall void unexpected_machine_check(struct pt_regs * regs, long error_
 void fastcall (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
 
 /* This has to be run for each processor */
-void __init mcheck_init(struct cpuinfo_x86 *c)
+void __devinit mcheck_init(struct cpuinfo_x86 *c)
 {
        if (mce_disabled==1)
                return;
index 8b16ceb929b400ea55ce042ad8154a63617d4976..0abccb6fdf9e1344dff1d79c409bcc97e1e9abf1 100644 (file)
@@ -78,7 +78,7 @@ fastcall void smp_thermal_interrupt(struct pt_regs *regs)
 }
 
 /* P4/Xeon Thermal regulation detect and init */
-static void __init intel_init_thermal(struct cpuinfo_x86 *c)
+static void __devinit intel_init_thermal(struct cpuinfo_x86 *c)
 {
        u32 l, h;
        unsigned int cpu = smp_processor_id();
@@ -232,7 +232,7 @@ static fastcall void intel_machine_check(struct pt_regs * regs, long error_code)
 }
 
 
-void __init intel_p4_mcheck_init(struct cpuinfo_x86 *c)
+void __devinit intel_p4_mcheck_init(struct cpuinfo_x86 *c)
 {
        u32 l, h;
        int i;
index c45a1b485c80df6f4b2855807026b2709918dea9..ec0614cd29250a6d15050781eabec475d439bdef 100644 (file)
@@ -29,7 +29,7 @@ static fastcall void pentium_machine_check(struct pt_regs * regs, long error_cod
 }
 
 /* Set up machine check reporting for processors with Intel style MCE */
-void __init intel_p5_mcheck_init(struct cpuinfo_x86 *c)
+void __devinit intel_p5_mcheck_init(struct cpuinfo_x86 *c)
 {
        u32 l, h;
        
index 46640f8c249415ddf045359c5e989d384b645c40..f01b73f947e1e010f5c3887ffeabb5aee91c5ea4 100644 (file)
@@ -80,7 +80,7 @@ static fastcall void intel_machine_check(struct pt_regs * regs, long error_code)
 }
 
 /* Set up machine check reporting for processors with Intel style MCE */
-void __init intel_p6_mcheck_init(struct cpuinfo_x86 *c)
+void __devinit intel_p6_mcheck_init(struct cpuinfo_x86 *c)
 {
        u32 l, h;
        int i;
index 753fa7acb9840bf3fd4e82933a5374dd3b90ce21..7bae68fa168fcbbe8325362730dfbf82ca9744ed 100644 (file)
@@ -23,7 +23,7 @@ static fastcall void winchip_machine_check(struct pt_regs * regs, long error_cod
 }
 
 /* Set up machine check reporting on the Winchip C6 series */
-void __init winchip_mcheck_init(struct cpuinfo_x86 *c)
+void __devinit winchip_mcheck_init(struct cpuinfo_x86 *c)
 {
        u32 lo, hi;
        machine_check_vector = winchip_machine_check;
index f468a979e9aab7296d120716c89c60016a3d395e..64d91f73a0a46210db764b885de72fe5d65378c9 100644 (file)
@@ -70,8 +70,7 @@ void __init get_mtrr_state(void)
 /*  Free resources associated with a struct mtrr_state  */
 void __init finalize_mtrr_state(void)
 {
-       if (mtrr_state.var_ranges)
-               kfree(mtrr_state.var_ranges);
+       kfree(mtrr_state.var_ranges);
        mtrr_state.var_ranges = NULL;
 }
 
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c
new file mode 100644 (file)
index 0000000..e5fab12
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Architecture specific (i386) functions for kexec based crash dumps.
+ *
+ * Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2004. All rights reserved.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/irq.h>
+#include <linux/reboot.h>
+#include <linux/kexec.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/elf.h>
+#include <linux/elfcore.h>
+
+#include <asm/processor.h>
+#include <asm/hardirq.h>
+#include <asm/nmi.h>
+#include <asm/hw_irq.h>
+#include <asm/apic.h>
+#include <mach_ipi.h>
+
+
+note_buf_t crash_notes[NR_CPUS];
+/* This keeps a track of which one is crashing cpu. */
+static int crashing_cpu;
+
+static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
+                                                              size_t data_len)
+{
+       struct elf_note note;
+
+       note.n_namesz = strlen(name) + 1;
+       note.n_descsz = data_len;
+       note.n_type   = type;
+       memcpy(buf, &note, sizeof(note));
+       buf += (sizeof(note) +3)/4;
+       memcpy(buf, name, note.n_namesz);
+       buf += (note.n_namesz + 3)/4;
+       memcpy(buf, data, note.n_descsz);
+       buf += (note.n_descsz + 3)/4;
+
+       return buf;
+}
+
+static void final_note(u32 *buf)
+{
+       struct elf_note note;
+
+       note.n_namesz = 0;
+       note.n_descsz = 0;
+       note.n_type   = 0;
+       memcpy(buf, &note, sizeof(note));
+}
+
+static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
+{
+       struct elf_prstatus prstatus;
+       u32 *buf;
+
+       if ((cpu < 0) || (cpu >= NR_CPUS))
+               return;
+
+       /* Using ELF notes here is opportunistic.
+        * I need a well defined structure format
+        * for the data I pass, and I need tags
+        * on the data to indicate what information I have
+        * squirrelled away.  ELF notes happen to provide
+        * all of that that no need to invent something new.
+        */
+       buf = &crash_notes[cpu][0];
+       memset(&prstatus, 0, sizeof(prstatus));
+       prstatus.pr_pid = current->pid;
+       elf_core_copy_regs(&prstatus.pr_reg, regs);
+       buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus,
+                               sizeof(prstatus));
+       final_note(buf);
+}
+
+static void crash_get_current_regs(struct pt_regs *regs)
+{
+       __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx));
+       __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx));
+       __asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx));
+       __asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi));
+       __asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi));
+       __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp));
+       __asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax));
+       __asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp));
+       __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss));
+       __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs));
+       __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds));
+       __asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes));
+       __asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags));
+
+       regs->eip = (unsigned long)current_text_addr();
+}
+
+/* CPU does not save ss and esp on stack if execution is already
+ * running in kernel mode at the time of NMI occurrence. This code
+ * fixes it.
+ */
+static void crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs)
+{
+       memcpy(newregs, oldregs, sizeof(*newregs));
+       newregs->esp = (unsigned long)&(oldregs->esp);
+       __asm__ __volatile__("xorl %eax, %eax;");
+       __asm__ __volatile__ ("movw %%ss, %%ax;" :"=a"(newregs->xss));
+}
+
+/* We may have saved_regs from where the error came from
+ * or it is NULL if via a direct panic().
+ */
+static void crash_save_self(struct pt_regs *saved_regs)
+{
+       struct pt_regs regs;
+       int cpu;
+
+       cpu = smp_processor_id();
+       if (saved_regs)
+               crash_setup_regs(&regs, saved_regs);
+       else
+               crash_get_current_regs(&regs);
+       crash_save_this_cpu(&regs, cpu);
+}
+
+#ifdef CONFIG_SMP
+static atomic_t waiting_for_crash_ipi;
+
+static int crash_nmi_callback(struct pt_regs *regs, int cpu)
+{
+       struct pt_regs fixed_regs;
+
+       /* Don't do anything if this handler is invoked on crashing cpu.
+        * Otherwise, system will completely hang. Crashing cpu can get
+        * an NMI if system was initially booted with nmi_watchdog parameter.
+        */
+       if (cpu == crashing_cpu)
+               return 1;
+       local_irq_disable();
+
+       if (!user_mode(regs)) {
+               crash_setup_regs(&fixed_regs, regs);
+               regs = &fixed_regs;
+       }
+       crash_save_this_cpu(regs, cpu);
+       disable_local_APIC();
+       atomic_dec(&waiting_for_crash_ipi);
+       /* Assume hlt works */
+       __asm__("hlt");
+       for(;;);
+
+       return 1;
+}
+
+/*
+ * By using the NMI code instead of a vector we just sneak thru the
+ * word generator coming out with just what we want.  AND it does
+ * not matter if clustered_apic_mode is set or not.
+ */
+static void smp_send_nmi_allbutself(void)
+{
+       send_IPI_allbutself(APIC_DM_NMI);
+}
+
+static void nmi_shootdown_cpus(void)
+{
+       unsigned long msecs;
+
+       atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+       /* Would it be better to replace the trap vector here? */
+       set_nmi_callback(crash_nmi_callback);
+       /* Ensure the new callback function is set before sending
+        * out the NMI
+        */
+       wmb();
+
+       smp_send_nmi_allbutself();
+
+       msecs = 1000; /* Wait at most a second for the other cpus to stop */
+       while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
+               mdelay(1);
+               msecs--;
+       }
+
+       /* Leave the nmi callback set */
+       disable_local_APIC();
+}
+#else
+static void nmi_shootdown_cpus(void)
+{
+       /* There are no cpus to shootdown */
+}
+#endif
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+       /* This function is only called after the system
+        * has paniced or is otherwise in a critical state.
+        * The minimum amount of code to allow a kexec'd kernel
+        * to run successfully needs to happen here.
+        *
+        * In practice this means shooting down the other cpus in
+        * an SMP system.
+        */
+       /* The kernel is broken so disable interrupts */
+       local_irq_disable();
+
+       /* Make a note of crashing cpu. Will be used in NMI callback.*/
+       crashing_cpu = smp_processor_id();
+       nmi_shootdown_cpus();
+       lapic_shutdown();
+#if defined(CONFIG_X86_IO_APIC)
+       disable_IO_APIC();
+#endif
+       crash_save_self(regs);
+}
index 6ed7e28f306cf2321d72b636f3327051fd0eb754..a3cdf894302b0d5fe48ecfcd1581be41d99c8932 100644 (file)
@@ -1,22 +1,15 @@
 #include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/acpi.h>
-#include <asm/io.h>
-#include <linux/pm.h>
-#include <asm/system.h>
 #include <linux/dmi.h>
 #include <linux/bootmem.h>
 
 
-struct dmi_header
-{
-       u8      type;
-       u8      length;
-       u16     handle;
+struct dmi_header {
+       u8 type;
+       u8 length;
+       u16 handle;
 };
 
 #undef DMI_DEBUG
@@ -29,15 +22,13 @@ struct dmi_header
 
 static char * __init dmi_string(struct dmi_header *dm, u8 s)
 {
-       u8 *bp=(u8 *)dm;
-       bp+=dm->length;
-       if(!s)
+       u8 *bp = ((u8 *) dm) + dm->length;
+
+       if (!s)
                return "";
        s--;
-       while(s>0 && *bp)
-       {
-               bp+=strlen(bp);
-               bp++;
+       while (s > 0 && *bp) {
+               bp += strlen(bp) + 1;
                s--;
        }
        return bp;
@@ -47,16 +38,14 @@ static char * __init dmi_string(struct dmi_header *dm, u8 s)
  *     We have to be cautious here. We have seen BIOSes with DMI pointers
  *     pointing to completely the wrong place for example
  */
-static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *))
+static int __init dmi_table(u32 base, int len, int num,
+                           void (*decode)(struct dmi_header *))
 {
-       u8 *buf;
-       struct dmi_header *dm;
-       u8 *data;
-       int i=0;
+       u8 *buf, *data;
+       int i = 0;
                
        buf = bt_ioremap(base, len);
-       if(buf==NULL)
+       if (buf == NULL)
                return -1;
 
        data = buf;
@@ -65,36 +54,34 @@ static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dm
         *      Stop when we see all the items the table claimed to have
         *      OR we run off the end of the table (also happens)
         */
-       while(i<num && data-buf+sizeof(struct dmi_header)<=len)
-       {
-               dm=(struct dmi_header *)data;
+       while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
+               struct dmi_header *dm = (struct dmi_header *)data;
                /*
                 *  We want to know the total length (formated area and strings)
                 *  before decoding to make sure we won't run off the table in
                 *  dmi_decode or dmi_string
                 */
-               data+=dm->length;
-               while(data-buf<len-1 && (data[0] || data[1]))
+               data += dm->length;
+               while ((data - buf < len - 1) && (data[0] || data[1]))
                        data++;
-               if(data-buf<len-1)
+               if (data - buf < len - 1)
                        decode(dm);
-               data+=2;
+               data += 2;
                i++;
        }
        bt_iounmap(buf, len);
        return 0;
 }
 
-
-inline static int __init dmi_checksum(u8 *buf)
+static int __init dmi_checksum(u8 *buf)
 {
-       u8 sum=0;
+       u8 sum = 0;
        int a;
        
-       for(a=0; a<15; a++)
-               sum+=buf[a];
-       return (sum==0);
+       for (a = 0; a < 15; a++)
+               sum += buf[a];
+
+       return sum == 0;
 }
 
 static int __init dmi_iterate(void (*decode)(struct dmi_header *))
@@ -110,28 +97,30 @@ static int __init dmi_iterate(void (*decode)(struct dmi_header *))
        p = ioremap(0xF0000, 0x10000);
        if (p == NULL)
                return -1;
+
        for (q = p; q < p + 0x10000; q += 16) {
                memcpy_fromio(buf, q, 15);
-               if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
-               {
-                       u16 num=buf[13]<<8|buf[12];
-                       u16 len=buf[7]<<8|buf[6];
-                       u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
+               if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
+                       u16 num = (buf[13] << 8) | buf[12];
+                       u16 len = (buf[7] << 8) | buf[6];
+                       u32 base = (buf[11] << 24) | (buf[10] << 16) |
+                                  (buf[9] << 8) | buf[8];
 
                        /*
                         * DMI version 0.0 means that the real version is taken from
                         * the SMBIOS version, which we don't know at this point.
                         */
-                       if(buf[14]!=0)
+                       if (buf[14] != 0)
                                printk(KERN_INFO "DMI %d.%d present.\n",
-                                       buf[14]>>4, buf[14]&0x0F);
+                                       buf[14] >> 4, buf[14] & 0xF);
                        else
                                printk(KERN_INFO "DMI present.\n");
+
                        dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
                                num, len));
-                       dmi_printk((KERN_INFO "DMI table at 0x%08X.\n",
-                               base));
-                       if(dmi_table(base,len, num, decode)==0)
+                       dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", base));
+
+                       if (dmi_table(base,len, num, decode) == 0)
                                return 0;
                }
        }
@@ -143,298 +132,65 @@ static char *dmi_ident[DMI_STRING_MAX];
 /*
  *     Save a DMI string
  */
 static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
 {
        char *d = (char*)dm;
        char *p = dmi_string(dm, d[string]);
-       if(p==NULL || *p == 0)
+
+       if (p == NULL || *p == 0)
                return;
        if (dmi_ident[slot])
                return;
-       dmi_ident[slot] = alloc_bootmem(strlen(p)+1);
+
+       dmi_ident[slot] = alloc_bootmem(strlen(p) + 1);
        if(dmi_ident[slot])
                strcpy(dmi_ident[slot], p);
        else
                printk(KERN_ERR "dmi_save_ident: out of memory.\n");
 }
 
-/*
- * Ugly compatibility crap.
- */
-#define dmi_blacklist  dmi_system_id
-#define NO_MATCH       { DMI_NONE, NULL}
-#define MATCH          DMI_MATCH
-
-/*
- * Toshiba keyboard likes to repeat keys when they are not repeated.
- */
-
-static __init int broken_toshiba_keyboard(struct dmi_blacklist *d)
-{
-       printk(KERN_WARNING "Toshiba with broken keyboard detected. If your keyboard sometimes generates 3 keypresses instead of one, see http://davyd.ucc.asn.au/projects/toshiba/README\n");
-       return 0;
-}
-
-
-#ifdef CONFIG_ACPI_SLEEP
-static __init int reset_videomode_after_s3(struct dmi_blacklist *d)
-{
-       /* See acpi_wakeup.S */
-       extern long acpi_video_flags;
-       acpi_video_flags |= 2;
-       return 0;
-}
-#endif
-
-
-#ifdef CONFIG_ACPI_BOOT
-extern int acpi_force;
-
-static __init __attribute__((unused)) int dmi_disable_acpi(struct dmi_blacklist *d) 
-{ 
-       if (!acpi_force) { 
-               printk(KERN_NOTICE "%s detected: acpi off\n",d->ident); 
-               disable_acpi();
-       } else { 
-               printk(KERN_NOTICE 
-                      "Warning: DMI blacklist says broken, but acpi forced\n"); 
-       }
-       return 0;
-} 
-
-/*
- * Limit ACPI to CPU enumeration for HT
- */
-static __init __attribute__((unused)) int force_acpi_ht(struct dmi_blacklist *d) 
-{ 
-       if (!acpi_force) { 
-               printk(KERN_NOTICE "%s detected: force use of acpi=ht\n", d->ident); 
-               disable_acpi();
-               acpi_ht = 1; 
-       } else { 
-               printk(KERN_NOTICE 
-                      "Warning: acpi=force overrules DMI blacklist: acpi=ht\n"); 
-       }
-       return 0;
-} 
-#endif
-
-#ifdef CONFIG_ACPI_PCI
-static __init int disable_acpi_irq(struct dmi_blacklist *d) 
-{
-       if (!acpi_force) {
-               printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n",
-                      d->ident);       
-               acpi_noirq_set();
-       }
-       return 0;
-}
-static __init int disable_acpi_pci(struct dmi_blacklist *d) 
-{
-       if (!acpi_force) {
-               printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n",
-                      d->ident);       
-               acpi_disable_pci();
-       }
-       return 0;
-}  
-#endif
-
-/*
- *     Process the DMI blacklists
- */
-
-/*
- *     This will be expanded over time to force things like the APM 
- *     interrupt mask settings according to the laptop
- */
-static __initdata struct dmi_blacklist dmi_blacklist[]={
-
-       { broken_toshiba_keyboard, "Toshiba Satellite 4030cdt", { /* Keyboard generates spurious repeats */
-                       MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
-                       NO_MATCH, NO_MATCH, NO_MATCH
-                       } },
-#ifdef CONFIG_ACPI_SLEEP
-       { reset_videomode_after_s3, "Toshiba Satellite 4030cdt", { /* Reset video mode after returning from ACPI S3 sleep */
-                       MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
-                       NO_MATCH, NO_MATCH, NO_MATCH
-                       } },
-#endif
-
-#ifdef CONFIG_ACPI_BOOT
-       /*
-        * If your system is blacklisted here, but you find that acpi=force
-        * works for you, please contact acpi-devel@sourceforge.net
-        */
-
-       /*
-        *      Boxes that need ACPI disabled
-        */
-
-       { dmi_disable_acpi, "IBM Thinkpad", {
-                       MATCH(DMI_BOARD_VENDOR, "IBM"),
-                       MATCH(DMI_BOARD_NAME, "2629H1G"),
-                       NO_MATCH, NO_MATCH }},
-
-       /*
-        *      Boxes that need acpi=ht 
-        */
-
-       { force_acpi_ht, "FSC Primergy T850", {
-                       MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
-                       MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"),
-                       NO_MATCH, NO_MATCH }},
-
-       { force_acpi_ht, "DELL GX240", {
-                       MATCH(DMI_BOARD_VENDOR, "Dell Computer Corporation"),
-                       MATCH(DMI_BOARD_NAME, "OptiPlex GX240"),
-                       NO_MATCH, NO_MATCH }},
-
-       { force_acpi_ht, "HP VISUALIZE NT Workstation", {
-                       MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
-                       MATCH(DMI_PRODUCT_NAME, "HP VISUALIZE NT Workstation"),
-                       NO_MATCH, NO_MATCH }},
-
-       { force_acpi_ht, "Compaq Workstation W8000", {
-                       MATCH(DMI_SYS_VENDOR, "Compaq"),
-                       MATCH(DMI_PRODUCT_NAME, "Workstation W8000"),
-                       NO_MATCH, NO_MATCH }},
-
-       { force_acpi_ht, "ASUS P4B266", {
-                       MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
-                       MATCH(DMI_BOARD_NAME, "P4B266"),
-                       NO_MATCH, NO_MATCH }},
-
-       { force_acpi_ht, "ASUS P2B-DS", {
-                       MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
-                       MATCH(DMI_BOARD_NAME, "P2B-DS"),
-                       NO_MATCH, NO_MATCH }},
-
-       { force_acpi_ht, "ASUS CUR-DLS", {
-                       MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
-                       MATCH(DMI_BOARD_NAME, "CUR-DLS"),
-                       NO_MATCH, NO_MATCH }},
-
-       { force_acpi_ht, "ABIT i440BX-W83977", {
-                       MATCH(DMI_BOARD_VENDOR, "ABIT <http://www.abit.com>"),
-                       MATCH(DMI_BOARD_NAME, "i440BX-W83977 (BP6)"),
-                       NO_MATCH, NO_MATCH }},
-
-       { force_acpi_ht, "IBM Bladecenter", {
-                       MATCH(DMI_BOARD_VENDOR, "IBM"),
-                       MATCH(DMI_BOARD_NAME, "IBM eServer BladeCenter HS20"),
-                       NO_MATCH, NO_MATCH }},
-
-       { force_acpi_ht, "IBM eServer xSeries 360", {
-                       MATCH(DMI_BOARD_VENDOR, "IBM"),
-                       MATCH(DMI_BOARD_NAME, "eServer xSeries 360"),
-                       NO_MATCH, NO_MATCH }},
-
-       { force_acpi_ht, "IBM eserver xSeries 330", {
-                       MATCH(DMI_BOARD_VENDOR, "IBM"),
-                       MATCH(DMI_BOARD_NAME, "eserver xSeries 330"),
-                       NO_MATCH, NO_MATCH }},
-
-       { force_acpi_ht, "IBM eserver xSeries 440", {
-                       MATCH(DMI_BOARD_VENDOR, "IBM"),
-                       MATCH(DMI_PRODUCT_NAME, "eserver xSeries 440"),
-                       NO_MATCH, NO_MATCH }},
-
-#endif // CONFIG_ACPI_BOOT
-
-#ifdef CONFIG_ACPI_PCI
-       /*
-        *      Boxes that need ACPI PCI IRQ routing disabled
-        */
-
-       { disable_acpi_irq, "ASUS A7V", {
-                       MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"),
-                       MATCH(DMI_BOARD_NAME, "<A7V>"),
-                       /* newer BIOS, Revision 1011, does work */
-                       MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1007"),
-                       NO_MATCH }},
-
-       /*
-        *      Boxes that need ACPI PCI IRQ routing and PCI scan disabled
-        */
-       { disable_acpi_pci, "ASUS PR-DLS", {    /* _BBN 0 bug */
-                       MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
-                       MATCH(DMI_BOARD_NAME, "PR-DLS"),
-                       MATCH(DMI_BIOS_VERSION, "ASUS PR-DLS ACPI BIOS Revision 1010"),
-                       MATCH(DMI_BIOS_DATE, "03/21/2003") }},
-
-       { disable_acpi_pci, "Acer TravelMate 36x Laptop", {
-                       MATCH(DMI_SYS_VENDOR, "Acer"),
-                       MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
-                       NO_MATCH, NO_MATCH
-                       } },
-
-#endif
-
-       { NULL, }
-};
-
 /*
  *     Process a DMI table entry. Right now all we care about are the BIOS
  *     and machine entries. For 2.5 we should pull the smbus controller info
  *     out of here.
  */
-
 static void __init dmi_decode(struct dmi_header *dm)
 {
-#ifdef DMI_DEBUG
-       u8 *data = (u8 *)dm;
-#endif
+       u8 *data __attribute__((__unused__)) = (u8 *)dm;
        
-       switch(dm->type)
-       {
-               case  0:
-                       dmi_printk(("BIOS Vendor: %s\n",
-                               dmi_string(dm, data[4])));
-                       dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
-                       dmi_printk(("BIOS Version: %s\n", 
-                               dmi_string(dm, data[5])));
-                       dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
-                       dmi_printk(("BIOS Release: %s\n",
-                               dmi_string(dm, data[8])));
-                       dmi_save_ident(dm, DMI_BIOS_DATE, 8);
-                       break;
-               case 1:
-                       dmi_printk(("System Vendor: %s\n",
-                               dmi_string(dm, data[4])));
-                       dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
-                       dmi_printk(("Product Name: %s\n",
-                               dmi_string(dm, data[5])));
-                       dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
-                       dmi_printk(("Version: %s\n",
-                               dmi_string(dm, data[6])));
-                       dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
-                       dmi_printk(("Serial Number: %s\n",
-                               dmi_string(dm, data[7])));
-                       break;
-               case 2:
-                       dmi_printk(("Board Vendor: %s\n",
-                               dmi_string(dm, data[4])));
-                       dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
-                       dmi_printk(("Board Name: %s\n",
-                               dmi_string(dm, data[5])));
-                       dmi_save_ident(dm, DMI_BOARD_NAME, 5);
-                       dmi_printk(("Board Version: %s\n",
-                               dmi_string(dm, data[6])));
-                       dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
-                       break;
+       switch(dm->type) {
+       case  0:
+               dmi_printk(("BIOS Vendor: %s\n", dmi_string(dm, data[4])));
+               dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
+               dmi_printk(("BIOS Version: %s\n", dmi_string(dm, data[5])));
+               dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
+               dmi_printk(("BIOS Release: %s\n", dmi_string(dm, data[8])));
+               dmi_save_ident(dm, DMI_BIOS_DATE, 8);
+               break;
+       case 1:
+               dmi_printk(("System Vendor: %s\n", dmi_string(dm, data[4])));
+               dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
+               dmi_printk(("Product Name: %s\n", dmi_string(dm, data[5])));
+               dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
+               dmi_printk(("Version: %s\n", dmi_string(dm, data[6])));
+               dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
+               dmi_printk(("Serial Number: %s\n", dmi_string(dm, data[7])));
+               dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
+               break;
+       case 2:
+               dmi_printk(("Board Vendor: %s\n", dmi_string(dm, data[4])));
+               dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
+               dmi_printk(("Board Name: %s\n", dmi_string(dm, data[5])));
+               dmi_save_ident(dm, DMI_BOARD_NAME, 5);
+               dmi_printk(("Board Version: %s\n", dmi_string(dm, data[6])));
+               dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
+               break;
        }
 }
 
 void __init dmi_scan_machine(void)
 {
-       int err = dmi_iterate(dmi_decode);
-       if(err == 0)
-               dmi_check_system(dmi_blacklist);
-       else
+       if (dmi_iterate(dmi_decode))
                printk(KERN_INFO "DMI not present.\n");
 }
 
@@ -470,7 +226,6 @@ fail:               d++;
 
        return count;
 }
-
 EXPORT_SYMBOL(dmi_check_system);
 
 /**
@@ -480,8 +235,8 @@ EXPORT_SYMBOL(dmi_check_system);
  *     Returns one DMI data value, can be used to perform
  *     complex DMI data checks.
  */
-char * dmi_get_system_info(int field)
+char *dmi_get_system_info(int field)
 {
        return dmi_ident[field];
 }
-
+EXPORT_SYMBOL(dmi_get_system_info);
index f732f427b418a02672409e8168f7701f032873bc..385883ea8c199d1008d0db050e1c71ec32ce64ec 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/ioport.h>
 #include <linux/module.h>
 #include <linux/efi.h>
+#include <linux/kexec.h>
 
 #include <asm/setup.h>
 #include <asm/io.h>
@@ -598,6 +599,9 @@ efi_initialize_iomem_resources(struct resource *code_resource,
                if (md->type == EFI_CONVENTIONAL_MEMORY) {
                        request_resource(res, code_resource);
                        request_resource(res, data_resource);
+#ifdef CONFIG_KEXEC
+                       request_resource(res, &crashk_res);
+#endif
                }
        }
 }
index e966fc8c44c49711f0fecbbc03cc183656aa6b40..4477bb107098c2863ee85a0ef8a27374147ca494 100644 (file)
@@ -299,7 +299,6 @@ is386:      movl $2,%ecx            # set MP
        movl %eax,%cr0
 
        call check_x87
-       incb ready
        lgdt cpu_gdt_descr
        lidt idt_descr
        ljmp $(__KERNEL_CS),$1f
@@ -316,8 +315,9 @@ is386:      movl $2,%ecx            # set MP
        lldt %ax
        cld                     # gcc2 wants the direction flag cleared at all times
 #ifdef CONFIG_SMP
-       movb ready, %cl 
-       cmpb $1,%cl
+       movb ready, %cl
+       movb $1, ready
+       cmpb $0,%cl
        je 1f                   # the first CPU calls start_kernel
                                # all other CPUs call initialize_secondary
        call initialize_secondary
index 2c4813b47e57a5603e7bec605129b8890d68c3de..178f4e9bac9d14c84a5046b6c967982000120f73 100644 (file)
@@ -268,10 +268,22 @@ static int i8259A_suspend(struct sys_device *dev, pm_message_t state)
        return 0;
 }
 
+static int i8259A_shutdown(struct sys_device *dev)
+{
+       /* Put the i8259A into a quiescent state that
+        * the kernel initialization code can get it
+        * out of.
+        */
+       outb(0xff, 0x21);       /* mask all of 8259A-1 */
+       outb(0xff, 0xA1);       /* mask all of 8259A-1 */
+       return 0;
+}
+
 static struct sysdev_class i8259_sysdev_class = {
        set_kset_name("i8259"),
        .suspend = i8259A_suspend,
        .resume = i8259A_resume,
+       .shutdown = i8259A_shutdown,
 };
 
 static struct sys_device device_i8259A = {
index 08540bc4ba3e19494a51f7424dddc3753726f9e9..6578f40bd5012a0af9385d889f8a6cd37a6546a9 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/smp.h>
 #include <asm/desc.h>
 #include <asm/timer.h>
+#include <asm/i8259.h>
 
 #include <mach_apic.h>
 
@@ -573,12 +574,14 @@ static int balanced_irq(void *unused)
        for ( ; ; ) {
                set_current_state(TASK_INTERRUPTIBLE);
                time_remaining = schedule_timeout(time_remaining);
-               try_to_freeze(PF_FREEZE);
+               try_to_freeze();
                if (time_after(jiffies,
                                prev_balance_time+balanced_irq_interval)) {
+                       preempt_disable();
                        do_irq_balance();
                        prev_balance_time = jiffies;
                        time_remaining = balanced_irq_interval;
+                       preempt_enable();
                }
        }
        return 0;
@@ -630,10 +633,8 @@ static int __init balanced_irq_init(void)
                printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq");
 failed:
        for (i = 0; i < NR_CPUS; i++) {
-               if(irq_cpu_data[i].irq_delta)
-                       kfree(irq_cpu_data[i].irq_delta);
-               if(irq_cpu_data[i].last_irq)
-                       kfree(irq_cpu_data[i].last_irq);
+               kfree(irq_cpu_data[i].irq_delta);
+               kfree(irq_cpu_data[i].last_irq);
        }
        return 0;
 }
@@ -1566,7 +1567,6 @@ void print_all_local_APICs (void)
 
 void /*__init*/ print_PIC(void)
 {
-       extern spinlock_t i8259A_lock;
        unsigned int v;
        unsigned long flags;
 
@@ -1634,12 +1634,43 @@ static void __init enable_IO_APIC(void)
  */
 void disable_IO_APIC(void)
 {
+       int pin;
        /*
         * Clear the IO-APIC before rebooting:
         */
        clear_IO_APIC();
 
-       disconnect_bsp_APIC();
+       /*
+        * If the i82559 is routed through an IOAPIC
+        * Put that IOAPIC in virtual wire mode
+        * so legacy interrups can be delivered.
+        */
+       pin = find_isa_irq_pin(0, mp_ExtINT);
+       if (pin != -1) {
+               struct IO_APIC_route_entry entry;
+               unsigned long flags;
+
+               memset(&entry, 0, sizeof(entry));
+               entry.mask            = 0; /* Enabled */
+               entry.trigger         = 0; /* Edge */
+               entry.irr             = 0;
+               entry.polarity        = 0; /* High */
+               entry.delivery_status = 0;
+               entry.dest_mode       = 0; /* Physical */
+               entry.delivery_mode   = 7; /* ExtInt */
+               entry.vector          = 0;
+               entry.dest.physical.physical_dest = 0;
+
+
+               /*
+                * Add it to the IO-APIC irq-routing table:
+                */
+               spin_lock_irqsave(&ioapic_lock, flags);
+               io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
+               io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
+               spin_unlock_irqrestore(&ioapic_lock, flags);
+       }
+       disconnect_bsp_APIC(pin != -1);
 }
 
 /*
index 73945a3c53c4c5559e2a1935f69cda24d20e6b18..ce66dcc26d9072cf14bea63c83ae1db8ddde1934 100644 (file)
@@ -15,6 +15,9 @@
 #include <linux/seq_file.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/delay.h>
 
 DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_maxaligned_in_smp;
 EXPORT_PER_CPU_SYMBOL(irq_stat);
@@ -153,6 +156,11 @@ void irq_ctx_init(int cpu)
                cpu,hardirq_ctx[cpu],softirq_ctx[cpu]);
 }
 
+void irq_ctx_exit(int cpu)
+{
+       hardirq_ctx[cpu] = NULL;
+}
+
 extern asmlinkage void __do_softirq(void);
 
 asmlinkage void do_softirq(void)
@@ -210,9 +218,8 @@ int show_interrupts(struct seq_file *p, void *v)
 
        if (i == 0) {
                seq_printf(p, "           ");
-               for (j=0; j<NR_CPUS; j++)
-                       if (cpu_online(j))
-                               seq_printf(p, "CPU%d       ",j);
+               for_each_cpu(j)
+                       seq_printf(p, "CPU%d       ",j);
                seq_putc(p, '\n');
        }
 
@@ -225,9 +232,8 @@ int show_interrupts(struct seq_file *p, void *v)
 #ifndef CONFIG_SMP
                seq_printf(p, "%10u ", kstat_irqs(i));
 #else
-               for (j = 0; j < NR_CPUS; j++)
-                       if (cpu_online(j))
-                               seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+               for_each_cpu(j)
+                       seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
                seq_printf(p, " %14s", irq_desc[i].handler->typename);
                seq_printf(p, "  %s", action->name);
@@ -240,16 +246,14 @@ skip:
                spin_unlock_irqrestore(&irq_desc[i].lock, flags);
        } else if (i == NR_IRQS) {
                seq_printf(p, "NMI: ");
-               for (j = 0; j < NR_CPUS; j++)
-                       if (cpu_online(j))
-                               seq_printf(p, "%10u ", nmi_count(j));
+               for_each_cpu(j)
+                       seq_printf(p, "%10u ", nmi_count(j));
                seq_putc(p, '\n');
 #ifdef CONFIG_X86_LOCAL_APIC
                seq_printf(p, "LOC: ");
-               for (j = 0; j < NR_CPUS; j++)
-                       if (cpu_online(j))
-                               seq_printf(p, "%10u ",
-                                       per_cpu(irq_stat,j).apic_timer_irqs);
+               for_each_cpu(j)
+                       seq_printf(p, "%10u ",
+                               per_cpu(irq_stat,j).apic_timer_irqs);
                seq_putc(p, '\n');
 #endif
                seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
@@ -259,3 +263,45 @@ skip:
        }
        return 0;
 }
+
+#ifdef CONFIG_HOTPLUG_CPU
+#include <mach_apic.h>
+
+void fixup_irqs(cpumask_t map)
+{
+       unsigned int irq;
+       static int warned;
+
+       for (irq = 0; irq < NR_IRQS; irq++) {
+               cpumask_t mask;
+               if (irq == 2)
+                       continue;
+
+               cpus_and(mask, irq_affinity[irq], map);
+               if (any_online_cpu(mask) == NR_CPUS) {
+                       printk("Breaking affinity for irq %i\n", irq);
+                       mask = map;
+               }
+               if (irq_desc[irq].handler->set_affinity)
+                       irq_desc[irq].handler->set_affinity(irq, mask);
+               else if (irq_desc[irq].action && !(warned++))
+                       printk("Cannot set affinity for irq %i\n", irq);
+       }
+
+#if 0
+       barrier();
+       /* Ingo Molnar says: "after the IO-APIC masks have been redirected
+          [note the nop - the interrupt-enable boundary on x86 is two
+          instructions from sti] - to flush out pending hardirqs and
+          IPIs. After this point nothing is supposed to reach this CPU." */
+       __asm__ __volatile__("sti; nop; cli");
+       barrier();
+#else
+       /* That doesn't seem sufficient.  Give it 1ms. */
+       local_irq_enable();
+       mdelay(1);
+       local_irq_disable();
+#endif
+}
+#endif
+
index 3762f6b35ab28f6c37dec2c147df6d058cd5630c..fc8b1752176189b7c12d367af9eb78efd323dff7 100644 (file)
@@ -127,48 +127,23 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
                regs->eip = (unsigned long)&p->ainsn.insn;
 }
 
-struct task_struct  *arch_get_kprobe_task(void *ptr)
-{
-       return ((struct thread_info *) (((unsigned long) ptr) &
-                                       (~(THREAD_SIZE -1))))->task;
-}
-
 void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
 {
        unsigned long *sara = (unsigned long *)&regs->esp;
-       struct kretprobe_instance *ri;
-       static void *orig_ret_addr;
+        struct kretprobe_instance *ri;
+
+        if ((ri = get_free_rp_inst(rp)) != NULL) {
+                ri->rp = rp;
+                ri->task = current;
+               ri->ret_addr = (kprobe_opcode_t *) *sara;
 
-       /*
-        * Save the return address when the return probe hits
-        * the first time, and use it to populate the (krprobe
-        * instance)->ret_addr for subsequent return probes at
-        * the same addrress since stack address would have
-        * the kretprobe_trampoline by then.
-        */
-       if (((void*) *sara) != kretprobe_trampoline)
-               orig_ret_addr = (void*) *sara;
-
-       if ((ri = get_free_rp_inst(rp)) != NULL) {
-               ri->rp = rp;
-               ri->stack_addr = sara;
-               ri->ret_addr = orig_ret_addr;
-               add_rp_inst(ri);
                /* Replace the return addr with trampoline addr */
                *sara = (unsigned long) &kretprobe_trampoline;
-       } else {
-               rp->nmissed++;
-       }
-}
 
-void arch_kprobe_flush_task(struct task_struct *tk)
-{
-       struct kretprobe_instance *ri;
-       while ((ri = get_rp_inst_tsk(tk)) != NULL) {
-               *((unsigned long *)(ri->stack_addr)) =
-                                       (unsigned long) ri->ret_addr;
-               recycle_rp_inst(ri);
-       }
+                add_rp_inst(ri);
+        } else {
+                rp->nmissed++;
+        }
 }
 
 /*
@@ -286,36 +261,59 @@ no_kprobe:
  */
 int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 {
-       struct task_struct *tsk;
-       struct kretprobe_instance *ri;
-       struct hlist_head *head;
-       struct hlist_node *node;
-       unsigned long *sara = ((unsigned long *) &regs->esp) - 1;
-
-       tsk = arch_get_kprobe_task(sara);
-       head = kretprobe_inst_table_head(tsk);
-
-       hlist_for_each_entry(ri, node, head, hlist) {
-               if (ri->stack_addr == sara && ri->rp) {
-                       if (ri->rp->handler)
-                               ri->rp->handler(ri, regs);
-               }
-       }
-       return 0;
-}
+        struct kretprobe_instance *ri = NULL;
+        struct hlist_head *head;
+        struct hlist_node *node, *tmp;
+       unsigned long orig_ret_address = 0;
+       unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
 
-void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs,
-                                               unsigned long flags)
-{
-       struct kretprobe_instance *ri;
-       /* RA already popped */
-       unsigned long *sara = ((unsigned long *)&regs->esp) - 1;
+        head = kretprobe_inst_table_head(current);
 
-       while ((ri = get_rp_inst(sara))) {
-               regs->eip = (unsigned long)ri->ret_addr;
+       /*
+        * It is possible to have multiple instances associated with a given
+        * task either because an multiple functions in the call path
+        * have a return probe installed on them, and/or more then one return
+        * return probe was registered for a target function.
+        *
+        * We can handle this because:
+        *     - instances are always inserted at the head of the list
+        *     - when multiple return probes are registered for the same
+         *       function, the first instance's ret_addr will point to the
+        *       real return address, and all the rest will point to
+        *       kretprobe_trampoline
+        */
+       hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+                if (ri->task != current)
+                       /* another task is sharing our hash bucket */
+                        continue;
+
+               if (ri->rp && ri->rp->handler)
+                       ri->rp->handler(ri, regs);
+
+               orig_ret_address = (unsigned long)ri->ret_addr;
                recycle_rp_inst(ri);
+
+               if (orig_ret_address != trampoline_address)
+                       /*
+                        * This is the real return address. Any other
+                        * instances associated with this task are for
+                        * other calls deeper on the call stack
+                        */
+                       break;
        }
-       regs->eflags &= ~TF_MASK;
+
+       BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+       regs->eip = orig_ret_address;
+
+       unlock_kprobes();
+       preempt_enable_no_resched();
+
+        /*
+         * By returning a non-zero value, we are telling
+         * kprobe_handler() that we have handled unlocking
+         * and re-enabling preemption.
+         */
+        return 1;
 }
 
 /*
@@ -403,8 +401,7 @@ static inline int post_kprobe_handler(struct pt_regs *regs)
                current_kprobe->post_handler(current_kprobe, regs, 0);
        }
 
-       if (current_kprobe->post_handler != trampoline_post_handler)
-               resume_execution(current_kprobe, regs);
+       resume_execution(current_kprobe, regs);
        regs->eflags |= kprobe_saved_eflags;
 
        /*Restore back the original saved kprobes variables and continue. */
@@ -534,3 +531,13 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
        }
        return 0;
 }
+
+static struct kprobe trampoline_p = {
+       .addr = (kprobe_opcode_t *) &kretprobe_trampoline,
+       .pre_handler = trampoline_probe_handler
+};
+
+int __init arch_init(void)
+{
+       return register_kprobe(&trampoline_p);
+}
diff --git a/arch/i386/kernel/machine_kexec.c b/arch/i386/kernel/machine_kexec.c
new file mode 100644 (file)
index 0000000..52ed18d
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * machine_kexec.c - handle transition of Linux booting another kernel
+ * Copyright (C) 2002-2005 Eric Biederman  <ebiederm@xmission.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/apic.h>
+#include <asm/cpufeature.h>
+
+static inline unsigned long read_cr3(void)
+{
+       unsigned long cr3;
+       asm volatile("movl %%cr3,%0": "=r"(cr3));
+       return cr3;
+}
+
+#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
+
+#define L0_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define L1_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define L2_ATTR (_PAGE_PRESENT)
+
+#define LEVEL0_SIZE (1UL << 12UL)
+
+#ifndef CONFIG_X86_PAE
+#define LEVEL1_SIZE (1UL << 22UL)
+static u32 pgtable_level1[1024] PAGE_ALIGNED;
+
+static void identity_map_page(unsigned long address)
+{
+       unsigned long level1_index, level2_index;
+       u32 *pgtable_level2;
+
+       /* Find the current page table */
+       pgtable_level2 = __va(read_cr3());
+
+       /* Find the indexes of the physical address to identity map */
+       level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE;
+       level2_index = address / LEVEL1_SIZE;
+
+       /* Identity map the page table entry */
+       pgtable_level1[level1_index] = address | L0_ATTR;
+       pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR;
+
+       /* Flush the tlb so the new mapping takes effect.
+        * Global tlb entries are not flushed but that is not an issue.
+        */
+       load_cr3(pgtable_level2);
+}
+
+#else
+#define LEVEL1_SIZE (1UL << 21UL)
+#define LEVEL2_SIZE (1UL << 30UL)
+static u64 pgtable_level1[512] PAGE_ALIGNED;
+static u64 pgtable_level2[512] PAGE_ALIGNED;
+
+static void identity_map_page(unsigned long address)
+{
+       unsigned long level1_index, level2_index, level3_index;
+       u64 *pgtable_level3;
+
+       /* Find the current page table */
+       pgtable_level3 = __va(read_cr3());
+
+       /* Find the indexes of the physical address to identity map */
+       level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE;
+       level2_index = (address % LEVEL2_SIZE)/LEVEL1_SIZE;
+       level3_index = address / LEVEL2_SIZE;
+
+       /* Identity map the page table entry */
+       pgtable_level1[level1_index] = address | L0_ATTR;
+       pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR;
+       set_64bit(&pgtable_level3[level3_index],
+                                              __pa(pgtable_level2) | L2_ATTR);
+
+       /* Flush the tlb so the new mapping takes effect.
+        * Global tlb entries are not flushed but that is not an issue.
+        */
+       load_cr3(pgtable_level3);
+}
+#endif
+
+
+static void set_idt(void *newidt, __u16 limit)
+{
+       unsigned char curidt[6];
+
+       /* ia32 supports unaliged loads & stores */
+       (*(__u16 *)(curidt)) = limit;
+       (*(__u32 *)(curidt +2)) = (unsigned long)(newidt);
+
+       __asm__ __volatile__ (
+               "lidt %0\n"
+               : "=m" (curidt)
+               );
+};
+
+
+static void set_gdt(void *newgdt, __u16 limit)
+{
+       unsigned char curgdt[6];
+
+       /* ia32 supports unaligned loads & stores */
+       (*(__u16 *)(curgdt)) = limit;
+       (*(__u32 *)(curgdt +2)) = (unsigned long)(newgdt);
+
+       __asm__ __volatile__ (
+               "lgdt %0\n"
+               : "=m" (curgdt)
+               );
+};
+
+static void load_segments(void)
+{
+#define __STR(X) #X
+#define STR(X) __STR(X)
+
+       __asm__ __volatile__ (
+               "\tljmp $"STR(__KERNEL_CS)",$1f\n"
+               "\t1:\n"
+               "\tmovl $"STR(__KERNEL_DS)",%eax\n"
+               "\tmovl %eax,%ds\n"
+               "\tmovl %eax,%es\n"
+               "\tmovl %eax,%fs\n"
+               "\tmovl %eax,%gs\n"
+               "\tmovl %eax,%ss\n"
+               );
+#undef STR
+#undef __STR
+}
+
+typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)(
+                                       unsigned long indirection_page,
+                                       unsigned long reboot_code_buffer,
+                                       unsigned long start_address,
+                                       unsigned int has_pae) ATTRIB_NORET;
+
+const extern unsigned char relocate_new_kernel[];
+extern void relocate_new_kernel_end(void);
+const extern unsigned int relocate_new_kernel_size;
+
+/*
+ * A architecture hook called to validate the
+ * proposed image and prepare the control pages
+ * as needed.  The pages for KEXEC_CONTROL_CODE_SIZE
+ * have been allocated, but the segments have yet
+ * been copied into the kernel.
+ *
+ * Do what every setup is needed on image and the
+ * reboot code buffer to allow us to avoid allocations
+ * later.
+ *
+ * Currently nothing.
+ */
+int machine_kexec_prepare(struct kimage *image)
+{
+       return 0;
+}
+
+/*
+ * Undo anything leftover by machine_kexec_prepare
+ * when an image is freed.
+ */
+void machine_kexec_cleanup(struct kimage *image)
+{
+}
+
+/*
+ * Do not allocate memory (or fail in any way) in machine_kexec().
+ * We are past the point of no return, committed to rebooting now.
+ */
+NORET_TYPE void machine_kexec(struct kimage *image)
+{
+       unsigned long page_list;
+       unsigned long reboot_code_buffer;
+
+       relocate_new_kernel_t rnk;
+
+       /* Interrupts aren't acceptable while we reboot */
+       local_irq_disable();
+
+       /* Compute some offsets */
+       reboot_code_buffer = page_to_pfn(image->control_code_page)
+                                                               << PAGE_SHIFT;
+       page_list = image->head;
+
+       /* Set up an identity mapping for the reboot_code_buffer */
+       identity_map_page(reboot_code_buffer);
+
+       /* copy it out */
+       memcpy((void *)reboot_code_buffer, relocate_new_kernel,
+                                               relocate_new_kernel_size);
+
+       /* The segment registers are funny things, they are
+        * automatically loaded from a table, in memory wherever you
+        * set them to a specific selector, but this table is never
+        * accessed again you set the segment to a different selector.
+        *
+        * The more common model is are caches where the behide
+        * the scenes work is done, but is also dropped at arbitrary
+        * times.
+        *
+        * I take advantage of this here by force loading the
+        * segments, before I zap the gdt with an invalid value.
+        */
+       load_segments();
+       /* The gdt & idt are now invalid.
+        * If you want to load them you must set up your own idt & gdt.
+        */
+       set_gdt(phys_to_virt(0),0);
+       set_idt(phys_to_virt(0),0);
+
+       /* now call it */
+       rnk = (relocate_new_kernel_t) reboot_code_buffer;
+       (*rnk)(page_list, reboot_code_buffer, image->start, cpu_has_pae);
+}
index 383a11600d2c35d4e940d5a3e8bb647accb45f6a..af917f609c7de00b3b959c28439aa48ebce09488 100644 (file)
@@ -67,7 +67,6 @@ unsigned long mp_lapic_addr;
 
 /* Processor that is doing the boot up */
 unsigned int boot_cpu_physical_apicid = -1U;
-unsigned int boot_cpu_logical_apicid = -1U;
 /* Internal processor count */
 static unsigned int __initdata num_processors;
 
@@ -180,7 +179,6 @@ static void __init MP_processor_info (struct mpc_config_processor *m)
        if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
                Dprintk("    Bootup CPU\n");
                boot_cpu_physical_apicid = m->mpc_apicid;
-               boot_cpu_logical_apicid = apicid;
        }
 
        if (num_processors >= NR_CPUS) {
index aea2ce1145df7327161acdf42230c1559fa27323..ba243a4cc119fd35774bfc26e3fb3587bb31c741 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <stdarg.h>
 
+#include <linux/cpu.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
@@ -55,6 +56,9 @@
 #include <linux/irq.h>
 #include <linux/err.h>
 
+#include <asm/tlbflush.h>
+#include <asm/cpu.h>
+
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
 static int hlt_counter;
@@ -143,14 +147,42 @@ static void poll_idle (void)
        }
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+#include <asm/nmi.h>
+/* We don't actually take CPU down, just spin without interrupts. */
+static inline void play_dead(void)
+{
+       /* This must be done before dead CPU ack */
+       cpu_exit_clear();
+       wbinvd();
+       mb();
+       /* Ack it */
+       __get_cpu_var(cpu_state) = CPU_DEAD;
+
+       /*
+        * With physical CPU hotplug, we should halt the cpu
+        */
+       local_irq_disable();
+       while (1)
+               __asm__ __volatile__("hlt":::"memory");
+}
+#else
+static inline void play_dead(void)
+{
+       BUG();
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 /*
  * The idle thread. There's no useful work to be
  * done, so just try to conserve power and have a
  * low exit latency (ie sit in a loop waiting for
  * somebody to say that they'd like to reschedule)
  */
-void cpu_idle (void)
+void cpu_idle(void)
 {
+       int cpu = raw_smp_processor_id();
+
        /* endless idle loop with no priority at all */
        while (1) {
                while (!need_resched()) {
@@ -165,6 +197,9 @@ void cpu_idle (void)
                        if (!idle)
                                idle = default_idle;
 
+                       if (cpu_is_offline(cpu))
+                               play_dead();
+
                        __get_cpu_var(irq_stat).idle_timestamp = jiffies;
                        idle();
                }
@@ -223,7 +258,7 @@ static void mwait_idle(void)
        }
 }
 
-void __init select_idle_routine(const struct cpuinfo_x86 *c)
+void __devinit select_idle_routine(const struct cpuinfo_x86 *c)
 {
        if (cpu_has(c, X86_FEATURE_MWAIT)) {
                printk("monitor/mwait feature present.\n");
@@ -581,6 +616,33 @@ handle_io_bitmap(struct thread_struct *next, struct tss_struct *tss)
        tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
 }
 
+/*
+ * This function selects if the context switch from prev to next
+ * has to tweak the TSC disable bit in the cr4.
+ */
+static inline void disable_tsc(struct task_struct *prev_p,
+                              struct task_struct *next_p)
+{
+       struct thread_info *prev, *next;
+
+       /*
+        * gcc should eliminate the ->thread_info dereference if
+        * has_secure_computing returns 0 at compile time (SECCOMP=n).
+        */
+       prev = prev_p->thread_info;
+       next = next_p->thread_info;
+
+       if (has_secure_computing(prev) || has_secure_computing(next)) {
+               /* slow path here */
+               if (has_secure_computing(prev) &&
+                   !has_secure_computing(next)) {
+                       write_cr4(read_cr4() & ~X86_CR4_TSD);
+               } else if (!has_secure_computing(prev) &&
+                          has_secure_computing(next))
+                       write_cr4(read_cr4() | X86_CR4_TSD);
+       }
+}
+
 /*
  *     switch_to(x,yn) should switch tasks from x to y.
  *
@@ -660,6 +722,8 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
        if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr))
                handle_io_bitmap(next, tss);
 
+       disable_tsc(prev_p, next_p);
+
        return prev_p;
 }
 
index db912209a8d312d5ebec4b6c155399b764d3cf82..b3e584849961e79872a92b6518ab15c47071e797 100644 (file)
@@ -26,7 +26,6 @@ static int reboot_mode;
 static int reboot_thru_bios;
 
 #ifdef CONFIG_SMP
-int reboot_smp = 0;
 static int reboot_cpu = -1;
 /* shamelessly grabbed from lib/vsprintf.c for readability */
 #define is_digit(c)    ((c) >= '0' && (c) <= '9')
@@ -49,7 +48,6 @@ static int __init reboot_setup(char *str)
                        break;
 #ifdef CONFIG_SMP
                case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
-                       reboot_smp = 1;
                        if (is_digit(*(str+1))) {
                                reboot_cpu = (int) (*(str+1) - '0');
                                if (is_digit(*(str+2))) 
@@ -88,33 +86,9 @@ static int __init set_bios_reboot(struct dmi_system_id *d)
        return 0;
 }
 
-/*
- * Some machines require the "reboot=s"  commandline option, this quirk makes that automatic.
- */
-static int __init set_smp_reboot(struct dmi_system_id *d)
-{
-#ifdef CONFIG_SMP
-       if (!reboot_smp) {
-               reboot_smp = 1;
-               printk(KERN_INFO "%s series board detected. Selecting SMP-method for reboots.\n", d->ident);
-       }
-#endif
-       return 0;
-}
-
-/*
- * Some machines require the "reboot=b,s"  commandline option, this quirk makes that automatic.
- */
-static int __init set_smp_bios_reboot(struct dmi_system_id *d)
-{
-       set_smp_reboot(d);
-       set_bios_reboot(d);
-       return 0;
-}
-
 static struct dmi_system_id __initdata reboot_dmi_table[] = {
        {       /* Handle problems with rebooting on Dell 1300's */
-               .callback = set_smp_bios_reboot,
+               .callback = set_bios_reboot,
                .ident = "Dell PowerEdge 1300",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
@@ -301,41 +275,32 @@ void machine_real_restart(unsigned char *code, int length)
 EXPORT_SYMBOL(machine_real_restart);
 #endif
 
-void machine_restart(char * __unused)
+void machine_shutdown(void)
 {
 #ifdef CONFIG_SMP
-       int cpuid;
-       
-       cpuid = GET_APIC_ID(apic_read(APIC_ID));
-
-       if (reboot_smp) {
-
-               /* check to see if reboot_cpu is valid 
-                  if its not, default to the BSP */
-               if ((reboot_cpu == -1) ||  
-                     (reboot_cpu > (NR_CPUS -1))  || 
-                     !physid_isset(cpuid, phys_cpu_present_map))
-                       reboot_cpu = boot_cpu_physical_apicid;
-
-               reboot_smp = 0;  /* use this as a flag to only go through this once*/
-               /* re-run this function on the other CPUs
-                  it will fall though this section since we have 
-                  cleared reboot_smp, and do the reboot if it is the
-                  correct CPU, otherwise it halts. */
-               if (reboot_cpu != cpuid)
-                       smp_call_function((void *)machine_restart , NULL, 1, 0);
+       int reboot_cpu_id;
+
+       /* The boot cpu is always logical cpu 0 */
+       reboot_cpu_id = 0;
+
+       /* See if there has been given a command line override */
+       if ((reboot_cpu_id != -1) && (reboot_cpu < NR_CPUS) &&
+               cpu_isset(reboot_cpu, cpu_online_map)) {
+               reboot_cpu_id = reboot_cpu;
        }
 
-       /* if reboot_cpu is still -1, then we want a tradional reboot, 
-          and if we are not running on the reboot_cpu,, halt */
-       if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
-               for (;;)
-               __asm__ __volatile__ ("hlt");
+       /* Make certain the cpu I'm rebooting on is online */
+       if (!cpu_isset(reboot_cpu_id, cpu_online_map)) {
+               reboot_cpu_id = smp_processor_id();
        }
-       /*
-        * Stop all CPUs and turn off local APICs and the IO-APIC, so
-        * other OSs see a clean IRQ state.
+
+       /* Make certain I only run on the appropriate processor */
+       set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
+
+       /* O.K. Now that I'm on the appropriate processor, stop
+        * all of the others, and disable their local APICs.
         */
+
        smp_send_stop();
 #endif /* CONFIG_SMP */
 
@@ -344,6 +309,11 @@ void machine_restart(char * __unused)
 #ifdef CONFIG_X86_IO_APIC
        disable_IO_APIC();
 #endif
+}
+
+void machine_restart(char * __unused)
+{
+       machine_shutdown();
 
        if (!reboot_thru_bios) {
                if (efi_enabled) {
diff --git a/arch/i386/kernel/relocate_kernel.S b/arch/i386/kernel/relocate_kernel.S
new file mode 100644 (file)
index 0000000..d312616
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * relocate_kernel.S - put the kernel image in place to boot
+ * Copyright (C) 2002-2004 Eric Biederman  <ebiederm@xmission.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <linux/linkage.h>
+
+       /*
+        * Must be relocatable PIC code callable as a C function, that once
+        * it starts can not use the previous processes stack.
+        */
+       .globl relocate_new_kernel
+relocate_new_kernel:
+       /* read the arguments and say goodbye to the stack */
+       movl  4(%esp), %ebx /* page_list */
+       movl  8(%esp), %ebp /* reboot_code_buffer */
+       movl  12(%esp), %edx /* start address */
+       movl  16(%esp), %ecx /* cpu_has_pae */
+
+       /* zero out flags, and disable interrupts */
+       pushl $0
+       popfl
+
+       /* set a new stack at the bottom of our page... */
+       lea   4096(%ebp), %esp
+
+       /* store the parameters back on the stack */
+       pushl   %edx /* store the start address */
+
+       /* Set cr0 to a known state:
+        * 31 0 == Paging disabled
+        * 18 0 == Alignment check disabled
+        * 16 0 == Write protect disabled
+        * 3  0 == No task switch
+        * 2  0 == Don't do FP software emulation.
+        * 0  1 == Proctected mode enabled
+        */
+       movl    %cr0, %eax
+       andl    $~((1<<31)|(1<<18)|(1<<16)|(1<<3)|(1<<2)), %eax
+       orl     $(1<<0), %eax
+       movl    %eax, %cr0
+
+       /* clear cr4 if applicable */
+       testl   %ecx, %ecx
+       jz      1f
+       /* Set cr4 to a known state:
+        * Setting everything to zero seems safe.
+        */
+       movl    %cr4, %eax
+       andl    $0, %eax
+       movl    %eax, %cr4
+
+       jmp 1f
+1:
+
+       /* Flush the TLB (needed?) */
+       xorl    %eax, %eax
+       movl    %eax, %cr3
+
+       /* Do the copies */
+       movl    %ebx, %ecx
+       jmp     1f
+
+0:     /* top, read another word from the indirection page */
+       movl    (%ebx), %ecx
+       addl    $4, %ebx
+1:
+       testl   $0x1,   %ecx  /* is it a destination page */
+       jz      2f
+       movl    %ecx,   %edi
+       andl    $0xfffff000, %edi
+       jmp     0b
+2:
+       testl   $0x2,   %ecx  /* is it an indirection page */
+       jz      2f
+       movl    %ecx,   %ebx
+       andl    $0xfffff000, %ebx
+       jmp     0b
+2:
+       testl   $0x4,   %ecx /* is it the done indicator */
+       jz      2f
+       jmp     3f
+2:
+       testl   $0x8,   %ecx /* is it the source indicator */
+       jz      0b           /* Ignore it otherwise */
+       movl    %ecx,   %esi /* For every source page do a copy */
+       andl    $0xfffff000, %esi
+
+       movl    $1024, %ecx
+       rep ; movsl
+       jmp     0b
+
+3:
+
+       /* To be certain of avoiding problems with self-modifying code
+        * I need to execute a serializing instruction here.
+        * So I flush the TLB, it's handy, and not processor dependent.
+        */
+       xorl    %eax, %eax
+       movl    %eax, %cr3
+
+       /* set all of the registers to known values */
+       /* leave %esp alone */
+
+       xorl    %eax, %eax
+       xorl    %ebx, %ebx
+       xorl    %ecx, %ecx
+       xorl    %edx, %edx
+       xorl    %esi, %esi
+       xorl    %edi, %edi
+       xorl    %ebp, %ebp
+       ret
+relocate_new_kernel_end:
+
+       .globl relocate_new_kernel_size
+relocate_new_kernel_size:
+       .long relocate_new_kernel_end - relocate_new_kernel
index 30406fd0b64c56e1f3586f398e3f18183604c5bf..7306353c520ec6dc4c74a6cac328f8b5ba446d64 100644 (file)
 #include <linux/init.h>
 #include <linux/edd.h>
 #include <linux/nodemask.h>
+#include <linux/kexec.h>
+#include <linux/crash_dump.h>
+
 #include <video/edid.h>
+
+#include <asm/apic.h>
 #include <asm/e820.h>
 #include <asm/mpspec.h>
 #include <asm/setup.h>
 #include "setup_arch_pre.h"
 #include <bios_ebda.h>
 
+/* Forward Declaration. */
+void __init find_max_pfn(void);
+
 /* This value is set up by the early boot code to point to the value
    immediately after the boot time page tables.  It contains a *physical*
    address, and must not be in the .bss segment! */
 unsigned long init_pg_tables_end __initdata = ~0UL;
 
-int disable_pse __initdata = 0;
+int disable_pse __devinitdata = 0;
 
 /*
  * Machine setup..
@@ -732,6 +740,15 @@ static void __init parse_cmdline_early (char ** cmdline_p)
                        if (to != command_line)
                                to--;
                        if (!memcmp(from+7, "exactmap", 8)) {
+#ifdef CONFIG_CRASH_DUMP
+                               /* If we are doing a crash dump, we
+                                * still need to know the real mem
+                                * size before original memory map is
+                                * reset.
+                                */
+                               find_max_pfn();
+                               saved_max_pfn = max_pfn;
+#endif
                                from += 8+7;
                                e820.nr_map = 0;
                                userdef = 1;
@@ -835,6 +852,44 @@ static void __init parse_cmdline_early (char ** cmdline_p)
 #endif /* CONFIG_X86_LOCAL_APIC */
 #endif /* CONFIG_ACPI_BOOT */
 
+#ifdef CONFIG_X86_LOCAL_APIC
+               /* enable local APIC */
+               else if (!memcmp(from, "lapic", 5))
+                       lapic_enable();
+
+               /* disable local APIC */
+               else if (!memcmp(from, "nolapic", 6))
+                       lapic_disable();
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_KEXEC
+               /* crashkernel=size@addr specifies the location to reserve for
+                * a crash kernel.  By reserving this memory we guarantee
+                * that linux never set's it up as a DMA target.
+                * Useful for holding code to do something appropriate
+                * after a kernel panic.
+                */
+               else if (!memcmp(from, "crashkernel=", 12)) {
+                       unsigned long size, base;
+                       size = memparse(from+12, &from);
+                       if (*from == '@') {
+                               base = memparse(from+1, &from);
+                               /* FIXME: Do I want a sanity check
+                                * to validate the memory range?
+                                */
+                               crashk_res.start = base;
+                               crashk_res.end   = base + size - 1;
+                       }
+               }
+#endif
+#ifdef CONFIG_CRASH_DUMP
+               /* elfcorehdr= specifies the location of elf core header
+                * stored by the crashed kernel.
+                */
+               else if (!memcmp(from, "elfcorehdr=", 11))
+                       elfcorehdr_addr = memparse(from+11, &from);
+#endif
+
                /*
                 * highmem=size forces highmem to be exactly 'size' bytes.
                 * This works even on boxes that have no highmem otherwise.
@@ -1113,8 +1168,8 @@ void __init setup_bootmem_allocator(void)
         * the (very unlikely) case of us accidentally initializing the
         * bootmem allocator with an invalid RAM area.
         */
-       reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(min_low_pfn) +
-                        bootmap_size + PAGE_SIZE-1) - (HIGH_MEMORY));
+       reserve_bootmem(__PHYSICAL_START, (PFN_PHYS(min_low_pfn) +
+                        bootmap_size + PAGE_SIZE-1) - (__PHYSICAL_START));
 
        /*
         * reserve physical page 0 - it's a special BIOS page on many boxes,
@@ -1170,6 +1225,11 @@ void __init setup_bootmem_allocator(void)
                }
        }
 #endif
+#ifdef CONFIG_KEXEC
+       if (crashk_res.start != crashk_res.end)
+               reserve_bootmem(crashk_res.start,
+                       crashk_res.end - crashk_res.start + 1);
+#endif
 }
 
 /*
@@ -1223,6 +1283,9 @@ legacy_init_iomem_resources(struct resource *code_resource, struct resource *dat
                         */
                        request_resource(res, code_resource);
                        request_resource(res, data_resource);
+#ifdef CONFIG_KEXEC
+                       request_resource(res, &crashk_res);
+#endif
                }
        }
 }
index b9b8f4e20fad6e79fbc5acef91115415cd3aaace..89ef7adc63a4be19611f57b580fddf46259dbd73 100644 (file)
@@ -608,10 +608,8 @@ int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
        if (!user_mode(regs))
                return 1;
 
-       if (current->flags & PF_FREEZE) {
-               refrigerator(0);
+       if (try_to_freeze())
                goto no_signal;
-       }
 
        if (!oldset)
                oldset = &current->blocked;
index 68be7d0c7238c1feaf4eff4856fac04f111ae0dd..cec4bde67161254106267d6c6e4715aaeea93a3a 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/cache.h>
 #include <linux/interrupt.h>
+#include <linux/cpu.h>
 #include <linux/module.h>
 
 #include <asm/mtrr.h>
@@ -164,7 +165,7 @@ void send_IPI_mask_bitmask(cpumask_t cpumask, int vector)
        unsigned long flags;
 
        local_irq_save(flags);
-               
+       WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]);
        /*
         * Wait for idle.
         */
@@ -346,21 +347,21 @@ out:
 static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
                                                unsigned long va)
 {
-       cpumask_t tmp;
        /*
         * A couple of (to be removed) sanity checks:
         *
-        * - we do not send IPIs to not-yet booted CPUs.
         * - current CPU must not be in mask
         * - mask must exist :)
         */
        BUG_ON(cpus_empty(cpumask));
-
-       cpus_and(tmp, cpumask, cpu_online_map);
-       BUG_ON(!cpus_equal(cpumask, tmp));
        BUG_ON(cpu_isset(smp_processor_id(), cpumask));
        BUG_ON(!mm);
 
+       /* If a CPU which we ran on has gone down, OK. */
+       cpus_and(cpumask, cpumask, cpu_online_map);
+       if (cpus_empty(cpumask))
+               return;
+
        /*
         * i'm not happy about this global shared spinlock in the
         * MM hot path, but we'll see how contended it is.
@@ -476,6 +477,7 @@ void flush_tlb_all(void)
  */
 void smp_send_reschedule(int cpu)
 {
+       WARN_ON(cpu_is_offline(cpu));
        send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
 }
 
@@ -493,6 +495,16 @@ struct call_data_struct {
        int wait;
 };
 
+void lock_ipi_call_lock(void)
+{
+       spin_lock_irq(&call_lock);
+}
+
+void unlock_ipi_call_lock(void)
+{
+       spin_unlock_irq(&call_lock);
+}
+
 static struct call_data_struct * call_data;
 
 /*
@@ -516,10 +528,15 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
  */
 {
        struct call_data_struct data;
-       int cpus = num_online_cpus()-1;
+       int cpus;
 
-       if (!cpus)
+       /* Holding any lock stops cpus from going down. */
+       spin_lock(&call_lock);
+       cpus = num_online_cpus() - 1;
+       if (!cpus) {
+               spin_unlock(&call_lock);
                return 0;
+       }
 
        /* Can deadlock when called with interrupts disabled */
        WARN_ON(irqs_disabled());
@@ -531,7 +548,6 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
        if (wait)
                atomic_set(&data.finished, 0);
 
-       spin_lock(&call_lock);
        call_data = &data;
        mb();
        
index c20d96d5c15c738709cc4667233a0e0945b093a0..d66bf489a2e90782044a09e2562fb84d06d893a0 100644 (file)
@@ -44,6 +44,9 @@
 #include <linux/smp_lock.h>
 #include <linux/irq.h>
 #include <linux/bootmem.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/percpu.h>
 
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h>
 #include <smpboot_hooks.h>
 
 /* Set if we find a B stepping CPU */
-static int __initdata smp_b_stepping;
+static int __devinitdata smp_b_stepping;
 
 /* Number of siblings per CPU package */
 int smp_num_siblings = 1;
 #ifdef CONFIG_X86_HT
 EXPORT_SYMBOL(smp_num_siblings);
 #endif
-int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
+
+/* Package ID of each logical CPU */
+int phys_proc_id[NR_CPUS] = {[0 ... NR_CPUS-1] = BAD_APICID};
 EXPORT_SYMBOL(phys_proc_id);
-int cpu_core_id[NR_CPUS]; /* Core ID of each logical CPU */
+
+/* Core ID of each logical CPU */
+int cpu_core_id[NR_CPUS] = {[0 ... NR_CPUS-1] = BAD_APICID};
 EXPORT_SYMBOL(cpu_core_id);
 
+cpumask_t cpu_sibling_map[NR_CPUS];
+EXPORT_SYMBOL(cpu_sibling_map);
+
+cpumask_t cpu_core_map[NR_CPUS];
+EXPORT_SYMBOL(cpu_core_map);
+
 /* bitmap of online cpus */
 cpumask_t cpu_online_map;
 EXPORT_SYMBOL(cpu_online_map);
@@ -77,6 +90,12 @@ cpumask_t cpu_callout_map;
 EXPORT_SYMBOL(cpu_callout_map);
 static cpumask_t smp_commenced_mask;
 
+/* TSC's upper 32 bits can't be written in eariler CPU (before prescott), there
+ * is no way to resync one AP against BP. TBD: for prescott and above, we
+ * should use IA64's algorithm
+ */
+static int __devinitdata tsc_sync_disabled;
+
 /* Per CPU bogomips and other parameters */
 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
 EXPORT_SYMBOL(cpu_data);
@@ -96,13 +115,16 @@ static int trampoline_exec;
 
 static void map_cpu_to_logical_apicid(void);
 
+/* State of each CPU. */
+DEFINE_PER_CPU(int, cpu_state) = { 0 };
+
 /*
  * Currently trivial. Write the real->protected mode
  * bootstrap into the page concerned. The caller
  * has made sure it's suitably aligned.
  */
 
-static unsigned long __init setup_trampoline(void)
+static unsigned long __devinit setup_trampoline(void)
 {
        memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data);
        return virt_to_phys(trampoline_base);
@@ -132,7 +154,7 @@ void __init smp_alloc_memory(void)
  * a given CPU
  */
 
-static void __init smp_store_cpu_info(int id)
+static void __devinit smp_store_cpu_info(int id)
 {
        struct cpuinfo_x86 *c = cpu_data + id;
 
@@ -326,7 +348,7 @@ extern void calibrate_delay(void);
 
 static atomic_t init_deasserted;
 
-static void __init smp_callin(void)
+static void __devinit smp_callin(void)
 {
        int cpuid, phys_id;
        unsigned long timeout;
@@ -411,16 +433,48 @@ static void __init smp_callin(void)
        /*
         *      Synchronize the TSC with the BP
         */
-       if (cpu_has_tsc && cpu_khz)
+       if (cpu_has_tsc && cpu_khz && !tsc_sync_disabled)
                synchronize_tsc_ap();
 }
 
 static int cpucount;
 
+static inline void
+set_cpu_sibling_map(int cpu)
+{
+       int i;
+
+       if (smp_num_siblings > 1) {
+               for (i = 0; i < NR_CPUS; i++) {
+                       if (!cpu_isset(i, cpu_callout_map))
+                               continue;
+                       if (cpu_core_id[cpu] == cpu_core_id[i]) {
+                               cpu_set(i, cpu_sibling_map[cpu]);
+                               cpu_set(cpu, cpu_sibling_map[i]);
+                       }
+               }
+       } else {
+               cpu_set(cpu, cpu_sibling_map[cpu]);
+       }
+
+       if (current_cpu_data.x86_num_cores > 1) {
+               for (i = 0; i < NR_CPUS; i++) {
+                       if (!cpu_isset(i, cpu_callout_map))
+                               continue;
+                       if (phys_proc_id[cpu] == phys_proc_id[i]) {
+                               cpu_set(i, cpu_core_map[cpu]);
+                               cpu_set(cpu, cpu_core_map[i]);
+                       }
+               }
+       } else {
+               cpu_core_map[cpu] = cpu_sibling_map[cpu];
+       }
+}
+
 /*
  * Activate a secondary processor.
  */
-static void __init start_secondary(void *unused)
+static void __devinit start_secondary(void *unused)
 {
        /*
         * Dont put anything before smp_callin(), SMP
@@ -443,7 +497,23 @@ static void __init start_secondary(void *unused)
         * the local TLBs too.
         */
        local_flush_tlb();
+
+       /* This must be done before setting cpu_online_map */
+       set_cpu_sibling_map(raw_smp_processor_id());
+       wmb();
+
+       /*
+        * We need to hold call_lock, so there is no inconsistency
+        * between the time smp_call_function() determines number of
+        * IPI receipients, and the time when the determination is made
+        * for which cpus receive the IPI. Holding this
+        * lock helps us to not include this cpu in a currently in progress
+        * smp_call_function().
+        */
+       lock_ipi_call_lock();
        cpu_set(smp_processor_id(), cpu_online_map);
+       unlock_ipi_call_lock();
+       per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
 
        /* We can take interrupts now: we're officially "up". */
        local_irq_enable();
@@ -458,7 +528,7 @@ static void __init start_secondary(void *unused)
  * from the task structure
  * This function must not return.
  */
-void __init initialize_secondary(void)
+void __devinit initialize_secondary(void)
 {
        /*
         * We don't actually need to load the full TSS,
@@ -572,7 +642,7 @@ static inline void __inquire_remote_apic(int apicid)
  * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
  * won't ... remember to clear down the APIC, etc later.
  */
-static int __init
+static int __devinit
 wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
 {
        unsigned long send_status = 0, accept_status = 0;
@@ -618,7 +688,7 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
 #endif /* WAKE_SECONDARY_VIA_NMI */
 
 #ifdef WAKE_SECONDARY_VIA_INIT
-static int __init
+static int __devinit
 wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
 {
        unsigned long send_status = 0, accept_status = 0;
@@ -753,8 +823,43 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
 #endif /* WAKE_SECONDARY_VIA_INIT */
 
 extern cpumask_t cpu_initialized;
+static inline int alloc_cpu_id(void)
+{
+       cpumask_t       tmp_map;
+       int cpu;
+       cpus_complement(tmp_map, cpu_present_map);
+       cpu = first_cpu(tmp_map);
+       if (cpu >= NR_CPUS)
+               return -ENODEV;
+       return cpu;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static struct task_struct * __devinitdata cpu_idle_tasks[NR_CPUS];
+static inline struct task_struct * alloc_idle_task(int cpu)
+{
+       struct task_struct *idle;
+
+       if ((idle = cpu_idle_tasks[cpu]) != NULL) {
+               /* initialize thread_struct.  we really want to avoid destroy
+                * idle tread
+                */
+               idle->thread.esp = (unsigned long)(((struct pt_regs *)
+                       (THREAD_SIZE + (unsigned long) idle->thread_info)) - 1);
+               init_idle(idle, cpu);
+               return idle;
+       }
+       idle = fork_idle(cpu);
+
+       if (!IS_ERR(idle))
+               cpu_idle_tasks[cpu] = idle;
+       return idle;
+}
+#else
+#define alloc_idle_task(cpu) fork_idle(cpu)
+#endif
 
-static int __init do_boot_cpu(int apicid)
+static int __devinit do_boot_cpu(int apicid, int cpu)
 /*
  * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
  * (ie clustered apic addressing mode), this is a LOGICAL apic ID.
@@ -763,16 +868,17 @@ static int __init do_boot_cpu(int apicid)
 {
        struct task_struct *idle;
        unsigned long boot_error;
-       int timeout, cpu;
+       int timeout;
        unsigned long start_eip;
        unsigned short nmi_high = 0, nmi_low = 0;
 
-       cpu = ++cpucount;
+       ++cpucount;
+
        /*
         * We can't use kernel_thread since we must avoid to
         * reschedule the child.
         */
-       idle = fork_idle(cpu);
+       idle = alloc_idle_task(cpu);
        if (IS_ERR(idle))
                panic("failed fork for CPU %d", cpu);
        idle->thread.eip = (unsigned long) start_secondary;
@@ -839,13 +945,16 @@ static int __init do_boot_cpu(int apicid)
                        inquire_remote_apic(apicid);
                }
        }
-       x86_cpu_to_apicid[cpu] = apicid;
+
        if (boot_error) {
                /* Try to put things back the way they were before ... */
                unmap_cpu_to_logical_apicid(cpu);
                cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */
                cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */
                cpucount--;
+       } else {
+               x86_cpu_to_apicid[cpu] = apicid;
+               cpu_set(cpu, cpu_present_map);
        }
 
        /* mark "stuck" area as not stuck */
@@ -854,6 +963,75 @@ static int __init do_boot_cpu(int apicid)
        return boot_error;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+void cpu_exit_clear(void)
+{
+       int cpu = raw_smp_processor_id();
+
+       idle_task_exit();
+
+       cpucount --;
+       cpu_uninit();
+       irq_ctx_exit(cpu);
+
+       cpu_clear(cpu, cpu_callout_map);
+       cpu_clear(cpu, cpu_callin_map);
+       cpu_clear(cpu, cpu_present_map);
+
+       cpu_clear(cpu, smp_commenced_mask);
+       unmap_cpu_to_logical_apicid(cpu);
+}
+
+struct warm_boot_cpu_info {
+       struct completion *complete;
+       int apicid;
+       int cpu;
+};
+
+static void __devinit do_warm_boot_cpu(void *p)
+{
+       struct warm_boot_cpu_info *info = p;
+       do_boot_cpu(info->apicid, info->cpu);
+       complete(info->complete);
+}
+
+int __devinit smp_prepare_cpu(int cpu)
+{
+       DECLARE_COMPLETION(done);
+       struct warm_boot_cpu_info info;
+       struct work_struct task;
+       int     apicid, ret;
+
+       lock_cpu_hotplug();
+       apicid = x86_cpu_to_apicid[cpu];
+       if (apicid == BAD_APICID) {
+               ret = -ENODEV;
+               goto exit;
+       }
+
+       info.complete = &done;
+       info.apicid = apicid;
+       info.cpu = cpu;
+       INIT_WORK(&task, do_warm_boot_cpu, &info);
+
+       tsc_sync_disabled = 1;
+
+       /* init low mem mapping */
+       memcpy(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+                       sizeof(swapper_pg_dir[0]) * KERNEL_PGD_PTRS);
+       flush_tlb_all();
+       schedule_work(&task);
+       wait_for_completion(&done);
+
+       tsc_sync_disabled = 0;
+       zap_low_mappings();
+       ret = 0;
+exit:
+       unlock_cpu_hotplug();
+       return ret;
+}
+#endif
+
 static void smp_tune_scheduling (void)
 {
        unsigned long cachesize;       /* kB   */
@@ -895,13 +1073,6 @@ void *xquad_portio;
 EXPORT_SYMBOL(xquad_portio);
 #endif
 
-cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
-#ifdef CONFIG_X86_HT
-EXPORT_SYMBOL(cpu_sibling_map);
-#endif
-cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
-EXPORT_SYMBOL(cpu_core_map);
-
 static void __init smp_boot_cpus(unsigned int max_cpus)
 {
        int apicid, cpu, bit, kicked;
@@ -1013,7 +1184,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
                if (max_cpus <= cpucount+1)
                        continue;
 
-               if (do_boot_cpu(apicid))
+               if (((cpu = alloc_cpu_id()) <= 0) || do_boot_cpu(apicid, cpu))
                        printk("CPU #%d not responding - cannot use it.\n",
                                                                apicid);
                else
@@ -1065,44 +1236,8 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
                cpus_clear(cpu_core_map[cpu]);
        }
 
-       for (cpu = 0; cpu < NR_CPUS; cpu++) {
-               struct cpuinfo_x86 *c = cpu_data + cpu;
-               int siblings = 0;
-               int i;
-               if (!cpu_isset(cpu, cpu_callout_map))
-                       continue;
-
-               if (smp_num_siblings > 1) {
-                       for (i = 0; i < NR_CPUS; i++) {
-                               if (!cpu_isset(i, cpu_callout_map))
-                                       continue;
-                               if (cpu_core_id[cpu] == cpu_core_id[i]) {
-                                       siblings++;
-                                       cpu_set(i, cpu_sibling_map[cpu]);
-                               }
-                       }
-               } else {
-                       siblings++;
-                       cpu_set(cpu, cpu_sibling_map[cpu]);
-               }
-
-               if (siblings != smp_num_siblings) {
-                       printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings);
-                       smp_num_siblings = siblings;
-               }
-
-               if (c->x86_num_cores > 1) {
-                       for (i = 0; i < NR_CPUS; i++) {
-                               if (!cpu_isset(i, cpu_callout_map))
-                                       continue;
-                               if (phys_proc_id[cpu] == phys_proc_id[i]) {
-                                       cpu_set(i, cpu_core_map[cpu]);
-                               }
-                       }
-               } else {
-                       cpu_core_map[cpu] = cpu_sibling_map[cpu];
-               }
-       }
+       cpu_set(0, cpu_sibling_map[0]);
+       cpu_set(0, cpu_core_map[0]);
 
        smpboot_setup_io_apic();
 
@@ -1119,6 +1254,9 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
    who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
+       smp_commenced_mask = cpumask_of_cpu(0);
+       cpu_callin_map = cpumask_of_cpu(0);
+       mb();
        smp_boot_cpus(max_cpus);
 }
 
@@ -1126,23 +1264,98 @@ void __devinit smp_prepare_boot_cpu(void)
 {
        cpu_set(smp_processor_id(), cpu_online_map);
        cpu_set(smp_processor_id(), cpu_callout_map);
+       cpu_set(smp_processor_id(), cpu_present_map);
+       per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
 }
 
-int __devinit __cpu_up(unsigned int cpu)
+#ifdef CONFIG_HOTPLUG_CPU
+static void
+remove_siblinginfo(int cpu)
 {
-       /* This only works at boot for x86.  See "rewrite" above. */
-       if (cpu_isset(cpu, smp_commenced_mask)) {
-               local_irq_enable();
-               return -ENOSYS;
+       int sibling;
+
+       for_each_cpu_mask(sibling, cpu_sibling_map[cpu])
+               cpu_clear(cpu, cpu_sibling_map[sibling]);
+       for_each_cpu_mask(sibling, cpu_core_map[cpu])
+               cpu_clear(cpu, cpu_core_map[sibling]);
+       cpus_clear(cpu_sibling_map[cpu]);
+       cpus_clear(cpu_core_map[cpu]);
+       phys_proc_id[cpu] = BAD_APICID;
+       cpu_core_id[cpu] = BAD_APICID;
+}
+
+int __cpu_disable(void)
+{
+       cpumask_t map = cpu_online_map;
+       int cpu = smp_processor_id();
+
+       /*
+        * Perhaps use cpufreq to drop frequency, but that could go
+        * into generic code.
+        *
+        * We won't take down the boot processor on i386 due to some
+        * interrupts only being able to be serviced by the BSP.
+        * Especially so if we're not using an IOAPIC   -zwane
+        */
+       if (cpu == 0)
+               return -EBUSY;
+
+       /* We enable the timer again on the exit path of the death loop */
+       disable_APIC_timer();
+       /* Allow any queued timer interrupts to get serviced */
+       local_irq_enable();
+       mdelay(1);
+       local_irq_disable();
+
+       remove_siblinginfo(cpu);
+
+       cpu_clear(cpu, map);
+       fixup_irqs(map);
+       /* It's now safe to remove this processor from the online map */
+       cpu_clear(cpu, cpu_online_map);
+       return 0;
+}
+
+void __cpu_die(unsigned int cpu)
+{
+       /* We don't do anything here: idle task is faking death itself. */
+       unsigned int i;
+
+       for (i = 0; i < 10; i++) {
+               /* They ack this in play_dead by setting CPU_DEAD */
+               if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
+                       printk ("CPU %d is now offline\n", cpu);
+                       return;
+               }
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(HZ/10);
        }
+       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 */
 
+int __devinit __cpu_up(unsigned int cpu)
+{
        /* In case one didn't come up */
        if (!cpu_isset(cpu, cpu_callin_map)) {
+               printk(KERN_DEBUG "skipping cpu%d, didn't come online\n", cpu);
                local_irq_enable();
                return -EIO;
        }
 
        local_irq_enable();
+       per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
        /* Unleash the CPU! */
        cpu_set(cpu, smp_commenced_mask);
        while (!cpu_isset(cpu, cpu_online_map))
@@ -1156,10 +1369,12 @@ void __init smp_cpus_done(unsigned int max_cpus)
        setup_ioapic_dest();
 #endif
        zap_low_mappings();
+#ifndef CONFIG_HOTPLUG_CPU
        /*
         * Disable executability of the SMP trampoline:
         */
        set_kernel_exec((unsigned long)trampoline_base, trampoline_exec);
+#endif
 }
 
 void __init smp_intr_init(void)
index d408afaf6495918b3591bbcda5dbcd5a95a34a36..3db9a04aec6ed3a96f34eeeffcd21c27242cbfef 100644 (file)
@@ -283,9 +283,11 @@ ENTRY(sys_call_table)
        .long sys_mq_timedreceive       /* 280 */
        .long sys_mq_notify
        .long sys_mq_getsetattr
-       .long sys_ni_syscall            /* reserved for kexec */
+       .long sys_kexec_load
        .long sys_waitid
        .long sys_ni_syscall            /* 285 */ /* available */
        .long sys_add_key
        .long sys_request_key
        .long sys_keyctl
+       .long sys_ioprio_set
+       .long sys_ioprio_get            /* 290 */
index 960d8bd137d0ce86b6b76ac22c3930bb2833711d..0bada1870bdf5691631e10558bf43cbb350691a1 100644 (file)
 
 extern asmlinkage void sysenter_entry(void);
 
-void enable_sep_cpu(void *info)
+void enable_sep_cpu(void)
 {
        int cpu = get_cpu();
        struct tss_struct *tss = &per_cpu(init_tss, cpu);
 
+       if (!boot_cpu_has(X86_FEATURE_SEP)) {
+               put_cpu();
+               return;
+       }
+
        tss->ss1 = __KERNEL_CS;
        tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss;
        wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
@@ -41,7 +46,7 @@ void enable_sep_cpu(void *info)
 extern const char vsyscall_int80_start, vsyscall_int80_end;
 extern const char vsyscall_sysenter_start, vsyscall_sysenter_end;
 
-static int __init sysenter_setup(void)
+int __init sysenter_setup(void)
 {
        void *page = (void *)get_zeroed_page(GFP_ATOMIC);
 
@@ -58,8 +63,5 @@ static int __init sysenter_setup(void)
               &vsyscall_sysenter_start,
               &vsyscall_sysenter_end - &vsyscall_sysenter_start);
 
-       on_each_cpu(enable_sep_cpu, NULL, 1, 1);
        return 0;
 }
-
-__initcall(sysenter_setup);
index e68d9fdb075962769a100f2eedce167187945463..2854c357377f18c8d98447e296dd63e3d877fb21 100644 (file)
@@ -68,7 +68,8 @@
 
 #include "io_ports.h"
 
-extern spinlock_t i8259A_lock;
+#include <asm/i8259.h>
+
 int pit_latch_buggy;              /* extern */
 
 #include "do_timer.h"
@@ -85,6 +86,8 @@ extern unsigned long wall_jiffies;
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL(rtc_lock);
 
+#include <asm/i8253.h>
+
 DEFINE_SPINLOCK(i8253_lock);
 EXPORT_SYMBOL(i8253_lock);
 
index 10a0cbb88e754e81cb01604bca90e989c5b9d50c..658c0629ba6aa9e9d2062cd9111ba14a3b888e0c 100644 (file)
@@ -50,7 +50,7 @@ static void hpet_writel(unsigned long d, unsigned long a)
  * comparator value and continue. Next tick can be caught by checking
  * for a change in the comparator value. Used in apic.c.
  */
-static void __init wait_hpet_tick(void)
+static void __devinit wait_hpet_tick(void)
 {
        unsigned int start_cmp_val, end_cmp_val;
 
index 37353bd318036f4f6d0dc4d00c5f1a7ea9c973e1..8163fe0cf1f0333dc59935ec5e4032aa8bab7a7a 100644 (file)
@@ -86,7 +86,7 @@ bad_ctc:
 #define CALIBRATE_CNT_HPET     (5 * hpet_tick)
 #define CALIBRATE_TIME_HPET    (5 * KERNEL_TICK_USEC)
 
-unsigned long __init calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr)
+unsigned long __devinit calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr)
 {
        unsigned long tsc_startlow, tsc_starthigh;
        unsigned long tsc_endlow, tsc_endhigh;
index f6f1206a11bb7ed9b2afc2c2714ef53b51157f57..13892a65c941b70ca77f51dcf88e607a018d821f 100644 (file)
@@ -17,9 +17,9 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/fixmap.h>
-#include "io_ports.h"
+#include <asm/i8253.h>
 
-extern spinlock_t i8253_lock;
+#include "io_ports.h"
 
 /* Number of usecs that the last interrupt was delayed */
 static int delay_at_last_interrupt;
index 967d5453cd0ece3742ce5d50f24385f8e40590fc..06de036a820c23d63395e559ac9db1f5daedc2a3 100644 (file)
@@ -15,9 +15,8 @@
 #include <asm/smp.h>
 #include <asm/io.h>
 #include <asm/arch_hooks.h>
+#include <asm/i8253.h>
 
-extern spinlock_t i8259A_lock;
-extern spinlock_t i8253_lock;
 #include "do_timer.h"
 #include "io_ports.h"
 
@@ -166,7 +165,6 @@ struct init_timer_opts __initdata timer_pit_init = {
 
 void setup_pit_timer(void)
 {
-       extern spinlock_t i8253_lock;
        unsigned long flags;
 
        spin_lock_irqsave(&i8253_lock, flags);
index 54c36b182021a3cbc0b9359b95581f499c522353..8f4e4d5bc560d58138f24ab514902f18a175bd57 100644 (file)
@@ -24,6 +24,7 @@
 #include "mach_timer.h"
 
 #include <asm/hpet.h>
+#include <asm/i8253.h>
 
 #ifdef CONFIG_HPET_TIMER
 static unsigned long hpet_usec_quotient;
@@ -33,9 +34,7 @@ static struct timer_opts timer_tsc;
 
 static inline void cpufreq_delayed_get(void);
 
-int tsc_disable __initdata = 0;
-
-extern spinlock_t i8253_lock;
+int tsc_disable __devinitdata = 0;
 
 static int use_tsc;
 /* Number of usecs that the last interrupt was delayed */
index e4d4e2162c7a3873d36f5d0e64c451c96852889b..a61f33d06ea34313b9a36a271d9fd69f2b2034db 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/ptrace.h>
 #include <linux/utsname.h>
 #include <linux/kprobes.h>
+#include <linux/kexec.h>
 
 #ifdef CONFIG_EISA
 #include <linux/ioport.h>
@@ -234,22 +235,22 @@ void show_registers(struct pt_regs *regs)
         * time of the fault..
         */
        if (in_kernel) {
-               u8 *eip;
+               u8 __user *eip;
 
                printk("\nStack: ");
                show_stack(NULL, (unsigned long*)esp);
 
                printk("Code: ");
 
-               eip = (u8 *)regs->eip - 43;
+               eip = (u8 __user *)regs->eip - 43;
                for (i = 0; i < 64; i++, eip++) {
                        unsigned char c;
 
-                       if (eip < (u8 *)PAGE_OFFSET || __get_user(c, eip)) {
+                       if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) {
                                printk(" Bad EIP value.");
                                break;
                        }
-                       if (eip == (u8 *)regs->eip)
+                       if (eip == (u8 __user *)regs->eip)
                                printk("<%02x> ", c);
                        else
                                printk("%02x ", c);
@@ -273,13 +274,13 @@ static void handle_BUG(struct pt_regs *regs)
 
        if (eip < PAGE_OFFSET)
                goto no_bug;
-       if (__get_user(ud2, (unsigned short *)eip))
+       if (__get_user(ud2, (unsigned short __user *)eip))
                goto no_bug;
        if (ud2 != 0x0b0f)
                goto no_bug;
-       if (__get_user(line, (unsigned short *)(eip + 2)))
+       if (__get_user(line, (unsigned short __user *)(eip + 2)))
                goto bug;
-       if (__get_user(file, (char **)(eip + 4)) ||
+       if (__get_user(file, (char * __user *)(eip + 4)) ||
                (unsigned long)file < PAGE_OFFSET || __get_user(c, file))
                file = "<bad filename>";
 
@@ -294,6 +295,9 @@ bug:
        printk("Kernel BUG\n");
 }
 
+/* This is gone through when something in the kernel
+ * has done something bad and is about to be terminated.
+*/
 void die(const char * str, struct pt_regs * regs, long err)
 {
        static struct {
@@ -341,6 +345,10 @@ void die(const char * str, struct pt_regs * regs, long err)
        bust_spinlocks(0);
        die.lock_owner = -1;
        spin_unlock_irq(&die.lock);
+
+       if (kexec_should_crash(current))
+               crash_kexec(regs);
+
        if (in_interrupt())
                panic("Fatal exception in interrupt");
 
@@ -361,6 +369,10 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long e
 static void do_trap(int trapnr, int signr, char *str, int vm86,
                           struct pt_regs * regs, long error_code, siginfo_t *info)
 {
+       struct task_struct *tsk = current;
+       tsk->thread.error_code = error_code;
+       tsk->thread.trap_no = trapnr;
+
        if (regs->eflags & VM_MASK) {
                if (vm86)
                        goto vm86_trap;
@@ -371,9 +383,6 @@ static void do_trap(int trapnr, int signr, char *str, int vm86,
                goto kernel_trap;
 
        trap_signal: {
-               struct task_struct *tsk = current;
-               tsk->thread.error_code = error_code;
-               tsk->thread.trap_no = trapnr;
                if (info)
                        force_sig_info(signr, info, tsk);
                else
@@ -486,6 +495,9 @@ fastcall void do_general_protection(struct pt_regs * regs, long error_code)
        }
        put_cpu();
 
+       current->thread.error_code = error_code;
+       current->thread.trap_no = 13;
+
        if (regs->eflags & VM_MASK)
                goto gp_in_vm86;
 
@@ -570,6 +582,15 @@ void die_nmi (struct pt_regs *regs, const char *msg)
        console_silent();
        spin_unlock(&nmi_print_lock);
        bust_spinlocks(0);
+
+       /* If we are in kernel we are probably nested up pretty bad
+        * and might aswell get out now while we still can.
+       */
+       if (!user_mode(regs)) {
+               current->thread.trap_no = 2;
+               crash_kexec(regs);
+       }
+
        do_exit(SIGSEGV);
 }
 
@@ -625,6 +646,14 @@ fastcall void do_nmi(struct pt_regs * regs, long error_code)
        nmi_enter();
 
        cpu = smp_processor_id();
+
+#ifdef CONFIG_HOTPLUG_CPU
+       if (!cpu_online(cpu)) {
+               nmi_exit();
+               return;
+       }
+#endif
+
        ++nmi_count(cpu);
 
        if (!nmi_callback(regs, cpu))
@@ -872,9 +901,9 @@ fastcall void do_simd_coprocessor_error(struct pt_regs * regs,
                                          error_code);
                        return;
                }
-               die_if_kernel("cache flush denied", regs, error_code);
                current->thread.trap_no = 19;
                current->thread.error_code = error_code;
+               die_if_kernel("cache flush denied", regs, error_code);
                force_sig(SIGSEGV, current);
        }
 }
index e0512cc8bea76b9b73c75177426209b0b6306095..7e01a528a83a168f86214907103d7bbe1f2e964d 100644 (file)
@@ -2,20 +2,23 @@
  * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
  */
 
+#define LOAD_OFFSET __PAGE_OFFSET
+
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/thread_info.h>
 #include <asm/page.h>
 
 OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
 OUTPUT_ARCH(i386)
-ENTRY(startup_32)
+ENTRY(phys_startup_32)
 jiffies = jiffies_64;
 SECTIONS
 {
-  . = __PAGE_OFFSET + 0x100000;
+  . = __KERNEL_START;
+  phys_startup_32 = startup_32 - LOAD_OFFSET;
   /* read-only */
   _text = .;                   /* Text and read-only data */
-  .text : {
+  .text : AT(ADDR(.text) - LOAD_OFFSET) {
        *(.text)
        SCHED_TEXT
        LOCK_TEXT
@@ -27,49 +30,55 @@ SECTIONS
 
   . = ALIGN(16);               /* Exception table */
   __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
+  __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) }
   __stop___ex_table = .;
 
   RODATA
 
   /* writeable */
-  .data : {                    /* Data */
+  .data : AT(ADDR(.data) - LOAD_OFFSET) {      /* Data */
        *(.data)
        CONSTRUCTORS
        }
 
   . = ALIGN(4096);
   __nosave_begin = .;
-  .data_nosave : { *(.data.nosave) }
+  .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) }
   . = ALIGN(4096);
   __nosave_end = .;
 
   . = ALIGN(4096);
-  .data.page_aligned : { *(.data.idt) }
+  .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+       *(.data.idt)
+  }
 
   . = ALIGN(32);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+  .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
+       *(.data.cacheline_aligned)
+  }
 
   _edata = .;                  /* End of data section */
 
   . = ALIGN(THREAD_SIZE);      /* init_task */
-  .data.init_task : { *(.data.init_task) }
+  .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
+       *(.data.init_task)
+  }
 
   /* will be freed after init */
   . = ALIGN(4096);             /* Init code and data */
   __init_begin = .;
-  .init.text : 
+  .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
        _sinittext = .;
        *(.init.text)
        _einittext = .;
   }
-  .init.data : { *(.init.data) }
+  .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) }
   . = ALIGN(16);
   __setup_start = .;
-  .init.setup : { *(.init.setup) }
+  .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : {
+  .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
        *(.initcall1.init) 
        *(.initcall2.init) 
        *(.initcall3.init) 
@@ -80,33 +89,41 @@ SECTIONS
   }
   __initcall_end = .;
   __con_initcall_start = .;
-  .con_initcall.init : { *(.con_initcall.init) }
+  .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
+       *(.con_initcall.init)
+  }
   __con_initcall_end = .;
   SECURITY_INIT
   . = ALIGN(4);
   __alt_instructions = .;
-  .altinstructions : { *(.altinstructions) } 
+  .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
+       *(.altinstructions)
+  }
   __alt_instructions_end = .; 
- .altinstr_replacement : { *(.altinstr_replacement) } 
+  .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
+       *(.altinstr_replacement)
+  }
   /* .exit.text is discard at runtime, not link time, to deal with references
      from .altinstructions and .eh_frame */
-  .exit.text : { *(.exit.text) }
-  .exit.data : { *(.exit.data) }
+  .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) }
+  .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) }
   . = ALIGN(4096);
   __initramfs_start = .;
-  .init.ramfs : { *(.init.ramfs) }
+  .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) }
   __initramfs_end = .;
   . = ALIGN(32);
   __per_cpu_start = .;
-  .data.percpu  : { *(.data.percpu) }
+  .data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) }
   __per_cpu_end = .;
   . = ALIGN(4096);
   __init_end = .;
   /* freed after init ends here */
        
   __bss_start = .;             /* BSS */
-  .bss : {
+  .bss.page_aligned : AT(ADDR(.bss.page_aligned) - LOAD_OFFSET) {
        *(.bss.page_aligned)
+  }
+  .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
        *(.bss)
   }
   . = ALIGN(4);
index 0aa08eaa893281f6c74e49a0ac7f34f5203a481f..e5a1a83d09ef8d6c4efe1e74c7fa1d77c5f371dc 100644 (file)
 #include <asm/acpi.h>
 #include <asm/arch_hooks.h>
 
+#ifdef CONFIG_HOTPLUG_CPU
+#define DEFAULT_SEND_IPI       (1)
+#else
+#define DEFAULT_SEND_IPI       (0)
+#endif
+
+int no_broadcast=DEFAULT_SEND_IPI;
+
 /**
  * pre_intr_init_hook - initialisation prior to setting up interrupt vectors
  *
@@ -104,3 +112,22 @@ void __init mca_nmi_hook(void)
        printk("NMI generated from unknown source!\n");
 }
 #endif
+
+static __init int no_ipi_broadcast(char *str)
+{
+       get_option(&str, &no_broadcast);
+       printk ("Using %s mode\n", no_broadcast ? "No IPI Broadcast" :
+                                                                                       "IPI Broadcast");
+       return 1;
+}
+
+__setup("no_ipi_broadcast", no_ipi_broadcast);
+
+static int __init print_ipi_mode(void)
+{
+       printk ("Using IPI %s mode\n", no_broadcast ? "No-Shortcut" :
+                                                                                       "Shortcut");
+       return 0;
+}
+
+late_initcall(print_ipi_mode);
index 5b3e8817dae828054dd3ee8449f1fd9c6ae6265d..23395fff35d16e59dcade164354dc0045ee95d1f 100644 (file)
@@ -73,12 +73,11 @@ static int __init topology_init(void)
 {
        int i;
 
-       for (i = 0; i < MAX_NUMNODES; i++) {
-               if (node_online(i))
-                       arch_register_node(i);
-       }
-       for (i = 0; i < NR_CPUS; i++)
-               if (cpu_possible(i)) arch_register_cpu(i);
+       for_each_online_node(i)
+               arch_register_node(i);
+
+       for_each_cpu(i)
+               arch_register_cpu(i);
        return 0;
 }
 
@@ -88,8 +87,8 @@ static int __init topology_init(void)
 {
        int i;
 
-       for (i = 0; i < NR_CPUS; i++)
-               if (cpu_possible(i)) arch_register_cpu(i);
+       for_each_cpu(i)
+               arch_register_cpu(i);
        return 0;
 }
 
index 5a22082147f4efc5fc738d5d2402c76118c561ae..5f3d7e6de37b9cc4440cc9f7e7ba6a52271477cc 100644 (file)
@@ -23,7 +23,6 @@ unsigned long mp_lapic_addr;
 
 /* Processor that is doing the boot up */
 unsigned int boot_cpu_physical_apicid = -1U;
-unsigned int boot_cpu_logical_apicid = -1U;
 
 /* Bitmask of physically existing CPUs */
 physid_mask_t phys_cpu_present_map;
@@ -52,10 +51,8 @@ static void __init MP_processor_info (struct mpc_config_processor *m)
                (m->mpc_cpufeature & CPU_MODEL_MASK) >> 4,
                m->mpc_apicver);
 
-       if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
+       if (m->mpc_cpuflag & CPU_BOOTPROCESSOR)
                boot_cpu_physical_apicid = m->mpc_apicid;
-               boot_cpu_logical_apicid = logical_apicid;
-       }
 
        ver = m->mpc_apicver;
        if ((ver >= 0x14 && m->mpc_apicid >= 0xff) || m->mpc_apicid >= 0xf) {
index 602aea240e9b55f67b5d1b4b7daf1f4a04b1e405..3e439ce5e1b22e47daa3f6285977d2958222299a 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/irq.h>
 #include <asm/tlbflush.h>
 #include <asm/arch_hooks.h>
+#include <asm/i8253.h>
 
 /*
  * Power off function, if any
@@ -182,7 +183,6 @@ voyager_timer_interrupt(struct pt_regs *regs)
                 * and swiftly introduce it to something sharp and
                 * pointy.  */
                __u16 val;
-               extern spinlock_t i8253_lock;
 
                spin_lock(&i8253_lock);
                
index f429c871e8450b5e344cf60aca1fc6cd97b01733..b358f0702a44fab313811594390f91fbd91aa7dc 100644 (file)
@@ -30,6 +30,8 @@
 #include <linux/initrd.h>
 #include <linux/nodemask.h>
 #include <linux/module.h>
+#include <linux/kexec.h>
+
 #include <asm/e820.h>
 #include <asm/setup.h>
 #include <asm/mmzone.h>
index a509237c4815ed6f8443e85b973dda2a0f2c0688..8e90339d6eaaa18c96a5292c53f6590235804764 100644 (file)
@@ -146,7 +146,7 @@ static int __is_prefetch(struct pt_regs *regs, unsigned long addr)
 
                if (instr > limit)
                        break;
-               if (__get_user(opcode, (unsigned char *) instr))
+               if (__get_user(opcode, (unsigned char __user *) instr))
                        break; 
 
                instr_hi = opcode & 0xf0; 
@@ -173,7 +173,7 @@ static int __is_prefetch(struct pt_regs *regs, unsigned long addr)
                        scan_more = 0;
                        if (instr > limit)
                                break;
-                       if (__get_user(opcode, (unsigned char *) instr)) 
+                       if (__get_user(opcode, (unsigned char __user *) instr))
                                break;
                        prefetch = (instr_lo == 0xF) &&
                                (opcode == 0x0D || opcode == 0x18);
@@ -463,6 +463,9 @@ no_context:
                printk(KERN_ALERT "*pte = %08lx\n", page);
        }
 #endif
+       tsk->thread.cr2 = address;
+       tsk->thread.trap_no = 14;
+       tsk->thread.error_code = error_code;
        die("Oops", regs, error_code);
        bust_spinlocks(0);
        do_exit(SIGKILL);
index 4b7aaf99d7ea7a1d9a19d2f821070fd4d1a85c4f..b6eb4dcb8777e60e173985b2ae67d3be5bc3a058 100644 (file)
@@ -75,6 +75,24 @@ void kunmap_atomic(void *kvaddr, enum km_type type)
        preempt_check_resched();
 }
 
+/* This is the same as kmap_atomic() but can map memory that doesn't
+ * have a struct page associated with it.
+ */
+void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
+{
+       enum fixed_addresses idx;
+       unsigned long vaddr;
+
+       inc_preempt_count();
+
+       idx = type + KM_TYPE_NR*smp_processor_id();
+       vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+       set_pte(kmap_pte-idx, pfn_pte(pfn, kmap_prot));
+       __flush_tlb_one(vaddr);
+
+       return (void*) vaddr;
+}
+
 struct page *kmap_atomic_to_page(void *ptr)
 {
        unsigned long idx, vaddr = (unsigned long)ptr;
index 3672e2ef51ae528dcf9fabb0f1552babc4faecc1..12216b52e28bf9b50060c509060fea3057fb298e 100644 (file)
@@ -352,7 +352,7 @@ static void __init pagetable_init (void)
 #endif
 }
 
-#if defined(CONFIG_PM_DISK) || defined(CONFIG_SOFTWARE_SUSPEND)
+#ifdef CONFIG_SOFTWARE_SUSPEND
 /*
  * Swap suspend & friends need this for resume because things like the intel-agp
  * driver might have split up a kernel 4MB mapping.
index d393eefc70524e8464a93845c99ddeac03ef1b0b..6b25afc933b605b0f515372d900cdc272ffc2e71 100644 (file)
@@ -243,7 +243,7 @@ void iounmap(volatile void __iomem *addr)
        write_lock(&vmlist_lock);
        p = __remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr));
        if (!p) { 
-               printk("iounmap: bad address %p\n", addr);
+               printk(KERN_WARNING "iounmap: bad address %p\n", addr);
                goto out_unlock;
        }
 
index 270c59f099a445f667dab7c0d403b14ed21d1939..bd2f7afc7a2a5d6726b14a35bdf48492bf4730a1 100644 (file)
@@ -32,9 +32,9 @@ void show_mem(void)
        unsigned long i;
        struct page_state ps;
 
-       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));
        for_each_pgdat(pgdat) {
                for (i = 0; i < pgdat->node_spanned_pages; ++i) {
                        page = pgdat_page_nr(pgdat, i);
@@ -49,18 +49,18 @@ void show_mem(void)
                                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);
 
        get_page_state(&ps);
-       printk("%lu pages dirty\n", ps.nr_dirty);
-       printk("%lu pages writeback\n", ps.nr_writeback);
-       printk("%lu pages mapped\n", ps.nr_mapped);
-       printk("%lu pages slab\n", ps.nr_slab);
-       printk("%lu pages pagetables\n", ps.nr_page_table_pages);
+       printk(KERN_INFO "%lu pages dirty\n", ps.nr_dirty);
+       printk(KERN_INFO "%lu pages writeback\n", ps.nr_writeback);
+       printk(KERN_INFO "%lu pages mapped\n", ps.nr_mapped);
+       printk(KERN_INFO "%lu pages slab\n", ps.nr_slab);
+       printk(KERN_INFO "%lu pages pagetables\n", ps.nr_page_table_pages);
 }
 
 /*
@@ -113,16 +113,16 @@ void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
        pmd_t *pmd;
 
        if (vaddr & (PMD_SIZE-1)) {             /* vaddr is misaligned */
-               printk ("set_pmd_pfn: vaddr misaligned\n");
+               printk(KERN_WARNING "set_pmd_pfn: vaddr misaligned\n");
                return; /* BUG(); */
        }
        if (pfn & (PTRS_PER_PTE-1)) {           /* pfn is misaligned */
-               printk ("set_pmd_pfn: pfn misaligned\n");
+               printk(KERN_WARNING "set_pmd_pfn: pfn misaligned\n");
                return; /* BUG(); */
        }
        pgd = swapper_pg_dir + pgd_index(vaddr);
        if (pgd_none(*pgd)) {
-               printk ("set_pmd_pfn: pgd_none\n");
+               printk(KERN_WARNING "set_pmd_pfn: pgd_none\n");
                return; /* BUG(); */
        }
        pud = pud_offset(pgd, vaddr);
index 720975e1af5046cdcef151f57e68e94fd2378d82..87325263cd4fbcdeb29994e69e96550b39981621 100644 (file)
@@ -25,7 +25,8 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
 
 int pci_routeirq;
 int pcibios_last_bus = -1;
-struct pci_bus *pci_root_bus = NULL;
+unsigned long pirq_table_addr;
+struct pci_bus *pci_root_bus;
 struct pci_raw_ops *raw_pci_ops;
 
 static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
@@ -133,7 +134,7 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
 
        printk("PCI: Probing PCI hardware (bus %02x)\n", busnum);
 
-       return pci_scan_bus(busnum, &pci_root_ops, NULL);
+       return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, NULL);
 }
 
 extern u8 pci_cache_line_size;
@@ -188,6 +189,9 @@ char * __devinit  pcibios_setup(char *str)
        } else if (!strcmp(str, "biosirq")) {
                pci_probe |= PCI_BIOS_IRQ_SCAN;
                return NULL;
+       } else if (!strncmp(str, "pirqaddr=", 9)) {
+               pirq_table_addr = simple_strtoul(str+9, NULL, 0);
+               return NULL;
        }
 #endif
 #ifdef CONFIG_PCI_DIRECT
index 83458f81e661ef7283936565e396f594780137e6..78ca1ecbb90728dad8e56b199550bfca66ac9d35 100644 (file)
@@ -57,6 +57,35 @@ struct irq_router_handler {
 
 int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL;
 
+/*
+ *  Check passed address for the PCI IRQ Routing Table signature
+ *  and perform checksum verification.
+ */
+
+static inline struct irq_routing_table * pirq_check_routing_table(u8 *addr)
+{
+       struct irq_routing_table *rt;
+       int i;
+       u8 sum;
+
+       rt = (struct irq_routing_table *) addr;
+       if (rt->signature != PIRQ_SIGNATURE ||
+           rt->version != PIRQ_VERSION ||
+           rt->size % 16 ||
+           rt->size < sizeof(struct irq_routing_table))
+               return NULL;
+       sum = 0;
+       for (i=0; i < rt->size; i++)
+               sum += addr[i];
+       if (!sum) {
+               DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt);
+               return rt;
+       }
+       return NULL;
+}
+
+
+
 /*
  *  Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
  */
@@ -65,23 +94,17 @@ static struct irq_routing_table * __init pirq_find_routing_table(void)
 {
        u8 *addr;
        struct irq_routing_table *rt;
-       int i;
-       u8 sum;
 
+       if (pirq_table_addr) {
+               rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr));
+               if (rt)
+                       return rt;
+               printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n");
+       }
        for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
-               rt = (struct irq_routing_table *) addr;
-               if (rt->signature != PIRQ_SIGNATURE ||
-                   rt->version != PIRQ_VERSION ||
-                   rt->size % 16 ||
-                   rt->size < sizeof(struct irq_routing_table))
-                       continue;
-               sum = 0;
-               for(i=0; i<rt->size; i++)
-                       sum += addr[i];
-               if (!sum) {
-                       DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt);
+               rt = pirq_check_routing_table(addr);
+               if (rt)
                        return rt;
-               }
        }
        return NULL;
 }
index 1492e375386908fd350ed50f52879ce6f5b853b6..149a9588c256797c1032c6f6cc1b1fa9645b2b3b 100644 (file)
@@ -45,6 +45,8 @@ static int __init pci_legacy_init(void)
 
        printk("PCI: Probing PCI hardware\n");
        pci_root_bus = pcibios_scan_root(0);
+       if (pci_root_bus)
+               pci_bus_add_devices(pci_root_bus);
 
        pcibios_fixup_peer_bridges();
 
index 021a50aa51f432020f23dcb27f6c927d6a3d639f..60f0e7a1162aafa3be94b2806384106dc1aee172 100644 (file)
 
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/acpi.h>
 #include "pci.h"
 
-/* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
-u32 pci_mmcfg_base_addr;
-
 #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
 
 /* The base address of the last MMCONFIG device accessed */
@@ -24,10 +22,31 @@ static u32 mmcfg_last_accessed_device;
 /*
  * Functions for accessing PCI configuration space with MMCONFIG accesses
  */
+static u32 get_base_addr(unsigned int seg, int bus)
+{
+       int cfg_num = -1;
+       struct acpi_table_mcfg_config *cfg;
+
+       while (1) {
+               ++cfg_num;
+               if (cfg_num >= pci_mmcfg_config_num) {
+                       /* something bad is going on, no cfg table is found. */
+                       /* so we fall back to the old way we used to do this */
+                       /* and just rely on the first entry to be correct. */
+                       return pci_mmcfg_config[0].base_address;
+               }
+               cfg = &pci_mmcfg_config[cfg_num];
+               if (cfg->pci_segment_group_number != seg)
+                       continue;
+               if ((cfg->start_bus_number <= bus) &&
+                   (cfg->end_bus_number >= bus))
+                       return cfg->base_address;
+       }
+}
 
-static inline void pci_exp_set_dev_base(int bus, int devfn)
+static inline void pci_exp_set_dev_base(unsigned int seg, int bus, int devfn)
 {
-       u32 dev_base = pci_mmcfg_base_addr | (bus << 20) | (devfn << 12);
+       u32 dev_base = get_base_addr(seg, bus) | (bus << 20) | (devfn << 12);
        if (dev_base != mmcfg_last_accessed_device) {
                mmcfg_last_accessed_device = dev_base;
                set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
@@ -44,7 +63,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
 
        spin_lock_irqsave(&pci_config_lock, flags);
 
-       pci_exp_set_dev_base(bus, devfn);
+       pci_exp_set_dev_base(seg, bus, devfn);
 
        switch (len) {
        case 1:
@@ -73,7 +92,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
 
        spin_lock_irqsave(&pci_config_lock, flags);
 
-       pci_exp_set_dev_base(bus, devfn);
+       pci_exp_set_dev_base(seg, bus, devfn);
 
        switch (len) {
        case 1:
@@ -101,7 +120,11 @@ static int __init pci_mmcfg_init(void)
 {
        if ((pci_probe & PCI_PROBE_MMCONF) == 0)
                goto out;
-       if (!pci_mmcfg_base_addr)
+
+       acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+       if ((pci_mmcfg_config_num == 0) ||
+           (pci_mmcfg_config == NULL) ||
+           (pci_mmcfg_config[0].base_address == 0))
                goto out;
 
        /* Kludge for now. Don't use mmconfig on AMD systems because
index 9e3695461899b1c5498d25a3006b23cfd40aec89..adbe17a38f6f932cb8e238767f85eab12632a2d6 100644 (file)
@@ -115,6 +115,8 @@ static int __init pci_numa_init(void)
                return 0;
 
        pci_root_bus = pcibios_scan_root(0);
+       if (pci_root_bus)
+               pci_bus_add_devices(pci_root_bus);
        if (num_online_nodes() > 1)
                for_each_online_node(quad) {
                        if (quad == 0)
index a8fc80ca69f309205371940dc35be6ddebb0d797..a80f0f55ff51b0dcea1c1d33670c5baae924a541 100644 (file)
@@ -27,6 +27,7 @@
 #define PCI_ASSIGN_ALL_BUSSES  0x4000
 
 extern unsigned int pci_probe;
+extern unsigned long pirq_table_addr;
 
 /* pci-i386.c */
 
index 6f521cf19a133924b026b13bb3695218fd2a2e6b..0e6b45b612514669d9dbaf8df092b56a4b0d6fb9 100644 (file)
 #include <linux/device.h>
 #include <linux/suspend.h>
 #include <linux/acpi.h>
+
 #include <asm/uaccess.h>
 #include <asm/acpi.h>
 #include <asm/tlbflush.h>
+#include <asm/processor.h>
 
 static struct saved_context saved_context;
 
@@ -33,8 +35,6 @@ unsigned long saved_context_esp, saved_context_ebp;
 unsigned long saved_context_esi, saved_context_edi;
 unsigned long saved_context_eflags;
 
-extern void enable_sep_cpu(void *);
-
 void __save_processor_state(struct saved_context *ctxt)
 {
        kernel_fpu_begin();
@@ -44,7 +44,6 @@ void __save_processor_state(struct saved_context *ctxt)
         */
        asm volatile ("sgdt %0" : "=m" (ctxt->gdt_limit));
        asm volatile ("sidt %0" : "=m" (ctxt->idt_limit));
-       asm volatile ("sldt %0" : "=m" (ctxt->ldt));
        asm volatile ("str %0"  : "=m" (ctxt->tr));
 
        /*
@@ -107,7 +106,6 @@ static void fix_processor_context(void)
 
 void __restore_processor_state(struct saved_context *ctxt)
 {
-
        /*
         * control registers
         */
@@ -116,6 +114,13 @@ void __restore_processor_state(struct saved_context *ctxt)
        asm volatile ("movl %0, %%cr2" :: "r" (ctxt->cr2));
        asm volatile ("movl %0, %%cr0" :: "r" (ctxt->cr0));
 
+       /*
+        * now restore the descriptor tables to their proper values
+        * ltr is done i fix_processor_context().
+        */
+       asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit));
+       asm volatile ("lidt %0" :: "m" (ctxt->idt_limit));
+
        /*
         * segment registers
         */
@@ -124,19 +129,11 @@ void __restore_processor_state(struct saved_context *ctxt)
        asm volatile ("movw %0, %%gs" :: "r" (ctxt->gs));
        asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
 
-       /*
-        * now restore the descriptor tables to their proper values
-        * ltr is done i fix_processor_context().
-        */
-       asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit));
-       asm volatile ("lidt %0" :: "m" (ctxt->idt_limit));
-       asm volatile ("lldt %0" :: "m" (ctxt->ldt));
-
        /*
         * sysenter MSRs
         */
        if (boot_cpu_has(X86_FEATURE_SEP))
-               enable_sep_cpu(NULL);
+               enable_sep_cpu();
 
        fix_processor_context();
        do_fpu_end();
index 487d2e36b0a6d47848720b8c9c8c70baad5ab212..c05613980300c0ac225a918984986b72c184792c 100644 (file)
@@ -99,7 +99,7 @@ CONFIG_ACPI_DEALLOCATE_IRQ=y
 # Firmware Drivers
 #
 CONFIG_EFI_VARS=y
-# CONFIG_EFI_PCDP is not set
+CONFIG_EFI_PCDP=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 
@@ -650,7 +650,7 @@ CONFIG_MMTIMER=y
 #
 # Console display driver support
 #
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_VGA_CONSOLE=y
 CONFIG_DUMMY_CONSOLE=y
 
 #
index 47f45341ac627debe084eee9b8c8c488e3456ba1..73454eee26f1968a319a4c91ba312c2cd02c1b9e 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-20050621
-# Tue Jun 21 14:03:24 2005
+# Linux kernel version: 2.6.13-rc1-20050629
+# Wed Jun 29 15:28:12 2005
 #
 
 #
@@ -80,18 +80,29 @@ CONFIG_MCKINLEY=y
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
 # CONFIG_IA64_PAGE_SIZE_64KB is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
 CONFIG_IA64_L1_CACHE_SHIFT=7
 # CONFIG_NUMA is not set
 CONFIG_VIRTUAL_MEM_MAP=y
 CONFIG_HOLES_IN_ZONE=y
 CONFIG_IA64_CYCLONE=y
 CONFIG_IOSAPIC=y
+# CONFIG_IA64_SGI_SN_XP is not set
 CONFIG_FORCE_MAX_ZONEORDER=18
 CONFIG_SMP=y
 CONFIG_NR_CPUS=4
 CONFIG_HOTPLUG_CPU=y
 # CONFIG_SCHED_SMT is not set
 # CONFIG_PREEMPT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_IA32_SUPPORT=y
 CONFIG_COMPAT=y
@@ -257,6 +268,7 @@ CONFIG_BLK_DEV_CMD64X=y
 # CONFIG_BLK_DEV_HPT366 is not set
 # CONFIG_BLK_DEV_SC1200 is not set
 CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_IT821X is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_BLK_DEV_PDC202XX_NEW is not set
@@ -395,6 +407,7 @@ CONFIG_UNIX=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
 # CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
@@ -407,6 +420,8 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_TUNNEL is not set
 CONFIG_IP_TCPDIAG=y
 # CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -598,9 +613,7 @@ CONFIG_GAMEPORT=m
 # CONFIG_GAMEPORT_NS558 is not set
 # CONFIG_GAMEPORT_L4 is not set
 # CONFIG_GAMEPORT_EMU10K1 is not set
-# CONFIG_GAMEPORT_VORTEX is not set
 # CONFIG_GAMEPORT_FM801 is not set
-# CONFIG_GAMEPORT_CS461X is not set
 
 #
 # Character devices
@@ -629,7 +642,6 @@ CONFIG_SERIAL_8250_NR_UARTS=6
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 # CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
 # CONFIG_SERIAL_8250_RSA is not set
 
 #
@@ -743,6 +755,7 @@ CONFIG_USB_DEVICEFS=y
 CONFIG_USB_EHCI_HCD=m
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=m
 # CONFIG_USB_OHCI_BIG_ENDIAN is not set
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
@@ -779,9 +792,11 @@ CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_HIDDEV is not set
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
 # CONFIG_USB_KBTAB is not set
 # CONFIG_USB_POWERMATE is not set
 # CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
 # CONFIG_USB_EGALAX is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
@@ -838,7 +853,7 @@ CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_TEST is not set
 
 #
-# USB ATM/DSL drivers
+# USB DSL modem support
 #
 
 #
@@ -856,6 +871,10 @@ CONFIG_USB_HIDINPUT=y
 #
 # CONFIG_INFINIBAND is not set
 
+#
+# SN Devices
+#
+
 #
 # File systems
 #
@@ -863,6 +882,7 @@ CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
 CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
@@ -922,7 +942,6 @@ CONFIG_NTFS_FS=m
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 CONFIG_TMPFS_XATTR=y
@@ -953,15 +972,18 @@ CONFIG_RAMFS=y
 #
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 CONFIG_NFS_V4=y
 CONFIG_NFS_DIRECTIO=y
 CONFIG_NFSD=m
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
 CONFIG_NFSD_V4=y
 CONFIG_NFSD_TCP=y
 CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
 CONFIG_SUNRPC_GSS=m
 CONFIG_RPCSEC_GSS_KRB5=m
@@ -1069,6 +1091,7 @@ CONFIG_LOG_BUF_SHIFT=20
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_FS is not set
+# CONFIG_KPROBES is not set
 CONFIG_IA64_GRANULE_16MB=y
 # CONFIG_IA64_GRANULE_64MB is not set
 # CONFIG_IA64_PRINT_HAZARDS is not set
@@ -1090,7 +1113,7 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_NULL is not set
 # CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_MD5=y
 # CONFIG_CRYPTO_SHA1 is not set
 # CONFIG_CRYPTO_SHA256 is not set
 # CONFIG_CRYPTO_SHA512 is not set
index 21d6f9bab5e98208c5fda8d191fae3b24d325992..b7755e4436d222e09d396d91bc924efc5a633b6f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10
-# Wed Dec 29 09:05:48 2004
+# Linux kernel version: 2.6.13-rc1-20050629
+# Wed Jun 29 15:31:11 2005
 #
 
 #
@@ -12,6 +12,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -24,23 +25,26 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=17
 CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
+# CONFIG_CPUSETS is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -59,12 +63,15 @@ CONFIG_IA64=y
 CONFIG_64BIT=y
 CONFIG_MMU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_TIME_INTERPOLATION=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 # CONFIG_IA64_GENERIC is not set
 # CONFIG_IA64_DIG is not set
 CONFIG_IA64_HP_ZX1=y
+# CONFIG_IA64_HP_ZX1_SWIOTLB is not set
 # CONFIG_IA64_SGI_SN2 is not set
 # CONFIG_IA64_HP_SIM is not set
 # CONFIG_ITANIUM is not set
@@ -73,22 +80,36 @@ CONFIG_MCKINLEY=y
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
 # CONFIG_IA64_PAGE_SIZE_64KB is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
 CONFIG_IA64_L1_CACHE_SHIFT=7
 # CONFIG_NUMA is not set
 CONFIG_VIRTUAL_MEM_MAP=y
+CONFIG_HOLES_IN_ZONE=y
 # CONFIG_IA64_CYCLONE is not set
 CONFIG_IOSAPIC=y
+# CONFIG_IA64_SGI_SN_XP is not set
 CONFIG_FORCE_MAX_ZONEORDER=18
 CONFIG_SMP=y
 CONFIG_NR_CPUS=16
 # CONFIG_HOTPLUG_CPU is not set
+# CONFIG_SCHED_SMT is not set
 # CONFIG_PREEMPT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_IA32_SUPPORT=y
 CONFIG_COMPAT=y
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
+CONFIG_ACPI_DEALLOCATE_IRQ=y
 
 #
 # Firmware Drivers
@@ -120,6 +141,7 @@ CONFIG_ACPI_BUS=y
 CONFIG_ACPI_POWER=y
 CONFIG_ACPI_PCI=y
 CONFIG_ACPI_SYSTEM=y
+# CONFIG_ACPI_CONTAINER is not set
 
 #
 # Bus options (PCI, PCMCIA)
@@ -129,6 +151,7 @@ CONFIG_PCI_DOMAINS=y
 # CONFIG_PCI_MSI is not set
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
 
 #
 # PCI Hotplug Support
@@ -138,7 +161,6 @@ CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_ACPI=y
 # CONFIG_HOTPLUG_PCI_ACPI_IBM is not set
 # CONFIG_HOTPLUG_PCI_CPCI is not set
-# CONFIG_HOTPLUG_PCI_PCIE is not set
 # CONFIG_HOTPLUG_PCI_SHPC is not set
 
 #
@@ -146,10 +168,6 @@ CONFIG_HOTPLUG_PCI_ACPI=y
 #
 # CONFIG_PCCARD is not set
 
-#
-# PC-card bridges
-#
-
 #
 # Device Drivers
 #
@@ -184,6 +202,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -203,6 +222,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -246,6 +266,7 @@ CONFIG_BLK_DEV_CMD64X=y
 # CONFIG_BLK_DEV_HPT366 is not set
 # CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_BLK_DEV_PDC202XX_NEW is not set
@@ -275,6 +296,7 @@ CONFIG_CHR_DEV_OSST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -288,6 +310,7 @@ CONFIG_SCSI_LOGGING=y
 #
 CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
@@ -303,13 +326,10 @@ CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
 # CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
@@ -319,8 +339,6 @@ CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 CONFIG_SCSI_QLOGIC_1280=y
@@ -331,7 +349,7 @@ CONFIG_SCSI_QLA2XXX=y
 # CONFIG_SCSI_QLA2300 is not set
 # CONFIG_SCSI_QLA2322 is not set
 # CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
+# CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
@@ -344,9 +362,9 @@ CONFIG_SCSI_QLA2XXX=y
 #
 # Fusion MPT device support
 #
-CONFIG_FUSION=y
-CONFIG_FUSION_MAX_SGE=40
-# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -368,12 +386,12 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
 # CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
@@ -386,6 +404,8 @@ CONFIG_IP_MULTICAST=y
 # CONFIG_INET_TUNNEL is not set
 # CONFIG_IP_TCPDIAG is not set
 # CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
 
 #
 # IP: Virtual Server Configuration
@@ -405,8 +425,6 @@ CONFIG_NETFILTER=y
 CONFIG_IP_NF_ARPTABLES=y
 # CONFIG_IP_NF_ARPFILTER is not set
 # CONFIG_IP_NF_ARP_MANGLE is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
@@ -483,7 +501,6 @@ CONFIG_NET_PCI=y
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 CONFIG_E100=y
-# CONFIG_E100_NAPI is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
@@ -505,9 +522,11 @@ CONFIG_E1000=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SKGE is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
+# CONFIG_BNX2 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -564,18 +583,6 @@ CONFIG_INPUT_JOYDEV=y
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
 
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
 #
 # Input Device Drivers
 #
@@ -585,6 +592,16 @@ CONFIG_SERIO=y
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
 #
 # Character devices
 #
@@ -603,7 +620,6 @@ CONFIG_SERIAL_8250_NR_UARTS=8
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 # CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
 # CONFIG_SERIAL_8250_RSA is not set
 
 #
@@ -611,6 +627,7 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -644,6 +661,12 @@ CONFIG_DRM_RADEON=y
 # CONFIG_DRM_SIS is not set
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_HPET is not set
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -668,6 +691,7 @@ CONFIG_I2C_ALGOPCF=y
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
@@ -691,10 +715,14 @@ CONFIG_I2C_ALGOPCF=y
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 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_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
@@ -705,21 +733,29 @@ CONFIG_I2C_ALGOPCF=y
 # CONFIG_SENSORS_LM85 is not set
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 
 #
 # Other I2C Chip support
 #
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
 # CONFIG_SENSORS_EEPROM is not set
 # 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_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
@@ -746,6 +782,7 @@ CONFIG_VIDEO_DEV=y
 #
 # Video Adapters
 #
+# CONFIG_TUNER_MULTI_I2C is not set
 # CONFIG_VIDEO_BT848 is not set
 # CONFIG_VIDEO_CPIA is not set
 # CONFIG_VIDEO_SAA5246A is not set
@@ -778,6 +815,11 @@ CONFIG_VIDEO_DEV=y
 # Graphics support
 #
 CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
 CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
 # CONFIG_FB_CIRRUS is not set
@@ -785,6 +827,7 @@ CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
+# CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_MATROX is not set
 # CONFIG_FB_RADEON_OLD is not set
@@ -801,6 +844,7 @@ CONFIG_FB_RADEON_DEBUG=y
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_PM3 is not set
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -820,6 +864,7 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
 CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -869,6 +914,8 @@ CONFIG_SND_AC97_CODEC=y
 # CONFIG_SND_CS46XX is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_CA0106 is not set
 # CONFIG_SND_KORG1212 is not set
 # CONFIG_SND_MIXART is not set
 # CONFIG_SND_NM256 is not set
@@ -876,6 +923,7 @@ CONFIG_SND_AC97_CODEC=y
 # CONFIG_SND_RME96 is not set
 # CONFIG_SND_RME9652 is not set
 # CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
 # CONFIG_SND_TRIDENT is not set
 # CONFIG_SND_YMFPCI is not set
 # CONFIG_SND_ALS4000 is not set
@@ -893,13 +941,14 @@ CONFIG_SND_FM801_TEA575X=y
 # CONFIG_SND_INTEL8X0M is not set
 # CONFIG_SND_SONICVIBES is not set
 # CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
+# CONFIG_SND_HDA_INTEL is not set
 
 #
 # USB devices
 #
 # CONFIG_SND_USB_AUDIO is not set
-# CONFIG_SND_USB_USX2Y is not set
 
 #
 # Open Sound System
@@ -909,6 +958,8 @@ CONFIG_SND_FM801_TEA575X=y
 #
 # USB support
 #
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
@@ -920,8 +971,6 @@ CONFIG_USB_BANDWIDTH=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
 # CONFIG_USB_OTG is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
 
 #
 # USB Host Controller Drivers
@@ -929,7 +978,10 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_EHCI_HCD=y
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_SL811_HCD is not set
 
@@ -947,12 +999,11 @@ CONFIG_USB_UHCI_HCD=y
 #
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_RW_DETECT 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_HP8200e 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
@@ -966,9 +1017,11 @@ CONFIG_USB_HIDINPUT=y
 CONFIG_USB_HIDDEV=y
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
 # CONFIG_USB_KBTAB is not set
 # CONFIG_USB_POWERMATE is not set
 # CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
 # CONFIG_USB_EGALAX is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
@@ -978,7 +1031,6 @@ CONFIG_USB_HIDDEV=y
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
 
 #
 # USB Multimedia devices
@@ -992,6 +1044,7 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_SE401 is not set
 # CONFIG_USB_SN9C102 is not set
 # CONFIG_USB_STV680 is not set
+# CONFIG_USB_PWC is not set
 
 #
 # USB Network Adapters
@@ -1001,6 +1054,7 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
 
 #
 # USB port drivers
@@ -1016,7 +1070,6 @@ CONFIG_USB_HIDDEV=y
 #
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
-# CONFIG_USB_TIGL is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
@@ -1025,9 +1078,11 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_CYTHERM is not set
 # CONFIG_USB_PHIDGETKIT is not set
 # CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_SISUSBVGA is not set
 
 #
-# USB ATM/DSL drivers
+# USB DSL modem support
 #
 
 #
@@ -1040,6 +1095,15 @@ CONFIG_USB_HIDDEV=y
 #
 # CONFIG_MMC is not set
 
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
 #
 # File systems
 #
@@ -1047,6 +1111,7 @@ CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 # CONFIG_EXT2_FS_POSIX_ACL is not set
 # CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
@@ -1056,6 +1121,10 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -1089,7 +1158,6 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 CONFIG_TMPFS_XATTR=y
@@ -1120,15 +1188,18 @@ CONFIG_RAMFS=y
 #
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 CONFIG_NFS_V4=y
 # CONFIG_NFS_DIRECTIO is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
 # CONFIG_NFSD_V4 is not set
 # CONFIG_NFSD_TCP is not set
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
 CONFIG_RPCSEC_GSS_KRB5=y
@@ -1209,6 +1280,8 @@ CONFIG_NLS_UTF8=y
 # CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
 
 #
 # Profiling support
@@ -1218,14 +1291,18 @@ CONFIG_CRC32=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=17
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_KPROBES=y
 CONFIG_IA64_GRANULE_16MB=y
 # CONFIG_IA64_GRANULE_64MB is not set
 CONFIG_IA64_PRINT_HAZARDS=y
@@ -1252,6 +1329,7 @@ CONFIG_CRYPTO_MD5=y
 # CONFIG_CRYPTO_SHA256 is not set
 # CONFIG_CRYPTO_SHA512 is not set
 # CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
 CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
index b8db6e3e5e8133bb0a4b055533ed968ce8837d73..11957598a8b9447dc4852fdca8c810546f315fb1 100644 (file)
 */
 #define DELAYED_RESOURCE_CNT   64
 
+#define PCI_DEVICE_ID_HP_SX2000_IOC    0x12ec
+
 #define ZX1_IOC_ID     ((PCI_DEVICE_ID_HP_ZX1_IOC << 16) | PCI_VENDOR_ID_HP)
 #define ZX2_IOC_ID     ((PCI_DEVICE_ID_HP_ZX2_IOC << 16) | PCI_VENDOR_ID_HP)
 #define REO_IOC_ID     ((PCI_DEVICE_ID_HP_REO_IOC << 16) | PCI_VENDOR_ID_HP)
 #define SX1000_IOC_ID  ((PCI_DEVICE_ID_HP_SX1000_IOC << 16) | PCI_VENDOR_ID_HP)
+#define SX2000_IOC_ID  ((PCI_DEVICE_ID_HP_SX2000_IOC << 16) | PCI_VENDOR_ID_HP)
 
 #define ZX1_IOC_OFFSET 0x1000  /* ACPI reports SBA, we want IOC */
 
@@ -1726,6 +1729,7 @@ static struct ioc_iommu ioc_iommu_info[] __initdata = {
        { ZX1_IOC_ID, "zx1", ioc_zx1_init },
        { ZX2_IOC_ID, "zx2", NULL },
        { SX1000_IOC_ID, "sx1000", NULL },
+       { SX2000_IOC_ID, "sx2000", NULL },
 };
 
 static struct ioc * __init
index 786e70718ce4fb69fc23985449e4fbe1999d01b5..7a8ae0f4b3876f0c888752e2959ccd1e36e23cb1 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 #include <linux/serial.h>
 #include <linux/serialP.h>
+#include <linux/sysrq.h>
 
 #include <asm/irq.h>
 #include <asm/hw_irq.h>
@@ -149,12 +150,17 @@ static  void receive_chars(struct tty_struct *tty, struct pt_regs *regs)
                                seen_esc = 2;
                                continue;
                        } else if ( seen_esc == 2 ) {
-                               if ( ch == 'P' ) show_state();          /* F1 key */
-#ifdef CONFIG_KDB
-                               if ( ch == 'S' )
-                                       kdb(KDB_REASON_KEYBOARD, 0, (kdb_eframe_t) regs);
+                               if ( ch == 'P' ) /* F1 */
+                                       show_state();
+#ifdef CONFIG_MAGIC_SYSRQ
+                               if ( ch == 'S' ) { /* F4 */
+                                       do
+                                               ch = ia64_ssc(0, 0, 0, 0,
+                                                             SSC_GETCHAR);
+                                       while (!ch);
+                                       handle_sysrq(ch, regs, NULL);
+                               }
 #endif
-
                                seen_esc = 0;
                                continue;
                        }
index 72dfd9e7de0ffc470e3922fab11927b8e3fd0916..cda06f88c66eb9ae28c79973f4882deda9545205 100644 (file)
@@ -236,9 +236,7 @@ acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end)
        if (BAD_MADT_ENTRY(iosapic, end))
                return -EINVAL;
 
-       iosapic_init(iosapic->address, iosapic->global_irq_base);
-
-       return 0;
+       return iosapic_init(iosapic->address, iosapic->global_irq_base);
 }
 
 
@@ -772,7 +770,7 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
  
 
 #ifdef CONFIG_ACPI_NUMA
-acpi_status __init
+acpi_status __devinit
 acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
 {
        struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
@@ -825,4 +823,28 @@ acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
        return AE_OK;
 }
 #endif /* CONFIG_NUMA */
+
+int
+acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base)
+{
+       int err;
+
+       if ((err = iosapic_init(phys_addr, gsi_base)))
+               return err;
+
+#if CONFIG_ACPI_NUMA
+       acpi_map_iosapic(handle, 0, NULL, NULL);
+#endif /* CONFIG_ACPI_NUMA */
+
+       return 0;
+}
+EXPORT_SYMBOL(acpi_register_ioapic);
+
+int
+acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base)
+{
+       return iosapic_remove(gsi_base);
+}
+EXPORT_SYMBOL(acpi_unregister_ioapic);
+
 #endif /* CONFIG_ACPI_BOOT */
index fe532c970438973393cb4e1dc40f502e15aef858..d65e87b6394fa2c636f9593718f6e84f29c9804c 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/topology.h>
 #include <linux/nodemask.h>
 
-#define SD_NODES_PER_DOMAIN 6
+#define SD_NODES_PER_DOMAIN 16
 
 #ifdef CONFIG_NUMA
 /**
@@ -27,7 +27,7 @@
  *
  * Should use nodemask_t.
  */
-static int __devinit find_next_best_node(int node, unsigned long *used_nodes)
+static int find_next_best_node(int node, unsigned long *used_nodes)
 {
        int i, n, val, min_val, best_node = 0;
 
@@ -66,7 +66,7 @@ static int __devinit find_next_best_node(int node, unsigned long *used_nodes)
  * should be one that prevents unnecessary balancing, but also spreads tasks
  * out optimally.
  */
-static cpumask_t __devinit sched_domain_node_span(int node)
+static cpumask_t sched_domain_node_span(int node)
 {
        int i;
        cpumask_t span, nodemask;
@@ -96,7 +96,7 @@ static cpumask_t __devinit sched_domain_node_span(int node)
 #ifdef CONFIG_SCHED_SMT
 static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
 static struct sched_group sched_group_cpus[NR_CPUS];
-static int __devinit cpu_to_cpu_group(int cpu)
+static int cpu_to_cpu_group(int cpu)
 {
        return cpu;
 }
@@ -104,7 +104,7 @@ static int __devinit cpu_to_cpu_group(int cpu)
 
 static DEFINE_PER_CPU(struct sched_domain, phys_domains);
 static struct sched_group sched_group_phys[NR_CPUS];
-static int __devinit cpu_to_phys_group(int cpu)
+static int cpu_to_phys_group(int cpu)
 {
 #ifdef CONFIG_SCHED_SMT
        return first_cpu(cpu_sibling_map[cpu]);
@@ -125,44 +125,36 @@ static struct sched_group *sched_group_nodes[MAX_NUMNODES];
 static DEFINE_PER_CPU(struct sched_domain, allnodes_domains);
 static struct sched_group sched_group_allnodes[MAX_NUMNODES];
 
-static int __devinit cpu_to_allnodes_group(int cpu)
+static int cpu_to_allnodes_group(int cpu)
 {
        return cpu_to_node(cpu);
 }
 #endif
 
 /*
- * Set up scheduler domains and groups.  Callers must hold the hotplug lock.
+ * Build sched domains for a given set of cpus and attach the sched domains
+ * to the individual cpus
  */
-void __devinit arch_init_sched_domains(void)
+void build_sched_domains(const cpumask_t *cpu_map)
 {
        int i;
-       cpumask_t cpu_default_map;
 
        /*
-        * Setup mask for cpus without special case scheduling requirements.
-        * For now this just excludes isolated cpus, but could be used to
-        * exclude other special cases in the future.
+        * Set up domains for cpus specified by the cpu_map.
         */
-       cpus_complement(cpu_default_map, cpu_isolated_map);
-       cpus_and(cpu_default_map, cpu_default_map, cpu_online_map);
-
-       /*
-        * Set up domains. Isolated domains just stay on the dummy domain.
-        */
-       for_each_cpu_mask(i, cpu_default_map) {
+       for_each_cpu_mask(i, *cpu_map) {
                int group;
                struct sched_domain *sd = NULL, *p;
                cpumask_t nodemask = node_to_cpumask(cpu_to_node(i));
 
-               cpus_and(nodemask, nodemask, cpu_default_map);
+               cpus_and(nodemask, nodemask, *cpu_map);
 
 #ifdef CONFIG_NUMA
                if (num_online_cpus()
                                > SD_NODES_PER_DOMAIN*cpus_weight(nodemask)) {
                        sd = &per_cpu(allnodes_domains, i);
                        *sd = SD_ALLNODES_INIT;
-                       sd->span = cpu_default_map;
+                       sd->span = *cpu_map;
                        group = cpu_to_allnodes_group(i);
                        sd->groups = &sched_group_allnodes[group];
                        p = sd;
@@ -173,7 +165,7 @@ void __devinit arch_init_sched_domains(void)
                *sd = SD_NODE_INIT;
                sd->span = sched_domain_node_span(cpu_to_node(i));
                sd->parent = p;
-               cpus_and(sd->span, sd->span, cpu_default_map);
+               cpus_and(sd->span, sd->span, *cpu_map);
 #endif
 
                p = sd;
@@ -190,7 +182,7 @@ void __devinit arch_init_sched_domains(void)
                group = cpu_to_cpu_group(i);
                *sd = SD_SIBLING_INIT;
                sd->span = cpu_sibling_map[i];
-               cpus_and(sd->span, sd->span, cpu_default_map);
+               cpus_and(sd->span, sd->span, *cpu_map);
                sd->parent = p;
                sd->groups = &sched_group_cpus[group];
 #endif
@@ -198,9 +190,9 @@ void __devinit arch_init_sched_domains(void)
 
 #ifdef CONFIG_SCHED_SMT
        /* Set up CPU (sibling) groups */
-       for_each_cpu_mask(i, cpu_default_map) {
+       for_each_cpu_mask(i, *cpu_map) {
                cpumask_t this_sibling_map = cpu_sibling_map[i];
-               cpus_and(this_sibling_map, this_sibling_map, cpu_default_map);
+               cpus_and(this_sibling_map, this_sibling_map, *cpu_map);
                if (i != first_cpu(this_sibling_map))
                        continue;
 
@@ -213,7 +205,7 @@ void __devinit arch_init_sched_domains(void)
        for (i = 0; i < MAX_NUMNODES; i++) {
                cpumask_t nodemask = node_to_cpumask(i);
 
-               cpus_and(nodemask, nodemask, cpu_default_map);
+               cpus_and(nodemask, nodemask, *cpu_map);
                if (cpus_empty(nodemask))
                        continue;
 
@@ -222,7 +214,7 @@ void __devinit arch_init_sched_domains(void)
        }
 
 #ifdef CONFIG_NUMA
-       init_sched_build_groups(sched_group_allnodes, cpu_default_map,
+       init_sched_build_groups(sched_group_allnodes, *cpu_map,
                                &cpu_to_allnodes_group);
 
        for (i = 0; i < MAX_NUMNODES; i++) {
@@ -233,12 +225,12 @@ void __devinit arch_init_sched_domains(void)
                cpumask_t covered = CPU_MASK_NONE;
                int j;
 
-               cpus_and(nodemask, nodemask, cpu_default_map);
+               cpus_and(nodemask, nodemask, *cpu_map);
                if (cpus_empty(nodemask))
                        continue;
 
                domainspan = sched_domain_node_span(i);
-               cpus_and(domainspan, domainspan, cpu_default_map);
+               cpus_and(domainspan, domainspan, *cpu_map);
 
                sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
                sched_group_nodes[i] = sg;
@@ -266,7 +258,7 @@ void __devinit arch_init_sched_domains(void)
                        int n = (i + j) % MAX_NUMNODES;
 
                        cpus_complement(notcovered, covered);
-                       cpus_and(tmp, notcovered, cpu_default_map);
+                       cpus_and(tmp, notcovered, *cpu_map);
                        cpus_and(tmp, tmp, domainspan);
                        if (cpus_empty(tmp))
                                break;
@@ -293,7 +285,7 @@ void __devinit arch_init_sched_domains(void)
 #endif
 
        /* Calculate CPU power for physical packages and nodes */
-       for_each_cpu_mask(i, cpu_default_map) {
+       for_each_cpu_mask(i, *cpu_map) {
                int power;
                struct sched_domain *sd;
 #ifdef CONFIG_SCHED_SMT
@@ -359,13 +351,35 @@ next_sg:
                cpu_attach_domain(sd, i);
        }
 }
+/*
+ * Set up scheduler domains and groups.  Callers must hold the hotplug lock.
+ */
+void arch_init_sched_domains(const cpumask_t *cpu_map)
+{
+       cpumask_t cpu_default_map;
+
+       /*
+        * Setup mask for cpus without special case scheduling requirements.
+        * For now this just excludes isolated cpus, but could be used to
+        * exclude other special cases in the future.
+        */
+       cpus_andnot(cpu_default_map, *cpu_map, cpu_isolated_map);
+
+       build_sched_domains(&cpu_default_map);
+}
 
-void __devinit arch_destroy_sched_domains(void)
+void arch_destroy_sched_domains(const cpumask_t *cpu_map)
 {
 #ifdef CONFIG_NUMA
        int i;
        for (i = 0; i < MAX_NUMNODES; i++) {
+               cpumask_t nodemask = node_to_cpumask(i);
                struct sched_group *oldsg, *sg = sched_group_nodes[i];
+
+               cpus_and(nodemask, nodemask, *cpu_map);
+               if (cpus_empty(nodemask))
+                       continue;
+
                if (sg == NULL)
                        continue;
                sg = sg->next;
index b1d5d3d5276c8424a41f96f2c1009f7d0d31cfab..69f88d561d629c1a37ae7491a9229726d5398e3b 100644 (file)
@@ -470,18 +470,6 @@ ENTRY(load_switch_stack)
        br.cond.sptk.many b7
 END(load_switch_stack)
 
-GLOBAL_ENTRY(__ia64_syscall)
-       .regstk 6,0,0,0
-       mov r15=in5                             // put syscall number in place
-       break __BREAK_SYSCALL
-       movl r2=errno
-       cmp.eq p6,p7=-1,r10
-       ;;
-(p6)   st4 [r2]=r8
-(p6)   mov r8=-1
-       br.ret.sptk.many rp
-END(__ia64_syscall)
-
 GLOBAL_ENTRY(execve)
        mov r15=__NR_execve                     // put syscall number in place
        break __BREAK_SYSCALL
@@ -637,7 +625,7 @@ END(ia64_ret_from_syscall)
  *           r8-r11: restored (syscall return value(s))
  *              r12: restored (user-level stack pointer)
  *              r13: restored (user-level thread pointer)
- *              r14: cleared
+ *              r14: set to __kernel_syscall_via_epc
  *              r15: restored (syscall #)
  *          r16-r17: cleared
  *              r18: user-level b6
@@ -658,7 +646,7 @@ END(ia64_ret_from_syscall)
  *               pr: restored (user-level pr)
  *               b0: restored (user-level rp)
  *               b6: restored
- *               b7: cleared
+ *               b7: set to __kernel_syscall_via_epc
  *          ar.unat: restored (user-level ar.unat)
  *           ar.pfs: restored (user-level ar.pfs)
  *           ar.rsc: restored (user-level ar.rsc)
@@ -704,72 +692,79 @@ ENTRY(ia64_leave_syscall)
        ;;
 (p6)   ld4 r31=[r18]                           // load current_thread_info()->flags
        ld8 r19=[r2],PT(B6)-PT(LOADRS)          // load ar.rsc value for "loadrs"
-       mov b7=r0               // clear b7
+       nop.i 0
        ;;
-       ld8 r23=[r3],PT(R11)-PT(AR_BSPSTORE)    // load ar.bspstore (may be garbage)
+       mov r16=ar.bsp                          // M2  get existing backing store pointer
        ld8 r18=[r2],PT(R9)-PT(B6)              // load b6
 (p6)   and r15=TIF_WORK_MASK,r31               // any work other than TIF_SYSCALL_TRACE?
        ;;
-       mov r16=ar.bsp                          // M2  get existing backing store pointer
+       ld8 r23=[r3],PT(R11)-PT(AR_BSPSTORE)    // load ar.bspstore (may be garbage)
 (p6)   cmp4.ne.unc p6,p0=r15, r0               // any special work pending?
 (p6)   br.cond.spnt .work_pending_syscall
        ;;
        // start restoring the state saved on the kernel stack (struct pt_regs):
        ld8 r9=[r2],PT(CR_IPSR)-PT(R9)
        ld8 r11=[r3],PT(CR_IIP)-PT(R11)
-       mov f6=f0               // clear f6
+(pNonSys) break 0              //      bug check: we shouldn't be here if pNonSys is TRUE!
        ;;
        invala                  // M0|1 invalidate ALAT
-       rsm psr.i | psr.ic      // M2 initiate turning off of interrupt and interruption collection
-       mov f9=f0               // clear f9
+       rsm psr.i | psr.ic      // M2   turn off interrupts and interruption collection
+       cmp.eq p9,p0=r0,r0      // A    set p9 to indicate that we should restore cr.ifs
 
-       ld8 r29=[r2],16         // load cr.ipsr
-       ld8 r28=[r3],16                 // load cr.iip
-       mov f8=f0               // clear f8
+       ld8 r29=[r2],16         // M0|1 load cr.ipsr
+       ld8 r28=[r3],16         // M0|1 load cr.iip
+       mov r22=r0              // A    clear r22
        ;;
        ld8 r30=[r2],16         // M0|1 load cr.ifs
        ld8 r25=[r3],16         // M0|1 load ar.unat
-       cmp.eq p9,p0=r0,r0      // set p9 to indicate that we should restore cr.ifs
+(pUStk) add r14=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13
        ;;
        ld8 r26=[r2],PT(B0)-PT(AR_PFS)  // M0|1 load ar.pfs
-(pKStk)        mov r22=psr             // M2 read PSR now that interrupts are disabled
-       mov f10=f0              // clear f10
+(pKStk)        mov r22=psr                     // M2   read PSR now that interrupts are disabled
+       nop 0
        ;;
-       ld8 r21=[r2],PT(AR_RNAT)-PT(B0) // load b0
-       ld8 r27=[r3],PT(PR)-PT(AR_RSC)  // load ar.rsc
-       mov f11=f0              // clear f11
+       ld8 r21=[r2],PT(AR_RNAT)-PT(B0) // M0|1 load b0
+       ld8 r27=[r3],PT(PR)-PT(AR_RSC)  // M0|1 load ar.rsc
+       mov f6=f0                       // F    clear f6
        ;;
-       ld8 r24=[r2],PT(AR_FPSR)-PT(AR_RNAT)    // load ar.rnat (may be garbage)
-       ld8 r31=[r3],PT(R1)-PT(PR)              // load predicates
-(pUStk) add r14=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13
+       ld8 r24=[r2],PT(AR_FPSR)-PT(AR_RNAT)    // M0|1 load ar.rnat (may be garbage)
+       ld8 r31=[r3],PT(R1)-PT(PR)              // M0|1 load predicates
+       mov f7=f0                               // F    clear f7
        ;;
-       ld8 r20=[r2],PT(R12)-PT(AR_FPSR)        // load ar.fpsr
-       ld8.fill r1=[r3],16     // load r1
-(pUStk) mov r17=1
+       ld8 r20=[r2],PT(R12)-PT(AR_FPSR)        // M0|1 load ar.fpsr
+       ld8.fill r1=[r3],16                     // M0|1 load r1
+(pUStk) mov r17=1                              // A
        ;;
-       srlz.d                  // M0  ensure interruption collection is off
-       ld8.fill r13=[r3],16
-       mov f7=f0               // clear f7
+(pUStk) st1 [r14]=r17                          // M2|3
+       ld8.fill r13=[r3],16                    // M0|1
+       mov f8=f0                               // F    clear f8
        ;;
-       ld8.fill r12=[r2]       // restore r12 (sp)
-       mov.m ar.ssd=r0         // M2 clear ar.ssd
-       mov r22=r0              // clear r22
+       ld8.fill r12=[r2]                       // M0|1 restore r12 (sp)
+       ld8.fill r15=[r3]                       // M0|1 restore r15
+       mov b6=r18                              // I0   restore b6
 
-       ld8.fill r15=[r3]       // restore r15
-(pUStk) st1 [r14]=r17
-       addl r3=THIS_CPU(ia64_phys_stacked_size_p8),r0
+       addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 // A
+       mov f9=f0                                       // F    clear f9
+(pKStk) br.cond.dpnt.many skip_rbs_switch              // B
+
+       srlz.d                          // M0   ensure interruption collection is off (for cover)
+       shr.u r18=r19,16                // I0|1 get byte size of existing "dirty" partition
+       cover                           // B    add current frame into dirty partition & set cr.ifs
        ;;
-(pUStk)        ld4 r17=[r3]            // r17 = cpu_data->phys_stacked_size_p8
-       mov.m ar.csd=r0         // M2 clear ar.csd
-       mov b6=r18              // I0  restore b6
+(pUStk) ld4 r17=[r17]                  // M0|1 r17 = cpu_data->phys_stacked_size_p8
+       mov r19=ar.bsp                  // M2   get new backing store pointer
+       mov f10=f0                      // F    clear f10
+
+       nop.m 0
+       movl r14=__kernel_syscall_via_epc // X
        ;;
-       mov r14=r0              // clear r14
-       shr.u r18=r19,16        // I0|1 get byte size of existing "dirty" partition
-(pKStk) br.cond.dpnt.many skip_rbs_switch
+       mov.m ar.csd=r0                 // M2   clear ar.csd
+       mov.m ar.ccv=r0                 // M2   clear ar.ccv
+       mov b7=r14                      // I0   clear b7 (hint with __kernel_syscall_via_epc)
 
-       mov.m ar.ccv=r0         // clear ar.ccv
-(pNonSys) br.cond.dpnt.many dont_preserve_current_frame
-       br.cond.sptk.many rbs_switch
+       mov.m ar.ssd=r0                 // M2   clear ar.ssd
+       mov f11=f0                      // F    clear f11
+       br.cond.sptk.many rbs_switch    // B
 END(ia64_leave_syscall)
 
 #ifdef CONFIG_IA32_SUPPORT
@@ -885,7 +880,7 @@ GLOBAL_ENTRY(ia64_leave_kernel)
        ldf.fill f7=[r2],PT(F11)-PT(F7)
        ldf.fill f8=[r3],32
        ;;
-       srlz.i                  // ensure interruption collection is off
+       srlz.d  // ensure that inter. collection is off (VHPT is don't care, since text is pinned)
        mov ar.ccv=r15
        ;;
        ldf.fill f11=[r2]
@@ -945,11 +940,10 @@ GLOBAL_ENTRY(ia64_leave_kernel)
         * NOTE: alloc, loadrs, and cover can't be predicated.
         */
 (pNonSys) br.cond.dpnt dont_preserve_current_frame
-
-rbs_switch:
        cover                           // add current frame into dirty partition and set cr.ifs
        ;;
        mov r19=ar.bsp                  // get new backing store pointer
+rbs_switch:
        sub r16=r16,r18                 // krbs = old bsp - size of dirty partition
        cmp.ne p9,p0=r0,r0              // clear p9 to skip restore of cr.ifs
        ;;
@@ -1024,14 +1018,14 @@ rse_clear_invalid:
        mov loc5=0
        mov loc6=0
        mov loc7=0
-(pRecurse) br.call.sptk.few b0=rse_clear_invalid
+(pRecurse) br.call.dptk.few b0=rse_clear_invalid
        ;;
        mov loc8=0
        mov loc9=0
        cmp.ne pReturn,p0=r0,in1        // if recursion count != 0, we need to do a br.ret
        mov loc10=0
        mov loc11=0
-(pReturn) br.ret.sptk.many b0
+(pReturn) br.ret.dptk.many b0
 #endif /* !CONFIG_ITANIUM */
 #      undef pRecurse
 #      undef pReturn
@@ -1577,8 +1571,8 @@ sys_call_table:
        data8 sys_add_key
        data8 sys_request_key
        data8 sys_keyctl
-       data8 sys_ni_syscall
-       data8 sys_ni_syscall                    // 1275
+       data8 sys_ioprio_set
+       data8 sys_ioprio_get                    // 1275
        data8 sys_set_zone_reclaim
        data8 sys_ni_syscall
        data8 sys_ni_syscall
index 962b6c4e32b5b92f8182ff0b600350d37b35242c..7d7684a369d38609a149e98db03084f898eacb90 100644 (file)
@@ -531,93 +531,114 @@ GLOBAL_ENTRY(fsys_bubble_down)
        .altrp b6
        .body
        /*
-        * We get here for syscalls that don't have a lightweight handler.  For those, we
-        * need to bubble down into the kernel and that requires setting up a minimal
-        * pt_regs structure, and initializing the CPU state more or less as if an
-        * interruption had occurred.  To make syscall-restarts work, we setup pt_regs
-        * such that cr_iip points to the second instruction in syscall_via_break.
-        * Decrementing the IP hence will restart the syscall via break and not
-        * decrementing IP will return us to the caller, as usual.  Note that we preserve
-        * the value of psr.pp rather than initializing it from dcr.pp.  This makes it
-        * possible to distinguish fsyscall execution from other privileged execution.
+        * We get here for syscalls that don't have a lightweight
+        * handler.  For those, we need to bubble down into the kernel
+        * and that requires setting up a minimal pt_regs structure,
+        * and initializing the CPU state more or less as if an
+        * interruption had occurred.  To make syscall-restarts work,
+        * we setup pt_regs such that cr_iip points to the second
+        * instruction in syscall_via_break.  Decrementing the IP
+        * hence will restart the syscall via break and not
+        * decrementing IP will return us to the caller, as usual.
+        * Note that we preserve the value of psr.pp rather than
+        * initializing it from dcr.pp.  This makes it possible to
+        * distinguish fsyscall execution from other privileged
+        * execution.
         *
         * On entry:
-        *      - normal fsyscall handler register usage, except that we also have:
+        *      - normal fsyscall handler register usage, except
+        *        that we also have:
         *      - r18: address of syscall entry point
         *      - r21: ar.fpsr
         *      - r26: ar.pfs
         *      - r27: ar.rsc
         *      - r29: psr
+        *
+        * We used to clear some PSR bits here but that requires slow
+        * serialization.  Fortuntely, that isn't really necessary.
+        * The rationale is as follows: we used to clear bits
+        * ~PSR_PRESERVED_BITS in PSR.L.  Since
+        * PSR_PRESERVED_BITS==PSR.{UP,MFL,MFH,PK,DT,PP,SP,RT,IC}, we
+        * ended up clearing PSR.{BE,AC,I,DFL,DFH,DI,DB,SI,TB}.
+        * However,
+        *
+        * PSR.BE : already is turned off in __kernel_syscall_via_epc()
+        * PSR.AC : don't care (kernel normally turns PSR.AC on)
+        * PSR.I  : already turned off by the time fsys_bubble_down gets
+        *          invoked
+        * PSR.DFL: always 0 (kernel never turns it on)
+        * PSR.DFH: don't care --- kernel never touches f32-f127 on its own
+        *          initiative
+        * PSR.DI : always 0 (kernel never turns it on)
+        * PSR.SI : always 0 (kernel never turns it on)
+        * PSR.DB : don't care --- kernel never enables kernel-level
+        *          breakpoints
+        * PSR.TB : must be 0 already; if it wasn't zero on entry to
+        *          __kernel_syscall_via_epc, the branch to fsys_bubble_down
+        *          will trigger a taken branch; the taken-trap-handler then
+        *          converts the syscall into a break-based system-call.
         */
-#      define PSR_PRESERVED_BITS       (IA64_PSR_UP | IA64_PSR_MFL | IA64_PSR_MFH | IA64_PSR_PK \
-                                        | IA64_PSR_DT | IA64_PSR_PP | IA64_PSR_SP | IA64_PSR_RT \
-                                        | IA64_PSR_IC)
        /*
-        * Reading psr.l gives us only bits 0-31, psr.it, and psr.mc.  The rest we have
-        * to synthesize.
+        * Reading psr.l gives us only bits 0-31, psr.it, and psr.mc.
+        * The rest we have to synthesize.
         */
-#      define PSR_ONE_BITS             ((3 << IA64_PSR_CPL0_BIT) | (0x1 << IA64_PSR_RI_BIT) \
+#      define PSR_ONE_BITS             ((3 << IA64_PSR_CPL0_BIT)       \
+                                        | (0x1 << IA64_PSR_RI_BIT)     \
                                         | IA64_PSR_BN | IA64_PSR_I)
 
-       invala
-       movl r8=PSR_ONE_BITS
+       invala                                  // M0|1
+       movl r14=ia64_ret_from_syscall          // X
 
-       mov r25=ar.unat                 // save ar.unat (5 cyc)
-       movl r9=PSR_PRESERVED_BITS
+       nop.m 0
+       movl r28=__kernel_syscall_via_break     // X    create cr.iip
+       ;;
 
-       mov ar.rsc=0                    // set enforced lazy mode, pl 0, little-endian, loadrs=0
-       movl r28=__kernel_syscall_via_break
+       mov r2=r16                              // A    get task addr to addl-addressable register
+       adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 // A
+       mov r31=pr                              // I0   save pr (2 cyc)
        ;;
-       mov r23=ar.bspstore             // save ar.bspstore (12 cyc)
-       mov r31=pr                      // save pr (2 cyc)
-       mov r20=r1                      // save caller's gp in r20
+       st1 [r16]=r0                            // M2|3 clear current->thread.on_ustack flag
+       addl r22=IA64_RBS_OFFSET,r2             // A    compute base of RBS
+       add r3=TI_FLAGS+IA64_TASK_SIZE,r2       // A
        ;;
-       mov r2=r16                      // copy current task addr to addl-addressable register
-       and r9=r9,r29
-       mov r19=b6                      // save b6 (2 cyc)
+       ld4 r3=[r3]                             // M0|1 r3 = current_thread_info()->flags
+       lfetch.fault.excl.nt1 [r22]             // M0|1 prefetch register backing-store
+       nop.i 0
        ;;
-       mov psr.l=r9                    // slam the door (17 cyc to srlz.i)
-       or r29=r8,r29                   // construct cr.ipsr value to save
-       addl r22=IA64_RBS_OFFSET,r2     // compute base of RBS
+       mov ar.rsc=0                            // M2   set enforced lazy mode, pl 0, LE, loadrs=0
+       nop.m 0
+       nop.i 0
        ;;
-       // GAS reports a spurious RAW hazard on the read of ar.rnat because it thinks
-       // we may be reading ar.itc after writing to psr.l.  Avoid that message with
-       // this directive:
-       dv_serialize_data
-       mov.m r24=ar.rnat               // read ar.rnat (5 cyc lat)
-       lfetch.fault.excl.nt1 [r22]
-       adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r2
-
-       // ensure previous insn group is issued before we stall for srlz.i:
+       mov r23=ar.bspstore                     // M2 (12 cyc) save ar.bspstore
+       mov.m r24=ar.rnat                       // M2 (5 cyc) read ar.rnat (dual-issues!)
+       nop.i 0
        ;;
-       srlz.i                          // ensure new psr.l has been established
-       /////////////////////////////////////////////////////////////////////////////
-       ////////// from this point on, execution is not interruptible anymore
-       /////////////////////////////////////////////////////////////////////////////
-       addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2    // compute base of memory stack
-       cmp.ne pKStk,pUStk=r0,r0        // set pKStk <- 0, pUStk <- 1
+       mov ar.bspstore=r22                     // M2 (6 cyc) switch to kernel RBS
+       movl r8=PSR_ONE_BITS                    // X
        ;;
-       st1 [r16]=r0                    // clear current->thread.on_ustack flag
-       mov ar.bspstore=r22             // switch to kernel RBS
-       mov b6=r18                      // copy syscall entry-point to b6 (7 cyc)
-       add r3=TI_FLAGS+IA64_TASK_SIZE,r2
+       mov r25=ar.unat                         // M2 (5 cyc) save ar.unat
+       mov r19=b6                              // I0   save b6 (2 cyc)
+       mov r20=r1                              // A    save caller's gp in r20
        ;;
-       ld4 r3=[r3]                             // r2 = current_thread_info()->flags
-       mov r18=ar.bsp                  // save (kernel) ar.bsp (12 cyc)
-       mov ar.rsc=0x3                  // set eager mode, pl 0, little-endian, loadrs=0
-       br.call.sptk.many b7=ia64_syscall_setup
-       ;;
-       ssm psr.i
-       movl r2=ia64_ret_from_syscall
+       or r29=r8,r29                           // A    construct cr.ipsr value to save
+       mov b6=r18                              // I0   copy syscall entry-point to b6 (7 cyc)
+       addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 // A compute base of memory stack
+
+       mov r18=ar.bsp                          // M2   save (kernel) ar.bsp (12 cyc)
+       cmp.ne pKStk,pUStk=r0,r0                // A    set pKStk <- 0, pUStk <- 1
+       br.call.sptk.many b7=ia64_syscall_setup // B
        ;;
-       mov rp=r2                               // set the real return addr
-       and r3=_TIF_SYSCALL_TRACEAUDIT,r3
+       mov ar.rsc=0x3                          // M2   set eager mode, pl 0, LE, loadrs=0
+       mov rp=r14                              // I0   set the real return addr
+       and r3=_TIF_SYSCALL_TRACEAUDIT,r3       // A
        ;;
-       cmp.eq p8,p0=r3,r0
+       ssm psr.i                               // M2   we're on kernel stacks now, reenable irqs
+       cmp.eq p8,p0=r3,r0                      // A
+(p10)  br.cond.spnt.many ia64_ret_from_syscall // B    return if bad call-frame or r15 is a NaT
 
-(p10)  br.cond.spnt.many ia64_ret_from_syscall // p10==true means out registers are more than 8
-(p8)   br.call.sptk.many b6=b6         // ignore this return addr
-       br.cond.sptk ia64_trace_syscall
+       nop.m 0
+(p8)   br.call.sptk.many b6=b6                 // B    (ignore return address)
+       br.cond.spnt ia64_trace_syscall         // B
 END(fsys_bubble_down)
 
        .rodata
index facf75acdc85d6d9d96cabdb1d1d716516d2717b..86948ce63e43ac8ac583eec74622434b86e5cd73 100644 (file)
@@ -72,38 +72,40 @@ GLOBAL_ENTRY(__kernel_syscall_via_epc)
         * bundle get executed.  The remaining code must be safe even if
         * they do not get executed.
         */
-       adds r17=-1024,r15
-       mov r10=0                               // default to successful syscall execution
-       epc
+       adds r17=-1024,r15                      // A
+       mov r10=0                               // A    default to successful syscall execution
+       epc                                     // B    causes split-issue
 }
        ;;
-       rsm psr.be // note: on McKinley "rsm psr.be/srlz.d" is slightly faster than "rum psr.be"
-       LOAD_FSYSCALL_TABLE(r14)
-
-       mov r16=IA64_KR(CURRENT)                // 12 cycle read latency
-       tnat.nz p10,p9=r15
-       mov r19=NR_syscalls-1
+       rsm psr.be | psr.i                      // M2 (5 cyc to srlz.d)
+       LOAD_FSYSCALL_TABLE(r14)                // X
        ;;
-       shladd r18=r17,3,r14
-
-       srlz.d
-       cmp.ne p8,p0=r0,r0                      // p8 <- FALSE
-       /* Note: if r17 is a NaT, p6 will be set to zero.  */
-       cmp.geu p6,p7=r19,r17                   // (syscall > 0 && syscall < 1024+NR_syscalls)?
-       ;;
-(p6)   ld8 r18=[r18]
-       mov r21=ar.fpsr
-       add r14=-8,r14                          // r14 <- addr of fsys_bubble_down entry
-       ;;
-(p6)   mov b7=r18
-(p6)   tbit.z p8,p0=r18,0
-(p8)   br.dptk.many b7
-
-(p6)   rsm psr.i
-       mov r27=ar.rsc
-       mov r26=ar.pfs
+       mov r16=IA64_KR(CURRENT)                // M2 (12 cyc)
+       shladd r18=r17,3,r14                    // A
+       mov r19=NR_syscalls-1                   // A
+       ;;
+       lfetch [r18]                            // M0|1
+       mov r29=psr                             // M2 (12 cyc)
+       // If r17 is a NaT, p6 will be zero
+       cmp.geu p6,p7=r19,r17                   // A    (sysnr > 0 && sysnr < 1024+NR_syscalls)?
+       ;;
+       mov r21=ar.fpsr                         // M2 (12 cyc)
+       tnat.nz p10,p9=r15                      // I0
+       mov.i r26=ar.pfs                        // I0 (would stall anyhow due to srlz.d...)
+       ;;
+       srlz.d                                  // M0 (forces split-issue) ensure PSR.BE==0
+(p6)   ld8 r18=[r18]                           // M0|1
+       nop.i 0
+       ;;
+       nop.m 0
+(p6)   tbit.z.unc p8,p0=r18,0                  // I0 (dual-issues with "mov b7=r18"!)
+       nop.i 0
        ;;
-       mov r29=psr                             // read psr (12 cyc load latency)
+(p8)   ssm psr.i
+(p6)   mov b7=r18                              // I0
+(p8)   br.dptk.many b7                         // B
+
+       mov r27=ar.rsc                          // M2 (12 cyc)
 /*
  * brl.cond doesn't work as intended because the linker would convert this branch
  * into a branch to a PLT.  Perhaps there will be a way to avoid this with some
@@ -111,6 +113,8 @@ GLOBAL_ENTRY(__kernel_syscall_via_epc)
  * instead.
  */
 #ifdef CONFIG_ITANIUM
+(p6)   add r14=-8,r14                          // r14 <- addr of fsys_bubble_down entry
+       ;;
 (p6)   ld8 r14=[r14]                           // r14 <- fsys_bubble_down
        ;;
 (p6)   mov b7=r14
@@ -118,7 +122,7 @@ GLOBAL_ENTRY(__kernel_syscall_via_epc)
 #else
        BRL_COND_FSYS_BUBBLE_DOWN(p6)
 #endif
-
+       ssm psr.i
        mov r10=-1
 (p10)  mov r8=EINVAL
 (p9)   mov r8=ENOSYS
index 7bbf019c9867842251b5552bd934274cdd532ee3..01572814abe42bfefff13b134c58bfe3ebd38e07 100644 (file)
@@ -58,9 +58,6 @@ EXPORT_SYMBOL(__strlen_user);
 EXPORT_SYMBOL(__strncpy_from_user);
 EXPORT_SYMBOL(__strnlen_user);
 
-#include <asm/unistd.h>
-EXPORT_SYMBOL(__ia64_syscall);
-
 /* from arch/ia64/lib */
 extern void __divsi3(void);
 extern void __udivsi3(void);
index 88b014381df5f8b11a73e8652d88757b0692cdf0..c170be095ccdcd56ea16aa0b3cfd087c949a26df 100644 (file)
@@ -129,14 +129,13 @@ static struct iosapic {
        char __iomem    *addr;          /* base address of IOSAPIC */
        unsigned int    gsi_base;       /* first GSI assigned to this IOSAPIC */
        unsigned short  num_rte;        /* number of RTE in this IOSAPIC */
+       int             rtes_inuse;     /* # of RTEs in use on this IOSAPIC */
 #ifdef CONFIG_NUMA
        unsigned short  node;           /* numa node association via pxm */
 #endif
 } iosapic_lists[NR_IOSAPICS];
 
-static int num_iosapic;
-
-static unsigned char pcat_compat __initdata;   /* 8259 compatibility flag */
+static unsigned char pcat_compat __devinitdata;        /* 8259 compatibility flag */
 
 static int iosapic_kmalloc_ok;
 static LIST_HEAD(free_rte_list);
@@ -149,7 +148,7 @@ find_iosapic (unsigned int gsi)
 {
        int i;
 
-       for (i = 0; i < num_iosapic; i++) {
+       for (i = 0; i < NR_IOSAPICS; i++) {
                if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
                        return i;
        }
@@ -598,6 +597,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
                rte->refcnt++;
                list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
                iosapic_intr_info[vector].count++;
+               iosapic_lists[index].rtes_inuse++;
        }
        else if (vector_is_shared(vector)) {
                struct iosapic_intr_info *info = &iosapic_intr_info[vector];
@@ -778,7 +778,7 @@ void
 iosapic_unregister_intr (unsigned int gsi)
 {
        unsigned long flags;
-       int irq, vector;
+       int irq, vector, index;
        irq_desc_t *idesc;
        u32 low32;
        unsigned long trigger, polarity;
@@ -819,6 +819,9 @@ iosapic_unregister_intr (unsigned int gsi)
                list_del(&rte->rte_list);
                iosapic_intr_info[vector].count--;
                iosapic_free_rte(rte);
+               index = find_iosapic(gsi);
+               iosapic_lists[index].rtes_inuse--;
+               WARN_ON(iosapic_lists[index].rtes_inuse < 0);
 
                trigger  = iosapic_intr_info[vector].trigger;
                polarity = iosapic_intr_info[vector].polarity;
@@ -952,30 +955,86 @@ iosapic_system_init (int system_pcat_compat)
        }
 }
 
-void __init
+static inline int
+iosapic_alloc (void)
+{
+       int index;
+
+       for (index = 0; index < NR_IOSAPICS; index++)
+               if (!iosapic_lists[index].addr)
+                       return index;
+
+       printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__);
+       return -1;
+}
+
+static inline void
+iosapic_free (int index)
+{
+       memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0]));
+}
+
+static inline int
+iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
+{
+       int index;
+       unsigned int gsi_end, base, end;
+
+       /* check gsi range */
+       gsi_end = gsi_base + ((ver >> 16) & 0xff);
+       for (index = 0; index < NR_IOSAPICS; index++) {
+               if (!iosapic_lists[index].addr)
+                       continue;
+
+               base = iosapic_lists[index].gsi_base;
+               end  = base + iosapic_lists[index].num_rte - 1;
+
+               if (gsi_base < base && gsi_end < base)
+                       continue;/* OK */
+
+               if (gsi_base > end && gsi_end > end)
+                       continue; /* OK */
+
+               return -EBUSY;
+       }
+       return 0;
+}
+
+int __devinit
 iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
 {
-       int num_rte;
+       int num_rte, err, index;
        unsigned int isa_irq, ver;
        char __iomem *addr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&iosapic_lock, flags);
+       {
+               addr = ioremap(phys_addr, 0);
+               ver = iosapic_version(addr);
 
-       addr = ioremap(phys_addr, 0);
-       ver = iosapic_version(addr);
+               if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
+                       iounmap(addr);
+                       spin_unlock_irqrestore(&iosapic_lock, flags);
+                       return err;
+               }
 
-       /*
-        * The MAX_REDIR register holds the highest input pin
-        * number (starting from 0).
-        * We add 1 so that we can use it for number of pins (= RTEs)
-        */
-       num_rte = ((ver >> 16) & 0xff) + 1;
+               /*
+                * The MAX_REDIR register holds the highest input pin
+                * number (starting from 0).
+                * We add 1 so that we can use it for number of pins (= RTEs)
+                */
+               num_rte = ((ver >> 16) & 0xff) + 1;
 
-       iosapic_lists[num_iosapic].addr = addr;
-       iosapic_lists[num_iosapic].gsi_base = gsi_base;
-       iosapic_lists[num_iosapic].num_rte = num_rte;
+               index = iosapic_alloc();
+               iosapic_lists[index].addr = addr;
+               iosapic_lists[index].gsi_base = gsi_base;
+               iosapic_lists[index].num_rte = num_rte;
 #ifdef CONFIG_NUMA
-       iosapic_lists[num_iosapic].node = MAX_NUMNODES;
+               iosapic_lists[index].node = MAX_NUMNODES;
 #endif
-       num_iosapic++;
+       }
+       spin_unlock_irqrestore(&iosapic_lock, flags);
 
        if ((gsi_base == 0) && pcat_compat) {
                /*
@@ -986,10 +1045,43 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
                for (isa_irq = 0; isa_irq < 16; ++isa_irq)
                        iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
        }
+       return 0;
+}
+
+#ifdef CONFIG_HOTPLUG
+int
+iosapic_remove (unsigned int gsi_base)
+{
+       int index, err = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&iosapic_lock, flags);
+       {
+               index = find_iosapic(gsi_base);
+               if (index < 0) {
+                       printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
+                              __FUNCTION__, gsi_base);
+                       goto out;
+               }
+
+               if (iosapic_lists[index].rtes_inuse) {
+                       err = -EBUSY;
+                       printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
+                              __FUNCTION__, gsi_base);
+                       goto out;
+               }
+
+               iounmap(iosapic_lists[index].addr);
+               iosapic_free(index);
+       }
+ out:
+       spin_unlock_irqrestore(&iosapic_lock, flags);
+       return err;
 }
+#endif /* CONFIG_HOTPLUG */
 
 #ifdef CONFIG_NUMA
-void __init
+void __devinit
 map_iosapic_to_node(unsigned int gsi_base, int node)
 {
        int index;
index 2bc085a73e30caa60ed47fab2689817216e2675a..3bb3a13c4047566d70057db9342c93da06fefd8e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/ia64/kernel/ivt.S
  *
- * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co
+ * Copyright (C) 1998-2001, 2003, 2005 Hewlett-Packard Co
  *     Stephane Eranian <eranian@hpl.hp.com>
  *     David Mosberger <davidm@hpl.hp.com>
  * Copyright (C) 2000, 2002-2003 Intel Co
@@ -692,82 +692,118 @@ ENTRY(break_fault)
         * to prevent leaking bits from kernel to user level.
         */
        DBG_FAULT(11)
-       mov r16=IA64_KR(CURRENT)                // r16 = current task; 12 cycle read lat.
-       mov r17=cr.iim
-       mov r18=__IA64_BREAK_SYSCALL
-       mov r21=ar.fpsr
-       mov r29=cr.ipsr
-       mov r19=b6
-       mov r25=ar.unat
-       mov r27=ar.rsc
-       mov r26=ar.pfs
-       mov r28=cr.iip
-       mov r31=pr                              // prepare to save predicates
-       mov r20=r1
-       ;;
+       mov.m r16=IA64_KR(CURRENT)              // M2 r16 <- current task (12 cyc)
+       mov r29=cr.ipsr                         // M2 (12 cyc)
+       mov r31=pr                              // I0 (2 cyc)
+
+       mov r17=cr.iim                          // M2 (2 cyc)
+       mov.m r27=ar.rsc                        // M2 (12 cyc)
+       mov r18=__IA64_BREAK_SYSCALL            // A
+
+       mov.m ar.rsc=0                          // M2
+       mov.m r21=ar.fpsr                       // M2 (12 cyc)
+       mov r19=b6                              // I0 (2 cyc)
+       ;;
+       mov.m r23=ar.bspstore                   // M2 (12 cyc)
+       mov.m r24=ar.rnat                       // M2 (5 cyc)
+       mov.i r26=ar.pfs                        // I0 (2 cyc)
+
+       invala                                  // M0|1
+       nop.m 0                                 // M
+       mov r20=r1                              // A                    save r1
+
+       nop.m 0
+       movl r30=sys_call_table                 // X
+
+       mov r28=cr.iip                          // M2 (2 cyc)
+       cmp.eq p0,p7=r18,r17                    // I0 is this a system call?
+(p7)   br.cond.spnt non_syscall                // B  no ->
+       //
+       // From this point on, we are definitely on the syscall-path
+       // and we can use (non-banked) scratch registers.
+       //
+///////////////////////////////////////////////////////////////////////
+       mov r1=r16                              // A    move task-pointer to "addl"-addressable reg
+       mov r2=r16                              // A    setup r2 for ia64_syscall_setup
+       add r9=TI_FLAGS+IA64_TASK_SIZE,r16      // A    r9 = &current_thread_info()->flags
+
        adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16
-       cmp.eq p0,p7=r18,r17                    // is this a system call? (p7 <- false, if so)
-(p7)   br.cond.spnt non_syscall
+       adds r15=-1024,r15                      // A    subtract 1024 from syscall number
+       mov r3=NR_syscalls - 1
        ;;
-       ld1 r17=[r16]                           // load current->thread.on_ustack flag
-       st1 [r16]=r0                            // clear current->thread.on_ustack flag
-       add r1=-IA64_TASK_THREAD_ON_USTACK_OFFSET,r16   // set r1 for MINSTATE_START_SAVE_MIN_VIRT
+       ld1.bias r17=[r16]                      // M0|1 r17 = current->thread.on_ustack flag
+       ld4 r9=[r9]                             // M0|1 r9 = current_thread_info()->flags
+       extr.u r8=r29,41,2                      // I0   extract ei field from cr.ipsr
+
+       shladd r30=r15,3,r30                    // A    r30 = sys_call_table + 8*(syscall-1024)
+       addl r22=IA64_RBS_OFFSET,r1             // A    compute base of RBS
+       cmp.leu p6,p7=r15,r3                    // A    syscall number in range?
        ;;
-       invala
 
-       /* adjust return address so we skip over the break instruction: */
+       lfetch.fault.excl.nt1 [r22]             // M0|1 prefetch RBS
+(p6)   ld8 r30=[r30]                           // M0|1 load address of syscall entry point
+       tnat.nz.or p7,p0=r15                    // I0   is syscall nr a NaT?
 
-       extr.u r8=r29,41,2                      // extract ei field from cr.ipsr
-       ;;
-       cmp.eq p6,p7=2,r8                       // isr.ei==2?
-       mov r2=r1                               // setup r2 for ia64_syscall_setup
-       ;;
-(p6)   mov r8=0                                // clear ei to 0
-(p6)   adds r28=16,r28                         // switch cr.iip to next bundle cr.ipsr.ei wrapped
-(p7)   adds r8=1,r8                            // increment ei to next slot
-       ;;
-       cmp.eq pKStk,pUStk=r0,r17               // are we in kernel mode already?
-       dep r29=r8,r29,41,2                     // insert new ei into cr.ipsr
+       mov.m ar.bspstore=r22                   // M2   switch to kernel RBS
+       cmp.eq p8,p9=2,r8                       // A    isr.ei==2?
        ;;
 
-       // switch from user to kernel RBS:
-       MINSTATE_START_SAVE_MIN_VIRT
-       br.call.sptk.many b7=ia64_syscall_setup
-       ;;
-       MINSTATE_END_SAVE_MIN_VIRT              // switch to bank 1
-       ssm psr.ic | PSR_DEFAULT_BITS
-       ;;
-       srlz.i                                  // guarantee that interruption collection is on
-       mov r3=NR_syscalls - 1
-       ;;
-(p15)  ssm psr.i                               // restore psr.i
-       // p10==true means out registers are more than 8 or r15's Nat is true
-(p10)  br.cond.spnt.many ia64_ret_from_syscall
-       ;;
-       movl r16=sys_call_table
+(p8)   mov r8=0                                // A    clear ei to 0
+(p7)   movl r30=sys_ni_syscall                 // X
 
-       adds r15=-1024,r15                      // r15 contains the syscall number---subtract 1024
-       movl r2=ia64_ret_from_syscall
-       ;;
-       shladd r20=r15,3,r16                    // r20 = sys_call_table + 8*(syscall-1024)
-       cmp.leu p6,p7=r15,r3                    // (syscall > 0 && syscall < 1024 + NR_syscalls) ?
-       mov rp=r2                               // set the real return addr
+(p8)   adds r28=16,r28                         // A    switch cr.iip to next bundle
+(p9)   adds r8=1,r8                            // A    increment ei to next slot
+       nop.i 0
        ;;
-(p6)   ld8 r20=[r20]                           // load address of syscall entry point
-(p7)   movl r20=sys_ni_syscall
 
-       add r2=TI_FLAGS+IA64_TASK_SIZE,r13
-       ;;
-       ld4 r2=[r2]                             // r2 = current_thread_info()->flags
-       ;;
-       and r2=_TIF_SYSCALL_TRACEAUDIT,r2       // mask trace or audit
+       mov.m r25=ar.unat                       // M2 (5 cyc)
+       dep r29=r8,r29,41,2                     // I0   insert new ei into cr.ipsr
+       adds r15=1024,r15                       // A    restore original syscall number
+       //
+       // If any of the above loads miss in L1D, we'll stall here until
+       // the data arrives.
+       //
+///////////////////////////////////////////////////////////////////////
+       st1 [r16]=r0                            // M2|3 clear current->thread.on_ustack flag
+       mov b6=r30                              // I0   setup syscall handler branch reg early
+       cmp.eq pKStk,pUStk=r0,r17               // A    were we on kernel stacks already?
+
+       and r9=_TIF_SYSCALL_TRACEAUDIT,r9       // A    mask trace or audit
+       mov r18=ar.bsp                          // M2 (12 cyc)
+(pKStk)        br.cond.spnt .break_fixup               // B    we're already in kernel-mode -- fix up RBS
+       ;;
+.back_from_break_fixup:
+(pUStk)        addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1 // A    compute base of memory stack
+       cmp.eq p14,p0=r9,r0                     // A    are syscalls being traced/audited?
+       br.call.sptk.many b7=ia64_syscall_setup // B
+1:
+       mov ar.rsc=0x3                          // M2   set eager mode, pl 0, LE, loadrs=0
+       nop 0
+       bsw.1                                   // B (6 cyc) regs are saved, switch to bank 1
        ;;
-       cmp.eq p8,p0=r2,r0
-       mov b6=r20
+
+       ssm psr.ic | PSR_DEFAULT_BITS           // M2   now it's safe to re-enable intr.-collection
+       movl r3=ia64_ret_from_syscall           // X
        ;;
-(p8)   br.call.sptk.many b6=b6                 // ignore this return addr
-       br.cond.sptk ia64_trace_syscall
+
+       srlz.i                                  // M0   ensure interruption collection is on
+       mov rp=r3                               // I0   set the real return addr
+(p10)  br.cond.spnt.many ia64_ret_from_syscall // B    return if bad call-frame or r15 is a NaT
+
+(p15)  ssm psr.i                               // M2   restore psr.i
+(p14)  br.call.sptk.many b6=b6                 // B    invoke syscall-handker (ignore return addr)
+       br.cond.spnt.many ia64_trace_syscall    // B    do syscall-tracing thingamagic
        // NOT REACHED
+///////////////////////////////////////////////////////////////////////
+       // On entry, we optimistically assumed that we're coming from user-space.
+       // For the rare cases where a system-call is done from within the kernel,
+       // we fix things up at this point:
+.break_fixup:
+       add r1=-IA64_PT_REGS_SIZE,sp            // A    allocate space for pt_regs structure
+       mov ar.rnat=r24                         // M2   restore kernel's AR.RNAT
+       ;;
+       mov ar.bspstore=r23                     // M2   restore kernel's AR.BSPSTORE
+       br.cond.sptk .back_from_break_fixup
 END(break_fault)
 
        .org ia64_ivt+0x3000
@@ -842,8 +878,6 @@ END(interrupt)
         *      - r31: saved pr
         *      -  b0: original contents (to be saved)
         * On exit:
-        *      - executing on bank 1 registers
-        *      - psr.ic enabled, interrupts restored
         *      -  p10: TRUE if syscall is invoked with more than 8 out
         *              registers or r15's Nat is true
         *      -  r1: kernel's gp
@@ -851,8 +885,11 @@ END(interrupt)
         *      -  r8: -EINVAL if p10 is true
         *      - r12: points to kernel stack
         *      - r13: points to current task
+        *      - r14: preserved (same as on entry)
+        *      - p13: preserved
         *      - p15: TRUE if interrupts need to be re-enabled
         *      - ar.fpsr: set to kernel settings
+        *      -  b6: preserved (same as on entry)
         */
 GLOBAL_ENTRY(ia64_syscall_setup)
 #if PT(B6) != 0
@@ -920,10 +957,10 @@ GLOBAL_ENTRY(ia64_syscall_setup)
 (p13)  mov in5=-1
        ;;
        st8 [r16]=r21,PT(R8)-PT(AR_FPSR)        // save ar.fpsr
-       tnat.nz p14,p0=in6
+       tnat.nz p13,p0=in6
        cmp.lt p10,p9=r11,r8    // frame size can't be more than local+8
        ;;
-       stf8 [r16]=f1           // ensure pt_regs.r8 != 0 (see handle_syscall_error)
+       mov r8=1
 (p9)   tnat.nz p10,p0=r15
        adds r12=-16,r1         // switch to kernel memory stack (with 16 bytes of scratch)
 
@@ -934,9 +971,9 @@ GLOBAL_ENTRY(ia64_syscall_setup)
        mov r13=r2                              // establish `current'
        movl r1=__gp                            // establish kernel global pointer
        ;;
-(p14)  mov in6=-1
+       st8 [r16]=r8            // ensure pt_regs.r8 != 0 (see handle_syscall_error)
+(p13)  mov in6=-1
 (p8)   mov in7=-1
-       nop.i 0
 
        cmp.eq pSys,pNonSys=r0,r0               // set pSys=1, pNonSys=0
        movl r17=FPSR_DEFAULT
@@ -1007,6 +1044,8 @@ END(dispatch_illegal_op_fault)
        FAULT(17)
 
 ENTRY(non_syscall)
+       mov ar.rsc=r27                  // restore ar.rsc before SAVE_MIN_WITH_COVER
+       ;;
        SAVE_MIN_WITH_COVER
 
        // There is no particular reason for this code to be here, other than that
@@ -1204,6 +1243,25 @@ END(disabled_fp_reg)
 // 0x5600 Entry 26 (size 16 bundles) Nat Consumption (11,23,37,50)
 ENTRY(nat_consumption)
        DBG_FAULT(26)
+
+       mov r16=cr.ipsr
+       mov r17=cr.isr
+       mov r31=pr                              // save PR
+       ;;
+       and r18=0xf,r17                         // r18 = cr.ipsr.code{3:0}
+       tbit.z p6,p0=r17,IA64_ISR_NA_BIT
+       ;;
+       cmp.ne.or p6,p0=IA64_ISR_CODE_LFETCH,r18
+       dep r16=-1,r16,IA64_PSR_ED_BIT,1
+(p6)   br.cond.spnt 1f         // branch if (cr.ispr.na == 0 || cr.ipsr.code{3:0} != LFETCH)
+       ;;
+       mov cr.ipsr=r16         // set cr.ipsr.na
+       mov pr=r31,-1
+       ;;
+       rfi
+
+1:     mov pr=r31,-1
+       ;;
        FAULT(26)
 END(nat_consumption)
 
index 5978823d5c63ce3fbc891c2108ddd6c98579e739..3aa3167edbec218241d4b167593728ad99542efd 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <asm/pgtable.h>
 #include <asm/kdebug.h>
+#include <asm/sections.h>
 
 extern void jprobe_inst_return(void);
 
@@ -263,13 +264,33 @@ static inline void get_kprobe_inst(bundle_t *bundle, uint slot,
        }
 }
 
+/* Returns non-zero if the addr is in the Interrupt Vector Table */
+static inline int in_ivt_functions(unsigned long addr)
+{
+       return (addr >= (unsigned long)__start_ivt_text
+               && addr < (unsigned long)__end_ivt_text);
+}
+
 static int valid_kprobe_addr(int template, int slot, unsigned long addr)
 {
        if ((slot > 2) || ((bundle_encoding[template][1] == L) && slot > 1)) {
-               printk(KERN_WARNING "Attempting to insert unaligned kprobe at 0x%lx\n",
-                               addr);
+               printk(KERN_WARNING "Attempting to insert unaligned kprobe "
+                               "at 0x%lx\n", addr);
                return -EINVAL;
        }
+
+       if (in_ivt_functions(addr)) {
+               printk(KERN_WARNING "Kprobes can't be inserted inside "
+                               "IVT functions at 0x%lx\n", addr);
+               return -EINVAL;
+       }
+
+       if (slot == 1 && bundle_encoding[template][1] != L) {
+               printk(KERN_WARNING "Inserting kprobes on slot #1 "
+                      "is not supported\n");
+               return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -290,6 +311,94 @@ static inline void set_current_kprobe(struct kprobe *p)
        current_kprobe = p;
 }
 
+static void kretprobe_trampoline(void)
+{
+}
+
+/*
+ * At this point the target function has been tricked into
+ * returning into our trampoline.  Lookup the associated instance
+ * and then:
+ *    - call the handler function
+ *    - cleanup by marking the instance as unused
+ *    - long jump back to the original return address
+ */
+int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct kretprobe_instance *ri = NULL;
+       struct hlist_head *head;
+       struct hlist_node *node, *tmp;
+       unsigned long orig_ret_address = 0;
+       unsigned long trampoline_address =
+               ((struct fnptr *)kretprobe_trampoline)->ip;
+
+        head = kretprobe_inst_table_head(current);
+
+       /*
+        * It is possible to have multiple instances associated with a given
+        * task either because an multiple functions in the call path
+        * have a return probe installed on them, and/or more then one return
+        * return probe was registered for a target function.
+        *
+        * We can handle this because:
+        *     - instances are always inserted at the head of the list
+        *     - when multiple return probes are registered for the same
+        *       function, the first instance's ret_addr will point to the
+        *       real return address, and all the rest will point to
+        *       kretprobe_trampoline
+        */
+       hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+                if (ri->task != current)
+                       /* another task is sharing our hash bucket */
+                        continue;
+
+               if (ri->rp && ri->rp->handler)
+                       ri->rp->handler(ri, regs);
+
+               orig_ret_address = (unsigned long)ri->ret_addr;
+               recycle_rp_inst(ri);
+
+               if (orig_ret_address != trampoline_address)
+                       /*
+                        * This is the real return address. Any other
+                        * instances associated with this task are for
+                        * other calls deeper on the call stack
+                        */
+                       break;
+       }
+
+       BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+       regs->cr_iip = orig_ret_address;
+
+       unlock_kprobes();
+       preempt_enable_no_resched();
+
+        /*
+         * By returning a non-zero value, we are telling
+         * kprobe_handler() that we have handled unlocking
+         * and re-enabling preemption.
+         */
+        return 1;
+}
+
+void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
+{
+       struct kretprobe_instance *ri;
+
+       if ((ri = get_free_rp_inst(rp)) != NULL) {
+               ri->rp = rp;
+               ri->task = current;
+               ri->ret_addr = (kprobe_opcode_t *)regs->b0;
+
+               /* Replace the return addr with trampoline addr */
+               regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip;
+
+               add_rp_inst(ri);
+       } else {
+               rp->nmissed++;
+       }
+}
+
 int arch_prepare_kprobe(struct kprobe *p)
 {
        unsigned long addr = (unsigned long) p->addr;
@@ -492,8 +601,8 @@ static int pre_kprobes_handler(struct die_args *args)
        if (p->pre_handler && p->pre_handler(p, regs))
                /*
                 * Our pre-handler is specifically requesting that we just
-                * do a return.  This is handling the case where the
-                * pre-handler is really our special jprobe pre-handler.
+                * do a return.  This is used for both the jprobe pre-handler
+                * and the kretprobe trampoline
                 */
                return 1;
 
@@ -599,3 +708,14 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
        *regs = jprobe_saved_regs;
        return 1;
 }
+
+static struct kprobe trampoline_p = {
+       .pre_handler = trampoline_probe_handler
+};
+
+int __init arch_init(void)
+{
+       trampoline_p.addr =
+               (kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip;
+       return register_kprobe(&trampoline_p);
+}
index ebb71f3d6d190632aed9819fd4e12fef5d1215b5..6e35bff05d595bb950f7708eda22f62289a30666 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/efi.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/kprobes.h>
 
 #include <asm/cpu.h>
 #include <asm/delay.h>
@@ -707,6 +708,13 @@ kernel_thread_helper (int (*fn)(void *), void *arg)
 void
 flush_thread (void)
 {
+       /*
+        * Remove function-return probe instances associated with this task
+        * and put them back on the free list. Do not insert an exit probe for
+        * this function, it will be disabled by kprobe_flush_task if you do.
+        */
+       kprobe_flush_task(current);
+
        /* drop floating-point and debug-register state if it exists: */
        current->thread.flags &= ~(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID);
        ia64_drop_fpu(current);
@@ -721,6 +729,14 @@ flush_thread (void)
 void
 exit_thread (void)
 {
+
+       /*
+        * Remove function-return probe instances associated with this task
+        * and put them back on the free list. Do not insert an exit probe for
+        * this function, it will be disabled by kprobe_flush_task if you do.
+        */
+       kprobe_flush_task(current);
+
        ia64_drop_fpu(current);
 #ifdef CONFIG_PERFMON
        /* if needed, stop monitoring and flush state to perfmon context */
index 6d57aebad485fd35db55c8ffbc9497fd6aba34b9..bbb8bc7c0552cdb860a466df3e302698b35da58c 100644 (file)
@@ -725,12 +725,32 @@ convert_to_non_syscall (struct task_struct *child, struct pt_regs  *pt,
                        break;
        }
 
+       /*
+        * Note: at the time of this call, the target task is blocked
+        * in notify_resume_user() and by clearling PRED_LEAVE_SYSCALL
+        * (aka, "pLvSys") we redirect execution from
+        * .work_pending_syscall_end to .work_processed_kernel.
+        */
        unw_get_pr(&prev_info, &pr);
-       pr &= ~(1UL << PRED_SYSCALL);
+       pr &= ~((1UL << PRED_SYSCALL) | (1UL << PRED_LEAVE_SYSCALL));
        pr |=  (1UL << PRED_NON_SYSCALL);
        unw_set_pr(&prev_info, pr);
 
        pt->cr_ifs = (1UL << 63) | cfm;
+       /*
+        * Clear the memory that is NOT written on syscall-entry to
+        * ensure we do not leak kernel-state to user when execution
+        * resumes.
+        */
+       pt->r2 = 0;
+       pt->r3 = 0;
+       pt->r14 = 0;
+       memset(&pt->r16, 0, 16*8);      /* clear r16-r31 */
+       memset(&pt->f6, 0, 6*16);       /* clear f6-f11 */
+       pt->b7 = 0;
+       pt->ar_ccv = 0;
+       pt->ar_csd = 0;
+       pt->ar_ssd = 0;
 }
 
 static int
index d14692e0920acc5c6f0350b9b14bddc801b07221..2693e1522d7cc45184e4b8b2e50819cdd2020cb1 100644 (file)
@@ -72,6 +72,8 @@ DEFINE_PER_CPU(unsigned long, ia64_phys_stacked_size_p8);
 unsigned long ia64_cycles_per_usec;
 struct ia64_boot_param *ia64_boot_param;
 struct screen_info screen_info;
+unsigned long vga_console_iobase;
+unsigned long vga_console_membase;
 
 unsigned long ia64_max_cacheline_size;
 unsigned long ia64_iobase;     /* virtual address for I/O accesses */
@@ -273,23 +275,25 @@ io_port_init (void)
 static inline int __init
 early_console_setup (char *cmdline)
 {
+       int earlycons = 0;
+
 #ifdef CONFIG_SERIAL_SGI_L1_CONSOLE
        {
                extern int sn_serial_console_early_setup(void);
                if (!sn_serial_console_early_setup())
-                       return 0;
+                       earlycons++;
        }
 #endif
 #ifdef CONFIG_EFI_PCDP
        if (!efi_setup_pcdp_console(cmdline))
-               return 0;
+               earlycons++;
 #endif
 #ifdef CONFIG_SERIAL_8250_CONSOLE
        if (!early_serial_console_init(cmdline))
-               return 0;
+               earlycons++;
 #endif
 
-       return -1;
+       return (earlycons) ? 0 : -1;
 }
 
 static inline void
index b49d4ddaab93a45f71f559631e2fed66a98c70f6..0166a984709536238d8f97641992038ce17cd27a 100644 (file)
@@ -231,13 +231,16 @@ smp_flush_tlb_all (void)
 void
 smp_flush_tlb_mm (struct mm_struct *mm)
 {
+       preempt_disable();
        /* this happens for the common case of a single-threaded fork():  */
        if (likely(mm == current->active_mm && atomic_read(&mm->mm_users) == 1))
        {
                local_finish_flush_tlb_mm(mm);
+               preempt_enable();
                return;
        }
 
+       preempt_enable();
        /*
         * We could optimize this further by using mm->cpu_vm_mask to track which CPUs
         * have been running in the address space.  It's not clear that this is worth the
index 3865f088ffa26d9c7db30c932098a09db0762ba0..623b0a54670973039d65b5c4ad38b7488d2314d4 100644 (file)
@@ -346,6 +346,7 @@ smp_callin (void)
        lock_ipi_calllock();
        cpu_set(cpuid, cpu_online_map);
        unlock_ipi_calllock();
+       per_cpu(cpu_state, cpuid) = CPU_ONLINE;
 
        smp_setup_percpu_timer();
 
@@ -611,6 +612,7 @@ void __devinit smp_prepare_boot_cpu(void)
 {
        cpu_set(smp_processor_id(), cpu_online_map);
        cpu_set(smp_processor_id(), cpu_callin_map);
+       per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
 }
 
 /*
@@ -688,6 +690,7 @@ int __cpu_disable(void)
                return -EBUSY;
 
        remove_siblinginfo(cpu);
+       cpu_clear(cpu, cpu_online_map);
        fixup_irqs();
        local_flush_tlb_all();
        cpu_clear(cpu, cpu_callin_map);
@@ -774,6 +777,7 @@ __cpu_up (unsigned int cpu)
        if (cpu_isset(cpu, cpu_callin_map))
                return -EINVAL;
 
+       per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
        /* Processor goes to start_secondary(), sets online flag */
        ret = do_boot_cpu(sapicid, cpu);
        if (ret < 0)
index b9f0db4c1b042682354d57492bcf620cffc5263f..a676e79e0681bb183986e3036e6484f8878c4e70 100644 (file)
@@ -8,6 +8,11 @@
 #define LOAD_OFFSET    (KERNEL_START - KERNEL_TR_PAGE_SIZE)
 #include <asm-generic/vmlinux.lds.h>
 
+#define IVT_TEXT                                                       \
+               VMLINUX_SYMBOL(__start_ivt_text) = .;                   \
+               *(.text.ivt)                                            \
+               VMLINUX_SYMBOL(__end_ivt_text) = .;
+
 OUTPUT_FORMAT("elf64-ia64-little")
 OUTPUT_ARCH(ia64)
 ENTRY(phys_start)
@@ -39,7 +44,7 @@ SECTIONS
 
   .text : AT(ADDR(.text) - LOAD_OFFSET)
     {
-       *(.text.ivt)
+       IVT_TEXT
        *(.text)
        SCHED_TEXT
        LOCK_TEXT
index e3fc4edea113a89855b8024acb4a8446b62e1674..720a861f88be283675a5b568bbf8837950e31d72 100644 (file)
@@ -312,7 +312,7 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
        acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window,
                        &info);
 
-       pbus = pci_scan_bus(bus, &pci_root_ops, controller);
+       pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller);
        if (pbus)
                pcibios_setup_root_windows(pbus, controller);
 
@@ -373,6 +373,25 @@ void pcibios_bus_to_resource(struct pci_dev *dev,
        res->end = region->end + offset;
 }
 
+static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
+{
+       unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
+       struct resource *devr = &dev->resource[idx];
+
+       if (!dev->bus)
+               return 0;
+       for (i=0; i<PCI_BUS_NUM_RESOURCES; i++) {
+               struct resource *busr = dev->bus->resource[i];
+
+               if (!busr || ((busr->flags ^ devr->flags) & type_mask))
+                       continue;
+               if ((devr->start) && (devr->start >= busr->start) &&
+                               (devr->end <= busr->end))
+                       return 1;
+       }
+       return 0;
+}
+
 static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
 {
        struct pci_bus_region region;
@@ -386,7 +405,8 @@ static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
                region.start = dev->resource[i].start;
                region.end = dev->resource[i].end;
                pcibios_bus_to_resource(dev, &dev->resource[i], &region);
-               pci_claim_resource(dev, i);
+               if ((is_valid_resource(dev, i)))
+                       pci_claim_resource(dev, i);
        }
 }
 
@@ -398,6 +418,10 @@ pcibios_fixup_bus (struct pci_bus *b)
 {
        struct pci_dev *dev;
 
+       if (b->self) {
+               pci_read_bridge_bases(b);
+               pcibios_fixup_device_resources(b->self);
+       }
        list_for_each_entry(dev, &b->devices, bus_list)
                pcibios_fixup_device_resources(dev);
 
@@ -418,18 +442,24 @@ pcibios_enable_resources (struct pci_dev *dev, int mask)
        u16 cmd, old_cmd;
        int idx;
        struct resource *r;
+       unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM;
 
        if (!dev)
                return -EINVAL;
 
        pci_read_config_word(dev, PCI_COMMAND, &cmd);
        old_cmd = cmd;
-       for (idx=0; idx<6; idx++) {
+       for (idx=0; idx<PCI_NUM_RESOURCES; idx++) {
                /* Only set up the desired resources.  */
                if (!(mask & (1 << idx)))
                        continue;
 
                r = &dev->resource[idx];
+               if (!(r->flags & type_mask))
+                       continue;
+               if ((idx == PCI_ROM_RESOURCE) &&
+                               (!(r->flags & IORESOURCE_ROM_ENABLE)))
+                       continue;
                if (!r->start && r->end) {
                        printk(KERN_ERR
                               "PCI: Device %s not available because of resource collisions\n",
@@ -441,8 +471,6 @@ pcibios_enable_resources (struct pci_dev *dev, int mask)
                if (r->flags & IORESOURCE_MEM)
                        cmd |= PCI_COMMAND_MEMORY;
        }
-       if (dev->resource[PCI_ROM_RESOURCE].start)
-               cmd |= PCI_COMMAND_MEMORY;
        if (cmd != old_cmd) {
                printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
                pci_write_config_word(dev, PCI_COMMAND, cmd);
index 9e07f5463f21d53fcac34ec658f443ca550b4222..783eb4323847c26f40a27893e9c94c313c898d50 100644 (file)
@@ -384,7 +384,7 @@ static int __init sn_pci_init(void)
        extern void register_sn_procfs(void);
 #endif
 
-       if (!ia64_platform_is("sn2") || IS_RUNNING_ON_SIMULATOR())
+       if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM())
                return 0;
 
        /*
index fec6d8b8237b7191b88cb2e9fca2d2df75e6970f..7ce3cdad627bf9ca50e657f2da6de70acf9c3589 100644 (file)
@@ -9,12 +9,16 @@
 #include <linux/module.h>
 #include <asm/io.h>
 #include <asm/delay.h>
+#include <asm/vga.h>
 #include <asm/sn/nodepda.h>
 #include <asm/sn/simulator.h>
 #include <asm/sn/pda.h>
 #include <asm/sn/sn_cpuid.h>
 #include <asm/sn/shub_mmr.h>
 
+#define IS_LEGACY_VGA_IOPORT(p) \
+       (((p) >= 0x3b0 && (p) <= 0x3bb) || ((p) >= 0x3c0 && (p) <= 0x3df))
+
 /**
  * sn_io_addr - convert an in/out port to an i/o address
  * @port: port to convert
@@ -26,6 +30,8 @@
 void *sn_io_addr(unsigned long port)
 {
        if (!IS_RUNNING_ON_SIMULATOR()) {
+               if (IS_LEGACY_VGA_IOPORT(port))
+                       port += vga_console_iobase;
                /* On sn2, legacy I/O ports don't point at anything */
                if (port < (64 * 1024))
                        return NULL;
index 44bfc7f318cbd611752fcede5459ee3182807191..22e10d282c7fc19744a8fa8defc080f1a3163260 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/machvec.h>
 #include <asm/system.h>
 #include <asm/processor.h>
+#include <asm/vga.h>
 #include <asm/sn/arch.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/pda.h>
@@ -95,6 +96,7 @@ u8 sn_coherency_id;
 EXPORT_SYMBOL(sn_coherency_id);
 u8 sn_region_size;
 EXPORT_SYMBOL(sn_region_size);
+int sn_prom_type;      /* 0=hardware, 1=medusa/realprom, 2=medusa/fakeprom */
 
 short physical_node_map[MAX_PHYSNODE_ID];
 
@@ -273,14 +275,17 @@ void __init sn_setup(char **cmdline_p)
 
        ia64_sn_plat_set_error_handling_features();
 
+#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
        /*
-        * If the generic code has enabled vga console support - lets
-        * get rid of it again. This is a kludge for the fact that ACPI
-        * currtently has no way of informing us if legacy VGA is available
-        * or not.
+        * If there was a primary vga adapter identified through the
+        * EFI PCDP table, make it the preferred console.  Otherwise
+        * zero out conswitchp.
         */
-#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
-       if (conswitchp == &vga_con) {
+
+       if (vga_console_membase) {
+               /* usable vga ... make tty0 the preferred default console */
+               add_preferred_console("tty", 0, NULL);
+       } else {
                printk(KERN_DEBUG "SGI: Disabling VGA console\n");
 #ifdef CONFIG_DUMMY_CONSOLE
                conswitchp = &dummy_con;
@@ -350,7 +355,7 @@ void __init sn_setup(char **cmdline_p)
 
        ia64_mark_idle = &snidle;
 
-       /* 
+       /*
         * For the bootcpu, we do this here. All other cpus will make the
         * call as part of cpu_init in slave cpu initialization.
         */
@@ -397,7 +402,7 @@ static void __init sn_init_pdas(char **cmdline_p)
                nodepdaindr[cnode] =
                    alloc_bootmem_node(NODE_DATA(cnode), sizeof(nodepda_t));
                memset(nodepdaindr[cnode], 0, sizeof(nodepda_t));
-               memset(nodepdaindr[cnode]->phys_cpuid, -1, 
+               memset(nodepdaindr[cnode]->phys_cpuid, -1,
                    sizeof(nodepdaindr[cnode]->phys_cpuid));
        }
 
@@ -427,7 +432,7 @@ static void __init sn_init_pdas(char **cmdline_p)
        }
 
        /*
-        * Initialize the per node hubdev.  This includes IO Nodes and 
+        * Initialize the per node hubdev.  This includes IO Nodes and
         * headless/memless nodes.
         */
        for (cnode = 0; cnode < numionodes; cnode++) {
@@ -455,6 +460,14 @@ void __init sn_cpu_init(void)
        int i;
        static int wars_have_been_checked;
 
+       if (smp_processor_id() == 0 && IS_MEDUSA()) {
+               if (ia64_sn_is_fake_prom())
+                       sn_prom_type = 2;
+               else
+                       sn_prom_type = 1;
+               printk("Running on medusa with %s PROM\n", (sn_prom_type == 1) ? "real" : "fake");
+       }
+
        memset(pda, 0, sizeof(pda));
        if (ia64_sn_get_sn_info(0, &sn_hub_info->shub2, &sn_hub_info->nasid_bitmask, &sn_hub_info->nasid_shift,
                                &sn_system_size, &sn_sharing_domain_size, &sn_partition_id,
@@ -520,7 +533,7 @@ void __init sn_cpu_init(void)
         */
        {
                u64 pio1[] = {SH1_PIO_WRITE_STATUS_0, 0, SH1_PIO_WRITE_STATUS_1, 0};
-               u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_1, 
+               u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_1,
                        SH2_PIO_WRITE_STATUS_2, SH2_PIO_WRITE_STATUS_3};
                u64 *pio;
                pio = is_shub1() ? pio1 : pio2;
@@ -552,6 +565,10 @@ static void __init scan_for_ionodes(void)
        int nasid = 0;
        lboard_t *brd;
 
+       /* fakeprom does not support klgraph */
+       if (IS_RUNNING_ON_FAKE_PROM())
+               return;
+
        /* Setup ionodes with memory */
        for (nasid = 0; nasid < MAX_PHYSNODE_ID; nasid += 2) {
                char *klgraph_header;
@@ -563,8 +580,6 @@ static void __init scan_for_ionodes(void)
                cnodeid = -1;
                klgraph_header = __va(ia64_sn_get_klconfig_addr(nasid));
                if (!klgraph_header) {
-                       if (IS_RUNNING_ON_SIMULATOR())
-                               continue;
                        BUG();  /* All nodes must have klconfig tables! */
                }
                cnodeid = nasid_to_cnodeid(nasid);
@@ -630,8 +645,8 @@ int
 nasid_slice_to_cpuid(int nasid, int slice)
 {
        long cpu;
-       
-       for (cpu=0; cpu < NR_CPUS; cpu++) 
+
+       for (cpu=0; cpu < NR_CPUS; cpu++)
                if (cpuid_to_nasid(cpu) == nasid &&
                                        cpuid_to_slice(cpu) == slice)
                        return cpu;
index 7947312801eccc797975e338af4e76f12ace0c55..96cb71d156820f9b33df9a07ea5049afe3bc77b9 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
  */
 
+#include <asm/types.h>
 #include <asm/sn/shub_mmr.h>
 
 #define DEADLOCKBIT    SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT
index a087b274847e52a265f94f473d707baa6d26fc89..8716f4d5314b968f4b2e8df5cd5d7931db233426 100644 (file)
@@ -204,8 +204,8 @@ cx_device_register(nasid_t nasid, int part_num, int mfg_num,
        cx_dev->dev.parent = NULL;
        cx_dev->dev.bus = &tiocx_bus_type;
        cx_dev->dev.release = tiocx_bus_release;
-       snprintf(cx_dev->dev.bus_id, BUS_ID_SIZE, "%d.0x%x",
-                cx_dev->cx_id.nasid, cx_dev->cx_id.part_num);
+       snprintf(cx_dev->dev.bus_id, BUS_ID_SIZE, "%d",
+                cx_dev->cx_id.nasid);
        device_register(&cx_dev->dev);
        get_device(&cx_dev->dev);
 
@@ -236,7 +236,6 @@ int cx_device_unregister(struct cx_dev *cx_dev)
  */
 static int cx_device_reload(struct cx_dev *cx_dev)
 {
-       device_remove_file(&cx_dev->dev, &dev_attr_cxdev_control);
        cx_device_unregister(cx_dev);
        return cx_device_register(cx_dev->cx_id.nasid, cx_dev->cx_id.part_num,
                                  cx_dev->cx_id.mfg_num, cx_dev->hubdev);
@@ -383,6 +382,7 @@ static int is_fpga_brick(int nasid)
        switch (tiocx_btchar_get(nasid)) {
        case L1_BRICKTYPE_SA:
        case L1_BRICKTYPE_ATHENA:
+       case L1_BRICKTYPE_DAYTONA:
                return 1;
        }
        return 0;
@@ -409,7 +409,7 @@ static int tiocx_reload(struct cx_dev *cx_dev)
                uint64_t cx_id;
 
                cx_id =
-                   *(volatile int32_t *)(TIO_SWIN_BASE(nasid, TIOCX_CORELET) +
+                   *(volatile uint64_t *)(TIO_SWIN_BASE(nasid, TIOCX_CORELET) +
                                          WIDGET_ID);
                part_num = XWIDGET_PART_NUM(cx_id);
                mfg_num = XWIDGET_MFG_NUM(cx_id);
@@ -458,6 +458,10 @@ static ssize_t store_cxdev_control(struct device *dev, struct device_attribute *
 
        switch (n) {
        case 1:
+               tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET);
+               tiocx_reload(cx_dev);
+               break;
+       case 2:
                tiocx_reload(cx_dev);
                break;
        case 3:
@@ -537,7 +541,7 @@ static void __exit tiocx_exit(void)
        bus_unregister(&tiocx_bus_type);
 }
 
-module_init(tiocx_init);
+subsys_initcall(tiocx_init);
 module_exit(tiocx_exit);
 
 /************************************************************************
index 1a0aed8490d177a7830dbe17f11b22e976fdc945..d0ee635daf2e7f4104c8b0dca480d9c4712d7dda 100644 (file)
@@ -87,7 +87,7 @@ struct xpc_rsvd_page {
        u8 partid;              /* partition ID from SAL */
        u8 version;
        u8 pad[6];              /* pad to u64 align */
-       u64 vars_pa;
+       volatile u64 vars_pa;
        u64 part_nasids[XP_NASID_MASK_WORDS] ____cacheline_aligned;
        u64 mach_nasids[XP_NASID_MASK_WORDS] ____cacheline_aligned;
 };
@@ -138,7 +138,7 @@ struct xpc_vars {
  * occupies half a cacheline.
  */
 struct xpc_vars_part {
-       u64 magic;
+       volatile u64 magic;
 
        u64 openclose_args_pa;  /* physical address of open and close args */
        u64 GPs_pa;             /* physical address of Get/Put values */
@@ -185,8 +185,8 @@ struct xpc_vars_part {
  * Define a Get/Put value pair (pointers) used with a message queue.
  */
 struct xpc_gp {
-       s64 get;        /* Get value */
-       s64 put;        /* Put value */
+       volatile s64 get;       /* Get value */
+       volatile s64 put;       /* Put value */
 };
 
 #define XPC_GP_SIZE \
@@ -231,7 +231,7 @@ struct xpc_openclose_args {
  */
 struct xpc_notify {
        struct semaphore sema;          /* notify semaphore */
-       u8 type;                        /* type of notification */
+       volatile u8 type;                       /* type of notification */
 
        /* the following two fields are only used if type == XPC_N_CALL */
        xpc_notify_func func;           /* user's notify function */
@@ -439,7 +439,7 @@ struct xpc_partition {
 
        /* XPC infrastructure referencing and teardown control */
 
-       u8 setup_state;                 /* infrastructure setup state */
+       volatile u8 setup_state;                        /* infrastructure setup state */
        wait_queue_head_t teardown_wq;  /* kthread waiting to teardown infra */
        atomic_t references;            /* #of references to infrastructure */
 
index 0bf6fbcc46d206bd2eb46d71066a5c44fc91ae99..6d02dac8056f99bc72d08553be8d2e28a4128211 100644 (file)
@@ -209,7 +209,7 @@ xpc_setup_infrastructure(struct xpc_partition *part)
         * With the setting of the partition setup_state to XPC_P_SETUP, we're
         * declaring that this partition is ready to go.
         */
-       (volatile u8) part->setup_state = XPC_P_SETUP;
+       part->setup_state = XPC_P_SETUP;
 
 
        /*
@@ -227,7 +227,7 @@ xpc_setup_infrastructure(struct xpc_partition *part)
        xpc_vars_part[partid].IPI_phys_cpuid =
                                        cpu_physical_id(smp_processor_id());
        xpc_vars_part[partid].nchannels = part->nchannels;
-       (volatile u64) xpc_vars_part[partid].magic = XPC_VP_MAGIC1;
+       xpc_vars_part[partid].magic = XPC_VP_MAGIC1;
 
        return xpcSuccess;
 }
@@ -355,7 +355,7 @@ xpc_pull_remote_vars_part(struct xpc_partition *part)
 
                /* let the other side know that we've pulled their variables */
 
-               (volatile u64) xpc_vars_part[partid].magic = XPC_VP_MAGIC2;
+               xpc_vars_part[partid].magic = XPC_VP_MAGIC2;
        }
 
        if (pulled_entry->magic == XPC_VP_MAGIC1) {
@@ -1183,7 +1183,7 @@ xpc_process_msg_IPI(struct xpc_partition *part, int ch_number)
                 */
                xpc_clear_local_msgqueue_flags(ch);
 
-               (volatile s64) ch->w_remote_GP.get = ch->remote_GP.get;
+               ch->w_remote_GP.get = ch->remote_GP.get;
 
                dev_dbg(xpc_chan, "w_remote_GP.get changed to %ld, partid=%d, "
                        "channel=%d\n", ch->w_remote_GP.get, ch->partid,
@@ -1211,7 +1211,7 @@ xpc_process_msg_IPI(struct xpc_partition *part, int ch_number)
                 */
                xpc_clear_remote_msgqueue_flags(ch);
 
-               (volatile s64) ch->w_remote_GP.put = ch->remote_GP.put;
+               ch->w_remote_GP.put = ch->remote_GP.put;
 
                dev_dbg(xpc_chan, "w_remote_GP.put changed to %ld, partid=%d, "
                        "channel=%d\n", ch->w_remote_GP.put, ch->partid,
@@ -1875,7 +1875,7 @@ xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type,
                notify = &ch->notify_queue[msg_number % ch->local_nentries];
                notify->func = func;
                notify->key = key;
-               (volatile u8) notify->type = notify_type;
+               notify->type = notify_type;
 
                // >>> is a mb() needed here?
 
index cd7ed73f0e7ab73a87b37ea4d567810b511ecee9..578265ea9e678bdaeca66c70b149ba5fa66104e0 100644 (file)
@@ -253,7 +253,7 @@ xpc_rsvd_page_init(void)
         * This signifies to the remote partition that our reserved
         * page is initialized.
         */
-       (volatile u64) rp->vars_pa = __pa(xpc_vars);
+       rp->vars_pa = __pa(xpc_vars);
 
        return rp;
 }
index 8dae9eb45456d97525a6745a766f903eee2323d6..05aa8c2fe9bbef0f129681388e92ea97cf6c282a 100644 (file)
@@ -336,7 +336,7 @@ tioca_dma_d48(struct pci_dev *pdev, uint64_t paddr)
        if (!ct_addr)
                return 0;
 
-       bus_addr = (dma_addr_t) (ct_addr & 0xffffffffffff);
+       bus_addr = (dma_addr_t) (ct_addr & 0xffffffffffffUL);
        node_upper = ct_addr >> 48;
 
        if (node_upper > 64) {
@@ -464,7 +464,7 @@ map_return:
  * For mappings created using the direct modes (64 or 48) there are no
  * resources to release.
  */
-void
+static void
 tioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir)
 {
        int i, entry;
@@ -514,7 +514,7 @@ tioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir)
  * The mapping mode used is based on the devices dma_mask.  As a last resort
  * use the GART mapped mode.
  */
-uint64_t
+static uint64_t
 tioca_dma_map(struct pci_dev *pdev, uint64_t paddr, size_t byte_count)
 {
        uint64_t mapaddr;
@@ -580,7 +580,7 @@ tioca_error_intr_handler(int irq, void *arg, struct pt_regs *pt)
  * On successful setup, returns the kernel version of tioca_common back to
  * the caller.
  */
-void *
+static void *
 tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft)
 {
        struct tioca_common *tioca_common;
index 50311eb07a2485f940288ff25127b36062d5d572..5aef7e406ef5f2a0a74e90a334ee4a5ad2817ffd 100644 (file)
@@ -371,10 +371,8 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
        if (!user_mode(regs))
                return 1;
 
-       if (current->flags & PF_FREEZE) {
-               refrigerator(0);
+       if (try_to_freeze()) 
                goto no_signal;
-       }
 
        if (!oldset)
                oldset = &current->blocked;
index 94f5a8eb2c22ec59e9fe951172aeb92749f4b937..bd9de7b00c0aa26b996e11c5fd7fb577a63c2278 100644 (file)
@@ -1416,6 +1416,12 @@ config HIGHMEM
        bool "High Memory Support"
        depends on MIPS32 && (CPU_R3000 || CPU_SB1 || CPU_R7000 || CPU_RM9000 || CPU_R10000) && !(MACH_DECSTATION || MOMENCO_JAGUAR_ATX)
 
+config ARCH_FLATMEM_ENABLE
+       def_bool y
+       depends on !NUMA
+
+source "mm/Kconfig"
+
 config SMP
        bool "Multi-Processing support"
        depends on CPU_RM9000 || (SIBYTE_SB1250 && !SIBYTE_STANDALONE) || SGI_IP27
index 6018ca25acebaf038ccc20988624033966252957..3a240e3e004c368c10cc86df391ac2fc2ceefdbe 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/root_dev.h>
 #include <linux/highmem.h>
 #include <linux/console.h>
+#include <linux/mmzone.h>
 
 #include <asm/addrspace.h>
 #include <asm/bootinfo.h>
@@ -356,6 +357,8 @@ static inline void bootmem_init(void)
        }
 #endif
 
+       memory_present(0, first_usable_pfn, max_low_pfn);
+
        /* Initialize the boot-time allocator with low memory only.  */
        bootmap_size = init_bootmem(first_usable_pfn, max_low_pfn);
 
@@ -557,6 +560,7 @@ void __init setup_arch(char **cmdline_p)
 
        parse_cmdline_early();
        bootmem_init();
+       sparse_init();
        paging_init();
        resource_init();
 }
index 508026ae584222fe93fb4d24ed747fc2314bfe28..65ee15396ffdefc52782ab24bd983baf08e90f30 100644 (file)
@@ -457,7 +457,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs)
        if (!user_mode(regs))
                return 1;
 
-       if (try_to_freeze(0))
+       if (try_to_freeze())
                goto no_signal;
 
        if (!oldset)
index 73843c5287782f3ef74a6adaec316445c8e20764..9c9a271c8a3ae440748d89a22c464ea46444c46c 100644 (file)
@@ -128,7 +128,7 @@ static void __init fixrange_init(unsigned long start, unsigned long end,
 #endif /* CONFIG_MIPS64 */
 #endif /* CONFIG_HIGHMEM */
 
-#ifndef CONFIG_DISCONTIGMEM
+#ifndef CONFIG_NEED_MULTIPLE_NODES
 extern void pagetable_init(void);
 
 void __init paging_init(void)
@@ -253,7 +253,7 @@ void __init mem_init(void)
               initsize >> 10,
               (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)));
 }
-#endif /* !CONFIG_DISCONTIGMEM */
+#endif /* !CONFIG_NEED_MULTIPLE_NODES */
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
index 3b88fdeef3294ec51ab46854b130f10f1303ab78..3fe94202da8ca7c21f1d8d973537aeb18b663711 100644 (file)
@@ -5,7 +5,7 @@
 
 void show_mem(void)
 {
-#ifndef CONFIG_DISCONTIGMEM  /* XXX(hch): later.. */
+#ifndef CONFIG_NEED_MULTIPLE_NODES  /* XXX(hch): later.. */
        int pfn, total = 0, reserved = 0;
        int shared = 0, cached = 0;
        int highmem = 0;
index 872085dea8a81c7a3d568174eb475640ff8e862c..6efaa9293eefff294dfe4e2a1bd6a045901d016d 100644 (file)
@@ -506,7 +506,7 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_NR_UARTS=17
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
index d28ebfa1070da3382eca3dff35da98f789957ff3..30fc03ed0cfbb53d58cf9c177d36024d3aa42a6e 100644 (file)
@@ -662,7 +662,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_CS=m
-CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_NR_UARTS=17
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
index 1700d7aec686c911be4f57909f3b6b1c070d4b6f..46c9511f32298ba462d1d3852b50eb94a7ce7555 100644 (file)
@@ -514,7 +514,7 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_NR_UARTS=13
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
index b27980161c31c3ce49e72a995566f1c04ad3595d..67aca6ccc9b03cd8d03ce53d96bf3c972ead669d 100644 (file)
@@ -661,7 +661,7 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_NR_UARTS=13
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
index ebd6301aa5999725141e5cdd0aba2c5e0f4eae5f..fdae21c503d78b562e621c148ca9950128c5beba 100644 (file)
@@ -517,7 +517,7 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_NR_UARTS=13
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
index 848f43970a4b4cd7123e0fa188e34ddd18ce20c3..a7835cd3f51f32500b316d0cc1d4bed5aaefdaae 100644 (file)
@@ -88,6 +88,9 @@ config 8xx
        depends on BROKEN
        bool "8xx"
 
+config E200
+       bool "e200"
+
 config E500
        bool "e500"
 
@@ -98,12 +101,12 @@ config PPC_FPU
 
 config BOOKE
        bool
-       depends on E500
+       depends on E200 || E500
        default y
 
 config FSL_BOOKE
        bool
-       depends on E500
+       depends on E200 || E500
        default y
 
 config PTE_64BIT
@@ -141,16 +144,16 @@ config ALTIVEC
 
 config SPE
        bool "SPE Support"
-       depends on E500
+       depends on E200 || E500
        ---help---
          This option enables kernel support for the Signal Processing
          Extensions (SPE) to the PowerPC processor. The kernel currently
          supports saving and restoring SPE registers, and turning on the
          'spe enable' bit so user processes can execute SPE instructions.
 
-         This option is only usefully if you have a processor that supports
+         This option is only useful if you have a processor that supports
          SPE (e500, otherwise known as 85xx series), but does not have any
-         affect on a non-spe cpu (it does, however add code to the kernel).
+         effect on a non-spe cpu (it does, however add code to the kernel).
 
          If in doubt, say Y here.
 
@@ -200,7 +203,7 @@ config TAU_AVERAGE
 
 config MATH_EMULATION
        bool "Math emulation"
-       depends on 4xx || 8xx || E500
+       depends on 4xx || 8xx || E200 || E500
        ---help---
          Some PowerPC chips designed for embedded applications do not have
          a floating-point unit and therefore do not implement the
@@ -214,6 +217,26 @@ config MATH_EMULATION
          here.  Saying Y here will not hurt performance (on any machine) but
          will increase the size of the kernel.
 
+config KEXEC
+       bool "kexec system call (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       help
+         kexec is a system call that implements the ability to shutdown your
+         current kernel, and to start another kernel.  It is like a reboot
+         but it is indepedent of the system firmware.   And like a reboot
+         you can start any kernel with it, not just Linux.
+
+         The name comes from the similiarity to the exec system call.
+
+         It is an ongoing process to be certain the hardware in a machine
+         is properly shutdown, so do not be surprised if this code does not
+         initially work for you.  It may help to enable device hotplugging
+         support.  As of this writing the exact hardware interface is
+         strongly in flux, so no good recommendation can be made.
+
+         In the GameCube implementation, kexec allows you to load and
+         run DOL files, including kernel and homebrew DOLs.
+
 source "drivers/cpufreq/Kconfig"
 
 config CPU_FREQ_PMAC
@@ -254,7 +277,7 @@ config PPC_STD_MMU
 
 config NOT_COHERENT_CACHE
        bool
-       depends on 4xx || 8xx
+       depends on 4xx || 8xx || E200
        default y
 
 endmenu
index d2e1eea8e8e4cc18ad4e2043b7e987d34c5d75f7..e16c7710d4bef3442160e3d1886b7ac2690ba786 100644 (file)
@@ -66,7 +66,7 @@ config SERIAL_TEXT_DEBUG
 
 config PPC_OCP
        bool
-       depends on IBM_OCP || FSL_OCP || XILINX_OCP
+       depends on IBM_OCP || XILINX_OCP
        default y
 
 endmenu
index 0432a25b47354e75d0a09e4b2817d1afe7849313..f9b0d778dd82ee1d0ec03b2273f46511a51cdf4c 100644 (file)
@@ -29,7 +29,7 @@ CPP           = $(CC) -E $(CFLAGS)
 
 CHECKFLAGS     += -D__powerpc__
 
-ifndef CONFIG_E500
+ifndef CONFIG_FSL_BOOKE
 CFLAGS         += -mstring
 endif
 
@@ -38,6 +38,7 @@ cpu-as-$(CONFIG_4xx)          += -Wa,-m405
 cpu-as-$(CONFIG_6xx)           += -Wa,-maltivec
 cpu-as-$(CONFIG_POWER4)                += -Wa,-maltivec
 cpu-as-$(CONFIG_E500)          += -Wa,-me500
+cpu-as-$(CONFIG_E200)          += -Wa,-me200
 
 AFLAGS += $(cpu-as-y)
 CFLAGS += $(cpu-as-y)
index 6fb4f738728c8fd09e0c3b40327d5a728df0111b..effe4a0624b0840d524a9c69e0a619c38f4c8edf 100644 (file)
@@ -39,7 +39,7 @@ char *avail_high;
 
 #define SCRATCH_SIZE   (128 << 10)
 
-static char scratch[SCRATCH_SIZE];     /* 1MB of scratch space for gunzip */
+static char scratch[SCRATCH_SIZE];     /* 128k of scratch space for gunzip */
 
 typedef void (*kernel_start_t)(int, int, void *, unsigned int, unsigned int);
 
index b284451802c95b45f9f8a312096f556c8ab1ff3f..b1457a8a9c0f0eff8cf3cf130396076438d8d7e5 100644 (file)
@@ -26,7 +26,10 @@ obj-$(CONFIG_KGDB)           += ppc-stub.o
 obj-$(CONFIG_SMP)              += smp.o smp-tbsync.o
 obj-$(CONFIG_TAU)              += temp.o
 obj-$(CONFIG_ALTIVEC)          += vecemu.o vector.o
+ifndef CONFIG_E200
 obj-$(CONFIG_FSL_BOOKE)                += perfmon_fsl_booke.o
+endif
+obj-$(CONFIG_KEXEC)            += machine_kexec.o relocate_kernel.o
 
 ifndef CONFIG_MATH_EMULATION
 obj-$(CONFIG_8xx)              += softemu8xx.o
index 01c226008dbf2abb71ec55a6a41df0dc68c16d56..50936cda0af9a723977c7897c44c9aa080d90daa 100644 (file)
@@ -903,7 +903,30 @@ struct cpu_spec    cpu_specs[] = {
                .dcache_bsize           = 32,
        },
 #endif /* CONFIG_44x */
-#ifdef CONFIG_E500
+#ifdef CONFIG_FSL_BOOKE
+       {       /* e200z5 */
+               .pvr_mask               = 0xfff00000,
+               .pvr_value              = 0x81000000,
+               .cpu_name               = "e200z5",
+               /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
+               .cpu_features           = CPU_FTR_USE_TB,
+               .cpu_user_features      = PPC_FEATURE_32 |
+                       PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_EFP_SINGLE |
+                       PPC_FEATURE_UNIFIED_CACHE,
+               .dcache_bsize           = 32,
+       },
+       {       /* e200z6 */
+               .pvr_mask               = 0xfff00000,
+               .pvr_value              = 0x81100000,
+               .cpu_name               = "e200z6",
+               /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
+               .cpu_features           = CPU_FTR_USE_TB,
+               .cpu_user_features      = PPC_FEATURE_32 |
+                       PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP |
+                       PPC_FEATURE_HAS_EFP_SINGLE |
+                       PPC_FEATURE_UNIFIED_CACHE,
+               .dcache_bsize           = 32,
+       },
        {       /* e500 */
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x80200000,
index 8377b6ca26da4039fabc0ba5dd46861edb4e9190..d4df68629cc6a750a22e1106018057b4fef9952c 100644 (file)
@@ -60,6 +60,11 @@ mcheck_transfer_to_handler:
        TRANSFER_TO_HANDLER_EXC_LEVEL(MCHECK)
        b       transfer_to_handler_full
 
+       .globl  debug_transfer_to_handler
+debug_transfer_to_handler:
+       TRANSFER_TO_HANDLER_EXC_LEVEL(DEBUG)
+       b       transfer_to_handler_full
+
        .globl  crit_transfer_to_handler
 crit_transfer_to_handler:
        TRANSFER_TO_HANDLER_EXC_LEVEL(CRIT)
@@ -835,6 +840,10 @@ ret_from_crit_exc:
        RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI)
 
 #ifdef CONFIG_BOOKE
+       .globl  ret_from_debug_exc
+ret_from_debug_exc:
+       RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI)
+
        .globl  ret_from_mcheck_exc
 ret_from_mcheck_exc:
        RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI)
index 9c50f9d2657c10d1e0dea4199f3f33149c9cb33f..9342acf12e72d1c45bbec42ca09f6bdebf2cfe42 100644 (file)
@@ -49,6 +49,7 @@
  *
  * On 40x critical is the only additional level
  * On 44x/e500 we have critical and machine check
+ * On e200 we have critical and debug (machine check occurs via critical)
  *
  * Additionally we reserve a SPRG for each priority level so we can free up a
  * GPR to use as the base for indirect access to the exception stacks.  This
 
 /* CRIT_SPRG only used in critical exception handling */
 #define CRIT_SPRG      SPRN_SPRG2
-/* MCHECK_SPRG only used in critical exception handling */
+/* MCHECK_SPRG only used in machine check exception handling */
 #define MCHECK_SPRG    SPRN_SPRG6W
 
 #define MCHECK_STACK_TOP       (exception_stack_top - 4096)
 #define CRIT_STACK_TOP         (exception_stack_top)
 
+/* only on e200 for now */
+#define DEBUG_STACK_TOP                (exception_stack_top - 4096)
+#define DEBUG_SPRG             SPRN_SPRG6W
+
 #ifdef CONFIG_SMP
 #define BOOKE_LOAD_EXC_LEVEL_STACK(level)              \
        mfspr   r8,SPRN_PIR;                            \
 
 #define CRITICAL_EXCEPTION_PROLOG \
                EXC_LEVEL_EXCEPTION_PROLOG(CRIT, SPRN_CSRR0, SPRN_CSRR1)
+#define DEBUG_EXCEPTION_PROLOG \
+               EXC_LEVEL_EXCEPTION_PROLOG(DEBUG, SPRN_DSRR0, SPRN_DSRR1)
 #define MCHECK_EXCEPTION_PROLOG \
                EXC_LEVEL_EXCEPTION_PROLOG(MCHECK, SPRN_MCSRR0, SPRN_MCSRR1)
 
@@ -205,6 +212,60 @@ label:
  * save (and later restore) the MSR via SPRN_CSRR1, which will still have
  * the MSR_DE bit set.
  */
+#ifdef CONFIG_E200
+#define DEBUG_EXCEPTION                                                              \
+       START_EXCEPTION(Debug);                                               \
+       DEBUG_EXCEPTION_PROLOG;                                               \
+                                                                             \
+       /*                                                                    \
+        * If there is a single step or branch-taken exception in an          \
+        * exception entry sequence, it was probably meant to apply to        \
+        * the code where the exception occurred (since exception entry       \
+        * doesn't turn off DE automatically).  We simulate the effect        \
+        * of turning off DE on entry to an exception handler by turning      \
+        * off DE in the CSRR1 value and clearing the debug status.           \
+        */                                                                   \
+       mfspr   r10,SPRN_DBSR;          /* check single-step/branch taken */  \
+       andis.  r10,r10,DBSR_IC@h;                                            \
+       beq+    2f;                                                           \
+                                                                             \
+       lis     r10,KERNELBASE@h;       /* check if exception in vectors */   \
+       ori     r10,r10,KERNELBASE@l;                                         \
+       cmplw   r12,r10;                                                      \
+       blt+    2f;                     /* addr below exception vectors */    \
+                                                                             \
+       lis     r10,Debug@h;                                                  \
+       ori     r10,r10,Debug@l;                                              \
+       cmplw   r12,r10;                                                      \
+       bgt+    2f;                     /* addr above exception vectors */    \
+                                                                             \
+       /* here it looks like we got an inappropriate debug exception. */     \
+1:     rlwinm  r9,r9,0,~MSR_DE;        /* clear DE in the CDRR1 value */     \
+       lis     r10,DBSR_IC@h;          /* clear the IC event */              \
+       mtspr   SPRN_DBSR,r10;                                                \
+       /* restore state and get out */                                       \
+       lwz     r10,_CCR(r11);                                                \
+       lwz     r0,GPR0(r11);                                                 \
+       lwz     r1,GPR1(r11);                                                 \
+       mtcrf   0x80,r10;                                                     \
+       mtspr   SPRN_DSRR0,r12;                                               \
+       mtspr   SPRN_DSRR1,r9;                                                \
+       lwz     r9,GPR9(r11);                                                 \
+       lwz     r12,GPR12(r11);                                               \
+       mtspr   DEBUG_SPRG,r8;                                                \
+       BOOKE_LOAD_EXC_LEVEL_STACK(DEBUG); /* r8 points to the debug stack */ \
+       lwz     r10,GPR10-INT_FRAME_SIZE(r8);                                 \
+       lwz     r11,GPR11-INT_FRAME_SIZE(r8);                                 \
+       mfspr   r8,DEBUG_SPRG;                                                \
+                                                                             \
+       RFDI;                                                                 \
+       b       .;                                                            \
+                                                                             \
+       /* continue normal handling for a critical exception... */            \
+2:     mfspr   r4,SPRN_DBSR;                                                 \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;                                   \
+       EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, debug_transfer_to_handler, ret_from_debug_exc)
+#else
 #define DEBUG_EXCEPTION                                                              \
        START_EXCEPTION(Debug);                                               \
        CRITICAL_EXCEPTION_PROLOG;                                            \
@@ -257,6 +318,7 @@ label:
 2:     mfspr   r4,SPRN_DBSR;                                                 \
        addi    r3,r1,STACK_FRAME_OVERHEAD;                                   \
        EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
+#endif
 
 #define INSTRUCTION_STORAGE_EXCEPTION                                        \
        START_EXCEPTION(InstructionStorage)                                   \
index ce36e88ba6277ea68631ddd0fc8fb13623e94fe6..eb804b7a3cb21117fbbcf45769aabb3788d0d37c 100644 (file)
@@ -102,6 +102,7 @@ invstr:     mflr    r6                              /* Make it accessible */
        or      r7,r7,r4
        mtspr   SPRN_MAS6,r7
        tlbsx   0,r6                            /* search MSR[IS], SPID=PID0 */
+#ifndef CONFIG_E200
        mfspr   r7,SPRN_MAS1
        andis.  r7,r7,MAS1_VALID@h
        bne     match_TLB
@@ -118,6 +119,7 @@ invstr:     mflr    r6                              /* Make it accessible */
        or      r7,r7,r4
        mtspr   SPRN_MAS6,r7
        tlbsx   0,r6                            /* Fall through, we had to match */
+#endif
 match_TLB:
        mfspr   r7,SPRN_MAS0
        rlwinm  r3,r7,16,20,31                  /* Extract MAS0(Entry) */
@@ -196,8 +198,10 @@ skpinv:    addi    r6,r6,1                         /* Increment */
 /* 4. Clear out PIDs & Search info */
        li      r6,0
        mtspr   SPRN_PID0,r6
+#ifndef CONFIG_E200
        mtspr   SPRN_PID1,r6
        mtspr   SPRN_PID2,r6
+#endif
        mtspr   SPRN_MAS6,r6
 
 /* 5. Invalidate mapping we started in */
@@ -277,7 +281,9 @@ skpinv:     addi    r6,r6,1                         /* Increment */
        SET_IVOR(32, SPEUnavailable);
        SET_IVOR(33, SPEFloatingPointData);
        SET_IVOR(34, SPEFloatingPointRound);
+#ifndef CONFIG_E200
        SET_IVOR(35, PerformanceMonitor);
+#endif
 
        /* Establish the interrupt vector base */
        lis     r4,interrupt_base@h     /* IVPR only uses the high 16-bits */
@@ -285,6 +291,9 @@ skpinv:     addi    r6,r6,1                         /* Increment */
 
        /* Setup the defaults for TLB entries */
        li      r2,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l
+#ifdef CONFIG_E200
+       oris    r2,r2,MAS4_TLBSELD(1)@h
+#endif
        mtspr   SPRN_MAS4, r2
 
 #if 0
@@ -293,6 +302,12 @@ skpinv:    addi    r6,r6,1                         /* Increment */
        oris    r2,r2,HID0_DOZE@h
        mtspr   SPRN_HID0, r2
 #endif
+#ifdef CONFIG_E200
+       /* enable dedicated debug exception handling resources (Debug APU) */
+       mfspr   r2,SPRN_HID0
+       ori     r2,r2,HID0_DAPUEN@l
+       mtspr   SPRN_HID0,r2
+#endif
 
 #if !defined(CONFIG_BDI_SWITCH)
        /*
@@ -414,7 +429,12 @@ interrupt_base:
        CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException)
 
        /* Machine Check Interrupt */
+#ifdef CONFIG_E200
+       /* no RFMCI, MCSRRs on E200 */
+       CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException)
+#else
        MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException)
+#endif
 
        /* Data Storage Interrupt */
        START_EXCEPTION(DataStorage)
@@ -519,8 +539,13 @@ interrupt_base:
        /* Floating Point Unavailable Interrupt */
 #ifdef CONFIG_PPC_FPU
        FP_UNAVAILABLE_EXCEPTION
+#else
+#ifdef CONFIG_E200
+       /* E200 treats 'normal' floating point instructions as FP Unavail exception */
+       EXCEPTION(0x0800, FloatingPointUnavailable, ProgramCheckException, EXC_XFER_EE)
 #else
        EXCEPTION(0x0800, FloatingPointUnavailable, UnknownException, EXC_XFER_EE)
+#endif
 #endif
 
        /* System Call Interrupt */
@@ -691,6 +716,7 @@ interrupt_base:
 /*
  * Local functions
  */
+
        /*
         * Data TLB exceptions will bail out to this point
         * if they can't resolve the lightweight TLB fault.
@@ -761,6 +787,31 @@ END_FTR_SECTION_IFSET(CPU_FTR_BIG_PHYS)
 2:     rlwimi  r11, r12, 0, 20, 31     /* Extract RPN from PTE and merge with perms */
        mtspr   SPRN_MAS3, r11
 #endif
+#ifdef CONFIG_E200
+       /* Round robin TLB1 entries assignment */
+       mfspr   r12, SPRN_MAS0
+
+       /* Extract TLB1CFG(NENTRY) */
+       mfspr   r11, SPRN_TLB1CFG
+       andi.   r11, r11, 0xfff
+
+       /* Extract MAS0(NV) */
+       andi.   r13, r12, 0xfff
+       addi    r13, r13, 1
+       cmpw    0, r13, r11
+       addi    r12, r12, 1
+
+       /* check if we need to wrap */
+       blt     7f
+
+       /* wrap back to first free tlbcam entry */
+       lis     r13, tlbcam_index@ha
+       lwz     r13, tlbcam_index@l(r13)
+       rlwimi  r12, r13, 0, 20, 31
+7:
+       mtspr   SPRN_MAS0,r12
+#endif /* CONFIG_E200 */
+
        tlbwe
 
        /* Done...restore registers and get out of here.  */
diff --git a/arch/ppc/kernel/machine_kexec.c b/arch/ppc/kernel/machine_kexec.c
new file mode 100644 (file)
index 0000000..84d65a8
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * machine_kexec.c - handle transition of Linux booting another kernel
+ * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
+ *
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/hw_irq.h>
+#include <asm/cacheflush.h>
+#include <asm/machdep.h>
+
+typedef NORET_TYPE void (*relocate_new_kernel_t)(
+                               unsigned long indirection_page,
+                               unsigned long reboot_code_buffer,
+                               unsigned long start_address) ATTRIB_NORET;
+
+const extern unsigned char relocate_new_kernel[];
+const extern unsigned int relocate_new_kernel_size;
+
+void machine_shutdown(void)
+{
+       if (ppc_md.machine_shutdown)
+               ppc_md.machine_shutdown();
+}
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+       if (ppc_md.machine_crash_shutdown)
+               ppc_md.machine_crash_shutdown();
+}
+
+/*
+ * Do what every setup is needed on image and the
+ * reboot code buffer to allow us to avoid allocations
+ * later.
+ */
+int machine_kexec_prepare(struct kimage *image)
+{
+       if (ppc_md.machine_kexec_prepare)
+               return ppc_md.machine_kexec_prepare(image);
+       /*
+        * Fail if platform doesn't provide its own machine_kexec_prepare
+        * implementation.
+        */
+       return -ENOSYS;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+       if (ppc_md.machine_kexec_cleanup)
+               ppc_md.machine_kexec_cleanup(image);
+}
+
+/*
+ * Do not allocate memory (or fail in any way) in machine_kexec().
+ * We are past the point of no return, committed to rebooting now.
+ */
+NORET_TYPE void machine_kexec(struct kimage *image)
+{
+       if (ppc_md.machine_kexec)
+               ppc_md.machine_kexec(image);
+       else {
+               /*
+                * Fall back to normal restart if platform doesn't provide
+                * its own kexec function, and user insist to kexec...
+                */
+               machine_restart(NULL);
+       }
+       for(;;);
+}
+
+/*
+ * This is a generic machine_kexec function suitable at least for
+ * non-OpenFirmware embedded platforms.
+ * It merely copies the image relocation code to the control page and
+ * jumps to it.
+ * A platform specific function may just call this one.
+ */
+void machine_kexec_simple(struct kimage *image)
+{
+       unsigned long page_list;
+       unsigned long reboot_code_buffer, reboot_code_buffer_phys;
+       relocate_new_kernel_t rnk;
+
+       /* Interrupts aren't acceptable while we reboot */
+       local_irq_disable();
+
+       page_list = image->head;
+
+       /* we need both effective and real address here */
+       reboot_code_buffer =
+                       (unsigned long)page_address(image->control_code_page);
+       reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer);
+
+       /* copy our kernel relocation code to the control code page */
+       memcpy((void *)reboot_code_buffer, relocate_new_kernel,
+                                               relocate_new_kernel_size);
+
+       flush_icache_range(reboot_code_buffer,
+                               reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);
+       printk(KERN_INFO "Bye!\n");
+
+       /* now call it */
+       rnk = (relocate_new_kernel_t) reboot_code_buffer;
+       (*rnk)(page_list, reboot_code_buffer_phys, image->start);
+}
+
index 7329ef177a18c36c4f068d2a09dad48d34fce92e..191a8def3bdba1c9b7739cbde931322838daaf0c 100644 (file)
@@ -593,6 +593,14 @@ _GLOBAL(flush_instruction_cache)
        iccci   0,r3
 #endif
 #elif CONFIG_FSL_BOOKE
+BEGIN_FTR_SECTION
+       mfspr   r3,SPRN_L1CSR0
+       ori     r3,r3,L1CSR0_CFI|L1CSR0_CLFC
+       /* msync; isync recommended here */
+       mtspr   SPRN_L1CSR0,r3
+       isync
+       blr
+END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
        mfspr   r3,SPRN_L1CSR1
        ori     r3,r3,L1CSR1_ICFI|L1CSR1_ICLFR
        mtspr   SPRN_L1CSR1,r3
@@ -1436,8 +1444,10 @@ _GLOBAL(sys_call_table)
        .long sys_mq_timedreceive       /* 265 */
        .long sys_mq_notify
        .long sys_mq_getsetattr
-       .long sys_ni_syscall            /* 268 reserved for sys_kexec_load */
+       .long sys_kexec_load
        .long sys_add_key
        .long sys_request_key           /* 270 */
        .long sys_keyctl
        .long sys_waitid
+       .long sys_ioprio_set
+       .long sys_ioprio_get
index 6d7b92d724582c87b9bd23b7e54752191c269666..70cfb6ffd877d8a9007abc859d0f4e87d40dd3f5 100644 (file)
@@ -1495,7 +1495,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
                *offset += hose->pci_mem_offset;
                res_bit = IORESOURCE_MEM;
        } else {
-               io_offset = (unsigned long)hose->io_base_virt;
+               io_offset = hose->io_base_virt - ___IO_BASE;
                *offset += io_offset;
                res_bit = IORESOURCE_IO;
        }
@@ -1522,7 +1522,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
 
                /* found it! construct the final physical address */
                if (mmap_state == pci_mmap_io)
-                       *offset += hose->io_base_phys - _IO_BASE;
+                       *offset += hose->io_base_phys - io_offset;
                return rp;
        }
 
@@ -1739,6 +1739,23 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
        return result;
 }
 
+void pci_resource_to_user(const struct pci_dev *dev, int bar,
+                         const struct resource *rsrc,
+                         u64 *start, u64 *end)
+{
+       struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+       unsigned long offset = 0;
+
+       if (hose == NULL)
+               return;
+
+       if (rsrc->flags & IORESOURCE_IO)
+               offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys;
+
+       *start = rsrc->start + offset;
+       *end = rsrc->end + offset;
+}
+
 void __init
 pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
                  int flags, char *name)
index 918f6b252e454cc9c8a3374abfe0bc6b57e60569..fa1dad96b8309f1b44a4a40aef2748a36b4cf3e0 100644 (file)
@@ -36,7 +36,7 @@
 /* A lock to regulate grabbing the interrupt */
 DEFINE_SPINLOCK(perfmon_lock);
 
-#ifdef CONFIG_FSL_BOOKE
+#if defined (CONFIG_FSL_BOOKE) && !defined (CONFIG_E200)
 static void dummy_perf(struct pt_regs *regs)
 {
        unsigned int pmgc0 = mfpmr(PMRN_PMGC0);
diff --git a/arch/ppc/kernel/relocate_kernel.S b/arch/ppc/kernel/relocate_kernel.S
new file mode 100644 (file)
index 0000000..9b2ad48
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * relocate_kernel.S - put the kernel image in place to boot
+ * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
+ *
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <asm/reg.h>
+#include <asm/ppc_asm.h>
+#include <asm/processor.h>
+
+#include <asm/kexec.h>
+
+#define PAGE_SIZE      4096 /* must be same value as in <asm/page.h> */
+
+       /*
+        * Must be relocatable PIC code callable as a C function.
+        */
+       .globl relocate_new_kernel
+relocate_new_kernel:
+       /* r3 = page_list   */
+       /* r4 = reboot_code_buffer */
+       /* r5 = start_address      */
+
+       li      r0, 0
+
+       /*
+        * Set Machine Status Register to a known status,
+        * switch the MMU off and jump to 1: in a single step.
+        */
+
+       mr      r8, r0
+       ori     r8, r8, MSR_RI|MSR_ME
+       mtspr   SPRN_SRR1, r8
+       addi    r8, r4, 1f - relocate_new_kernel
+       mtspr   SPRN_SRR0, r8
+       sync
+       rfi
+
+1:
+       /* from this point address translation is turned off */
+       /* and interrupts are disabled */
+
+       /* set a new stack at the bottom of our page... */
+       /* (not really needed now) */
+       addi    r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */
+       stw     r0, 0(r1)
+
+       /* Do the copies */
+       li      r6, 0 /* checksum */
+       mr      r0, r3
+       b       1f
+
+0:     /* top, read another word for the indirection page */
+       lwzu    r0, 4(r3)
+
+1:
+       /* is it a destination page? (r8) */
+       rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
+       beq     2f
+
+       rlwinm  r8, r0, 0, 0, 19 /* clear kexec flags, page align */
+       b       0b
+
+2:     /* is it an indirection page? (r3) */
+       rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
+       beq     2f
+
+       rlwinm  r3, r0, 0, 0, 19 /* clear kexec flags, page align */
+       subi    r3, r3, 4
+       b       0b
+
+2:     /* are we done? */
+       rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
+       beq     2f
+       b       3f
+
+2:     /* is it a source page? (r9) */
+       rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
+       beq     0b
+
+       rlwinm  r9, r0, 0, 0, 19 /* clear kexec flags, page align */
+
+       li      r7, PAGE_SIZE / 4
+       mtctr   r7
+       subi    r9, r9, 4
+       subi    r8, r8, 4
+9:
+       lwzu    r0, 4(r9)  /* do the copy */
+       xor     r6, r6, r0
+       stwu    r0, 4(r8)
+       dcbst   0, r8
+       sync
+       icbi    0, r8
+       bdnz    9b
+
+       addi    r9, r9, 4
+       addi    r8, r8, 4
+       b       0b
+
+3:
+
+       /* To be certain of avoiding problems with self-modifying code
+        * execute a serializing instruction here.
+        */
+       isync
+       sync
+
+       /* jump to the entry point, usually the setup routine */
+       mtlr    r5
+       blrl
+
+1:     b       1b
+
+relocate_new_kernel_end:
+
+       .globl relocate_new_kernel_size
+relocate_new_kernel_size:
+       .long relocate_new_kernel_end - relocate_new_kernel
+
index 7c8437da09d5d470407dee3eb07680e97404433a..8aaeb6f4e750249026e257b3e416604eb09c075f 100644 (file)
@@ -705,8 +705,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
        unsigned long frame, newsp;
        int signr, ret;
 
-       if (current->flags & PF_FREEZE) {
-               refrigerator(PF_FREEZE);
+       if (try_to_freeze()) {
                signr = 0;
                if (!signal_pending(current))
                        goto no_signal;
index 2ca8ecfeefd978058bb65d6ca3d526d1e640a483..9e6ae5696650259da8212b076ca441f145fd5dbb 100644 (file)
@@ -173,13 +173,13 @@ static inline int check_io_access(struct pt_regs *regs)
 /* On 4xx, the reason for the machine check or program exception
    is in the ESR. */
 #define get_reason(regs)       ((regs)->dsisr)
-#ifndef CONFIG_E500
+#ifndef CONFIG_FSL_BOOKE
 #define get_mc_reason(regs)    ((regs)->dsisr)
 #else
 #define get_mc_reason(regs)    (mfspr(SPRN_MCSR))
 #endif
 #define REASON_FP              ESR_FP
-#define REASON_ILLEGAL         ESR_PIL
+#define REASON_ILLEGAL         (ESR_PIL | ESR_PUO)
 #define REASON_PRIVILEGED      ESR_PPR
 #define REASON_TRAP            ESR_PTR
 
@@ -302,7 +302,25 @@ void MachineCheckException(struct pt_regs *regs)
                printk("Bus - Instruction Parity Error\n");
        if (reason & MCSR_BUS_RPERR)
                printk("Bus - Read Parity Error\n");
-#else /* !CONFIG_4xx && !CONFIG_E500 */
+#elif defined (CONFIG_E200)
+       printk("Machine check in kernel mode.\n");
+       printk("Caused by (from MCSR=%lx): ", reason);
+
+       if (reason & MCSR_MCP)
+               printk("Machine Check Signal\n");
+       if (reason & MCSR_CP_PERR)
+               printk("Cache Push Parity Error\n");
+       if (reason & MCSR_CPERR)
+               printk("Cache Parity Error\n");
+       if (reason & MCSR_EXCP_ERR)
+               printk("ISI, ITLB, or Bus Error on first instruction fetch for an exception handler\n");
+       if (reason & MCSR_BUS_IRERR)
+               printk("Bus - Read Bus Error on instruction fetch\n");
+       if (reason & MCSR_BUS_DRERR)
+               printk("Bus - Read Bus Error on data load\n");
+       if (reason & MCSR_BUS_WRERR)
+               printk("Bus - Write Bus Error on buffered store or cache line push\n");
+#else /* !CONFIG_4xx && !CONFIG_E500 && !CONFIG_E200 */
        printk("Machine check in kernel mode.\n");
        printk("Caused by (from SRR1=%lx): ", reason);
        switch (reason & 0x601F0000) {
index 72f7c0d1c0ed90fccaa3fe2e56f02680ba3d44a1..3d79ce281b677f52eb359f6067e945706cf963c4 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/bootmem.h>
 #include <linux/highmem.h>
 
 #include <asm/pgalloc.h>
index a7f61614038110436c534ba86929e4e467555db7..b7bcbc232f394cfc891c255716af34ff3657b8c8 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/bootmem.h>
 #include <linux/highmem.h>
 
 #include <asm/pgalloc.h>
index e07990efa046e238b8dcc4deadff38bb80afcf3d..af9ca0eb6d55b6aba7fd0903371cbeef313c2199 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/bootmem.h>
 #include <linux/highmem.h>
 
 #include <asm/pgalloc.h>
@@ -126,7 +125,7 @@ void settlbcam(int index, unsigned long virt, phys_addr_t phys,
                flags |= _PAGE_COHERENT;
 #endif
 
-       TLBCAM[index].MAS0 = MAS0_TLBSEL(1) | MAS0_ESEL(index);
+       TLBCAM[index].MAS0 = MAS0_TLBSEL(1) | MAS0_ESEL(index) | MAS0_NV(index+1);
        TLBCAM[index].MAS1 = MAS1_VALID | MAS1_IPROT | MAS1_TSIZE(tsize) | MAS1_TID(pid);
        TLBCAM[index].MAS2 = virt & PAGE_MASK;
 
index 334ef4150d9291165fc9a3e78f77756c742f8221..6164a2b3473389ddc882ef286ec30535abf02f25 100644 (file)
@@ -606,9 +606,19 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
                struct page *page = pfn_to_page(pfn);
                if (!PageReserved(page)
                    && !test_bit(PG_arch_1, &page->flags)) {
-                       if (vma->vm_mm == current->active_mm)
+                       if (vma->vm_mm == current->active_mm) {
+#ifdef CONFIG_8xx
+                       /* On 8xx, cache control instructions (particularly 
+                        * "dcbst" from flush_dcache_icache) fault as write 
+                        * operation if there is an unpopulated TLB entry 
+                        * for the address in question. To workaround that, 
+                        * we invalidate the TLB here, thus avoiding dcbst 
+                        * misbehaviour.
+                        */
+                               _tlbie(address);
+#endif
                                __flush_dcache_icache((void *) address);
-                       else
+                       else
                                flush_dcache_icache_page(page);
                        set_bit(PG_arch_1, &page->flags);
                }
index 37ece1542799cefdb069ff58e120fcfe5a89af86..ddd04d4c1ea9ecb0b95413d6e51fc01b0856fe38 100644 (file)
@@ -94,20 +94,24 @@ mpc834x_sys_setup_arch(void)
 
        /* setup the board related information for the enet controllers */
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC1);
-       pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-       pdata->interruptPHY = MPC83xx_IRQ_EXT1;
-       pdata->phyid = 0;
-       /* fixup phy address */
-       pdata->phy_reg_addr += binfo->bi_immr_base;
-       memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+       if (pdata) {
+               pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+               pdata->interruptPHY = MPC83xx_IRQ_EXT1;
+               pdata->phyid = 0;
+               /* fixup phy address */
+               pdata->phy_reg_addr += binfo->bi_immr_base;
+               memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+       }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC2);
-       pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-       pdata->interruptPHY = MPC83xx_IRQ_EXT2;
-       pdata->phyid = 1;
-       /* fixup phy address */
-       pdata->phy_reg_addr += binfo->bi_immr_base;
-       memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+       if (pdata) {
+               pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+               pdata->interruptPHY = MPC83xx_IRQ_EXT2;
+               pdata->phyid = 1;
+               /* fixup phy address */
+               pdata->phy_reg_addr += binfo->bi_immr_base;
+               memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+       }
 
 #ifdef CONFIG_BLK_DEV_INITRD
        if (initrd_start)
index a2ed611cd936877f836e381b23c14cf0193969a2..f761fdf160db5ee353c8cd56518f45ac955102f6 100644 (file)
@@ -92,28 +92,34 @@ mpc8540ads_setup_arch(void)
 
        /* setup the board related information for the enet controllers */
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
-       pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-       pdata->interruptPHY = MPC85xx_IRQ_EXT5;
-       pdata->phyid = 0;
-       /* fixup phy address */
-       pdata->phy_reg_addr += binfo->bi_immr_base;
-       memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+       if (pdata) {
+               pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+               pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+               pdata->phyid = 0;
+               /* fixup phy address */
+               pdata->phy_reg_addr += binfo->bi_immr_base;
+               memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+       }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
-       pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-       pdata->interruptPHY = MPC85xx_IRQ_EXT5;
-       pdata->phyid = 1;
-       /* fixup phy address */
-       pdata->phy_reg_addr += binfo->bi_immr_base;
-       memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+       if (pdata) {
+               pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+               pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+               pdata->phyid = 1;
+               /* fixup phy address */
+               pdata->phy_reg_addr += binfo->bi_immr_base;
+               memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+       }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC);
-       pdata->board_flags = 0;
-       pdata->interruptPHY = MPC85xx_IRQ_EXT5;
-       pdata->phyid = 3;
-       /* fixup phy address */
-       pdata->phy_reg_addr += binfo->bi_immr_base;
-       memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6);
+       if (pdata) {
+               pdata->board_flags = 0;
+               pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+               pdata->phyid = 3;
+               /* fixup phy address */
+               pdata->phy_reg_addr += binfo->bi_immr_base;
+               memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6);
+       }
 
 #ifdef CONFIG_BLK_DEV_INITRD
        if (initrd_start)
index d87dfd5ce0a23d62fed242154763b70e99e56f17..e18380258b6889b6e6bc77e875fc32299ebca10e 100644 (file)
@@ -90,20 +90,24 @@ mpc8560ads_setup_arch(void)
 
        /* setup the board related information for the enet controllers */
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
-       pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-       pdata->interruptPHY = MPC85xx_IRQ_EXT5;
-       pdata->phyid = 0;
-       /* fixup phy address */
-       pdata->phy_reg_addr += binfo->bi_immr_base;
-       memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+       if (pdata) {
+               pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+               pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+               pdata->phyid = 0;
+               /* fixup phy address */
+               pdata->phy_reg_addr += binfo->bi_immr_base;
+               memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+       }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
-       pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-       pdata->interruptPHY = MPC85xx_IRQ_EXT5;
-       pdata->phyid = 1;
-       /* fixup phy address */
-       pdata->phy_reg_addr += binfo->bi_immr_base;
-       memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+       if (pdata) {
+               pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+               pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+               pdata->phyid = 1;
+               /* fixup phy address */
+               pdata->phy_reg_addr += binfo->bi_immr_base;
+               memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+       }
 
 #ifdef CONFIG_BLK_DEV_INITRD
        if (initrd_start)
index 3dbdd73618ebd9ce31d7377e60b9a2d57ffa3e33..165df94d4aa6d6d248479220e64b8005333aef1c 100644 (file)
@@ -129,20 +129,24 @@ sbc8560_setup_arch(void)
 
        /* setup the board related information for the enet controllers */
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
-       pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-       pdata->interruptPHY = MPC85xx_IRQ_EXT6;
-       pdata->phyid = 25;
-       /* fixup phy address */
-       pdata->phy_reg_addr += binfo->bi_immr_base;
-       memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+       if (pdata) {
+               pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+               pdata->interruptPHY = MPC85xx_IRQ_EXT6;
+               pdata->phyid = 25;
+               /* fixup phy address */
+               pdata->phy_reg_addr += binfo->bi_immr_base;
+               memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+       }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
-       pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-       pdata->interruptPHY = MPC85xx_IRQ_EXT7;
-       pdata->phyid = 26;
-       /* fixup phy address */
-       pdata->phy_reg_addr += binfo->bi_immr_base;
-       memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+       if (pdata) {
+               pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+               pdata->interruptPHY = MPC85xx_IRQ_EXT7;
+               pdata->phyid = 26;
+               /* fixup phy address */
+               pdata->phy_reg_addr += binfo->bi_immr_base;
+               memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+       }
 
 #ifdef CONFIG_BLK_DEV_INITRD
        if (initrd_start)
index 9455bb6b45e933dfe220c62afe96a8bf4543b1ac..bb41265cfc85ca72675db8fd4ae7b46e9b8dfaad 100644 (file)
@@ -122,19 +122,23 @@ gp3_setup_arch(void)
 
        /* setup the board related information for the enet controllers */
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
-/*     pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */
-       pdata->interruptPHY = MPC85xx_IRQ_EXT5;
-       pdata->phyid = 2;
-       pdata->phy_reg_addr += binfo->bi_immr_base;
-       memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+       if (pdata) {
+       /*      pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */
+               pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+               pdata->phyid = 2;
+               pdata->phy_reg_addr += binfo->bi_immr_base;
+               memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+       }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
-/*     pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */
-       pdata->interruptPHY = MPC85xx_IRQ_EXT5;
-       pdata->phyid = 4;
-       /* fixup phy address */
-       pdata->phy_reg_addr += binfo->bi_immr_base;
-       memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+       if (pdata) {
+       /*      pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */
+               pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+               pdata->phyid = 4;
+               /* fixup phy address */
+               pdata->phy_reg_addr += binfo->bi_immr_base;
+               memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+       }
 
 #ifdef CONFIG_BLK_DEV_INITRD
        if (initrd_start)
index 7d0ee308f662c7247c72f60484f58277a938b190..7d3fbb5c5db2955a1f5db8b1fc5cf13c2a2cd94e 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/ide.h>
-#include <linux/bootmem.h>
 
 #include <asm/io.h>
 #include <asm/pgtable.h>
index eda922ac31677db6bf12f18b0766a2beceaf8dcb..169dbf6534b9d0aec791a1c235d7a10635e4851b 100644 (file)
 #include <linux/root_dev.h>
 #include <linux/delay.h>
 #include <linux/seq_file.h>
-#include <linux/bootmem.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mv643xx.h>
 #ifdef CONFIG_BOOTIMG
 #include <linux/bootimg.h>
 #endif
+#include <asm/io.h>
 #include <asm/page.h>
 #include <asm/time.h>
 #include <asm/smp.h>
index f6ff5192406115765036aaf0d386431acbb23073..719fb49fe2bcb22147988b7e96bdd0cd6c331579 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/bootmem.h>
 
 #include <asm/sections.h>
 #include <asm/io.h>
index f459ade1bd6309769c7ff2617641edc0bd087349..016a74649155b83b8547ba2b85656a7914e78674 100644 (file)
@@ -46,7 +46,7 @@
        .section .text
        .align  5
 
-#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ_PMAC)
+#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC)
 
 /* This gets called by via-pmu.c late during the sleep process.
  * The PMU was already send the sleep command and will shut us down
@@ -382,7 +382,7 @@ turn_on_mmu:
        isync
        rfi
 
-#endif /* defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ) */
+#endif /* defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ) */
 
        .section .data
        .balign L1_CACHE_LINE_SIZE
index de60ccc7db9f267d4d525113dd95be83af9c0833..778ce4fec36836db8d7a3b53ed86960fa863986d 100644 (file)
@@ -206,7 +206,7 @@ via_calibrate_decr(void)
        return 1;
 }
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 /*
  * Reset the time after a sleep.
  */
@@ -238,7 +238,7 @@ time_sleep_notify(struct pmu_sleep_notifier *self, int when)
 static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = {
        time_sleep_notify, SLEEP_LEVEL_MISC,
 };
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
 /*
  * Query the OF and get the decr frequency.
@@ -251,9 +251,9 @@ pmac_calibrate_decr(void)
        struct device_node *cpu;
        unsigned int freq, *fp;
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
        pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
        /* We assume MacRISC2 machines have correct device-tree
         * calibration. That's better since the VIA itself seems
index 70e58f43f2b84b47043494c2e15c9b5a12ebb563..8b149c2fc54f110412a17efc7a93d3c75443def3 100644 (file)
@@ -324,6 +324,7 @@ sandpoint_setup_arch(void)
                        pdata[1].irq = 0;
                        pdata[1].mapbase = 0;
                }
+       }
 
        printk(KERN_INFO "Motorola SPS Sandpoint Test Platform\n");
        printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
index ea5e77080e8db58fbf2c970479f9881779d865d7..4c19a4ac7163134340b63077fb3df29b2312c6e0 100644 (file)
@@ -21,8 +21,8 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
-#include <linux/bootmem.h>
 #include <linux/module.h>
+#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mpc8260.h>
 #include <asm/page.h>
index a5a752609e2c426c265a4c52fd274956a1f63d09..e71488469704bbea18077cbf903871b72d34afeb 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/bootmem.h>
 
 #include <asm/io.h>
 #include <asm/prom.h>
index 580ed658e87253b51873b624ed5b8f0d228f1ba5..8f01e0f1d847404ceea8ce035f390c1fa2091f6c 100644 (file)
@@ -79,7 +79,7 @@ static struct ipic_info ipic_info[] = {
                .prio_mask = 7,
        },
        [17] = {
-               .pend   = IPIC_SIPNR_H,
+               .pend   = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_A,
                .force  = IPIC_SEFCR,
@@ -87,7 +87,7 @@ static struct ipic_info ipic_info[] = {
                .prio_mask = 5,
        },
        [18] = {
-               .pend   = IPIC_SIPNR_H,
+               .pend   = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_A,
                .force  = IPIC_SEFCR,
@@ -95,7 +95,7 @@ static struct ipic_info ipic_info[] = {
                .prio_mask = 6,
        },
        [19] = {
-               .pend   = IPIC_SIPNR_H,
+               .pend   = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_A,
                .force  = IPIC_SEFCR,
@@ -103,7 +103,7 @@ static struct ipic_info ipic_info[] = {
                .prio_mask = 7,
        },
        [20] = {
-               .pend   = IPIC_SIPNR_H,
+               .pend   = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_B,
                .force  = IPIC_SEFCR,
@@ -111,7 +111,7 @@ static struct ipic_info ipic_info[] = {
                .prio_mask = 4,
        },
        [21] = {
-               .pend   = IPIC_SIPNR_H,
+               .pend   = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_B,
                .force  = IPIC_SEFCR,
@@ -119,7 +119,7 @@ static struct ipic_info ipic_info[] = {
                .prio_mask = 5,
        },
        [22] = {
-               .pend   = IPIC_SIPNR_H,
+               .pend   = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_B,
                .force  = IPIC_SEFCR,
@@ -127,7 +127,7 @@ static struct ipic_info ipic_info[] = {
                .prio_mask = 6,
        },
        [23] = {
-               .pend   = IPIC_SIPNR_H,
+               .pend   = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_B,
                .force  = IPIC_SEFCR,
index 7b241e7876bda9ca46ac5ffe7444bc5b90a7eb8b..cc77177fa1c620eb6aad9efb5f1776a8d0b816cb 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/string.h>
-#include <linux/bootmem.h>
 #include <linux/spinlock.h>
 #include <linux/mv643xx.h>
 
index b6f0f5dcf6eeaeb907ef39c460a513c0bd79eaf5..5b827e2bbe22f47a3d3b2e5ff44df82a4a65c384 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/string.h>
-#include <linux/bootmem.h>
 #include <linux/mv643xx.h>
 
 #include <asm/byteorder.h>
index b45d8268bf93e84619b1d44382d19688d11aa204..ad39b86ca92ca545c879c951307a05c3f0404208 100644 (file)
@@ -370,8 +370,9 @@ void __init openpic_init(int offset)
        /* Initialize IPI interrupts */
        if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb);
        for (i = 0; i < OPENPIC_NUM_IPI; i++) {
-               /* Disabled, Priority 10..13 */
-               openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+offset);
+               /* Disabled, increased priorities 10..13 */
+               openpic_initipi(i, OPENPIC_PRIORITY_IPI_BASE+i,
+                               OPENPIC_VEC_IPI+i+offset);
                /* IPIs are per-CPU */
                irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU;
                irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi;
@@ -399,8 +400,9 @@ void __init openpic_init(int offset)
                if (sense & IRQ_SENSE_MASK)
                        irq_desc[i+offset].status = IRQ_LEVEL;
 
-               /* Enabled, Priority 8 */
-               openpic_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK),
+               /* Enabled, Default priority */
+               openpic_initirq(i, OPENPIC_PRIORITY_DEFAULT, i+offset,
+                               (sense & IRQ_POLARITY_MASK),
                                (sense & IRQ_SENSE_MASK));
                /* Processor 0 */
                openpic_mapirq(i, CPU_MASK_CPU0, CPU_MASK_NONE);
@@ -655,6 +657,18 @@ static void __init openpic_maptimer(u_int timer, cpumask_t cpumask)
                      cpus_addr(phys)[0]);
 }
 
+/*
+ * Change the priority of an interrupt
+ */
+void __init
+openpic_set_irq_priority(u_int irq, u_int pri)
+{
+       check_arg_irq(irq);
+       openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority,
+                               OPENPIC_PRIORITY_MASK,
+                               pri << OPENPIC_PRIORITY_SHIFT);
+}
+
 /*
  * Initalize the interrupt source which will generate an NMI.
  * This raises the interrupt's priority from 8 to 9.
@@ -665,9 +679,7 @@ void __init
 openpic_init_nmi_irq(u_int irq)
 {
        check_arg_irq(irq);
-       openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority,
-                               OPENPIC_PRIORITY_MASK,
-                               9 << OPENPIC_PRIORITY_SHIFT);
+       openpic_set_irq_priority(irq, OPENPIC_PRIORITY_NMI);
 }
 
 /*
index cb27068bfcd49694123c1cf9cc27c692a80c2c9d..f804f25232ac5fc75168ad7c344ee88dc9dff6ee 100644 (file)
@@ -142,6 +142,23 @@ config PPC_SPLPAR
          processors, that is, which share physical processors between
          two or more partitions.
 
+config KEXEC
+       bool "kexec system call (EXPERIMENTAL)"
+       depends on PPC_MULTIPLATFORM && EXPERIMENTAL
+       help
+         kexec is a system call that implements the ability to shutdown your
+         current kernel, and to start another kernel.  It is like a reboot
+         but it is indepedent of the system firmware.  And like a reboot
+         you can start any kernel with it, not just Linux.
+
+         The name comes from the similiarity to the exec system call.
+
+         It is an ongoing process to be certain the hardware in a machine
+         is properly shutdown, so do not be surprised if this code does not
+         initially work for you.  It may help to enable device hotplugging
+         support.  As of this writing the exact hardware interface is
+         strongly in flux, so no good recommendation can be made.
+
 config IBMVIO
        depends on PPC_PSERIES || PPC_ISERIES
        bool
@@ -270,26 +287,7 @@ config SCHED_SMT
          when dealing with POWER5 cpus at a cost of slightly increased
          overhead in some places. If unsure say N here.
 
-config PREEMPT
-       bool "Preemptible Kernel"
-       help
-         This option reduces the latency of the kernel when reacting to
-         real-time or interactive events by allowing a low priority process to
-         be preempted even if it is in kernel mode executing a system call.
-
-         Say Y here if you are building a kernel for a desktop, embedded
-         or real-time system.  Say N if you are unsure.
-
-config PREEMPT_BKL
-       bool "Preempt The Big Kernel Lock"
-       depends on PREEMPT
-       default y
-       help
-         This option reduces the latency of the kernel by making the
-         big kernel lock preemptible.
-
-         Say Y here if you are building a kernel for a desktop system.
-         Say N if you are unsure.
+source "kernel/Kconfig.preempt"
 
 config EEH
        bool "PCI Extended Error Handling (EEH)" if EMBEDDED
index d3e1d6af920365810397b9baf714aba0beab1ba0..683b2d43c15fe2facb4a7a1d7f388f260481c3a0 100644 (file)
@@ -52,7 +52,7 @@ obj-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.o, $(section)))
 src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.c, $(section)))
 gz-sec  = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.gz, $(section)))
 
-hostprogs-y            := piggy addnote addRamDisk
+hostprogs-y            := addnote addRamDisk
 targets                += zImage zImage.initrd imagesize.c \
                           $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \
                           $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \
@@ -78,9 +78,6 @@ addsection = $(CROSS32OBJCOPY) $(1) \
 quiet_cmd_addnote = ADDNOTE $@ 
       cmd_addnote = $(CROSS32LD) $(BOOTLFLAGS) -o $@ $(obj-boot) && $(obj)/addnote $@
 
-quiet_cmd_piggy = PIGGY   $@
-      cmd_piggy = $(obj)/piggyback $(@:.o=) < $< | $(CROSS32AS) -o $@
-
 $(call gz-sec, $(required)): $(obj)/kernel-%.gz: % FORCE
        $(call if_changed,gzip)
 
index da12ea2ca46497d6bae9f1e6453817cbb0ca2e97..199d9804f61c418a9351697846e1e83964f6f615 100644 (file)
@@ -17,7 +17,6 @@
 
 extern void *finddevice(const char *);
 extern int getprop(void *, const char *, void *, int);
-extern void printk(char *fmt, ...);
 extern void printf(const char *fmt, ...);
 extern int sprintf(char *buf, const char *fmt, ...);
 void gunzip(void *, int, unsigned char *, int *);
@@ -147,10 +146,10 @@ void start(unsigned long a1, unsigned long a2, void *promptr)
                }
                a1 = initrd.addr;
                a2 = initrd.size;
-               printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r",
+               printf("initial ramdisk moving 0x%lx <- 0x%lx (0x%lx bytes)\n\r",
                       initrd.addr, (unsigned long)_initrd_start, initrd.size);
                memmove((void *)initrd.addr, (void *)_initrd_start, initrd.size);
-               printf("initrd head: 0x%lx\n\r", *((u32 *)initrd.addr));
+               printf("initrd head: 0x%lx\n\r", *((unsigned long *)initrd.addr));
        }
 
        /* Eventually gunzip the kernel */
@@ -201,9 +200,6 @@ void start(unsigned long a1, unsigned long a2, void *promptr)
 
        flush_cache((void *)vmlinux.addr, vmlinux.size);
 
-       if (a1)
-               printf("initrd head: 0x%lx\n\r", *((u32 *)initrd.addr));
-
        kernel_entry = (kernel_entry_t)vmlinux.addr;
 #ifdef DEBUG
        printf( "kernel:\n\r"
diff --git a/arch/ppc64/boot/mknote.c b/arch/ppc64/boot/mknote.c
deleted file mode 100644 (file)
index 120cc1d..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) Cort Dougan 1999.
- *
- * 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.
- *
- * Generate a note section as per the CHRP specification.
- *
- */
-
-#include <stdio.h>
-
-#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff );
-
-int main(void)
-{
-/* header */
-       /* namesz */
-       PL(strlen("PowerPC")+1);
-       /* descrsz */
-       PL(6*4);
-       /* type */
-       PL(0x1275);
-       /* name */
-       printf("PowerPC"); printf("%c", 0);
-       
-/* descriptor */
-       /* real-mode */
-       PL(0xffffffff);
-       /* real-base */
-       PL(0x00c00000);
-       /* real-size */
-       PL(0xffffffff);
-       /* virt-base */
-       PL(0xffffffff);
-       /* virt-size */
-       PL(0xffffffff);
-       /* load-base */
-       PL(0x4000);
-       return 0;
-}
diff --git a/arch/ppc64/boot/piggyback.c b/arch/ppc64/boot/piggyback.c
deleted file mode 100644 (file)
index 235c7a8..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2001 IBM Corp 
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-
-extern long ce_exec_config[];
-
-int main(int argc, char *argv[])
-{
-       int i, cnt, pos, len;
-       unsigned int cksum, val;
-       unsigned char *lp;
-       unsigned char buf[8192];
-       char *varname;
-       if (argc != 2)
-       {
-               fprintf(stderr, "usage: %s name <in-file >out-file\n",
-                       argv[0]);
-               exit(1);
-       }
-
-       varname = strrchr(argv[1], '/');
-       if (varname)
-               varname++;
-       else
-               varname = argv[1];
-
-       fprintf(stdout, "#\n");
-       fprintf(stdout, "# Miscellaneous data structures:\n");
-       fprintf(stdout, "# WARNING - this file is automatically generated!\n");
-       fprintf(stdout, "#\n");
-       fprintf(stdout, "\n");
-       fprintf(stdout, "\t.data\n");
-       fprintf(stdout, "\t.globl %s_data\n", varname);
-       fprintf(stdout, "%s_data:\n", varname);
-       pos = 0;
-       cksum = 0;
-       while ((len = read(0, buf, sizeof(buf))) > 0)
-       {
-               cnt = 0;
-               lp = (unsigned char *)buf;
-               len = (len + 3) & ~3;  /* Round up to longwords */
-               for (i = 0;  i < len;  i += 4)
-               {
-                       if (cnt == 0)
-                       {
-                               fprintf(stdout, "\t.long\t");
-                       }
-                       fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
-                       val = *(unsigned long *)lp;
-                       cksum ^= val;
-                       lp += 4;
-                       if (++cnt == 4)
-                       {
-                               cnt = 0;
-                               fprintf(stdout, " # %x \n", pos+i-12);
-                               fflush(stdout);
-                       } else
-                       {
-                               fprintf(stdout, ",");
-                       }
-               }
-               if (cnt)
-               {
-                       fprintf(stdout, "0\n");
-               }
-               pos += len;
-       }
-       fprintf(stdout, "\t.globl %s_len\n", varname);
-       fprintf(stdout, "%s_len:\t.long\t0x%x\n", varname, pos);
-       fflush(stdout);
-       fclose(stdout);
-       fprintf(stderr, "cksum = %x\n", cksum);
-       exit(0);
-}
-
index d5218b15824e93444a5b2c8810ffff5e0e6416d4..5e48b80ff5a07471bd2f07feba550bd85cf9bbaf 100644 (file)
@@ -40,7 +40,7 @@ void *finddevice(const char *name);
 int getprop(void *phandle, const char *name, void *buf, int buflen);
 void chrpboot(int a1, int a2, void *prom);     /* in main.c */
 
-void printk(char *fmt, ...);
+int printf(char *fmt, ...);
 
 /* there is no convenient header to get this from...  -- paulus */
 extern unsigned long strlen(const char *);
@@ -220,7 +220,7 @@ readchar(void)
                case 1:
                        return ch;
                case -1:
-                       printk("read(stdin) returned -1\r\n");
+                       printf("read(stdin) returned -1\r\n");
                        return -1;
                }
        }
@@ -627,18 +627,6 @@ int sprintf(char * buf, const char *fmt, ...)
 
 static char sprint_buf[1024];
 
-void
-printk(char *fmt, ...)
-{
-       va_list args;
-       int n;
-
-       va_start(args, fmt);
-       n = vsprintf(sprint_buf, fmt, args);
-       va_end(args);
-       write(stdout, sprint_buf, n);
-}
-
 int
 printf(char *fmt, ...)
 {
index cdea00d7707f641e0dcabc4559ce90de101052ba..4231861288a3cb5b9fe88e6219fa7cedc19ec730 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ItLpQueue.c
  * Copyright (C) 2001 Mike Corrigan  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
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
 #include <asm/system.h>
 #include <asm/paca.h>
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/iSeries/HvLpEvent.h>
 #include <asm/iSeries/HvCallEvent.h>
 
-static __inline__ int set_inUse( struct ItLpQueue * lpQueue )
-{
-       int t;
-       u32 * inUseP = &(lpQueue->xInUseWord);
-
-       __asm__ __volatile__("\n\
-1:     lwarx   %0,0,%2         \n\
-       cmpwi   0,%0,0          \n\
-       li      %0,0            \n\
-       bne-    2f              \n\
-       addi    %0,%0,1         \n\
-       stwcx.  %0,0,%2         \n\
-       bne-    1b              \n\
-2:     eieio"
-       : "=&r" (t), "=m" (lpQueue->xInUseWord)
-       : "r" (inUseP), "m" (lpQueue->xInUseWord)
-       : "cc");
-
-       return t;
-}
+/*
+ * The LpQueue is used to pass event data from the hypervisor to
+ * the partition.  This is where I/O interrupt events are communicated.
+ *
+ * It is written to by the hypervisor so cannot end up in the BSS.
+ */
+struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data")));
 
-static __inline__ void clear_inUse( struct ItLpQueue * lpQueue )
-{
-       lpQueue->xInUseWord = 0;
-}
+DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts);
+
+static char *event_types[HvLpEvent_Type_NumTypes] = {
+       "Hypervisor",
+       "Machine Facilities",
+       "Session Manager",
+       "SPD I/O",
+       "Virtual Bus",
+       "PCI I/O",
+       "RIO I/O",
+       "Virtual Lan",
+       "Virtual I/O"
+};
 
 /* Array of LpEvent handler functions */
 extern LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];
-unsigned long ItLpQueueInProcess = 0;
 
-struct HvLpEvent * ItLpQueue_getNextLpEvent( struct ItLpQueue * lpQueue )
+static struct HvLpEvent * get_next_hvlpevent(void)
 {
-       struct HvLpEvent * nextLpEvent = 
-               (struct HvLpEvent *)lpQueue->xSlicCurEventPtr;
-       if ( nextLpEvent->xFlags.xValid ) {
+       struct HvLpEvent * event;
+       event = (struct HvLpEvent *)hvlpevent_queue.xSlicCurEventPtr;
+
+       if (event->xFlags.xValid) {
                /* rmb() needed only for weakly consistent machines (regatta) */
                rmb();
                /* Set pointer to next potential event */
-               lpQueue->xSlicCurEventPtr += ((nextLpEvent->xSizeMinus1 +
-                                     LpEventAlign ) /
-                                     LpEventAlign ) *
-                                     LpEventAlign;
+               hvlpevent_queue.xSlicCurEventPtr += ((event->xSizeMinus1 +
+                               LpEventAlign) / LpEventAlign) * LpEventAlign;
+
                /* Wrap to beginning if no room at end */
-               if (lpQueue->xSlicCurEventPtr > lpQueue->xSlicLastValidEventPtr)
-                       lpQueue->xSlicCurEventPtr = lpQueue->xSlicEventStackPtr;
+               if (hvlpevent_queue.xSlicCurEventPtr >
+                               hvlpevent_queue.xSlicLastValidEventPtr) {
+                       hvlpevent_queue.xSlicCurEventPtr =
+                               hvlpevent_queue.xSlicEventStackPtr;
+               }
+       } else {
+               event = NULL;
        }
-       else 
-               nextLpEvent = NULL;
 
-       return nextLpEvent;
+       return event;
 }
 
-int ItLpQueue_isLpIntPending( struct ItLpQueue * lpQueue )
+static unsigned long spread_lpevents = NR_CPUS;
+
+int hvlpevent_is_pending(void)
 {
-       int retval = 0;
-       struct HvLpEvent * nextLpEvent;
-       if ( lpQueue ) {
-               nextLpEvent = (struct HvLpEvent *)lpQueue->xSlicCurEventPtr;
-               retval = nextLpEvent->xFlags.xValid | lpQueue->xPlicOverflowIntPending;
-       }
-       return retval;
+       struct HvLpEvent *next_event;
+
+       if (smp_processor_id() >= spread_lpevents)
+               return 0;
+
+       next_event = (struct HvLpEvent *)hvlpevent_queue.xSlicCurEventPtr;
+
+       return next_event->xFlags.xValid |
+               hvlpevent_queue.xPlicOverflowIntPending;
 }
 
-void ItLpQueue_clearValid( struct HvLpEvent * event )
+static void hvlpevent_clear_valid(struct HvLpEvent * event)
 {
-       /* Clear the valid bit of the event
-        * Also clear bits within this event that might
-        * look like valid bits (on 64-byte boundaries)
-        */
-       unsigned extra = (( event->xSizeMinus1 + LpEventAlign ) /
-                                                LpEventAlign ) - 1;
-       switch ( extra ) {
-         case 3:
-          ((struct HvLpEvent*)((char*)event+3*LpEventAlign))->xFlags.xValid=0;
-         case 2:
-          ((struct HvLpEvent*)((char*)event+2*LpEventAlign))->xFlags.xValid=0;
-         case 1:
-          ((struct HvLpEvent*)((char*)event+1*LpEventAlign))->xFlags.xValid=0;
-         case 0:
-          ;    
+       /* Tell the Hypervisor that we're done with this event.
+        * Also clear bits within this event that might look like valid bits.
+        * ie. on 64-byte boundaries.
+        */
+       struct HvLpEvent *tmp;
+       unsigned extra = ((event->xSizeMinus1 + LpEventAlign) /
+                                                LpEventAlign) - 1;
+
+       switch (extra) {
+       case 3:
+               tmp = (struct HvLpEvent*)((char*)event + 3 * LpEventAlign);
+               tmp->xFlags.xValid = 0;
+       case 2:
+               tmp = (struct HvLpEvent*)((char*)event + 2 * LpEventAlign);
+               tmp->xFlags.xValid = 0;
+       case 1:
+               tmp = (struct HvLpEvent*)((char*)event + 1 * LpEventAlign);
+               tmp->xFlags.xValid = 0;
        }
+
        mb();
+
        event->xFlags.xValid = 0;
 }
 
-unsigned ItLpQueue_process( struct ItLpQueue * lpQueue, struct pt_regs *regs )
+void process_hvlpevents(struct pt_regs *regs)
 {
-       unsigned numIntsProcessed = 0;
-       struct HvLpEvent * nextLpEvent;
+       struct HvLpEvent * event;
 
        /* If we have recursed, just return */
-       if ( !set_inUse( lpQueue ) )
-               return 0;
-       
-       if (ItLpQueueInProcess == 0)
-               ItLpQueueInProcess = 1;
-       else
-               BUG();
+       if (!spin_trylock(&hvlpevent_queue.lock))
+               return;
 
        for (;;) {
-               nextLpEvent = ItLpQueue_getNextLpEvent( lpQueue );
-               if ( nextLpEvent ) {
-                       /* Count events to return to caller
-                        * and count processed events in lpQueue
-                        */
-                       ++numIntsProcessed;
-                       lpQueue->xLpIntCount++;         
-                       /* Call appropriate handler here, passing 
+               event = get_next_hvlpevent();
+               if (event) {
+                       /* Call appropriate handler here, passing
                         * a pointer to the LpEvent.  The handler
                         * must make a copy of the LpEvent if it
                         * needs it in a bottom half. (perhaps for
                         * an ACK)
-                        *      
-                        *  Handlers are responsible for ACK processing 
+                        *
+                        *  Handlers are responsible for ACK processing
                         *
                         * The Hypervisor guarantees that LpEvents will
                         * only be delivered with types that we have
                         * registered for, so no type check is necessary
                         * here!
-                        */
-                       if ( nextLpEvent->xType < HvLpEvent_Type_NumTypes )
-                               lpQueue->xLpIntCountByType[nextLpEvent->xType]++;
-                       if ( nextLpEvent->xType < HvLpEvent_Type_NumTypes &&
-                            lpEventHandler[nextLpEvent->xType] ) 
-                               lpEventHandler[nextLpEvent->xType](nextLpEvent, regs);
+                        */
+                       if (event->xType < HvLpEvent_Type_NumTypes)
+                               __get_cpu_var(hvlpevent_counts)[event->xType]++;
+                       if (event->xType < HvLpEvent_Type_NumTypes &&
+                                       lpEventHandler[event->xType])
+                               lpEventHandler[event->xType](event, regs);
                        else
-                               printk(KERN_INFO "Unexpected Lp Event type=%d\n", nextLpEvent->xType );
-                       
-                       ItLpQueue_clearValid( nextLpEvent );
-               } else if ( lpQueue->xPlicOverflowIntPending )
+                               printk(KERN_INFO "Unexpected Lp Event type=%d\n", event->xType );
+
+                       hvlpevent_clear_valid(event);
+               } else if (hvlpevent_queue.xPlicOverflowIntPending)
                        /*
                         * No more valid events. If overflow events are
                         * pending process them
                         */
-                       HvCallEvent_getOverflowLpEvents( lpQueue->xIndex);
+                       HvCallEvent_getOverflowLpEvents(hvlpevent_queue.xIndex);
                else
                        break;
        }
 
-       ItLpQueueInProcess = 0;
-       mb();
-       clear_inUse( lpQueue );
+       spin_unlock(&hvlpevent_queue.lock);
+}
+
+static int set_spread_lpevents(char *str)
+{
+       unsigned long val = simple_strtoul(str, NULL, 0);
+
+       /*
+        * The parameter is the number of processors to share in processing
+        * lp events.
+        */
+       if (( val > 0) && (val <= NR_CPUS)) {
+               spread_lpevents = val;
+               printk("lpevent processing spread over %ld processors\n", val);
+       } else {
+               printk("invalid spread_lpevents %ld\n", val);
+       }
 
-       get_paca()->lpevent_count += numIntsProcessed;
+       return 1;
+}
+__setup("spread_lpevents=", set_spread_lpevents);
+
+void setup_hvlpevent_queue(void)
+{
+       void *eventStack;
+
+       /*
+        * Allocate a page for the Event Stack. The Hypervisor needs the
+        * absolute real address, so we subtract out the KERNELBASE and add
+        * in the absolute real address of the kernel load area.
+        */
+       eventStack = alloc_bootmem_pages(LpEventStackSize);
+       memset(eventStack, 0, LpEventStackSize);
+
+       /* Invoke the hypervisor to initialize the event stack */
+       HvCallEvent_setLpEventStack(0, eventStack, LpEventStackSize);
+
+       hvlpevent_queue.xSlicEventStackPtr = (char *)eventStack;
+       hvlpevent_queue.xSlicCurEventPtr = (char *)eventStack;
+       hvlpevent_queue.xSlicLastValidEventPtr = (char *)eventStack +
+                                       (LpEventStackSize - LpEventMaxSize);
+       hvlpevent_queue.xIndex = 0;
+}
+
+static int proc_lpevents_show(struct seq_file *m, void *v)
+{
+       int cpu, i;
+       unsigned long sum;
+       static unsigned long cpu_totals[NR_CPUS];
+
+       /* FIXME: do we care that there's no locking here? */
+       sum = 0;
+       for_each_online_cpu(cpu) {
+               cpu_totals[cpu] = 0;
+               for (i = 0; i < HvLpEvent_Type_NumTypes; i++) {
+                       cpu_totals[cpu] += per_cpu(hvlpevent_counts, cpu)[i];
+               }
+               sum += cpu_totals[cpu];
+       }
+
+       seq_printf(m, "LpEventQueue 0\n");
+       seq_printf(m, "  events processed:\t%lu\n", sum);
+
+       for (i = 0; i < HvLpEvent_Type_NumTypes; ++i) {
+               sum = 0;
+               for_each_online_cpu(cpu) {
+                       sum += per_cpu(hvlpevent_counts, cpu)[i];
+               }
+
+               seq_printf(m, "    %-20s %10lu\n", event_types[i], sum);
+       }
+
+       seq_printf(m, "\n  events processed by processor:\n");
+
+       for_each_online_cpu(cpu) {
+               seq_printf(m, "    CPU%02d  %10lu\n", cpu, cpu_totals[cpu]);
+       }
+
+       return 0;
+}
+
+static int proc_lpevents_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, proc_lpevents_show, NULL);
+}
 
-       return numIntsProcessed;
+static struct file_operations proc_lpevents_operations = {
+       .open           = proc_lpevents_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int __init proc_lpevents_init(void)
+{
+       struct proc_dir_entry *e;
+
+       e = create_proc_entry("iSeries/lpevents", S_IFREG|S_IRUGO, NULL);
+       if (e)
+               e->proc_fops = &proc_lpevents_operations;
+
+       return 0;
 }
+__initcall(proc_lpevents_init);
+
index badc5a443614829bebdd36b3dd5fa4a86a068bd3..6ffcf67dd50762bca3bf4383ea7986a4ff7678b0 100644 (file)
 #include <asm/iSeries/IoHriProcessorVpd.h>
 #include <asm/iSeries/ItSpCommArea.h>
 
-/* The LpQueue is used to pass event data from the hypervisor to
- * the partition.  This is where I/O interrupt events are communicated.
- */
-
-/* May be filled in by the hypervisor so cannot end up in the BSS */
-struct ItLpQueue xItLpQueue __attribute__((__section__(".data")));
-
 
 /* The HvReleaseData is the root of the information shared between 
  * the hypervisor and Linux.  
@@ -200,7 +193,7 @@ struct ItVpdAreas itVpdAreas = {
                0,0,0,                  /* 13 - 15 */
                sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */
                0,0,0,0,0,0,            /* 17 - 22  */
-               sizeof(struct ItLpQueue),/*     23 length of Lp Queue */
+               sizeof(struct hvlpevent_queue), /* 23 length of Lp Queue */
                0,0                     /* 24 - 25 */
                },
        .xSlicVpdAdrs = {                       /* VPD addresses */
@@ -218,7 +211,7 @@ struct ItVpdAreas itVpdAreas = {
                0,0,0,                  /* 13 - 15 */
                &xIoHriProcessorVpd,    /*      16 Proc Vpd */
                0,0,0,0,0,0,            /* 17 - 22 */
-               &xItLpQueue,            /*      23 Lp Queue */
+               &hvlpevent_queue,       /*      23 Lp Queue */
                0,0
        }
 };
index dffbfb7ac8d50590c9cabb2ee2eb58dd068785c0..d9b2660ef221f694e3b5a80c646b9fa508db0f41 100644 (file)
@@ -36,6 +36,7 @@ obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \
 obj-$(CONFIG_PPC_BPA) += bpa_setup.o bpa_iommu.o bpa_nvram.o \
                         bpa_iic.o spider-pic.o
 
+obj-$(CONFIG_KEXEC)            += machine_kexec.o
 obj-$(CONFIG_EEH)              += eeh.o
 obj-$(CONFIG_PROC_FS)          += proc_ppc64.o
 obj-$(CONFIG_RTAS_FLASH)       += rtas_flash.o
index 02c8f4e3e4bc644f66dbdde07b31544d9063266b..675c2708588f002758ff747490ec68817cb1d803 100644 (file)
@@ -1194,7 +1194,7 @@ _GLOBAL(pSeries_secondary_smp_init)
        bl      .__restore_cpu_setup
 
        /* Set up a paca value for this processor. Since we have the
-        * physical cpu id in r3, we need to search the pacas to find
+        * physical cpu id in r24, we need to search the pacas to find
         * which logical id maps to our physical one.
         */
        LOADADDR(r13, paca)             /* Get base vaddr of paca array  */
@@ -1207,8 +1207,8 @@ _GLOBAL(pSeries_secondary_smp_init)
        cmpwi   r5,NR_CPUS
        blt     1b
 
-99:    HMT_LOW                         /* Couldn't find our CPU id      */
-       b       99b
+       mr      r3,r24                  /* not found, copy phys to r3    */
+       b       .kexec_wait             /* next kernel might do better   */
 
 2:     mtspr   SPRG3,r13               /* Save vaddr of paca in SPRG3   */
        /* From now on, r24 is expected to be logica cpuid */
index 356bd9931fcc923e7e3645557bc3392331f855b4..0fe3116eba29c017d66a12ecec53a1df64391d12 100644 (file)
@@ -40,50 +40,6 @@ static int __init iseries_proc_create(void)
 }
 core_initcall(iseries_proc_create);
 
-static char *event_types[9] = {
-       "Hypervisor\t\t",
-       "Machine Facilities\t",
-       "Session Manager\t",
-       "SPD I/O\t\t",
-       "Virtual Bus\t\t",
-       "PCI I/O\t\t",
-       "RIO I/O\t\t",
-       "Virtual Lan\t\t",
-       "Virtual I/O\t\t"
-};
-
-static int proc_lpevents_show(struct seq_file *m, void *v)
-{
-       unsigned int i;
-
-       seq_printf(m, "LpEventQueue 0\n");
-       seq_printf(m, "  events processed:\t%lu\n",
-                  (unsigned long)xItLpQueue.xLpIntCount);
-
-       for (i = 0; i < 9; ++i)
-               seq_printf(m, "    %s %10lu\n", event_types[i],
-                          (unsigned long)xItLpQueue.xLpIntCountByType[i]);
-
-       seq_printf(m, "\n  events processed by processor:\n");
-
-       for_each_online_cpu(i)
-               seq_printf(m, "    CPU%02d  %10u\n", i, paca[i].lpevent_count);
-
-       return 0;
-}
-
-static int proc_lpevents_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, proc_lpevents_show, NULL);
-}
-
-static struct file_operations proc_lpevents_operations = {
-       .open           = proc_lpevents_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
 static unsigned long startTitan = 0;
 static unsigned long startTb = 0;
 
@@ -148,10 +104,6 @@ static int __init iseries_proc_init(void)
 {
        struct proc_dir_entry *e;
 
-       e = create_proc_entry("iSeries/lpevents", S_IFREG|S_IRUGO, NULL);
-       if (e)
-               e->proc_fops = &proc_lpevents_operations;
-
        e = create_proc_entry("iSeries/titanTod", S_IFREG|S_IRUGO, NULL);
        if (e)
                e->proc_fops = &proc_titantod_operations;
index 86966ce76b58e26578322f67629f7ad590424091..b3f770f6d4022ef4e0484ccb4c3c26ececdd7601 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/smp.h>
 #include <linux/param.h>
 #include <linux/string.h>
-#include <linux/bootmem.h>
 #include <linux/initrd.h>
 #include <linux/seq_file.h>
 #include <linux/kdev_t.h>
@@ -676,7 +675,6 @@ static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr)
  */
 static void __init iSeries_setup_arch(void)
 {
-       void *eventStack;
        unsigned procIx = get_paca()->lppaca.dyn_hv_phys_proc_index;
 
        /* Add an eye catcher and the systemcfg layout version number */
@@ -685,24 +683,7 @@ static void __init iSeries_setup_arch(void)
        systemcfg->version.minor = SYSTEMCFG_MINOR;
 
        /* Setup the Lp Event Queue */
-
-       /* Allocate a page for the Event Stack
-        * The hypervisor wants the absolute real address, so
-        * we subtract out the KERNELBASE and add in the
-        * absolute real address of the kernel load area
-        */
-       eventStack = alloc_bootmem_pages(LpEventStackSize);
-       memset(eventStack, 0, LpEventStackSize);
-
-       /* Invoke the hypervisor to initialize the event stack */
-       HvCallEvent_setLpEventStack(0, eventStack, LpEventStackSize);
-
-       /* Initialize fields in our Lp Event Queue */
-       xItLpQueue.xSlicEventStackPtr = (char *)eventStack;
-       xItLpQueue.xSlicCurEventPtr = (char *)eventStack;
-       xItLpQueue.xSlicLastValidEventPtr = (char *)eventStack +
-                                       (LpEventStackSize - LpEventMaxSize);
-       xItLpQueue.xIndex = 0;
+       setup_hvlpevent_queue();
 
        /* Compute processor frequency */
        procFreqHz = ((1UL << 34) * 1000000) /
@@ -853,28 +834,6 @@ static int __init iSeries_src_init(void)
 
 late_initcall(iSeries_src_init);
 
-static int set_spread_lpevents(char *str)
-{
-       unsigned long i;
-       unsigned long val = simple_strtoul(str, NULL, 0);
-
-       /*
-        * The parameter is the number of processors to share in processing
-        * lp events.
-        */
-       if (( val > 0) && (val <= NR_CPUS)) {
-               for (i = 1; i < val; ++i)
-                       paca[i].lpqueue_ptr = paca[0].lpqueue_ptr;
-
-               printk("lpevent processing spread over %ld processors\n", val);
-       } else {
-               printk("invalid spread_lpevents %ld\n", val);
-       }
-
-       return 1;
-}
-__setup("spread_lpevents=", set_spread_lpevents);
-
 #ifndef CONFIG_PCI
 void __init iSeries_init_IRQ(void) { }
 #endif
index bdf13b4dc1c832972733e907b6e68ab83704ff01..08952c7e621648e9d8593e395e14de143e674e22 100644 (file)
@@ -88,7 +88,7 @@ static int iSeries_idle(void)
 
        while (1) {
                if (lpaca->lppaca.shared_proc) {
-                       if (ItLpQueue_isLpIntPending(lpaca->lpqueue_ptr))
+                       if (hvlpevent_is_pending())
                                process_iSeries_events();
                        if (!need_resched())
                                yield_shared_processor();
@@ -100,7 +100,7 @@ static int iSeries_idle(void)
 
                                while (!need_resched()) {
                                        HMT_medium();
-                                       if (ItLpQueue_isLpIntPending(lpaca->lpqueue_ptr))
+                                       if (hvlpevent_is_pending())
                                                process_iSeries_events();
                                        HMT_low();
                                }
index 3defc8c33adf567ad95988ec077174c992dc6ac3..f41afe545045ee6710e58206f83d752dd62df8b0 100644 (file)
@@ -66,7 +66,6 @@ EXPORT_SYMBOL(irq_desc);
 int distribute_irqs = 1;
 int __irq_offset_value;
 int ppc_spurious_interrupts;
-unsigned long lpevent_count;
 u64 ppc64_interrupt_controller;
 
 int show_interrupts(struct seq_file *p, void *v)
@@ -245,7 +244,7 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)
 
                spin_lock(&desc->lock);
                if (!noirqdebug)
-                       note_interrupt(irq, desc, action_ret);
+                       note_interrupt(irq, desc, action_ret, regs);
                if (likely(!(desc->status & IRQ_PENDING)))
                        break;
                desc->status &= ~IRQ_PENDING;
@@ -269,7 +268,6 @@ out:
 void do_IRQ(struct pt_regs *regs)
 {
        struct paca_struct *lpaca;
-       struct ItLpQueue *lpq;
 
        irq_enter();
 
@@ -295,9 +293,8 @@ void do_IRQ(struct pt_regs *regs)
                iSeries_smp_message_recv(regs);
        }
 #endif /* CONFIG_SMP */
-       lpq = lpaca->lpqueue_ptr;
-       if (lpq && ItLpQueue_isLpIntPending(lpq))
-               lpevent_count += ItLpQueue_process(lpq, regs);
+       if (hvlpevent_is_pending())
+               process_hvlpevents(regs);
 
        irq_exit();
 
index 782ce3efa2c10d04718d70157d7acb9d56786039..1d2ff6d6b0b368733d47862b1ce9e4eae9fa3905 100644 (file)
@@ -36,6 +36,8 @@
 #include <asm/kdebug.h>
 #include <asm/sstep.h>
 
+static DECLARE_MUTEX(kprobe_mutex);
+
 static struct kprobe *current_kprobe;
 static unsigned long kprobe_status, kprobe_saved_msr;
 static struct kprobe *kprobe_prev;
@@ -54,6 +56,15 @@ int arch_prepare_kprobe(struct kprobe *p)
                printk("Cannot register a kprobe on rfid or mtmsrd\n");
                ret = -EINVAL;
        }
+
+       /* insn must be on a special executable page on ppc64 */
+       if (!ret) {
+               up(&kprobe_mutex);
+               p->ainsn.insn = get_insn_slot();
+               down(&kprobe_mutex);
+               if (!p->ainsn.insn)
+                       ret = -ENOMEM;
+       }
        return ret;
 }
 
@@ -79,16 +90,22 @@ void arch_disarm_kprobe(struct kprobe *p)
 
 void arch_remove_kprobe(struct kprobe *p)
 {
+       up(&kprobe_mutex);
+       free_insn_slot(p->ainsn.insn);
+       down(&kprobe_mutex);
 }
 
 static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 {
+       kprobe_opcode_t insn = *p->ainsn.insn;
+
        regs->msr |= MSR_SE;
-       /*single step inline if it a breakpoint instruction*/
-       if (p->opcode == BREAKPOINT_INSTRUCTION)
+
+       /* single step inline if it is a trap variant */
+       if (IS_TW(insn) || IS_TD(insn) || IS_TWI(insn) || IS_TDI(insn))
                regs->nip = (unsigned long)p->addr;
        else
-               regs->nip = (unsigned long)&p->ainsn.insn;
+               regs->nip = (unsigned long)p->ainsn.insn;
 }
 
 static inline void save_previous_kprobe(void)
@@ -105,6 +122,23 @@ static inline void restore_previous_kprobe(void)
        kprobe_saved_msr = kprobe_saved_msr_prev;
 }
 
+void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
+{
+       struct kretprobe_instance *ri;
+
+       if ((ri = get_free_rp_inst(rp)) != NULL) {
+               ri->rp = rp;
+               ri->task = current;
+               ri->ret_addr = (kprobe_opcode_t *)regs->link;
+
+               /* Replace the return addr with trampoline addr */
+               regs->link = (unsigned long)kretprobe_trampoline;
+               add_rp_inst(ri);
+       } else {
+               rp->nmissed++;
+       }
+}
+
 static inline int kprobe_handler(struct pt_regs *regs)
 {
        struct kprobe *p;
@@ -194,6 +228,78 @@ no_kprobe:
        return ret;
 }
 
+/*
+ * Function return probe trampoline:
+ *     - init_kprobes() establishes a probepoint here
+ *     - When the probed function returns, this probe
+ *             causes the handlers to fire
+ */
+void kretprobe_trampoline_holder(void)
+{
+       asm volatile(".global kretprobe_trampoline\n"
+                       "kretprobe_trampoline:\n"
+                       "nop\n");
+}
+
+/*
+ * Called when the probe at kretprobe trampoline is hit
+ */
+int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+{
+        struct kretprobe_instance *ri = NULL;
+        struct hlist_head *head;
+        struct hlist_node *node, *tmp;
+       unsigned long orig_ret_address = 0;
+       unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
+
+        head = kretprobe_inst_table_head(current);
+
+       /*
+        * It is possible to have multiple instances associated with a given
+        * task either because an multiple functions in the call path
+        * have a return probe installed on them, and/or more then one return
+        * return probe was registered for a target function.
+        *
+        * We can handle this because:
+        *     - instances are always inserted at the head of the list
+        *     - when multiple return probes are registered for the same
+         *       function, the first instance's ret_addr will point to the
+        *       real return address, and all the rest will point to
+        *       kretprobe_trampoline
+        */
+       hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+                if (ri->task != current)
+                       /* another task is sharing our hash bucket */
+                        continue;
+
+               if (ri->rp && ri->rp->handler)
+                       ri->rp->handler(ri, regs);
+
+               orig_ret_address = (unsigned long)ri->ret_addr;
+               recycle_rp_inst(ri);
+
+               if (orig_ret_address != trampoline_address)
+                       /*
+                        * This is the real return address. Any other
+                        * instances associated with this task are for
+                        * other calls deeper on the call stack
+                        */
+                       break;
+       }
+
+       BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+       regs->nip = orig_ret_address;
+
+       unlock_kprobes();
+
+        /*
+         * By returning a non-zero value, we are telling
+         * kprobe_handler() that we have handled unlocking
+         * and re-enabling preemption.
+         */
+        return 1;
+}
+
 /*
  * Called after single-stepping.  p->addr is the address of the
  * instruction whose first byte has been replaced by the "breakpoint"
@@ -205,9 +311,10 @@ no_kprobe:
 static void resume_execution(struct kprobe *p, struct pt_regs *regs)
 {
        int ret;
+       unsigned int insn = *p->ainsn.insn;
 
        regs->nip = (unsigned long)p->addr;
-       ret = emulate_step(regs, p->ainsn.insn[0]);
+       ret = emulate_step(regs, insn);
        if (ret == 0)
                regs->nip = (unsigned long)p->addr + 4;
 }
@@ -331,3 +438,13 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
        memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs));
        return 1;
 }
+
+static struct kprobe trampoline_p = {
+       .addr = (kprobe_opcode_t *) &kretprobe_trampoline,
+       .pre_handler = trampoline_probe_handler
+};
+
+int __init arch_init(void)
+{
+       return register_kprobe(&trampoline_p);
+}
index 387923fcf9b06492a07b0b9e63c8748197de0e7b..02e96627fa6604999b3ac6aafd926fea185e2676 100644 (file)
@@ -34,6 +34,7 @@
 #include <asm/system.h>
 #include <asm/time.h>
 #include <asm/iSeries/ItExtVpdPanel.h>
+#include <asm/prom.h>
 
 #define MODULE_VERS "1.6"
 #define MODULE_NAME "lparcfg"
diff --git a/arch/ppc64/kernel/machine_kexec.c b/arch/ppc64/kernel/machine_kexec.c
new file mode 100644 (file)
index 0000000..fdb2fc6
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * machine_kexec.c - handle transition of Linux booting another kernel
+ *
+ * Copyright (C) 2004-2005, IBM Corp.
+ *
+ * Created by: Milton D Miller II
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+
+#include <linux/cpumask.h>
+#include <linux/kexec.h>
+#include <linux/smp.h>
+#include <linux/thread_info.h>
+#include <linux/errno.h>
+
+#include <asm/page.h>
+#include <asm/current.h>
+#include <asm/machdep.h>
+#include <asm/cacheflush.h>
+#include <asm/paca.h>
+#include <asm/mmu.h>
+#include <asm/sections.h>      /* _end */
+#include <asm/prom.h>
+
+#define HASH_GROUP_SIZE 0x80   /* size of each hash group, asm/mmu.h */
+
+/* Have this around till we move it into crash specific file */
+note_buf_t crash_notes[NR_CPUS];
+
+/* Dummy for now. Not sure if we need to have a crash shutdown in here
+ * and if what it will achieve. Letting it be now to compile the code
+ * in generic kexec environment
+ */
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+       /* do nothing right now */
+       /* smp_relase_cpus() if we want smp on panic kernel */
+       /* cpu_irq_down to isolate us until we are ready */
+}
+
+int machine_kexec_prepare(struct kimage *image)
+{
+       int i;
+       unsigned long begin, end;       /* limits of segment */
+       unsigned long low, high;        /* limits of blocked memory range */
+       struct device_node *node;
+       unsigned long *basep;
+       unsigned int *sizep;
+
+       if (!ppc_md.hpte_clear_all)
+               return -ENOENT;
+
+       /*
+        * Since we use the kernel fault handlers and paging code to
+        * handle the virtual mode, we must make sure no destination
+        * overlaps kernel static data or bss.
+        */
+       for (i = 0; i < image->nr_segments; i++)
+               if (image->segment[i].mem < __pa(_end))
+                       return -ETXTBSY;
+
+       /*
+        * For non-LPAR, we absolutely can not overwrite the mmu hash
+        * table, since we are still using the bolted entries in it to
+        * do the copy.  Check that here.
+        *
+        * It is safe if the end is below the start of the blocked
+        * region (end <= low), or if the beginning is after the
+        * end of the blocked region (begin >= high).  Use the
+        * boolean identity !(a || b)  === (!a && !b).
+        */
+       if (htab_address) {
+               low = __pa(htab_address);
+               high = low + (htab_hash_mask + 1) * HASH_GROUP_SIZE;
+
+               for (i = 0; i < image->nr_segments; i++) {
+                       begin = image->segment[i].mem;
+                       end = begin + image->segment[i].memsz;
+
+                       if ((begin < high) && (end > low))
+                               return -ETXTBSY;
+               }
+       }
+
+       /* We also should not overwrite the tce tables */
+       for (node = of_find_node_by_type(NULL, "pci"); node != NULL;
+                       node = of_find_node_by_type(node, "pci")) {
+               basep = (unsigned long *)get_property(node, "linux,tce-base",
+                                                       NULL);
+               sizep = (unsigned int *)get_property(node, "linux,tce-size",
+                                                       NULL);
+               if (basep == NULL || sizep == NULL)
+                       continue;
+
+               low = *basep;
+               high = low + (*sizep);
+
+               for (i = 0; i < image->nr_segments; i++) {
+                       begin = image->segment[i].mem;
+                       end = begin + image->segment[i].memsz;
+
+                       if ((begin < high) && (end > low))
+                               return -ETXTBSY;
+               }
+       }
+
+       return 0;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+       /* we do nothing in prepare that needs to be undone */
+}
+
+#define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE)
+
+static void copy_segments(unsigned long ind)
+{
+       unsigned long entry;
+       unsigned long *ptr;
+       void *dest;
+       void *addr;
+
+       /*
+        * We rely on kexec_load to create a lists that properly
+        * initializes these pointers before they are used.
+        * We will still crash if the list is wrong, but at least
+        * the compiler will be quiet.
+        */
+       ptr = NULL;
+       dest = NULL;
+
+       for (entry = ind; !(entry & IND_DONE); entry = *ptr++) {
+               addr = __va(entry & PAGE_MASK);
+
+               switch (entry & IND_FLAGS) {
+               case IND_DESTINATION:
+                       dest = addr;
+                       break;
+               case IND_INDIRECTION:
+                       ptr = addr;
+                       break;
+               case IND_SOURCE:
+                       copy_page(dest, addr);
+                       dest += PAGE_SIZE;
+               }
+       }
+}
+
+void kexec_copy_flush(struct kimage *image)
+{
+       long i, nr_segments = image->nr_segments;
+       struct  kexec_segment ranges[KEXEC_SEGMENT_MAX];
+
+       /* save the ranges on the stack to efficiently flush the icache */
+       memcpy(ranges, image->segment, sizeof(ranges));
+
+       /*
+        * After this call we may not use anything allocated in dynamic
+        * memory, including *image.
+        *
+        * Only globals and the stack are allowed.
+        */
+       copy_segments(image->head);
+
+       /*
+        * we need to clear the icache for all dest pages sometime,
+        * including ones that were in place on the original copy
+        */
+       for (i = 0; i < nr_segments; i++)
+               flush_icache_range(ranges[i].mem + KERNELBASE,
+                               ranges[i].mem + KERNELBASE +
+                               ranges[i].memsz);
+}
+
+#ifdef CONFIG_SMP
+
+/* FIXME: we should schedule this function to be called on all cpus based
+ * on calling the interrupts, but we would like to call it off irq level
+ * so that the interrupt controller is clean.
+ */
+void kexec_smp_down(void *arg)
+{
+       if (ppc_md.cpu_irq_down)
+               ppc_md.cpu_irq_down();
+
+       local_irq_disable();
+       kexec_smp_wait();
+       /* NOTREACHED */
+}
+
+static void kexec_prepare_cpus(void)
+{
+       int my_cpu, i, notified=-1;
+
+       smp_call_function(kexec_smp_down, NULL, 0, /* wait */0);
+       my_cpu = get_cpu();
+
+       /* check the others cpus are now down (via paca hw cpu id == -1) */
+       for (i=0; i < NR_CPUS; i++) {
+               if (i == my_cpu)
+                       continue;
+
+               while (paca[i].hw_cpu_id != -1) {
+                       if (!cpu_possible(i)) {
+                               printk("kexec: cpu %d hw_cpu_id %d is not"
+                                               " possible, ignoring\n",
+                                               i, paca[i].hw_cpu_id);
+                               break;
+                       }
+                       if (!cpu_online(i)) {
+                               /* Fixme: this can be spinning in
+                                * pSeries_secondary_wait with a paca
+                                * waiting for it to go online.
+                                */
+                               printk("kexec: cpu %d hw_cpu_id %d is not"
+                                               " online, ignoring\n",
+                                               i, paca[i].hw_cpu_id);
+                               break;
+                       }
+                       if (i != notified) {
+                               printk( "kexec: waiting for cpu %d (physical"
+                                               " %d) to go down\n",
+                                               i, paca[i].hw_cpu_id);
+                               notified = i;
+                       }
+               }
+       }
+
+       /* after we tell the others to go down */
+       if (ppc_md.cpu_irq_down)
+               ppc_md.cpu_irq_down();
+
+       put_cpu();
+
+       local_irq_disable();
+}
+
+#else /* ! SMP */
+
+static void kexec_prepare_cpus(void)
+{
+       /*
+        * move the secondarys to us so that we can copy
+        * the new kernel 0-0x100 safely
+        *
+        * do this if kexec in setup.c ?
+        */
+       smp_relase_cpus();
+       if (ppc_md.cpu_irq_down)
+               ppc_md.cpu_irq_down();
+       local_irq_disable();
+}
+
+#endif /* SMP */
+
+/*
+ * kexec thread structure and stack.
+ *
+ * We need to make sure that this is 16384-byte aligned due to the
+ * way process stacks are handled.  It also must be statically allocated
+ * or allocated as part of the kimage, because everything else may be
+ * overwritten when we copy the kexec image.  We piggyback on the
+ * "init_task" linker section here to statically allocate a stack.
+ *
+ * We could use a smaller stack if we don't care about anything using
+ * current, but that audit has not been performed.
+ */
+union thread_union kexec_stack
+       __attribute__((__section__(".data.init_task"))) = { };
+
+/* Our assembly helper, in kexec_stub.S */
+extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start,
+                                       void *image, void *control,
+                                       void (*clear_all)(void)) ATTRIB_NORET;
+
+/* too late to fail here */
+void machine_kexec(struct kimage *image)
+{
+
+       /* prepare control code if any */
+
+       /* shutdown other cpus into our wait loop and quiesce interrupts */
+       kexec_prepare_cpus();
+
+       /* switch to a staticly allocated stack.  Based on irq stack code.
+        * XXX: the task struct will likely be invalid once we do the copy!
+        */
+       kexec_stack.thread_info.task = current_thread_info()->task;
+       kexec_stack.thread_info.flags = 0;
+
+       /* Some things are best done in assembly.  Finding globals with
+        * a toc is easier in C, so pass in what we can.
+        */
+       kexec_sequence(&kexec_stack, image->start, image,
+                       page_address(image->control_code_page),
+                       ppc_md.hpte_clear_all);
+       /* NOTREACHED */
+}
index d98bebf7042faf990e63a8732c8dab4c91991033..ef4a338ebd01540ded3d27515de87e94c68dee81 100644 (file)
@@ -801,10 +801,8 @@ int mf_get_boot_rtc(struct rtc_time *tm)
                return rc;
        /* We need to poll here as we are not yet taking interrupts */
        while (rtc_data.busy) {
-               extern unsigned long lpevent_count;
-               struct ItLpQueue *lpq = get_paca()->lpqueue_ptr;
-               if (lpq && ItLpQueue_isLpIntPending(lpq))
-                       lpevent_count += ItLpQueue_process(lpq, NULL);
+               if (hvlpevent_is_pending())
+                       process_hvlpevents(NULL);
        }
        return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);
 }
index e3c73b3425dc016447d7e417f536d7a66fde39c4..f3dea0c5a88c201caefe0bc35f429e7e020885f3 100644 (file)
@@ -680,6 +680,177 @@ _GLOBAL(kernel_thread)
        ld      r30,-16(r1)
        blr
 
+/* kexec_wait(phys_cpu)
+ *
+ * wait for the flag to change, indicating this kernel is going away but
+ * the slave code for the next one is at addresses 0 to 100.
+ *
+ * This is used by all slaves.
+ *
+ * Physical (hardware) cpu id should be in r3.
+ */
+_GLOBAL(kexec_wait)
+       bl      1f
+1:     mflr    r5
+       addi    r5,r5,kexec_flag-1b
+
+99:    HMT_LOW
+#ifdef CONFIG_KEXEC            /* use no memory without kexec */
+       lwz     r4,0(r5)
+       cmpwi   0,r4,0
+       bnea    0x60
+#endif
+       b       99b
+
+/* this can be in text because we won't change it until we are
+ * running in real anyways
+ */
+kexec_flag:
+       .long   0
+
+
+#ifdef CONFIG_KEXEC
+
+/* kexec_smp_wait(void)
+ *
+ * call with interrupts off
+ * note: this is a terminal routine, it does not save lr
+ *
+ * get phys id from paca
+ * set paca id to -1 to say we got here
+ * switch to real mode
+ * join other cpus in kexec_wait(phys_id)
+ */
+_GLOBAL(kexec_smp_wait)
+       lhz     r3,PACAHWCPUID(r13)
+       li      r4,-1
+       sth     r4,PACAHWCPUID(r13)     /* let others know we left */
+       bl      real_mode
+       b       .kexec_wait
+
+/*
+ * switch to real mode (turn mmu off)
+ * we use the early kernel trick that the hardware ignores bits
+ * 0 and 1 (big endian) of the effective address in real mode
+ *
+ * don't overwrite r3 here, it is live for kexec_wait above.
+ */
+real_mode:     /* assume normal blr return */
+1:     li      r9,MSR_RI
+       li      r10,MSR_DR|MSR_IR
+       mflr    r11             /* return address to SRR0 */
+       mfmsr   r12
+       andc    r9,r12,r9
+       andc    r10,r12,r10
+
+       mtmsrd  r9,1
+       mtspr   SPRN_SRR1,r10
+       mtspr   SPRN_SRR0,r11
+       rfid
+
+
+/*
+ * kexec_sequence(newstack, start, image, control, clear_all())
+ *
+ * does the grungy work with stack switching and real mode switches
+ * also does simple calls to other code
+ */
+
+_GLOBAL(kexec_sequence)
+       mflr    r0
+       std     r0,16(r1)
+
+       /* switch stacks to newstack -- &kexec_stack.stack */
+       stdu    r1,THREAD_SIZE-112(r3)
+       mr      r1,r3
+
+       li      r0,0
+       std     r0,16(r1)
+
+       /* save regs for local vars on new stack.
+        * yes, we won't go back, but ...
+        */
+       std     r31,-8(r1)
+       std     r30,-16(r1)
+       std     r29,-24(r1)
+       std     r28,-32(r1)
+       std     r27,-40(r1)
+       std     r26,-48(r1)
+       std     r25,-56(r1)
+
+       stdu    r1,-112-64(r1)
+
+       /* save args into preserved regs */
+       mr      r31,r3                  /* newstack (both) */
+       mr      r30,r4                  /* start (real) */
+       mr      r29,r5                  /* image (virt) */
+       mr      r28,r6                  /* control, unused */
+       mr      r27,r7                  /* clear_all() fn desc */
+       mr      r26,r8                  /* spare */
+       lhz     r25,PACAHWCPUID(r13)    /* get our phys cpu from paca */
+
+       /* disable interrupts, we are overwriting kernel data next */
+       mfmsr   r3
+       rlwinm  r3,r3,0,17,15
+       mtmsrd  r3,1
+
+       /* copy dest pages, flush whole dest image */
+       mr      r3,r29
+       bl      .kexec_copy_flush       /* (image) */
+
+       /* turn off mmu */
+       bl      real_mode
+
+       /* clear out hardware hash page table and tlb */
+       ld      r5,0(r27)               /* deref function descriptor */
+       mtctr   r5
+       bctrl                           /* ppc_md.hash_clear_all(void); */
+
+/*
+ *   kexec image calling is:
+ *      the first 0x100 bytes of the entry point are copied to 0
+ *
+ *      all slaves branch to slave = 0x60 (absolute)
+ *              slave(phys_cpu_id);
+ *
+ *      master goes to start = entry point
+ *              start(phys_cpu_id, start, 0);
+ *
+ *
+ *   a wrapper is needed to call existing kernels, here is an approximate
+ *   description of one method:
+ *
+ * v2: (2.6.10)
+ *   start will be near the boot_block (maybe 0x100 bytes before it?)
+ *   it will have a 0x60, which will b to boot_block, where it will wait
+ *   and 0 will store phys into struct boot-block and load r3 from there,
+ *   copy kernel 0-0x100 and tell slaves to back down to 0x60 again
+ *
+ * v1: (2.6.9)
+ *    boot block will have all cpus scanning device tree to see if they
+ *    are the boot cpu ?????
+ *    other device tree differences (prop sizes, va vs pa, etc)...
+ */
+
+       /* copy  0x100 bytes starting at start to 0 */
+       li      r3,0
+       mr      r4,r30
+       li      r5,0x100
+       li      r6,0
+       bl      .copy_and_flush /* (dest, src, copy limit, start offset) */
+1:     /* assume normal blr return */
+
+       /* release other cpus to the new kernel secondary start at 0x60 */
+       mflr    r5
+       li      r6,1
+       stw     r6,kexec_flag-1b(5)
+       mr      r3,r25  # my phys cpu
+       mr      r4,r30  # start, aka phys mem offset
+       mtlr    4
+       li      r5,0
+       blr     /* image->start(physid, image->start, 0); */
+#endif /* CONFIG_KEXEC */
+
 /* Why isn't this a) automatic, b) written in 'C'? */  
        .balign 8
 _GLOBAL(sys_call_table32)
@@ -951,7 +1122,7 @@ _GLOBAL(sys_call_table32)
        .llong .compat_sys_mq_timedreceive /* 265 */
        .llong .compat_sys_mq_notify
        .llong .compat_sys_mq_getsetattr
-       .llong .sys_ni_syscall          /* 268 reserved for sys_kexec_load */
+       .llong .compat_sys_kexec_load
        .llong .sys32_add_key
        .llong .sys32_request_key
        .llong .compat_sys_keyctl
@@ -1227,7 +1398,7 @@ _GLOBAL(sys_call_table)
        .llong .sys_mq_timedreceive     /* 265 */
        .llong .sys_mq_notify
        .llong .sys_mq_getsetattr
-       .llong .sys_ni_syscall          /* 268 reserved for sys_kexec_load */
+       .llong .sys_kexec_load
        .llong .sys_add_key
        .llong .sys_request_key         /* 270 */
        .llong .sys_keyctl
index 593ea5b82afa0502e33478896aa65abfbe46f25c..e8fbab1df37f842cda79e59f8eb077228b93c6d9 100644 (file)
@@ -792,6 +792,35 @@ void mpic_setup_this_cpu(void)
 #endif /* CONFIG_SMP */
 }
 
+/*
+ * XXX: someone who knows mpic should check this.
+ * do we need to eoi the ipi here (see xics comments)?
+ * or can we reset the mpic in the new kernel?
+ */
+void mpic_teardown_this_cpu(void)
+{
+       struct mpic *mpic = mpic_primary;
+       unsigned long flags;
+       u32 msk = 1 << hard_smp_processor_id();
+       unsigned int i;
+
+       BUG_ON(mpic == NULL);
+
+       DBG("%s: teardown_this_cpu(%d)\n", mpic->name, hard_smp_processor_id());
+       spin_lock_irqsave(&mpic_lock, flags);
+
+       /* let the mpic know we don't want intrs.  */
+       for (i = 0; i < mpic->num_sources ; i++)
+               mpic_irq_write(i, MPIC_IRQ_DESTINATION,
+                       mpic_irq_read(i, MPIC_IRQ_DESTINATION) & ~msk);
+
+       /* Set current processor priority to max */
+       mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf);
+
+       spin_unlock_irqrestore(&mpic_lock, flags);
+}
+
+
 void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask)
 {
        struct mpic *mpic = mpic_primary;
index 63e177143eac2f05a839e6d69e0e0f892fc093db..99fbbc9a084c46bec6e37789aca5987233177dd0 100644 (file)
@@ -255,6 +255,9 @@ extern unsigned int mpic_irq_get_priority(unsigned int irq);
 /* Setup a non-boot CPU */
 extern void mpic_setup_this_cpu(void);
 
+/* Clean up for kexec (or cpu offline or ...) */
+extern void mpic_teardown_this_cpu(void);
+
 /* Request IPIs on primary mpic */
 extern void mpic_request_ipis(void);
 
index 4e71781a44143e2a4ff65adbea2513c2c559dfc2..4fb1a9f5060deb66b78867755ba31c320afd71b8 100644 (file)
@@ -338,9 +338,8 @@ static int nvram_remove_os_partition(void)
  */
 static int nvram_create_os_partition(void)
 {
-       struct list_head * p;
-       struct nvram_partition *part = NULL;
-       struct nvram_partition *new_part = NULL;
+       struct nvram_partition *part;
+       struct nvram_partition *new_part;
        struct nvram_partition *free_part = NULL;
        int seq_init[2] = { 0, 0 };
        loff_t tmp_index;
@@ -349,8 +348,7 @@ static int nvram_create_os_partition(void)
        
        /* Find a free partition that will give us the maximum needed size 
           If can't find one that will give us the minimum size needed */
-       list_for_each(p, &nvram_part->partition) {
-               part = list_entry(p, struct nvram_partition, partition);
+       list_for_each_entry(part, &nvram_part->partition, partition) {
                if (part->header.signature != NVRAM_SIG_FREE)
                        continue;
 
index f2b41243342c483a63088c5d5f8228744b09c2ef..44d9af72d225038da83e43d5f8dab15d4bb055eb 100644 (file)
@@ -187,14 +187,16 @@ static void __init pSeries_setup_arch(void)
 {
        /* Fixup ppc_md depending on the type of interrupt controller */
        if (ppc64_interrupt_controller == IC_OPEN_PIC) {
-               ppc_md.init_IRQ       = pSeries_init_mpic; 
+               ppc_md.init_IRQ       = pSeries_init_mpic;
                ppc_md.get_irq        = mpic_get_irq;
+               ppc_md.cpu_irq_down   = mpic_teardown_this_cpu;
                /* Allocate the mpic now, so that find_and_init_phbs() can
                 * fill the ISUs */
                pSeries_setup_mpic();
        } else {
                ppc_md.init_IRQ       = xics_init_IRQ;
                ppc_md.get_irq        = xics_get_irq;
+               ppc_md.cpu_irq_down   = xics_teardown_cpu;
        }
 
 #ifdef CONFIG_SMP
index 30154140f7e2403662935f1ee00c192f34ac3e6f..62c55a123560cf6850dc1c10c5a171c953a7290c 100644 (file)
@@ -93,10 +93,13 @@ static int query_cpu_stopped(unsigned int pcpu)
 
 int pSeries_cpu_disable(void)
 {
+       int cpu = smp_processor_id();
+
+       cpu_clear(cpu, cpu_online_map);
        systemcfg->processorCount--;
 
        /*fix boot_cpuid here*/
-       if (smp_processor_id() == boot_cpuid)
+       if (cpu == boot_cpuid)
                boot_cpuid = any_online_cpu(cpu_online_map);
 
        /* FIXME: abstract this to not be platform specific later on */
index a3e0975c26c1a9938fc30dee663a428801866e38..6316188737b6eea0861e10cfa0041997456061c5 100644 (file)
@@ -42,21 +42,7 @@ extern unsigned long __toc_start;
  * processors.  The processor VPD array needs one entry per physical
  * processor (not thread).
  */
-#ifdef CONFIG_PPC_ISERIES
-#define EXTRA_INITS(number, lpq)                                           \
-       .lppaca_ptr = &paca[number].lppaca,                                 \
-       .lpqueue_ptr = (lpq),           /* &xItLpQueue, */                  \
-       .reg_save_ptr = &paca[number].reg_save,                             \
-       .reg_save = {                                                       \
-               .xDesc = 0xd397d9e2,    /* "LpRS" */                        \
-               .xSize = sizeof(struct ItLpRegSave)                         \
-       },
-#else
-#define EXTRA_INITS(number, lpq)
-#endif
-
-#define PACAINITDATA(number,start,lpq,asrr,asrv)                           \
-{                                                                          \
+#define PACA_INIT_COMMON(number, start, asrr, asrv)                        \
        .lock_token = 0x8000,                                               \
        .paca_index = (number),         /* Paca Index */                    \
        .default_decr = 0x00ff0000,     /* Initial Decr */                  \
@@ -74,147 +60,79 @@ extern unsigned long __toc_start;
                .end_of_quantum = 0xfffffffffffffffful,                     \
                .slb_count = 64,                                            \
        },                                                                  \
-       EXTRA_INITS((number), (lpq))                                        \
-}
 
-struct paca_struct paca[] = {
 #ifdef CONFIG_PPC_ISERIES
-       PACAINITDATA( 0, 1, &xItLpQueue, 0, STAB0_VIRT_ADDR),
+#define PACA_INIT_ISERIES(number)                                          \
+       .lppaca_ptr = &paca[number].lppaca,                                 \
+       .reg_save_ptr = &paca[number].reg_save,                             \
+       .reg_save = {                                                       \
+               .xDesc = 0xd397d9e2,    /* "LpRS" */                        \
+               .xSize = sizeof(struct ItLpRegSave)                         \
+       }
+
+#define PACA_INIT(number)                                                  \
+{                                                                          \
+       PACA_INIT_COMMON(number, 0, 0, 0)                                   \
+       PACA_INIT_ISERIES(number)                                           \
+}
+
+#define BOOTCPU_PACA_INIT(number)                                          \
+{                                                                          \
+       PACA_INIT_COMMON(number, 1, 0, STAB0_VIRT_ADDR)                     \
+       PACA_INIT_ISERIES(number)                                           \
+}
+
 #else
-       PACAINITDATA( 0, 1, NULL, STAB0_PHYS_ADDR, STAB0_VIRT_ADDR),
+#define PACA_INIT(number)                                                  \
+{                                                                          \
+       PACA_INIT_COMMON(number, 0, 0, 0)                                   \
+}
+
+#define BOOTCPU_PACA_INIT(number)                                          \
+{                                                                          \
+       PACA_INIT_COMMON(number, 1, STAB0_PHYS_ADDR, STAB0_VIRT_ADDR)       \
+}
 #endif
+
+struct paca_struct paca[] = {
+       BOOTCPU_PACA_INIT(0),
 #if NR_CPUS > 1
-       PACAINITDATA( 1, 0, NULL, 0, 0),
-       PACAINITDATA( 2, 0, NULL, 0, 0),
-       PACAINITDATA( 3, 0, NULL, 0, 0),
+       PACA_INIT(  1), PACA_INIT(  2), PACA_INIT(  3),
 #if NR_CPUS > 4
-       PACAINITDATA( 4, 0, NULL, 0, 0),
-       PACAINITDATA( 5, 0, NULL, 0, 0),
-       PACAINITDATA( 6, 0, NULL, 0, 0),
-       PACAINITDATA( 7, 0, NULL, 0, 0),
+       PACA_INIT(  4), PACA_INIT(  5), PACA_INIT(  6), PACA_INIT(  7),
 #if NR_CPUS > 8
-       PACAINITDATA( 8, 0, NULL, 0, 0),
-       PACAINITDATA( 9, 0, NULL, 0, 0),
-       PACAINITDATA(10, 0, NULL, 0, 0),
-       PACAINITDATA(11, 0, NULL, 0, 0),
-       PACAINITDATA(12, 0, NULL, 0, 0),
-       PACAINITDATA(13, 0, NULL, 0, 0),
-       PACAINITDATA(14, 0, NULL, 0, 0),
-       PACAINITDATA(15, 0, NULL, 0, 0),
-       PACAINITDATA(16, 0, NULL, 0, 0),
-       PACAINITDATA(17, 0, NULL, 0, 0),
-       PACAINITDATA(18, 0, NULL, 0, 0),
-       PACAINITDATA(19, 0, NULL, 0, 0),
-       PACAINITDATA(20, 0, NULL, 0, 0),
-       PACAINITDATA(21, 0, NULL, 0, 0),
-       PACAINITDATA(22, 0, NULL, 0, 0),
-       PACAINITDATA(23, 0, NULL, 0, 0),
-       PACAINITDATA(24, 0, NULL, 0, 0),
-       PACAINITDATA(25, 0, NULL, 0, 0),
-       PACAINITDATA(26, 0, NULL, 0, 0),
-       PACAINITDATA(27, 0, NULL, 0, 0),
-       PACAINITDATA(28, 0, NULL, 0, 0),
-       PACAINITDATA(29, 0, NULL, 0, 0),
-       PACAINITDATA(30, 0, NULL, 0, 0),
-       PACAINITDATA(31, 0, NULL, 0, 0),
+       PACA_INIT(  8), PACA_INIT(  9), PACA_INIT( 10), PACA_INIT( 11),
+       PACA_INIT( 12), PACA_INIT( 13), PACA_INIT( 14), PACA_INIT( 15),
+       PACA_INIT( 16), PACA_INIT( 17), PACA_INIT( 18), PACA_INIT( 19),
+       PACA_INIT( 20), PACA_INIT( 21), PACA_INIT( 22), PACA_INIT( 23),
+       PACA_INIT( 24), PACA_INIT( 25), PACA_INIT( 26), PACA_INIT( 27),
+       PACA_INIT( 28), PACA_INIT( 29), PACA_INIT( 30), PACA_INIT( 31),
 #if NR_CPUS > 32
-       PACAINITDATA(32, 0, NULL, 0, 0),
-       PACAINITDATA(33, 0, NULL, 0, 0),
-       PACAINITDATA(34, 0, NULL, 0, 0),
-       PACAINITDATA(35, 0, NULL, 0, 0),
-       PACAINITDATA(36, 0, NULL, 0, 0),
-       PACAINITDATA(37, 0, NULL, 0, 0),
-       PACAINITDATA(38, 0, NULL, 0, 0),
-       PACAINITDATA(39, 0, NULL, 0, 0),
-       PACAINITDATA(40, 0, NULL, 0, 0),
-       PACAINITDATA(41, 0, NULL, 0, 0),
-       PACAINITDATA(42, 0, NULL, 0, 0),
-       PACAINITDATA(43, 0, NULL, 0, 0),
-       PACAINITDATA(44, 0, NULL, 0, 0),
-       PACAINITDATA(45, 0, NULL, 0, 0),
-       PACAINITDATA(46, 0, NULL, 0, 0),
-       PACAINITDATA(47, 0, NULL, 0, 0),
-       PACAINITDATA(48, 0, NULL, 0, 0),
-       PACAINITDATA(49, 0, NULL, 0, 0),
-       PACAINITDATA(50, 0, NULL, 0, 0),
-       PACAINITDATA(51, 0, NULL, 0, 0),
-       PACAINITDATA(52, 0, NULL, 0, 0),
-       PACAINITDATA(53, 0, NULL, 0, 0),
-       PACAINITDATA(54, 0, NULL, 0, 0),
-       PACAINITDATA(55, 0, NULL, 0, 0),
-       PACAINITDATA(56, 0, NULL, 0, 0),
-       PACAINITDATA(57, 0, NULL, 0, 0),
-       PACAINITDATA(58, 0, NULL, 0, 0),
-       PACAINITDATA(59, 0, NULL, 0, 0),
-       PACAINITDATA(60, 0, NULL, 0, 0),
-       PACAINITDATA(61, 0, NULL, 0, 0),
-       PACAINITDATA(62, 0, NULL, 0, 0),
-       PACAINITDATA(63, 0, NULL, 0, 0),
+       PACA_INIT( 32), PACA_INIT( 33), PACA_INIT( 34), PACA_INIT( 35),
+       PACA_INIT( 36), PACA_INIT( 37), PACA_INIT( 38), PACA_INIT( 39),
+       PACA_INIT( 40), PACA_INIT( 41), PACA_INIT( 42), PACA_INIT( 43),
+       PACA_INIT( 44), PACA_INIT( 45), PACA_INIT( 46), PACA_INIT( 47),
+       PACA_INIT( 48), PACA_INIT( 49), PACA_INIT( 50), PACA_INIT( 51),
+       PACA_INIT( 52), PACA_INIT( 53), PACA_INIT( 54), PACA_INIT( 55),
+       PACA_INIT( 56), PACA_INIT( 57), PACA_INIT( 58), PACA_INIT( 59),
+       PACA_INIT( 60), PACA_INIT( 61), PACA_INIT( 62), PACA_INIT( 63),
 #if NR_CPUS > 64
-       PACAINITDATA(64, 0, NULL, 0, 0),
-       PACAINITDATA(65, 0, NULL, 0, 0),
-       PACAINITDATA(66, 0, NULL, 0, 0),
-       PACAINITDATA(67, 0, NULL, 0, 0),
-       PACAINITDATA(68, 0, NULL, 0, 0),
-       PACAINITDATA(69, 0, NULL, 0, 0),
-       PACAINITDATA(70, 0, NULL, 0, 0),
-       PACAINITDATA(71, 0, NULL, 0, 0),
-       PACAINITDATA(72, 0, NULL, 0, 0),
-       PACAINITDATA(73, 0, NULL, 0, 0),
-       PACAINITDATA(74, 0, NULL, 0, 0),
-       PACAINITDATA(75, 0, NULL, 0, 0),
-       PACAINITDATA(76, 0, NULL, 0, 0),
-       PACAINITDATA(77, 0, NULL, 0, 0),
-       PACAINITDATA(78, 0, NULL, 0, 0),
-       PACAINITDATA(79, 0, NULL, 0, 0),
-       PACAINITDATA(80, 0, NULL, 0, 0),
-       PACAINITDATA(81, 0, NULL, 0, 0),
-       PACAINITDATA(82, 0, NULL, 0, 0),
-       PACAINITDATA(83, 0, NULL, 0, 0),
-       PACAINITDATA(84, 0, NULL, 0, 0),
-       PACAINITDATA(85, 0, NULL, 0, 0),
-       PACAINITDATA(86, 0, NULL, 0, 0),
-       PACAINITDATA(87, 0, NULL, 0, 0),
-       PACAINITDATA(88, 0, NULL, 0, 0),
-       PACAINITDATA(89, 0, NULL, 0, 0),
-       PACAINITDATA(90, 0, NULL, 0, 0),
-       PACAINITDATA(91, 0, NULL, 0, 0),
-       PACAINITDATA(92, 0, NULL, 0, 0),
-       PACAINITDATA(93, 0, NULL, 0, 0),
-       PACAINITDATA(94, 0, NULL, 0, 0),
-       PACAINITDATA(95, 0, NULL, 0, 0),
-       PACAINITDATA(96, 0, NULL, 0, 0),
-       PACAINITDATA(97, 0, NULL, 0, 0),
-       PACAINITDATA(98, 0, NULL, 0, 0),
-       PACAINITDATA(99, 0, NULL, 0, 0),
-       PACAINITDATA(100, 0, NULL, 0, 0),
-       PACAINITDATA(101, 0, NULL, 0, 0),
-       PACAINITDATA(102, 0, NULL, 0, 0),
-       PACAINITDATA(103, 0, NULL, 0, 0),
-       PACAINITDATA(104, 0, NULL, 0, 0),
-       PACAINITDATA(105, 0, NULL, 0, 0),
-       PACAINITDATA(106, 0, NULL, 0, 0),
-       PACAINITDATA(107, 0, NULL, 0, 0),
-       PACAINITDATA(108, 0, NULL, 0, 0),
-       PACAINITDATA(109, 0, NULL, 0, 0),
-       PACAINITDATA(110, 0, NULL, 0, 0),
-       PACAINITDATA(111, 0, NULL, 0, 0),
-       PACAINITDATA(112, 0, NULL, 0, 0),
-       PACAINITDATA(113, 0, NULL, 0, 0),
-       PACAINITDATA(114, 0, NULL, 0, 0),
-       PACAINITDATA(115, 0, NULL, 0, 0),
-       PACAINITDATA(116, 0, NULL, 0, 0),
-       PACAINITDATA(117, 0, NULL, 0, 0),
-       PACAINITDATA(118, 0, NULL, 0, 0),
-       PACAINITDATA(119, 0, NULL, 0, 0),
-       PACAINITDATA(120, 0, NULL, 0, 0),
-       PACAINITDATA(121, 0, NULL, 0, 0),
-       PACAINITDATA(122, 0, NULL, 0, 0),
-       PACAINITDATA(123, 0, NULL, 0, 0),
-       PACAINITDATA(124, 0, NULL, 0, 0),
-       PACAINITDATA(125, 0, NULL, 0, 0),
-       PACAINITDATA(126, 0, NULL, 0, 0),
-       PACAINITDATA(127, 0, NULL, 0, 0),
+       PACA_INIT( 64), PACA_INIT( 65), PACA_INIT( 66), PACA_INIT( 67),
+       PACA_INIT( 68), PACA_INIT( 69), PACA_INIT( 70), PACA_INIT( 71),
+       PACA_INIT( 72), PACA_INIT( 73), PACA_INIT( 74), PACA_INIT( 75),
+       PACA_INIT( 76), PACA_INIT( 77), PACA_INIT( 78), PACA_INIT( 79),
+       PACA_INIT( 80), PACA_INIT( 81), PACA_INIT( 82), PACA_INIT( 83),
+       PACA_INIT( 84), PACA_INIT( 85), PACA_INIT( 86), PACA_INIT( 87),
+       PACA_INIT( 88), PACA_INIT( 89), PACA_INIT( 90), PACA_INIT( 91),
+       PACA_INIT( 92), PACA_INIT( 93), PACA_INIT( 94), PACA_INIT( 95),
+       PACA_INIT( 96), PACA_INIT( 97), PACA_INIT( 98), PACA_INIT( 99),
+       PACA_INIT(100), PACA_INIT(101), PACA_INIT(102), PACA_INIT(103),
+       PACA_INIT(104), PACA_INIT(105), PACA_INIT(106), PACA_INIT(107),
+       PACA_INIT(108), PACA_INIT(109), PACA_INIT(110), PACA_INIT(111),
+       PACA_INIT(112), PACA_INIT(113), PACA_INIT(114), PACA_INIT(115),
+       PACA_INIT(116), PACA_INIT(117), PACA_INIT(118), PACA_INIT(119),
+       PACA_INIT(120), PACA_INIT(121), PACA_INIT(122), PACA_INIT(123),
+       PACA_INIT(124), PACA_INIT(125), PACA_INIT(126), PACA_INIT(127),
 #endif
 #endif
 #endif
index 580676f87d23a11a33a85f0b0f21417c52803d84..ae6f579d3fa0f0f41cffa6e5c78c439ac430723b 100644 (file)
@@ -351,7 +351,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
                *offset += hose->pci_mem_offset;
                res_bit = IORESOURCE_MEM;
        } else {
-               io_offset = (unsigned long)hose->io_base_virt;
+               io_offset = (unsigned long)hose->io_base_virt - pci_io_base;
                *offset += io_offset;
                res_bit = IORESOURCE_IO;
        }
@@ -378,7 +378,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
 
                /* found it! construct the final physical address */
                if (mmap_state == pci_mmap_io)
-                       *offset += hose->io_base_phys - io_offset;
+                       *offset += hose->io_base_phys - io_offset;
                return rp;
        }
 
@@ -944,4 +944,22 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
 }
 EXPORT_SYMBOL(pci_read_irq_line);
 
+void pci_resource_to_user(const struct pci_dev *dev, int bar,
+                         const struct resource *rsrc,
+                         u64 *start, u64 *end)
+{
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+       unsigned long offset = 0;
+
+       if (hose == NULL)
+               return;
+
+       if (rsrc->flags & IORESOURCE_IO)
+               offset = pci_io_base - (unsigned long)hose->io_base_virt +
+                       hose->io_base_phys;
+
+       *start = rsrc->start + offset;
+       *end = rsrc->end + offset;
+}
+
 #endif /* CONFIG_PPC_MULTIPLATFORM */
index b230a63fe4c802e3fbeb5bb7e77910b1ef6edd1d..705742f4eec6074531f469fb5885a410d173b14c 100644 (file)
@@ -75,6 +75,7 @@ EXPORT_SYMBOL(giveup_fpu);
 EXPORT_SYMBOL(giveup_altivec);
 #endif
 EXPORT_SYMBOL(__flush_icache_range);
+EXPORT_SYMBOL(flush_dcache_range);
 
 #ifdef CONFIG_SMP
 #ifdef CONFIG_PPC_ISERIES
index aba89554d89df912f268e465fab3f74f5cb7e90f..f7cae05e40fb2cbfcfb255998ec938c6eee72676 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/kallsyms.h>
 #include <linux/interrupt.h>
 #include <linux/utsname.h>
+#include <linux/kprobes.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -307,6 +308,8 @@ void show_regs(struct pt_regs * regs)
 
 void exit_thread(void)
 {
+       kprobe_flush_task(current);
+
 #ifndef CONFIG_SMP
        if (last_task_used_math == current)
                last_task_used_math = NULL;
@@ -321,6 +324,7 @@ void flush_thread(void)
 {
        struct thread_info *t = current_thread_info();
 
+       kprobe_flush_task(current);
        if (t->flags & _TIF_ABI_PENDING)
                t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT);
 
index 9f8c6087ae568aaa9a7a2dd999ce65d3ea9828b9..2993f108d96d309f6f333bb47b38c86373551239 100644 (file)
@@ -305,6 +305,8 @@ static void do_syscall_trace(void)
 
 void do_syscall_trace_enter(struct pt_regs *regs)
 {
+       secure_computing(regs->gpr[0]);
+
        if (test_thread_flag(TIF_SYSCALL_TRACE)
            && (current->ptrace & PT_PTRACED))
                do_syscall_trace();
@@ -320,8 +322,6 @@ void do_syscall_trace_enter(struct pt_regs *regs)
 
 void do_syscall_trace_leave(struct pt_regs *regs)
 {
-       secure_computing(regs->gpr[0]);
-
        if (unlikely(current->audit_context))
                audit_syscall_exit(current, 
                                   (regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
index 0a47a5ef428dfaae3d1aee77f520b7c3470abc39..d5e4866e9ac2e22599a5abf7979b99616071c65c 100644 (file)
@@ -677,11 +677,16 @@ void __init setup_system(void)
        DBG(" <- setup_system()\n");
 }
 
-
-void machine_restart(char *cmd)
+/* also used by kexec */
+void machine_shutdown(void)
 {
        if (ppc_md.nvram_sync)
                ppc_md.nvram_sync();
+}
+
+void machine_restart(char *cmd)
+{
+       machine_shutdown();
        ppc_md.restart(cmd);
 #ifdef CONFIG_SMP
        smp_send_stop();
@@ -690,13 +695,11 @@ void machine_restart(char *cmd)
        local_irq_disable();
        while (1) ;
 }
-
 EXPORT_SYMBOL(machine_restart);
-  
+
 void machine_power_off(void)
 {
-       if (ppc_md.nvram_sync)
-               ppc_md.nvram_sync();
+       machine_shutdown();
        ppc_md.power_off();
 #ifdef CONFIG_SMP
        smp_send_stop();
@@ -705,13 +708,11 @@ void machine_power_off(void)
        local_irq_disable();
        while (1) ;
 }
-
 EXPORT_SYMBOL(machine_power_off);
-  
+
 void machine_halt(void)
 {
-       if (ppc_md.nvram_sync)
-               ppc_md.nvram_sync();
+       machine_shutdown();
        ppc_md.halt();
 #ifdef CONFIG_SMP
        smp_send_stop();
@@ -720,7 +721,6 @@ void machine_halt(void)
        local_irq_disable();
        while (1) ;
 }
-
 EXPORT_SYMBOL(machine_halt);
 
 static int ppc64_panic_event(struct notifier_block *this,
index c8fa6569b2fd789fc3476a3c5ab86c3bf6b3c203..2f704a2cafb1a4f5dc9ece21349c6837b0dc8f72 100644 (file)
@@ -400,7 +400,12 @@ static int __init topology_init(void)
                struct cpu *c = &per_cpu(cpu_devices, cpu);
 
 #ifdef CONFIG_NUMA
-               parent = &node_devices[cpu_to_node(cpu)];
+               /* The node to which a cpu belongs can't be known
+                * until the cpu is made present.
+                */
+               parent = NULL;
+               if (cpu_present(cpu))
+                       parent = &node_devices[cpu_to_node(cpu)];
 #endif
                /*
                 * For now, we just see if the system supports making
index 2348a75e050dc4fe523105b049fd80f44f35d428..909462e1adeaf7cc1bab5ec9b766315d2ee63ec8 100644 (file)
@@ -91,6 +91,7 @@ unsigned long tb_to_xs;
 unsigned      tb_to_us;
 unsigned long processor_freq;
 DEFINE_SPINLOCK(rtc_lock);
+EXPORT_SYMBOL_GPL(rtc_lock);
 
 unsigned long tb_to_ns_scale;
 unsigned long tb_to_ns_shift;
@@ -98,7 +99,6 @@ unsigned long tb_to_ns_shift;
 struct gettimeofday_struct do_gtod;
 
 extern unsigned long wall_jiffies;
-extern unsigned long lpevent_count;
 extern int smp_tb_synchronized;
 
 extern struct timezone sys_tz;
@@ -366,11 +366,8 @@ int timer_interrupt(struct pt_regs * regs)
        set_dec(next_dec);
 
 #ifdef CONFIG_PPC_ISERIES
-       {
-               struct ItLpQueue *lpq = lpaca->lpqueue_ptr;
-               if (lpq && ItLpQueue_isLpIntPending(lpq))
-                       lpevent_count += ItLpQueue_process(lpq, regs);
-       }
+       if (hvlpevent_is_pending())
+               process_hvlpevents(regs);
 #endif
 
 /* collect purr register values often, for accurate calculations */
index 879f39b90a337df2b63a88d5399fcf4971da36e7..677c4450984a85c3b53161f7409895309f907ce8 100644 (file)
@@ -647,6 +647,31 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
        }
 }
 
+void xics_teardown_cpu(void)
+{
+       int cpu = smp_processor_id();
+       int status;
+
+       ops->cppr_info(cpu, 0x00);
+       iosync();
+
+       /*
+        * we need to EOI the IPI if we got here from kexec down IPI
+        *
+        * xics doesn't care if we duplicate an EOI as long as we
+        * don't EOI and raise priority.
+        *
+        * probably need to check all the other interrupts too
+        * should we be flagging idle loop instead?
+        * or creating some task to be scheduled?
+        */
+       ops->xirr_info_set(cpu, XICS_IPI);
+
+       status = rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE,
+               (1UL << interrupt_server_size) - 1 - default_distrib_server, 0);
+       WARN_ON(status != 0);
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 
 /* Interrupts are disabled. */
index 52b6b9305341e3774b94bba7bca216cbd6ce3bd0..4fec05817d660bcb95db16380745f4f209bfd62e 100644 (file)
@@ -304,6 +304,50 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va,
        local_irq_restore(flags);
 }
 
+/*
+ * clear all mappings on kexec.  All cpus are in real mode (or they will
+ * be when they isi), and we are the only one left.  We rely on our kernel
+ * mapping being 0xC0's and the hardware ignoring those two real bits.
+ *
+ * TODO: add batching support when enabled.  remember, no dynamic memory here,
+ * athough there is the control page available...
+ */
+static void native_hpte_clear(void)
+{
+       unsigned long slot, slots, flags;
+       HPTE *hptep = htab_address;
+       Hpte_dword0 dw0;
+       unsigned long pteg_count;
+
+       pteg_count = htab_hash_mask + 1;
+
+       local_irq_save(flags);
+
+       /* we take the tlbie lock and hold it.  Some hardware will
+        * deadlock if we try to tlbie from two processors at once.
+        */
+       spin_lock(&native_tlbie_lock);
+
+       slots = pteg_count * HPTES_PER_GROUP;
+
+       for (slot = 0; slot < slots; slot++, hptep++) {
+               /*
+                * we could lock the pte here, but we are the only cpu
+                * running,  right?  and for crash dump, we probably
+                * don't want to wait for a maybe bad cpu.
+                */
+               dw0 = hptep->dw0.dw0;
+
+               if (dw0.v) {
+                       hptep->dw0.dword0 = 0;
+                       tlbie(slot2va(dw0.avpn, dw0.l, dw0.h, slot), dw0.l);
+               }
+       }
+
+       spin_unlock(&native_tlbie_lock);
+       local_irq_restore(flags);
+}
+
 static void native_flush_hash_range(unsigned long context,
                                    unsigned long number, int local)
 {
@@ -415,7 +459,8 @@ void hpte_init_native(void)
        ppc_md.hpte_updatepp    = native_hpte_updatepp;
        ppc_md.hpte_updateboltedpp = native_hpte_updateboltedpp;
        ppc_md.hpte_insert      = native_hpte_insert;
-       ppc_md.hpte_remove      = native_hpte_remove;
+       ppc_md.hpte_remove      = native_hpte_remove;
+       ppc_md.hpte_clear_all   = native_hpte_clear;
        if (tlb_batching_enabled())
                ppc_md.flush_hash_range = native_flush_hash_range;
        htab_finish_init();
index 32696c1d92806c7cac9eebaa20220aacd6793993..6600ee87f896938bd7e71f30bc4e43c69e148c2a 100644 (file)
@@ -455,6 +455,14 @@ config NO_IDLE_HZ_INIT
          The HZ timer is switched off in idle by default. That means the
          HZ timer is already disabled at boot time.
 
+config KEXEC
+       bool "kexec system call (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       help
+         kexec is a system call that implements the ability to shutdown your
+         current kernel, and to start another kernel.  It is like a reboot
+         but is independent of hardware/microcode support.
+
 endmenu
 
 config PCMCIA
index 07fd0414a4bf5eebf7e7d7259fbadd16a68ecfbb..89850b2c27ea0e94bd7a2daa25df18816ddc0587 100644 (file)
@@ -245,6 +245,7 @@ CONFIG_S390_TAPE_BLOCK=y
 #
 CONFIG_S390_TAPE_34XX=m
 # CONFIG_VMLOGRDR is not set
+# CONFIG_VMCP is not set
 # CONFIG_MONREADER is not set
 # CONFIG_DCSS_SHM is not set
 
index b41e0e199a7cf8aa9d5b8f221b72b4f58b27b4bc..ab1e49d2e5185dad2116aa8ff8afacf5e6f2cf2e 100644 (file)
@@ -25,6 +25,16 @@ obj-$(CONFIG_ARCH_S390X)     += entry64.o reipl64.o
 
 obj-$(CONFIG_VIRT_TIMER)       += vtime.o
 
+# Kexec part
+S390_KEXEC_OBJS := machine_kexec.o crash.o
+ifeq ($(CONFIG_ARCH_S390X),y)
+S390_KEXEC_OBJS += relocate_kernel64.o
+else
+S390_KEXEC_OBJS += relocate_kernel.o
+endif
+obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS)
+
+
 #
 # This is just to get the dependencies...
 #
index 7a607b1d03808f6abdb36e47de42d6c5ef91e2d8..bf529739c8ab6a53709b4bf5507ae7c4ca7410f0 100644 (file)
@@ -1441,3 +1441,11 @@ compat_sys_waitid_wrapper:
        lgfr    %r5,%r5                 # int
        llgtr   %r6,%r6                 # struct rusage_emu31 *
        jg      compat_sys_waitid
+
+       .globl  compat_sys_kexec_load_wrapper
+compat_sys_kexec_load_wrapper:
+       llgfr   %r2,%r2                 # unsigned long
+       llgfr   %r3,%r3                 # unsigned long
+       llgtr   %r4,%r4                 # struct kexec_segment *
+       llgfr   %r5,%r5                 # unsigned long
+       jg      compat_sys_kexec_load
index 44df8dc07c5923080626fe1b9603fe557d54fbc4..20062145e84e29bc1dcddcc258b7a29276991f84 100644 (file)
@@ -2,7 +2,7 @@
  *  arch/s390/kernel/cpcmd.c
  *
  *  S390 version
- *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright (C) 1999,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  *               Christian Borntraeger (cborntra@de.ibm.com),
  */
 #include <asm/system.h>
 
 static DEFINE_SPINLOCK(cpcmd_lock);
-static char cpcmd_buf[240];
+static char cpcmd_buf[241];
 
 /*
  * the caller of __cpcmd has to ensure that the response buffer is below 2 GB
  */
-void __cpcmd(char *cmd, char *response, int rlen)
+int  __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
 {
        const int mask = 0x40000000L;
        unsigned long flags;
+       int return_code;
+       int return_len;
        int cmdlen;
 
        spin_lock_irqsave(&cpcmd_lock, flags);
        cmdlen = strlen(cmd);
        BUG_ON(cmdlen > 240);
-       strcpy(cpcmd_buf, cmd);
+       memcpy(cpcmd_buf, cmd, cmdlen);
        ASCEBC(cpcmd_buf, cmdlen);
 
        if (response != NULL && rlen > 0) {
                memset(response, 0, rlen);
 #ifndef CONFIG_ARCH_S390X
-               asm volatile ("LRA   2,0(%0)\n\t"
-                              "LR    4,%1\n\t"
-                              "O     4,%4\n\t"
-                              "LRA   3,0(%2)\n\t"
-                              "LR    5,%3\n\t"
-                              ".long 0x83240008 # Diagnose X'08'\n\t"
-                              : /* no output */
-                              : "a" (cpcmd_buf), "d" (cmdlen),
-                                "a" (response), "d" (rlen), "m" (mask)
-                              : "cc", "2", "3", "4", "5" );
+               asm volatile (  "lra    2,0(%2)\n"
+                               "lr     4,%3\n"
+                               "o      4,%6\n"
+                               "lra    3,0(%4)\n"
+                               "lr     5,%5\n"
+                               "diag   2,4,0x8\n"
+                               "brc    8, .Litfits\n"
+                               "ar     5, %5\n"
+                               ".Litfits: \n"
+                               "lr     %0,4\n"
+                               "lr     %1,5\n"
+                               : "=d" (return_code), "=d" (return_len)
+                               : "a" (cpcmd_buf), "d" (cmdlen),
+                               "a" (response), "d" (rlen), "m" (mask)
+                               : "cc", "2", "3", "4", "5" );
 #else /* CONFIG_ARCH_S390X */
-                asm volatile ("   lrag  2,0(%0)\n"
-                              "   lgr   4,%1\n"
-                              "   o     4,%4\n"
-                              "   lrag  3,0(%2)\n"
-                              "   lgr   5,%3\n"
-                              "   sam31\n"
-                              "   .long 0x83240008 # Diagnose X'08'\n"
-                              "   sam64"
-                              : /* no output */
-                              : "a" (cpcmd_buf), "d" (cmdlen),
-                                "a" (response), "d" (rlen), "m" (mask)
-                              : "cc", "2", "3", "4", "5" );
+                asm volatile ( "lrag   2,0(%2)\n"
+                               "lgr    4,%3\n"
+                               "o      4,%6\n"
+                               "lrag   3,0(%4)\n"
+                               "lgr    5,%5\n"
+                               "sam31\n"
+                               "diag   2,4,0x8\n"
+                               "sam64\n"
+                               "brc    8, .Litfits\n"
+                               "agr    5, %5\n"
+                               ".Litfits: \n"
+                               "lgr    %0,4\n"
+                               "lgr    %1,5\n"
+                               : "=d" (return_code), "=d" (return_len)
+                               : "a" (cpcmd_buf), "d" (cmdlen),
+                               "a" (response), "d" (rlen), "m" (mask)
+                               : "cc", "2", "3", "4", "5" );
 #endif /* CONFIG_ARCH_S390X */
                 EBCASC(response, rlen);
         } else {
+               return_len = 0;
 #ifndef CONFIG_ARCH_S390X
-                asm volatile ("LRA   2,0(%0)\n\t"
-                              "LR    3,%1\n\t"
-                              ".long 0x83230008 # Diagnose X'08'\n\t"
-                              : /* no output */
-                              : "a" (cpcmd_buf), "d" (cmdlen)
-                              : "2", "3"  );
+                asm volatile ( "lra    2,0(%1)\n"
+                               "lr     3,%2\n"
+                               "diag   2,3,0x8\n"
+                               "lr     %0,3\n"
+                               : "=d" (return_code)
+                               : "a" (cpcmd_buf), "d" (cmdlen)
+                               : "2", "3"  );
 #else /* CONFIG_ARCH_S390X */
-                asm volatile ("   lrag  2,0(%0)\n"
-                              "   lgr   3,%1\n"
-                              "   sam31\n"
-                              "   .long 0x83230008 # Diagnose X'08'\n"
-                              "   sam64"
-                              : /* no output */
-                              : "a" (cpcmd_buf), "d" (cmdlen)
-                              : "2", "3"  );
+                asm volatile ( "lrag   2,0(%1)\n"
+                               "lgr    3,%2\n"
+                               "sam31\n"
+                               "diag   2,3,0x8\n"
+                               "sam64\n"
+                               "lgr    %0,3\n"
+                               : "=d" (return_code)
+                               : "a" (cpcmd_buf), "d" (cmdlen)
+                               : "2", "3" );
 #endif /* CONFIG_ARCH_S390X */
         }
        spin_unlock_irqrestore(&cpcmd_lock, flags);
+       if (response_code != NULL)
+               *response_code = return_code;
+       return return_len;
 }
 
 EXPORT_SYMBOL(__cpcmd);
 
 #ifdef CONFIG_ARCH_S390X
-void cpcmd(char *cmd, char *response, int rlen)
+int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
 {
        char *lowbuf;
+       int len;
+
        if ((rlen == 0) || (response == NULL)
            || !((unsigned long)response >> 31))
-               __cpcmd(cmd, response, rlen);
+               len = __cpcmd(cmd, response, rlen, response_code);
        else {
                lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
                if (!lowbuf) {
                        printk(KERN_WARNING
                                "cpcmd: could not allocate response buffer\n");
-                       return;
+                       return -ENOMEM;
                }
-               __cpcmd(cmd, lowbuf, rlen);
+               len = __cpcmd(cmd, lowbuf, rlen, response_code);
                memcpy(response, lowbuf, rlen);
                kfree(lowbuf);
        }
+       return len;
 }
 
 EXPORT_SYMBOL(cpcmd);
diff --git a/arch/s390/kernel/crash.c b/arch/s390/kernel/crash.c
new file mode 100644 (file)
index 0000000..7bd169c
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * arch/s390/kernel/crash.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ *
+ */
+
+#include <linux/threads.h>
+#include <linux/kexec.h>
+
+note_buf_t crash_notes[NR_CPUS];
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+}
index 91f8ce5543d3b405287056b562e4d754b987476e..960ba6029c3a00c0f77727519450b3591278a272 100644 (file)
 #include <linux/sysctl.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
-
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
 
 #include <asm/debug.h>
 
 #define DEBUG_PROLOG_ENTRY -1
 
+#define ALL_AREAS 0 /* copy all debug areas */
+#define NO_AREAS  1 /* copy no debug areas */
+
 /* typedefs */
 
 typedef struct file_private_info {
        loff_t offset;                  /* offset of last read in file */
        int    act_area;                /* number of last formated area */
+       int    act_page;                /* act page in given area */
        int    act_entry;               /* last formated entry (offset */
                                         /* relative to beginning of last */
-                                        /* formated area) */ 
+                                        /* formated page) */
        size_t act_entry_offset;        /* up to this offset we copied */
                                        /* in last read the last formated */
                                        /* entry to userland */
@@ -51,8 +56,8 @@ typedef struct
         * This assumes that all args are converted into longs 
         * on L/390 this is the case for all types of parameter 
         * except of floats, and long long (32 bit) 
-         *
-         */
+        *
+        */
        long args[0];
 } debug_sprintf_entry_t;
 
@@ -63,32 +68,38 @@ extern void tod_to_timeval(uint64_t todval, struct timeval *xtime);
 
 static int debug_init(void);
 static ssize_t debug_output(struct file *file, char __user *user_buf,
-                           size_t user_len, loff_t * offset);
+                       size_t user_len, loff_t * offset);
 static ssize_t debug_input(struct file *file, const char __user *user_buf,
-                          size_t user_len, loff_t * offset);
+                       size_t user_len, loff_t * offset);
 static int debug_open(struct inode *inode, struct file *file);
 static int debug_close(struct inode *inode, struct file *file);
-static debug_info_t*  debug_info_create(char *name, int page_order, int nr_areas, int buf_size);
+static debug_info_t*  debug_info_create(char *name, int pages_per_area,
+                       int nr_areas, int buf_size);
 static void debug_info_get(debug_info_t *);
 static void debug_info_put(debug_info_t *);
 static int debug_prolog_level_fn(debug_info_t * id,
-                                struct debug_view *view, char *out_buf);
+                       struct debug_view *view, char *out_buf);
 static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
-                               struct file *file, const char __user *user_buf,
-                               size_t user_buf_size, loff_t * offset);
+                       struct file *file, const char __user *user_buf,
+                       size_t user_buf_size, loff_t * offset);
+static int debug_prolog_pages_fn(debug_info_t * id,
+                       struct debug_view *view, char *out_buf);
+static int debug_input_pages_fn(debug_info_t * id, struct debug_view *view,
+                       struct file *file, const char __user *user_buf,
+                       size_t user_buf_size, loff_t * offset);
 static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
-                                struct file *file, const char __user *user_buf,
-                                size_t user_buf_size, loff_t * offset);
+                       struct file *file, const char __user *user_buf,
+                       size_t user_buf_size, loff_t * offset);
 static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
-                                char *out_buf, const char *in_buf);
+                       char *out_buf, const char *in_buf);
 static int debug_raw_format_fn(debug_info_t * id,
-                                struct debug_view *view, char *out_buf,
-                                const char *in_buf);
+                       struct debug_view *view, char *out_buf,
+                       const char *in_buf);
 static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
-                         int area, debug_entry_t * entry, char *out_buf);
+                       int area, debug_entry_t * entry, char *out_buf);
 
 static int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
-                                  char *out_buf, debug_sprintf_entry_t *curr_event);
+                       char *out_buf, debug_sprintf_entry_t *curr_event);
 
 /* globals */
 
@@ -119,6 +130,15 @@ struct debug_view debug_level_view = {
        NULL
 };
 
+struct debug_view debug_pages_view = {
+       "pages",
+       &debug_prolog_pages_fn,
+       NULL,
+       NULL,
+       &debug_input_pages_fn,
+       NULL
+};
+
 struct debug_view debug_flush_view = {
         "flush",
         NULL,
@@ -149,98 +169,161 @@ DECLARE_MUTEX(debug_lock);
 static int initialized;
 
 static struct file_operations debug_file_ops = {
-       .owner   = THIS_MODULE,
+       .owner   = THIS_MODULE,
        .read    = debug_output,
-       .write   = debug_input, 
+       .write   = debug_input,
        .open    = debug_open,
        .release = debug_close,
 };
 
-static struct proc_dir_entry *debug_proc_root_entry;
+static struct dentry *debug_debugfs_root_entry;
 
 /* functions */
 
+/*
+ * debug_areas_alloc
+ * - Debug areas are implemented as a threedimensonal array:
+ *   areas[areanumber][pagenumber][pageoffset]
+ */
+
+static debug_entry_t***
+debug_areas_alloc(int pages_per_area, int nr_areas)
+{
+       debug_entry_t*** areas;
+       int i,j;
+
+       areas = (debug_entry_t ***) kmalloc(nr_areas *
+                                       sizeof(debug_entry_t**),
+                                       GFP_KERNEL);
+       if (!areas)
+               goto fail_malloc_areas;
+       for (i = 0; i < nr_areas; i++) {
+               areas[i] = (debug_entry_t**) kmalloc(pages_per_area *
+                               sizeof(debug_entry_t*),GFP_KERNEL);
+               if (!areas[i]) {
+                       goto fail_malloc_areas2;
+               }
+               for(j = 0; j < pages_per_area; j++) {
+                       areas[i][j] = (debug_entry_t*)kmalloc(PAGE_SIZE,
+                                               GFP_KERNEL);
+                       if(!areas[i][j]) {
+                               for(j--; j >=0 ; j--) {
+                                       kfree(areas[i][j]);
+                               }
+                               kfree(areas[i]);
+                               goto fail_malloc_areas2;
+                       } else {
+                               memset(areas[i][j],0,PAGE_SIZE);
+                       }
+               }
+       }
+       return areas;
+
+fail_malloc_areas2:
+       for(i--; i >= 0; i--){
+               for(j=0; j < pages_per_area;j++){
+                       kfree(areas[i][j]);
+               }
+               kfree(areas[i]);
+       }
+       kfree(areas);
+fail_malloc_areas:
+       return NULL;
+
+}
+
+
 /*
  * debug_info_alloc
  * - alloc new debug-info
  */
 
-static debug_info_t*  debug_info_alloc(char *name, int page_order,
-                                        int nr_areas, int buf_size)
+static debug_info_t*
+debug_info_alloc(char *name, int pages_per_area, int nr_areas, int buf_size,
+               int level, int mode)
 {
        debug_info_t* rc;
-       int i;
 
        /* alloc everything */
 
-       rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC);
+       rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_KERNEL);
        if(!rc)
                goto fail_malloc_rc;
-       rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC);
-       if(!rc->active_entry)
-               goto fail_malloc_active_entry;
-       memset(rc->active_entry, 0, nr_areas * sizeof(int));
-       rc->areas = (debug_entry_t **) kmalloc(nr_areas *
-                                               sizeof(debug_entry_t *),
-                                               GFP_ATOMIC);
-       if (!rc->areas)
-               goto fail_malloc_areas;
-       for (i = 0; i < nr_areas; i++) {
-               rc->areas[i] = (debug_entry_t *) __get_free_pages(GFP_ATOMIC,
-                                                               page_order);
-               if (!rc->areas[i]) {
-                       for (i--; i >= 0; i--) {
-                               free_pages((unsigned long) rc->areas[i],
-                                               page_order);
-                       }
-                       goto fail_malloc_areas2;
-               } else {
-                       memset(rc->areas[i], 0, PAGE_SIZE << page_order);
-               }
+       rc->active_entries = (int*)kmalloc(nr_areas * sizeof(int), GFP_KERNEL);
+       if(!rc->active_entries)
+               goto fail_malloc_active_entries;
+       memset(rc->active_entries, 0, nr_areas * sizeof(int));
+       rc->active_pages = (int*)kmalloc(nr_areas * sizeof(int), GFP_KERNEL);
+       if(!rc->active_pages)
+               goto fail_malloc_active_pages;
+       memset(rc->active_pages, 0, nr_areas * sizeof(int));
+       if((mode == ALL_AREAS) && (pages_per_area != 0)){
+               rc->areas = debug_areas_alloc(pages_per_area, nr_areas);
+               if(!rc->areas)
+                       goto fail_malloc_areas;
+       } else {
+               rc->areas = NULL;
        }
 
        /* initialize members */
 
        spin_lock_init(&rc->lock);
-       rc->page_order  = page_order;
-       rc->nr_areas    = nr_areas;
-       rc->active_area = 0;
-       rc->level       = DEBUG_DEFAULT_LEVEL;
-       rc->buf_size    = buf_size;
-       rc->entry_size  = sizeof(debug_entry_t) + buf_size;
-       strlcpy(rc->name, name, sizeof(rc->name));
+       rc->pages_per_area = pages_per_area;
+       rc->nr_areas       = nr_areas;
+       rc->active_area    = 0;
+       rc->level          = level;
+       rc->buf_size       = buf_size;
+       rc->entry_size     = sizeof(debug_entry_t) + buf_size;
+       strlcpy(rc->name, name, sizeof(rc->name)-1);
        memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
-#ifdef CONFIG_PROC_FS
-       memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS *
-               sizeof(struct proc_dir_entry*));
-#endif /* CONFIG_PROC_FS */
+       memset(rc->debugfs_entries, 0 ,DEBUG_MAX_VIEWS *
+               sizeof(struct dentry*));
        atomic_set(&(rc->ref_count), 0);
 
        return rc;
 
-fail_malloc_areas2:
-       kfree(rc->areas);
 fail_malloc_areas:
-       kfree(rc->active_entry);
-fail_malloc_active_entry:
+       kfree(rc->active_pages);
+fail_malloc_active_pages:
+       kfree(rc->active_entries);
+fail_malloc_active_entries:
        kfree(rc);
 fail_malloc_rc:
        return NULL;
 }
 
 /*
- * debug_info_free
- * - free memory debug-info
+ * debug_areas_free
+ * - free all debug areas
  */
 
-static void debug_info_free(debug_info_t* db_info){
-       int i;
+static void
+debug_areas_free(debug_info_t* db_info)
+{
+       int i,j;
+
+       if(!db_info->areas)
+               return;
        for (i = 0; i < db_info->nr_areas; i++) {
-               free_pages((unsigned long) db_info->areas[i],
-               db_info->page_order);
+               for(j = 0; j < db_info->pages_per_area; j++) {
+                       kfree(db_info->areas[i][j]);
+               }
+               kfree(db_info->areas[i]);
        }
        kfree(db_info->areas);
-       kfree(db_info->active_entry);
+       db_info->areas = NULL;
+}
+
+/*
+ * debug_info_free
+ * - free memory debug-info
+ */
+
+static void
+debug_info_free(debug_info_t* db_info){
+       debug_areas_free(db_info);
+       kfree(db_info->active_entries);
+       kfree(db_info->active_pages);
        kfree(db_info);
 }
 
@@ -249,21 +332,22 @@ static void debug_info_free(debug_info_t* db_info){
  * - create new debug-info
  */
 
-static debug_info_t*  debug_info_create(char *name, int page_order, 
-                                        int nr_areas, int buf_size)
+static debug_info_t*
+debug_info_create(char *name, int pages_per_area, int nr_areas, int buf_size)
 {
        debug_info_t* rc;
 
-        rc = debug_info_alloc(name, page_order, nr_areas, buf_size);
+        rc = debug_info_alloc(name, pages_per_area, nr_areas, buf_size,
+                               DEBUG_DEFAULT_LEVEL, ALL_AREAS);
         if(!rc) 
                goto out;
 
-
-       /* create proc rood directory */
-        rc->proc_root_entry = proc_mkdir(rc->name, debug_proc_root_entry);
+       /* create root directory */
+        rc->debugfs_root_entry = debugfs_create_dir(rc->name,
+                                       debug_debugfs_root_entry);
 
        /* append new element to linked list */
-        if (debug_area_first == NULL) {
+        if (!debug_area_first) {
                 /* first element in list */
                 debug_area_first = rc;
                 rc->prev = NULL;
@@ -285,17 +369,21 @@ out:
  * - copy debug-info
  */
 
-static debug_info_t* debug_info_copy(debug_info_t* in)
+static debug_info_t*
+debug_info_copy(debug_info_t* in, int mode)
 {
-        int i;
+        int i,j;
         debug_info_t* rc;
-        rc = debug_info_alloc(in->name, in->page_order, 
-                                in->nr_areas, in->buf_size);
-        if(!rc)
+
+        rc = debug_info_alloc(in->name, in->pages_per_area, in->nr_areas,
+                               in->buf_size, in->level, mode);
+        if(!rc || (mode == NO_AREAS))
                 goto out;
 
         for(i = 0; i < in->nr_areas; i++){
-                memcpy(rc->areas[i],in->areas[i], PAGE_SIZE << in->page_order);
+               for(j = 0; j < in->pages_per_area; j++) {
+                       memcpy(rc->areas[i][j], in->areas[i][j],PAGE_SIZE);
+               }
         }
 out:
         return rc;
@@ -306,7 +394,8 @@ out:
  * - increments reference count for debug-info
  */
 
-static void debug_info_get(debug_info_t * db_info)
+static void
+debug_info_get(debug_info_t * db_info)
 {
        if (db_info)
                atomic_inc(&db_info->ref_count);
@@ -317,29 +406,20 @@ static void debug_info_get(debug_info_t * db_info)
  * - decreases reference count for debug-info and frees it if necessary
  */
 
-static void debug_info_put(debug_info_t *db_info)
+static void
+debug_info_put(debug_info_t *db_info)
 {
        int i;
 
        if (!db_info)
                return;
        if (atomic_dec_and_test(&db_info->ref_count)) {
-#ifdef DEBUG
-               printk(KERN_INFO "debug: freeing debug area %p (%s)\n",
-                      db_info, db_info->name);
-#endif
                for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
-                       if (db_info->views[i] == NULL)
+                       if (!db_info->views[i])
                                continue;
-#ifdef CONFIG_PROC_FS
-                       remove_proc_entry(db_info->proc_entries[i]->name,
-                                         db_info->proc_root_entry);
-#endif
+                       debugfs_remove(db_info->debugfs_entries[i]);
                }
-#ifdef CONFIG_PROC_FS
-               remove_proc_entry(db_info->proc_root_entry->name,
-                                 debug_proc_root_entry);
-#endif
+               debugfs_remove(db_info->debugfs_root_entry);
                if(db_info == debug_area_first)
                        debug_area_first = db_info->next;
                if(db_info == debug_area_last)
@@ -355,9 +435,9 @@ static void debug_info_put(debug_info_t *db_info)
  * - format one debug entry and return size of formated data
  */
 
-static int debug_format_entry(file_private_info_t *p_info)
+static int
+debug_format_entry(file_private_info_t *p_info)
 {
-       debug_info_t *id_org    = p_info->debug_info_org;
        debug_info_t *id_snap   = p_info->debug_info_snap;
        struct debug_view *view = p_info->view;
        debug_entry_t *act_entry;
@@ -365,22 +445,23 @@ static int debug_format_entry(file_private_info_t *p_info)
        if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
                /* print prolog */
                if (view->prolog_proc)
-                       len += view->prolog_proc(id_org, view,p_info->temp_buf);
+                       len += view->prolog_proc(id_snap,view,p_info->temp_buf);
                goto out;
        }
-
-       act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area] +
-                                       p_info->act_entry);
+       if (!id_snap->areas) /* this is true, if we have a prolog only view */
+               goto out;    /* or if 'pages_per_area' is 0 */
+       act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area]
+                               [p_info->act_page] + p_info->act_entry);
                         
        if (act_entry->id.stck == 0LL)
                        goto out;  /* empty entry */
        if (view->header_proc)
-               len += view->header_proc(id_org, view, p_info->act_area, 
+               len += view->header_proc(id_snap, view, p_info->act_area,
                                        act_entry, p_info->temp_buf + len);
        if (view->format_proc)
-               len += view->format_proc(id_org, view, p_info->temp_buf + len,
+               len += view->format_proc(id_snap, view, p_info->temp_buf + len,
                                                DEBUG_DATA(act_entry));
-      out:
+out:
         return len;
 }
 
@@ -389,20 +470,30 @@ static int debug_format_entry(file_private_info_t *p_info)
  * - goto next entry in p_info
  */
 
-extern inline int debug_next_entry(file_private_info_t *p_info)
+extern inline int
+debug_next_entry(file_private_info_t *p_info)
 {
-       debug_info_t *id = p_info->debug_info_snap;
+       debug_info_t *id;
+
+       id = p_info->debug_info_snap;
        if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
                p_info->act_entry = 0;
+               p_info->act_page  = 0;
                goto out;
        }
-       if ((p_info->act_entry += id->entry_size)
-               > ((PAGE_SIZE << (id->page_order)) 
-               - id->entry_size)){
-
-               /* next area */
+       if(!id->areas)
+               return 1;
+       p_info->act_entry += id->entry_size;
+       /* switch to next page, if we reached the end of the page  */
+       if (p_info->act_entry > (PAGE_SIZE - id->entry_size)){
+               /* next page */
                p_info->act_entry = 0;
-               p_info->act_area++;
+               p_info->act_page += 1;
+               if((p_info->act_page % id->pages_per_area) == 0) {
+                       /* next area */
+                       p_info->act_area++;
+                       p_info->act_page=0;
+               }
                if(p_info->act_area >= id->nr_areas)
                        return 1;
        }
@@ -416,13 +507,14 @@ out:
  * - copies formated debug entries to the user buffer
  */
 
-static ssize_t debug_output(struct file *file,         /* file descriptor */
-                           char __user *user_buf,      /* user buffer */
-                           size_t  len,                /* length of buffer */
-                           loff_t *offset)           /* offset in the file */
+static ssize_t
+debug_output(struct file *file,                /* file descriptor */
+           char __user *user_buf,      /* user buffer */
+           size_t  len,                /* length of buffer */
+           loff_t *offset)             /* offset in the file */
 {
        size_t count = 0;
-       size_t entry_offset, size = 0;
+       size_t entry_offset;
        file_private_info_t *p_info;
 
        p_info = ((file_private_info_t *) file->private_data);
@@ -430,27 +522,33 @@ static ssize_t debug_output(struct file *file,            /* file descriptor */
                return -EPIPE;
        if(p_info->act_area >= p_info->debug_info_snap->nr_areas)
                return 0;
-
        entry_offset = p_info->act_entry_offset;
-
        while(count < len){
-               size = debug_format_entry(p_info);
-               size = min((len - count), (size - entry_offset));
-
-               if(size){
-                       if (copy_to_user(user_buf + count, 
-                                       p_info->temp_buf + entry_offset, size))
-                       return -EFAULT;
+               int formatted_line_size;
+               int formatted_line_residue;
+               int user_buf_residue;
+               size_t copy_size;
+
+               formatted_line_size = debug_format_entry(p_info);
+               formatted_line_residue = formatted_line_size - entry_offset;
+               user_buf_residue = len-count;
+               copy_size = min(user_buf_residue, formatted_line_residue);
+               if(copy_size){
+                       if (copy_to_user(user_buf + count, p_info->temp_buf
+                                       + entry_offset, copy_size))
+                               return -EFAULT;
+                       count += copy_size;
+                       entry_offset += copy_size;
                }
-               count += size;
-               entry_offset = 0;
-               if(count != len)
-                       if(debug_next_entry(p_info)) 
+               if(copy_size == formatted_line_residue){
+                       entry_offset = 0;
+                       if(debug_next_entry(p_info))
                                goto out;
+               }
        }
 out:
        p_info->offset           = *offset + count;
-       p_info->act_entry_offset = size;        
+       p_info->act_entry_offset = entry_offset;
        *offset = p_info->offset;
        return count;
 }
@@ -461,9 +559,9 @@ out:
  * - calls input function of view
  */
 
-static ssize_t debug_input(struct file *file,
-                          const char __user *user_buf, size_t length,
-                          loff_t *offset)
+static ssize_t
+debug_input(struct file *file, const char __user *user_buf, size_t length,
+               loff_t *offset)
 {
        int rc = 0;
        file_private_info_t *p_info;
@@ -487,26 +585,23 @@ static ssize_t debug_input(struct file *file,
  *   handle
  */
 
-static int debug_open(struct inode *inode, struct file *file)
+static int
+debug_open(struct inode *inode, struct file *file)
 {
        int i = 0, rc = 0;
        file_private_info_t *p_info;
        debug_info_t *debug_info, *debug_info_snapshot;
 
-#ifdef DEBUG
-       printk("debug_open\n");
-#endif
        down(&debug_lock);
 
        /* find debug log and view */
-
        debug_info = debug_area_first;
        while(debug_info != NULL){
                for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
-                       if (debug_info->views[i] == NULL)
+                       if (!debug_info->views[i])
                                continue;
-                       else if (debug_info->proc_entries[i] ==
-                                PDE(file->f_dentry->d_inode)) {
+                       else if (debug_info->debugfs_entries[i] ==
+                                file->f_dentry) {
                                goto found;     /* found view ! */
                        }
                }
@@ -516,41 +611,42 @@ static int debug_open(struct inode *inode, struct file *file)
        rc = -EINVAL;
        goto out;
 
-      found:
+found:
 
-       /* make snapshot of current debug areas to get it consistent */
+       /* Make snapshot of current debug areas to get it consistent.     */
+       /* To copy all the areas is only needed, if we have a view which  */
+       /* formats the debug areas. */
 
-       debug_info_snapshot = debug_info_copy(debug_info);
+       if(!debug_info->views[i]->format_proc &&
+               !debug_info->views[i]->header_proc){
+               debug_info_snapshot = debug_info_copy(debug_info, NO_AREAS);
+       } else {
+               debug_info_snapshot = debug_info_copy(debug_info, ALL_AREAS);
+       }
 
        if(!debug_info_snapshot){
-#ifdef DEBUG
-               printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\n");
-#endif
                rc = -ENOMEM;
                goto out;
        }
-
-       if ((file->private_data =
-            kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
-#ifdef DEBUG
-               printk(KERN_ERR "debug_open: kmalloc failed\n");
-#endif
-               debug_info_free(debug_info_snapshot);   
+       p_info = (file_private_info_t *) kmalloc(sizeof(file_private_info_t),
+                                               GFP_KERNEL);
+       if(!p_info){
+               if(debug_info_snapshot)
+                       debug_info_free(debug_info_snapshot);
                rc = -ENOMEM;
                goto out;
        }
-       p_info = (file_private_info_t *) file->private_data;
        p_info->offset = 0;
        p_info->debug_info_snap = debug_info_snapshot;
        p_info->debug_info_org  = debug_info;
        p_info->view = debug_info->views[i];
        p_info->act_area = 0;
+       p_info->act_page = 0;
        p_info->act_entry = DEBUG_PROLOG_ENTRY;
        p_info->act_entry_offset = 0;
-
+       file->private_data = p_info;
        debug_info_get(debug_info);
-
-      out:
+out:
        up(&debug_lock);
        return rc;
 }
@@ -561,14 +657,13 @@ static int debug_open(struct inode *inode, struct file *file)
  * - deletes  private_data area of the file handle
  */
 
-static int debug_close(struct inode *inode, struct file *file)
+static int
+debug_close(struct inode *inode, struct file *file)
 {
        file_private_info_t *p_info;
-#ifdef DEBUG
-       printk("debug_close\n");
-#endif
        p_info = (file_private_info_t *) file->private_data;
-       debug_info_free(p_info->debug_info_snap);
+       if(p_info->debug_info_snap)
+               debug_info_free(p_info->debug_info_snap);
        debug_info_put(p_info->debug_info_org);
        kfree(file->private_data);
        return 0;               /* success */
@@ -580,8 +675,8 @@ static int debug_close(struct inode *inode, struct file *file)
  * - returns handle for debug area
  */
 
-debug_info_t *debug_register
-    (char *name, int page_order, int nr_areas, int buf_size) 
+debug_info_t*
+debug_register (char *name, int pages_per_area, int nr_areas, int buf_size)
 {
        debug_info_t *rc = NULL;
 
@@ -591,18 +686,14 @@ debug_info_t *debug_register
 
         /* create new debug_info */
 
-       rc = debug_info_create(name, page_order, nr_areas, buf_size);
+       rc = debug_info_create(name, pages_per_area, nr_areas, buf_size);
        if(!rc) 
                goto out;
        debug_register_view(rc, &debug_level_view);
         debug_register_view(rc, &debug_flush_view);
-#ifdef DEBUG
-       printk(KERN_INFO
-              "debug: reserved %d areas of %d pages for debugging %s\n",
-              nr_areas, 1 << page_order, rc->name);
-#endif
-      out:
-        if (rc == NULL){
+       debug_register_view(rc, &debug_pages_view);
+out:
+        if (!rc){
                printk(KERN_ERR "debug: debug_register failed for %s\n",name);
         }
        up(&debug_lock);
@@ -614,27 +705,65 @@ debug_info_t *debug_register
  * - give back debug area
  */
 
-void debug_unregister(debug_info_t * id)
+void
+debug_unregister(debug_info_t * id)
 {
        if (!id)
                goto out;
        down(&debug_lock);
-#ifdef DEBUG
-       printk(KERN_INFO "debug: unregistering %s\n", id->name);
-#endif
        debug_info_put(id);
        up(&debug_lock);
 
-      out:
+out:
        return;
 }
 
+/*
+ * debug_set_size:
+ * - set area size (number of pages) and number of areas
+ */
+static int
+debug_set_size(debug_info_t* id, int nr_areas, int pages_per_area)
+{
+       unsigned long flags;
+       debug_entry_t *** new_areas;
+       int rc=0;
+
+       if(!id || (nr_areas <= 0) || (pages_per_area < 0))
+               return -EINVAL;
+       if(pages_per_area > 0){
+               new_areas = debug_areas_alloc(pages_per_area, nr_areas);
+               if(!new_areas) {
+                       printk(KERN_WARNING "debug: could not allocate memory "\
+                                        "for pagenumber: %i\n",pages_per_area);
+                       rc = -ENOMEM;
+                       goto out;
+               }
+       } else {
+               new_areas = NULL;
+       }
+       spin_lock_irqsave(&id->lock,flags);
+       debug_areas_free(id);
+       id->areas = new_areas;
+       id->nr_areas = nr_areas;
+       id->pages_per_area = pages_per_area;
+       id->active_area = 0;
+       memset(id->active_entries,0,sizeof(int)*id->nr_areas);
+       memset(id->active_pages, 0, sizeof(int)*id->nr_areas);
+       spin_unlock_irqrestore(&id->lock,flags);
+       printk(KERN_INFO "debug: %s: set new size (%i pages)\n"\
+                        ,id->name, pages_per_area);
+out:
+       return rc;
+}
+
 /*
  * debug_set_level:
  * - set actual debug level
  */
 
-void debug_set_level(debug_info_t* id, int new_level)
+void
+debug_set_level(debug_info_t* id, int new_level)
 {
        unsigned long flags;
        if(!id)
@@ -649,10 +778,6 @@ void debug_set_level(debug_info_t* id, int new_level)
                         id->name, new_level, 0, DEBUG_MAX_LEVEL);
         } else {
                 id->level = new_level;
-#ifdef DEBUG
-                printk(KERN_INFO 
-                       "debug: %s: new level %i\n",id->name,id->level);
-#endif
         }
        spin_unlock_irqrestore(&id->lock,flags);
 }
@@ -663,11 +788,16 @@ void debug_set_level(debug_info_t* id, int new_level)
  * - set active entry to next in the ring buffer
  */
 
-extern inline void proceed_active_entry(debug_info_t * id)
+extern inline void
+proceed_active_entry(debug_info_t * id)
 {
-       if ((id->active_entry[id->active_area] += id->entry_size)
-           > ((PAGE_SIZE << (id->page_order)) - id->entry_size))
-               id->active_entry[id->active_area] = 0;
+       if ((id->active_entries[id->active_area] += id->entry_size)
+           > (PAGE_SIZE - id->entry_size)){
+               id->active_entries[id->active_area] = 0;
+               id->active_pages[id->active_area] =
+                       (id->active_pages[id->active_area] + 1) %
+                       id->pages_per_area;
+       }
 }
 
 /*
@@ -675,7 +805,8 @@ extern inline void proceed_active_entry(debug_info_t * id)
  * - set active area to next in the ring buffer
  */
 
-extern inline void proceed_active_area(debug_info_t * id)
+extern inline void
+proceed_active_area(debug_info_t * id)
 {
        id->active_area++;
        id->active_area = id->active_area % id->nr_areas;
@@ -685,10 +816,12 @@ extern inline void proceed_active_area(debug_info_t * id)
  * get_active_entry:
  */
 
-extern inline debug_entry_t *get_active_entry(debug_info_t * id)
+extern inline debug_entry_t*
+get_active_entry(debug_info_t * id)
 {
-       return (debug_entry_t *) ((char *) id->areas[id->active_area] +
-                                 id->active_entry[id->active_area]);
+       return (debug_entry_t *) (((char *) id->areas[id->active_area]
+                                       [id->active_pages[id->active_area]]) +
+                                       id->active_entries[id->active_area]);
 }
 
 /*
@@ -696,8 +829,9 @@ extern inline debug_entry_t *get_active_entry(debug_info_t * id)
  * - set timestamp, caller address, cpu number etc.
  */
 
-extern inline void debug_finish_entry(debug_info_t * id, debug_entry_t* active,
-               int level, int exception)
+extern inline void
+debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level,
+                       int exception)
 {
        STCK(active->id.stck);
        active->id.fields.cpuid = smp_processor_id();
@@ -721,7 +855,8 @@ static int debug_active=1;
  * always allow read, allow write only if debug_stoppable is set or
  * if debug_active is already off
  */
-static int s390dbf_procactive(ctl_table *table, int write, struct file *filp,
+static int
+s390dbf_procactive(ctl_table *table, int write, struct file *filp,
                      void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        if (!write || debug_stoppable || !debug_active)
@@ -766,7 +901,8 @@ static struct ctl_table s390dbf_dir_table[] = {
 
 struct ctl_table_header *s390dbf_sysctl_header;
 
-void debug_stop_all(void)
+void
+debug_stop_all(void)
 {
        if (debug_stoppable)
                debug_active = 0;
@@ -778,13 +914,13 @@ void debug_stop_all(void)
  * - write debug entry with given size
  */
 
-debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf,
-                                 int len)
+debug_entry_t*
+debug_event_common(debug_info_t * id, int level, const void *buf, int len)
 {
        unsigned long flags;
        debug_entry_t *active;
 
-       if (!debug_active)
+       if (!debug_active || !id->areas)
                return NULL;
        spin_lock_irqsave(&id->lock, flags);
        active = get_active_entry(id);
@@ -801,13 +937,13 @@ debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf,
  * - write debug entry with given size and switch to next debug area
  */
 
-debug_entry_t *debug_exception_common(debug_info_t * id, int level, 
-                                      const void *buf, int len)
+debug_entry_t
+*debug_exception_common(debug_info_t * id, int level, const void *buf, int len)
 {
        unsigned long flags;
        debug_entry_t *active;
 
-       if (!debug_active)
+       if (!debug_active || !id->areas)
                return NULL;
        spin_lock_irqsave(&id->lock, flags);
        active = get_active_entry(id);
@@ -823,7 +959,8 @@ debug_entry_t *debug_exception_common(debug_info_t * id, int level,
  * counts arguments in format string for sprintf view
  */
 
-extern inline int debug_count_numargs(char *string)
+extern inline int
+debug_count_numargs(char *string)
 {
        int numargs=0;
 
@@ -838,8 +975,8 @@ extern inline int debug_count_numargs(char *string)
  * debug_sprintf_event:
  */
 
-debug_entry_t *debug_sprintf_event(debug_info_t* id,
-                                   int level,char *string,...)
+debug_entry_t*
+debug_sprintf_event(debug_info_t* id, int level,char *string,...)
 {
        va_list   ap;
        int numargs,idx;
@@ -849,7 +986,7 @@ debug_entry_t *debug_sprintf_event(debug_info_t* id,
 
        if((!id) || (level > id->level))
                return NULL;
-       if (!debug_active)
+       if (!debug_active || !id->areas)
                return NULL;
        numargs=debug_count_numargs(string);
 
@@ -871,8 +1008,8 @@ debug_entry_t *debug_sprintf_event(debug_info_t* id,
  * debug_sprintf_exception:
  */
 
-debug_entry_t *debug_sprintf_exception(debug_info_t* id,
-                                       int level,char *string,...)
+debug_entry_t*
+debug_sprintf_exception(debug_info_t* id, int level,char *string,...)
 {
        va_list   ap;
        int numargs,idx;
@@ -882,7 +1019,7 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id,
 
        if((!id) || (level > id->level))
                return NULL;
-       if (!debug_active)
+       if (!debug_active || !id->areas)
                return NULL;
 
        numargs=debug_count_numargs(string);
@@ -906,15 +1043,14 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id,
  * - is called exactly once to initialize the debug feature
  */
 
-static int __init debug_init(void)
+static int
+__init debug_init(void)
 {
        int rc = 0;
 
        s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table, 1);
        down(&debug_lock);
-#ifdef CONFIG_PROC_FS
-       debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
-#endif /* CONFIG_PROC_FS */
+       debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT,NULL);
        printk(KERN_INFO "debug: Initialization complete\n");
        initialized = 1;
        up(&debug_lock);
@@ -926,13 +1062,14 @@ static int __init debug_init(void)
  * debug_register_view:
  */
 
-int debug_register_view(debug_info_t * id, struct debug_view *view)
+int
+debug_register_view(debug_info_t * id, struct debug_view *view)
 {
        int rc = 0;
        int i;
        unsigned long flags;
        mode_t mode = S_IFREG;
-       struct proc_dir_entry *pde;
+       struct dentry *pde;
 
        if (!id)
                goto out;
@@ -940,16 +1077,17 @@ int debug_register_view(debug_info_t * id, struct debug_view *view)
                mode |= S_IRUSR;
        if (view->input_proc)
                mode |= S_IWUSR;
-       pde = create_proc_entry(view->name, mode, id->proc_root_entry);
+       pde = debugfs_create_file(view->name, mode, id->debugfs_root_entry,
+                               NULL, &debug_file_ops);
        if (!pde){
-               printk(KERN_WARNING "debug: create_proc_entry() failed! Cannot register view %s/%s\n", id->name,view->name);
+               printk(KERN_WARNING "debug: debugfs_create_file() failed!"\
+                       " Cannot register view %s/%s\n", id->name,view->name);
                rc = -1;
                goto out;
        }
-
        spin_lock_irqsave(&id->lock, flags);
        for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
-               if (id->views[i] == NULL)
+               if (!id->views[i])
                        break;
        }
        if (i == DEBUG_MAX_VIEWS) {
@@ -957,16 +1095,14 @@ int debug_register_view(debug_info_t * id, struct debug_view *view)
                        id->name,view->name);
                printk(KERN_WARNING 
                        "debug: maximum number of views reached (%i)!\n", i);
-               remove_proc_entry(pde->name, id->proc_root_entry);
+               debugfs_remove(pde);
                rc = -1;
-       }
-       else {
+       } else {
                id->views[i] = view;
-               pde->proc_fops = &debug_file_ops;
-               id->proc_entries[i] = pde;
+               id->debugfs_entries[i] = pde;
        }
        spin_unlock_irqrestore(&id->lock, flags);
-      out:
+out:
        return rc;
 }
 
@@ -974,7 +1110,8 @@ int debug_register_view(debug_info_t * id, struct debug_view *view)
  * debug_unregister_view:
  */
 
-int debug_unregister_view(debug_info_t * id, struct debug_view *view)
+int
+debug_unregister_view(debug_info_t * id, struct debug_view *view)
 {
        int rc = 0;
        int i;
@@ -990,15 +1127,46 @@ int debug_unregister_view(debug_info_t * id, struct debug_view *view)
        if (i == DEBUG_MAX_VIEWS)
                rc = -1;
        else {
-#ifdef CONFIG_PROC_FS
-               remove_proc_entry(id->proc_entries[i]->name,
-                                 id->proc_root_entry);
-#endif
+               debugfs_remove(id->debugfs_entries[i]);
                id->views[i] = NULL;
                rc = 0;
        }
        spin_unlock_irqrestore(&id->lock, flags);
-      out:
+out:
+       return rc;
+}
+
+static inline char *
+debug_get_user_string(const char __user *user_buf, size_t user_len)
+{
+       char* buffer;
+
+       buffer = kmalloc(user_len + 1, GFP_KERNEL);
+       if (!buffer)
+               return ERR_PTR(-ENOMEM);
+       if (copy_from_user(buffer, user_buf, user_len) != 0) {
+               kfree(buffer);
+               return ERR_PTR(-EFAULT);
+       }
+       /* got the string, now strip linefeed. */
+       if (buffer[user_len - 1] == '\n')
+               buffer[user_len - 1] = 0;
+       else
+               buffer[user_len] = 0;
+        return buffer;
+}
+
+static inline int
+debug_get_uint(char *buf)
+{
+       int rc;
+
+       for(; isspace(*buf); buf++);
+       rc = simple_strtoul(buf, &buf, 10);
+       if(*buf){
+               printk("debug: no integer specified!\n");
+               rc = -EINVAL;
+       }
        return rc;
 }
 
@@ -1011,13 +1179,69 @@ int debug_unregister_view(debug_info_t * id, struct debug_view *view)
  * prints out actual debug level
  */
 
-static int debug_prolog_level_fn(debug_info_t * id,
+static int
+debug_prolog_pages_fn(debug_info_t * id,
                                 struct debug_view *view, char *out_buf)
+{
+       return sprintf(out_buf, "%i\n", id->pages_per_area);
+}
+
+/*
+ * reads new size (number of pages per debug area)
+ */
+
+static int
+debug_input_pages_fn(debug_info_t * id, struct debug_view *view,
+                       struct file *file, const char __user *user_buf,
+                       size_t user_len, loff_t * offset)
+{
+       char *str;
+       int rc,new_pages;
+
+       if (user_len > 0x10000)
+                user_len = 0x10000;
+       if (*offset != 0){
+               rc = -EPIPE;
+               goto out;
+       }
+       str = debug_get_user_string(user_buf,user_len);
+       if(IS_ERR(str)){
+               rc = PTR_ERR(str);
+               goto out;
+       }
+       new_pages = debug_get_uint(str);
+       if(new_pages < 0){
+               rc = -EINVAL;
+               goto free_str;
+       }
+       rc = debug_set_size(id,id->nr_areas, new_pages);
+       if(rc != 0){
+               rc = -EINVAL;
+               goto free_str;
+       }
+       rc = user_len;
+free_str:
+       kfree(str);
+out:
+       *offset += user_len;
+       return rc;              /* number of input characters */
+}
+
+/*
+ * prints out actual debug level
+ */
+
+static int
+debug_prolog_level_fn(debug_info_t * id, struct debug_view *view, char *out_buf)
 {
        int rc = 0;
 
-       if(id->level == -1) rc = sprintf(out_buf,"-\n");
-       else rc = sprintf(out_buf, "%i\n", id->level);
+       if(id->level == DEBUG_OFF_LEVEL) {
+               rc = sprintf(out_buf,"-\n");
+       }
+       else {
+               rc = sprintf(out_buf, "%i\n", id->level);
+       }
        return rc;
 }
 
@@ -1025,30 +1249,43 @@ static int debug_prolog_level_fn(debug_info_t * id,
  * reads new debug level
  */
 
-static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
-                               struct file *file, const char __user *user_buf,
-                               size_t in_buf_size, loff_t * offset)
+static int
+debug_input_level_fn(debug_info_t * id, struct debug_view *view,
+                       struct file *file, const char __user *user_buf,
+                       size_t user_len, loff_t * offset)
 {
-       char input_buf[1];
-       int rc = in_buf_size;
+       char *str;
+       int rc,new_level;
 
-       if (*offset != 0)
+       if (user_len > 0x10000)
+                user_len = 0x10000;
+       if (*offset != 0){
+               rc = -EPIPE;
                goto out;
-       if (copy_from_user(input_buf, user_buf, 1)){
-               rc = -EFAULT;
+       }
+       str = debug_get_user_string(user_buf,user_len);
+       if(IS_ERR(str)){
+               rc = PTR_ERR(str);
                goto out;
        }
-       if (isdigit(input_buf[0])) {
-               int new_level = ((int) input_buf[0] - (int) '0');
-               debug_set_level(id, new_level);
-       } else if(input_buf[0] == '-') {
+       if(str[0] == '-'){
                debug_set_level(id, DEBUG_OFF_LEVEL);
+               rc = user_len;
+               goto free_str;
        } else {
-               printk(KERN_INFO "debug: level `%c` is not valid\n",
-                      input_buf[0]);
+               new_level = debug_get_uint(str);
        }
-      out:
-       *offset += in_buf_size;
+       if(new_level < 0) {
+               printk(KERN_INFO "debug: level `%s` is not valid\n", str);
+               rc = -EINVAL;
+       } else {
+               debug_set_level(id, new_level);
+               rc = user_len;
+       }
+free_str:
+       kfree(str);
+out:
+       *offset += user_len;
        return rc;              /* number of input characters */
 }
 
@@ -1057,29 +1294,36 @@ static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
  * flushes debug areas
  */
  
-void debug_flush(debug_info_t* id, int area)
+void
+debug_flush(debug_info_t* id, int area)
 {
         unsigned long flags;
-        int i;
+        int i,j;
 
-        if(!id)
+        if(!id || !id->areas)
                 return;
         spin_lock_irqsave(&id->lock,flags);
         if(area == DEBUG_FLUSH_ALL){
                 id->active_area = 0;
-                memset(id->active_entry, 0, id->nr_areas * sizeof(int));
-                for (i = 0; i < id->nr_areas; i++) 
-                        memset(id->areas[i], 0, PAGE_SIZE << id->page_order);
+                memset(id->active_entries, 0, id->nr_areas * sizeof(int));
+                for (i = 0; i < id->nr_areas; i++) {
+                       id->active_pages[i] = 0;
+                       for(j = 0; j < id->pages_per_area; j++) {
+                               memset(id->areas[i][j], 0, PAGE_SIZE);
+                       }
+               }
                 printk(KERN_INFO "debug: %s: all areas flushed\n",id->name);
         } else if(area >= 0 && area < id->nr_areas) {
-                id->active_entry[area] = 0;
-                memset(id->areas[area], 0, PAGE_SIZE << id->page_order);
-                printk(KERN_INFO
-                        "debug: %s: area %i has been flushed\n",
+                id->active_entries[area] = 0;
+               id->active_pages[area] = 0;
+               for(i = 0; i < id->pages_per_area; i++) {
+                       memset(id->areas[area][i],0,PAGE_SIZE);
+               }
+                printk(KERN_INFO "debug: %s: area %i has been flushed\n",
                         id->name, area);
         } else {
                 printk(KERN_INFO
-                        "debug: %s: area %i cannot be flushed (range: %i - %i)\n",
+                      "debug: %s: area %i cannot be flushed (range: %i - %i)\n",
                         id->name, area, 0, id->nr_areas-1);
         }
         spin_unlock_irqrestore(&id->lock,flags);
@@ -1089,15 +1333,20 @@ void debug_flush(debug_info_t* id, int area)
  * view function: flushes debug areas 
  */
 
-static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
-                                struct file *file, const char __user *user_buf,
-                                size_t in_buf_size, loff_t * offset)
+static int
+debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
+                       struct file *file, const char __user *user_buf,
+                       size_t user_len, loff_t * offset)
 {
         char input_buf[1];
-        int rc = in_buf_size;
-        if (*offset != 0)
+        int rc = user_len;
+
+       if (user_len > 0x10000)
+                user_len = 0x10000;
+        if (*offset != 0){
+               rc = -EPIPE;
                 goto out;
+       }
         if (copy_from_user(input_buf, user_buf, 1)){
                 rc = -EFAULT;
                 goto out;
@@ -1114,8 +1363,8 @@ static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
 
         printk(KERN_INFO "debug: area `%c` is not valid\n", input_buf[0]);
 
-      out:
-        *offset += in_buf_size;
+out:
+        *offset += user_len;
         return rc;              /* number of input characters */
 }
 
@@ -1123,8 +1372,9 @@ static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
  * prints debug header in raw format
  */
 
-int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
-                         int area, debug_entry_t * entry, char *out_buf)
+static int
+debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
+                       int area, debug_entry_t * entry, char *out_buf)
 {
         int rc;
 
@@ -1137,7 +1387,8 @@ int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
  * prints debug data in raw format
  */
 
-static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
+static int
+debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
                               char *out_buf, const char *in_buf)
 {
        int rc;
@@ -1151,8 +1402,9 @@ static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
  * prints debug data in hex/ascii format
  */
 
-static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
-                                 char *out_buf, const char *in_buf)
+static int
+debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+                         char *out_buf, const char *in_buf)
 {
        int i, rc = 0;
 
@@ -1176,7 +1428,8 @@ static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
  * prints header for debug entry
  */
 
-int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
+int
+debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
                         int area, debug_entry_t * entry, char *out_buf)
 {
        struct timeval time_val;
@@ -1210,8 +1463,9 @@ int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
 
 #define DEBUG_SPRINTF_MAX_ARGS 10
 
-int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
-                            char *out_buf, debug_sprintf_entry_t *curr_event)
+static int
+debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
+                        char *out_buf, debug_sprintf_entry_t *curr_event)
 {
        int num_longs, num_used_args = 0,i, rc = 0;
        int index[DEBUG_SPRINTF_MAX_ARGS];
@@ -1251,14 +1505,10 @@ out:
 /*
  * clean up module
  */
-void __exit debug_exit(void)
+void
+__exit debug_exit(void)
 {
-#ifdef DEBUG
-       printk("debug_cleanup_module: \n");
-#endif
-#ifdef CONFIG_PROC_FS
-       remove_proc_entry(debug_proc_root_entry->name, NULL);
-#endif /* CONFIG_PROC_FS */
+       debugfs_remove(debug_debugfs_root_entry);
        unregister_sysctl_table(s390dbf_sysctl_header);
        return;
 }
@@ -1266,7 +1516,7 @@ void __exit debug_exit(void)
 /*
  * module definitions
  */
-core_initcall(debug_init);
+postcore_initcall(debug_init);
 module_exit(debug_exit);
 MODULE_LICENSE("GPL");
 
index c0e09b33febe6fc265cc8a30a0a0bda6c7891e45..5b262b5d869f7625f5262b2e0d50137838a37aa1 100644 (file)
@@ -7,6 +7,7 @@
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  *               Hartmut Penner (hp@de.ibm.com),
  *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *              Heiko Carstens <heiko.carstens@de.ibm.com>
  */
 
 #include <linux/sys.h>
@@ -49,9 +50,9 @@ SP_ILC       =  STACK_FRAME_OVERHEAD + __PT_ILC
 SP_TRAP      =  STACK_FRAME_OVERHEAD + __PT_TRAP
 SP_SIZE      =  STACK_FRAME_OVERHEAD + __PT_SIZE
 
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING | \
                 _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
 
 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
 STACK_SIZE  = 1 << STACK_SHIFT
@@ -121,7 +122,11 @@ STACK_SIZE  = 1 << STACK_SHIFT
        bz      BASED(stack_overflow)
 3:
 #endif
-2:     s       %r15,BASED(.Lc_spsize)  # make room for registers & psw
+2:
+       .endm
+
+       .macro  CREATE_STACK_FRAME psworg,savearea
+       s       %r15,BASED(.Lc_spsize)  # make room for registers & psw
        mvc     SP_PSW(8,%r15),0(%r12)  # move user PSW to stack
        la      %r12,\psworg
        st      %r2,SP_ORIG_R2(%r15)    # store original content of gpr 2
@@ -161,6 +166,13 @@ __switch_to_base:
         be      __switch_to_noper-__switch_to_base(%r1)        # we got away w/o bashing TLB's
         lctl    %c9,%c11,__THREAD_per(%r3)     # Nope we didn't
 __switch_to_noper:
+       l       %r4,__THREAD_info(%r2)          # get thread_info of prev
+       tm      __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending?
+       bz      __switch_to_no_mcck-__switch_to_base(%r1)
+       ni      __TI_flags+3(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
+       l       %r4,__THREAD_info(%r3)          # get thread_info of next
+       oi      __TI_flags+3(%r4),_TIF_MCCK_PENDING # set it in next
+__switch_to_no_mcck:
         stm     %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
        st      %r15,__THREAD_ksp(%r2)  # store kernel stack to prev->tss.ksp
        l       %r15,__THREAD_ksp(%r3)  # load kernel stack from next->tss.ksp
@@ -185,6 +197,7 @@ system_call:
 sysc_saveall:
        SAVE_ALL_BASE __LC_SAVE_AREA
         SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        lh      %r7,0x8a          # get svc number from lowcore
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 sysc_vtime:
@@ -234,6 +247,8 @@ sysc_work_loop:
 # One of the work bits is on. Find out which one.
 #
 sysc_work:
+       tm      __TI_flags+3(%r9),_TIF_MCCK_PENDING
+       bo      BASED(sysc_mcck_pending)
        tm      __TI_flags+3(%r9),_TIF_NEED_RESCHED
        bo      BASED(sysc_reschedule)
        tm      __TI_flags+3(%r9),_TIF_SIGPENDING
@@ -252,6 +267,14 @@ sysc_reschedule:
        la      %r14,BASED(sysc_work_loop)
        br      %r1                    # call scheduler
 
+#
+# _TIF_MCCK_PENDING is set, call handler
+#
+sysc_mcck_pending:
+       l       %r1,BASED(.Ls390_handle_mcck)
+       la      %r14,BASED(sysc_work_loop)
+       br      %r1                     # TIF bit will be cleared by handler
+
 #
 # _TIF_SIGPENDING is set, call do_signal
 #
@@ -430,6 +453,7 @@ pgm_check_handler:
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         bnz     BASED(pgm_per)           # got per exception -> special case
        SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        bz      BASED(pgm_no_vtime)
@@ -468,6 +492,7 @@ pgm_per:
 #
 pgm_per_std:
        SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        bz      BASED(pgm_no_vtime2)
@@ -493,6 +518,7 @@ pgm_no_vtime2:
 #
 pgm_svcper:
        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        bz      BASED(pgm_no_vtime3)
@@ -521,6 +547,7 @@ io_int_handler:
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+16
         SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0
+       CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+16
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        bz      BASED(io_no_vtime)
@@ -578,15 +605,25 @@ io_work:
        lr      %r15,%r1
 #
 # One of the work bits is on. Find out which one.
-# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED
+# Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED and _TIF_MCCK_PENDING
 #
 io_work_loop:
+       tm      __TI_flags+3(%r9),_TIF_MCCK_PENDING
+       bo      BASED(io_mcck_pending)
        tm      __TI_flags+3(%r9),_TIF_NEED_RESCHED
        bo      BASED(io_reschedule)
        tm      __TI_flags+3(%r9),_TIF_SIGPENDING
        bo      BASED(io_sigpending)
        b       BASED(io_leave)
 
+#
+# _TIF_MCCK_PENDING is set, call handler
+#
+io_mcck_pending:
+       l       %r1,BASED(.Ls390_handle_mcck)
+       l       %r14,BASED(io_work_loop)
+       br      %r1                    # TIF bit will be cleared by handler
+
 #
 # _TIF_NEED_RESCHED is set, call schedule
 #      
@@ -621,6 +658,7 @@ ext_int_handler:
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+16
         SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0
+       CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        bz      BASED(ext_no_vtime)
@@ -642,19 +680,62 @@ ext_no_vtime:
 
         .globl mcck_int_handler
 mcck_int_handler:
-       STORE_TIMER __LC_ASYNC_ENTER_TIMER
+       spt     __LC_CPU_TIMER_SAVE_AREA        # revalidate cpu timer
+       lm      %r0,%r15,__LC_GPREGS_SAVE_AREA  # revalidate gprs
        SAVE_ALL_BASE __LC_SAVE_AREA+32
-        SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32,0
+       la      %r12,__LC_MCK_OLD_PSW
+       tm      __LC_MCCK_CODE,0x80     # system damage?
+       bo      BASED(mcck_int_main)    # yes -> rest of mcck code invalid
+       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
+       bo      BASED(0f)
+       spt     __LC_LAST_UPDATE_TIMER  # revalidate cpu timer
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_EXIT_TIMER
+0:     tm      __LC_MCCK_CODE+2,0x08   # mwp of old psw valid?
+       bno     BASED(mcck_no_vtime)    # no -> skip cleanup critical
+       tm      __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
        bz      BASED(mcck_no_vtime)
        UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
        UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
        mvc     __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
 mcck_no_vtime:
 #endif
+0:
+       tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
+       bno     BASED(mcck_int_main)    # no -> skip cleanup critical
+       tm      __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
+       bnz     BASED(mcck_int_main)    # from user -> load async stack
+       clc     __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_end)
+       bhe     BASED(mcck_int_main)
+       clc     __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_start)
+       bl      BASED(mcck_int_main)
+       l       %r14,BASED(.Lcleanup_critical)
+       basr    %r14,%r14
+mcck_int_main:
+       l       %r14,__LC_PANIC_STACK   # are we already on the panic stack?
+       slr     %r14,%r15
+       sra     %r14,PAGE_SHIFT
+       be      BASED(0f)
+       l       %r15,__LC_PANIC_STACK   # load panic stack
+0:     CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32
+       l       %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
+       la      %r2,SP_PTREGS(%r15)     # load pt_regs
        l       %r1,BASED(.Ls390_mcck)
-       basr    %r14,%r1          # call machine check handler
+       basr    %r14,%r1                # call machine check handler
+       tm      SP_PSW+1(%r15),0x01     # returning to user ?
+       bno     BASED(mcck_return)
+       l       %r1,__LC_KERNEL_STACK   # switch to kernel stack
+       s       %r1,BASED(.Lc_spsize)
+       mvc     SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+       xc      __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+       lr      %r15,%r1
+       stosm   __SF_EMPTY(%r15),0x04   # turn dat on
+       tm      __TI_flags+3(%r9),_TIF_MCCK_PENDING
+       bno     BASED(mcck_return)
+       l       %r1,BASED(.Ls390_handle_mcck)
+       basr    %r14,%r1                # call machine check handler
 mcck_return:
         RESTORE_ALL 0
 
@@ -742,7 +823,7 @@ cleanup_critical:
        clc     4(4,%r12),BASED(cleanup_table_sysc_work_loop)
        bl      BASED(0f)
        clc     4(4,%r12),BASED(cleanup_table_sysc_work_loop+4)
-       bl      BASED(cleanup_sysc_leave)
+       bl      BASED(cleanup_sysc_return)
 0:
        br      %r14
 
@@ -760,6 +841,7 @@ cleanup_system_call:
        mvc     __LC_SAVE_AREA(16),__LC_SAVE_AREA+16
 0:     st      %r13,__LC_SAVE_AREA+20
        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        st      %r15,__LC_SAVE_AREA+28
        lh      %r7,0x8a
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -834,6 +916,8 @@ cleanup_sysc_leave_insn:
  * Symbol constants
  */
 .Ls390_mcck:   .long  s390_do_machine_check
+.Ls390_handle_mcck:
+              .long  s390_handle_mcck
 .Ldo_IRQ:      .long  do_IRQ
 .Ldo_extint:   .long  do_extint
 .Ldo_signal:   .long  do_signal
index 51527ab8c8f974b646fe92e599fc513fefc869d3..57ca75d0ad7f4af184d9003f6dfb7b3e7513e306 100644 (file)
@@ -7,6 +7,7 @@
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  *               Hartmut Penner (hp@de.ibm.com),
  *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *              Heiko Carstens <heiko.carstens@de.ibm.com>
  */
 
 #include <linux/sys.h>
@@ -52,9 +53,9 @@ SP_SIZE      =  STACK_FRAME_OVERHEAD + __PT_SIZE
 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
 STACK_SIZE  = 1 << STACK_SHIFT
 
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING | \
                 _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
 
 #define BASED(name) name-system_call(%r13)
 
@@ -114,7 +115,11 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
        jz      stack_overflow
 3:
 #endif
-2:     aghi    %r15,-SP_SIZE           # make room for registers & psw
+2:
+       .endm
+
+       .macro  CREATE_STACK_FRAME psworg,savearea
+       aghi    %r15,-SP_SIZE           # make room for registers & psw
        mvc     SP_PSW(16,%r15),0(%r12) # move user PSW to stack
        la      %r12,\psworg
        stg     %r2,SP_ORIG_R2(%r15)    # store original content of gpr 2
@@ -152,6 +157,13 @@ __switch_to:
         je      __switch_to_noper            # we got away without bashing TLB's
         lctlg   %c9,%c11,__THREAD_per(%r3)     # Nope we didn't
 __switch_to_noper:
+       lg      %r4,__THREAD_info(%r2)              # get thread_info of prev
+       tm      __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending?
+       jz      __switch_to_no_mcck
+       ni      __TI_flags+7(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
+       lg      %r4,__THREAD_info(%r3)              # get thread_info of next
+       oi      __TI_flags+7(%r4),_TIF_MCCK_PENDING # set it in next
+__switch_to_no_mcck:
         stmg    %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
        stg     %r15,__THREAD_ksp(%r2)  # store kernel stack to prev->tss.ksp
        lg      %r15,__THREAD_ksp(%r3)  # load kernel stack from next->tss.ksp
@@ -176,6 +188,7 @@ system_call:
 sysc_saveall:
        SAVE_ALL_BASE __LC_SAVE_AREA
         SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        llgh    %r7,__LC_SVC_INT_CODE # get svc number from lowcore
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 sysc_vtime:
@@ -232,6 +245,8 @@ sysc_work_loop:
 # One of the work bits is on. Find out which one.
 #
 sysc_work:
+       tm      __TI_flags+7(%r9),_TIF_MCCK_PENDING
+       jo      sysc_mcck_pending
        tm      __TI_flags+7(%r9),_TIF_NEED_RESCHED
        jo      sysc_reschedule
        tm      __TI_flags+7(%r9),_TIF_SIGPENDING
@@ -249,6 +264,13 @@ sysc_reschedule:
        larl    %r14,sysc_work_loop
         jg      schedule            # return point is sysc_return
 
+#
+# _TIF_MCCK_PENDING is set, call handler
+#
+sysc_mcck_pending:
+       larl    %r14,sysc_work_loop
+       jg      s390_handle_mcck    # TIF bit will be cleared by handler
+
 #
 # _TIF_SIGPENDING is set, call do_signal
 #
@@ -474,6 +496,7 @@ pgm_check_handler:
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         jnz     pgm_per                  # got per exception -> special case
        SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        jz      pgm_no_vtime
@@ -512,6 +535,7 @@ pgm_per:
 #
 pgm_per_std:
        SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        jz      pgm_no_vtime2
@@ -537,6 +561,7 @@ pgm_no_vtime2:
 #
 pgm_svcper:
        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        jz      pgm_no_vtime3
@@ -564,6 +589,7 @@ io_int_handler:
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+32
         SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0
+       CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+32
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        jz      io_no_vtime
@@ -621,15 +647,24 @@ io_work:
        lgr     %r15,%r1
 #
 # One of the work bits is on. Find out which one.
-# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED
+# Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED and _TIF_MCCK_PENDING
 #
 io_work_loop:
+       tm      __TI_flags+7(%r9),_TIF_MCCK_PENDING
+       jo      io_mcck_pending
        tm      __TI_flags+7(%r9),_TIF_NEED_RESCHED
        jo      io_reschedule
        tm      __TI_flags+7(%r9),_TIF_SIGPENDING
        jo      io_sigpending
        j       io_leave
 
+#
+# _TIF_MCCK_PENDING is set, call handler
+#
+io_mcck_pending:
+       larl    %r14,io_work_loop
+       jg      s390_handle_mcck        # TIF bit will be cleared by handler
+
 #
 # _TIF_NEED_RESCHED is set, call schedule
 #      
@@ -661,6 +696,7 @@ ext_int_handler:
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+32
         SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0
+       CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        jz      ext_no_vtime
@@ -680,18 +716,60 @@ ext_no_vtime:
  */
         .globl mcck_int_handler
 mcck_int_handler:
-       STORE_TIMER __LC_ASYNC_ENTER_TIMER
+       la      %r1,4095                # revalidate r1
+       spt     __LC_CPU_TIMER_SAVE_AREA-4095(%r1)      # revalidate cpu timer
+       lmg     %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
        SAVE_ALL_BASE __LC_SAVE_AREA+64
-        SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64,0
+       la      %r12,__LC_MCK_OLD_PSW
+       tm      __LC_MCCK_CODE,0x80     # system damage?
+       jo      mcck_int_main           # yes -> rest of mcck code invalid
+       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
+       jo      0f
+       spt     __LC_LAST_UPDATE_TIMER
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_EXIT_TIMER
+0:     tm      __LC_MCCK_CODE+2,0x08   # mwp of old psw valid?
+       jno     mcck_no_vtime           # no -> no timer update
+       tm      __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
        jz      mcck_no_vtime
        UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
        UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
        mvc     __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
 mcck_no_vtime:
 #endif
-       brasl   %r14,s390_do_machine_check
+0:
+       tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
+       jno     mcck_int_main           # no -> skip cleanup critical
+       tm      __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
+       jnz     mcck_int_main           # from user -> load kernel stack
+       clc     __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_end)
+       jhe     mcck_int_main
+       clc     __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_start)
+       jl      mcck_int_main
+       brasl   %r14,cleanup_critical
+mcck_int_main:
+       lg      %r14,__LC_PANIC_STACK   # are we already on the panic stack?
+       slgr    %r14,%r15
+       srag    %r14,%r14,PAGE_SHIFT
+       jz      0f
+       lg      %r15,__LC_PANIC_STACK   # load panic stack
+0:     CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64
+       lg      %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
+       la      %r2,SP_PTREGS(%r15)     # load pt_regs
+       brasl   %r14,s390_do_machine_check
+       tm      SP_PSW+1(%r15),0x01     # returning to user ?
+       jno     mcck_return
+       lg      %r1,__LC_KERNEL_STACK   # switch to kernel stack
+       aghi    %r1,-SP_SIZE
+       mvc     SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+       xc      __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+       lgr     %r15,%r1
+       stosm   __SF_EMPTY(%r15),0x04   # turn dat on
+       tm      __TI_flags+7(%r9),_TIF_MCCK_PENDING
+       jno     mcck_return
+       brasl   %r14,s390_handle_mcck
 mcck_return:
         RESTORE_ALL 0
 
@@ -775,7 +853,7 @@ cleanup_critical:
        clc     8(8,%r12),BASED(cleanup_table_sysc_work_loop)
        jl      0f
        clc     8(8,%r12),BASED(cleanup_table_sysc_work_loop+8)
-       jl      cleanup_sysc_leave
+       jl      cleanup_sysc_return
 0:
        br      %r14
 
@@ -793,6 +871,7 @@ cleanup_system_call:
        mvc     __LC_SAVE_AREA(32),__LC_SAVE_AREA+32
 0:     stg     %r13,__LC_SAVE_AREA+40
        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        stg     %r15,__LC_SAVE_AREA+56
        llgh    %r7,__LC_SVC_INT_CODE
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
new file mode 100644 (file)
index 0000000..2721c3a
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * arch/s390/kernel/machine_kexec.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *
+ */
+
+/*
+ * s390_machine_kexec.c - handle the transition of Linux booting another kernel
+ * on the S390 architecture.
+ */
+
+#include <asm/cio.h>
+#include <asm/setup.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/system.h>
+
+static void kexec_halt_all_cpus(void *);
+
+typedef void (*relocate_kernel_t) (kimage_entry_t *, unsigned long);
+
+const extern unsigned char relocate_kernel[];
+const extern unsigned long long relocate_kernel_len;
+
+int
+machine_kexec_prepare(struct kimage *image)
+{
+       unsigned long reboot_code_buffer;
+
+       /* We don't support anything but the default image type for now. */
+       if (image->type != KEXEC_TYPE_DEFAULT)
+               return -EINVAL;
+
+       /* Get the destination where the assembler code should be copied to.*/
+       reboot_code_buffer = page_to_pfn(image->control_code_page)<<PAGE_SHIFT;
+
+       /* Then copy it */
+       memcpy((void *) reboot_code_buffer, relocate_kernel,
+              relocate_kernel_len);
+       return 0;
+}
+
+void
+machine_kexec_cleanup(struct kimage *image)
+{
+}
+
+void
+machine_shutdown(void)
+{
+       printk(KERN_INFO "kexec: machine_shutdown called\n");
+}
+
+NORET_TYPE void
+machine_kexec(struct kimage *image)
+{
+       clear_all_subchannels();
+
+       /* Disable lowcore protection */
+       ctl_clear_bit(0,28);
+
+       on_each_cpu(kexec_halt_all_cpus, image, 0, 0);
+       for (;;);
+}
+
+static void
+kexec_halt_all_cpus(void *kernel_image)
+{
+       static atomic_t cpuid = ATOMIC_INIT(-1);
+       int cpu;
+       struct kimage *image;
+       relocate_kernel_t data_mover;
+
+       if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid))
+               signal_processor(smp_processor_id(), sigp_stop);
+
+       /* Wait for all other cpus to enter stopped state */
+       for_each_online_cpu(cpu) {
+               if (cpu == smp_processor_id())
+                       continue;
+               while (!smp_cpu_not_running(cpu))
+                       cpu_relax();
+       }
+
+       image = (struct kimage *) kernel_image;
+       data_mover = (relocate_kernel_t)
+               (page_to_pfn(image->control_code_page) << PAGE_SHIFT);
+
+       /* Call the moving routine */
+       (*data_mover) (&image->head, image->start);
+}
index 7aea25d6e3003744758cc62542b56e3a5a8ef2c8..9f3dff6c0b72286a7c769787dcb0d9046bc29d93 100644 (file)
@@ -91,13 +91,12 @@ void do_monitor_call(struct pt_regs *regs, long interruption_code)
                            (void *)(long) smp_processor_id());
 }
 
+extern void s390_handle_mcck(void);
 /*
  * The idle loop on a S390...
  */
 void default_idle(void)
 {
-       psw_t wait_psw;
-       unsigned long reg;
        int cpu, rc;
 
        local_irq_disable();
@@ -125,38 +124,17 @@ void default_idle(void)
                cpu_die();
 #endif
 
-       /* 
-        * Wait for external, I/O or machine check interrupt and
-        * switch off machine check bit after the wait has ended.
-        */
-       wait_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK | PSW_MASK_WAIT |
-               PSW_MASK_IO | PSW_MASK_EXT;
-#ifndef CONFIG_ARCH_S390X
-       asm volatile (
-               "    basr %0,0\n"
-               "0:  la   %0,1f-0b(%0)\n"
-               "    st   %0,4(%1)\n"
-               "    oi   4(%1),0x80\n"
-               "    lpsw 0(%1)\n"
-               "1:  la   %0,2f-1b(%0)\n"
-               "    st   %0,4(%1)\n"
-               "    oi   4(%1),0x80\n"
-               "    ni   1(%1),0xf9\n"
-               "    lpsw 0(%1)\n"
-               "2:"
-               : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
-#else /* CONFIG_ARCH_S390X */
-       asm volatile (
-               "    larl  %0,0f\n"
-               "    stg   %0,8(%1)\n"
-               "    lpswe 0(%1)\n"
-               "0:  larl  %0,1f\n"
-               "    stg   %0,8(%1)\n"
-               "    ni    1(%1),0xf9\n"
-               "    lpswe 0(%1)\n"
-               "1:"
-               : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
-#endif /* CONFIG_ARCH_S390X */
+       local_mcck_disable();
+       if (test_thread_flag(TIF_MCCK_PENDING)) {
+               local_mcck_enable();
+               local_irq_enable();
+               s390_handle_mcck();
+               return;
+       }
+
+       /* Wait for external, I/O or machine check interrupt. */
+       __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT |
+                       PSW_MASK_IO | PSW_MASK_EXT);
 }
 
 void cpu_idle(void)
diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S
new file mode 100644 (file)
index 0000000..d5e4a62
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * arch/s390/kernel/relocate_kernel.S
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *
+ */
+
+/*
+ * moves the new kernel to its destination...
+ * %r2 = pointer to first kimage_entry_t
+ * %r3 = start address - where to jump to after the job is done...
+ *
+ * %r5 will be used as temp. storage
+ * %r6 holds the destination address
+ * %r7 = PAGE_SIZE
+ * %r8 holds the source address
+ * %r9 = PAGE_SIZE
+ * %r10 is a page mask
+ */
+
+       .text
+       .globl          relocate_kernel
+       relocate_kernel:
+               basr    %r13,0          #base address
+       .base:
+               spx     zero64-.base(%r13)      #absolute addressing mode
+               stnsm   sys_msk-.base(%r13),0xf8        #disable DAT and IRQ (external)
+               lhi     %r10,-1         #preparing the mask
+               sll     %r10,12         #shift it such that it becomes 0xf000
+       .top:
+               lhi     %r7,4096        #load PAGE_SIZE in r7
+               lhi     %r9,4096        #load PAGE_SIZE in r9
+               l       %r5,0(%r2)      #read another word for indirection page
+               ahi     %r2,4           #increment pointer
+               tml     %r5,0x1         #is it a destination page?
+               je      .indir_check    #NO, goto "indir_check"
+               lr      %r6,%r5         #r6 = r5
+               nr      %r6,%r10        #mask it out and...
+               j       .top            #...next iteration
+       .indir_check:
+               tml     %r5,0x2         #is it a indirection page?
+               je      .done_test      #NO, goto "done_test"
+               nr      %r5,%r10        #YES, mask out,
+               lr      %r2,%r5         #move it into the right register,
+               j       .top            #and read next...
+       .done_test:
+               tml     %r5,0x4         #is it the done indicator?
+               je      .source_test    #NO! Well, then it should be the source indicator...
+               j       .done           #ok, lets finish it here...
+       .source_test:
+               tml     %r5,0x8         #it should be a source indicator...
+               je      .top            #NO, ignore it...
+               lr      %r8,%r5         #r8 = r5
+               nr      %r8,%r10        #masking
+       0:      mvcle   %r6,%r8,0x0     #copy PAGE_SIZE bytes from r8 to r6 - pad with 0
+               jo      0b
+               j       .top
+       .done:
+               sr      %r0,%r0         #clear register r0
+               la      %r4,load_psw-.base(%r13)        #load psw-address into the register
+               o       %r3,4(%r4)      #or load address into psw
+               st      %r3,4(%r4)
+               mvc     0(8,%r0),0(%r4) #copy psw to absolute address 0
+               sr      %r1,%r1         #clear %r1
+               sr      %r2,%r2         #clear %r2
+               sigp    %r1,%r2,0x12    #set cpuid to zero
+               lpsw    0               #hopefully start new kernel...
+
+               .align  8
+       zero64:
+               .quad   0
+       load_psw:
+               .long   0x00080000,0x80000000
+       sys_msk:
+               .quad   0
+       relocate_kernel_end:
+       .globl  relocate_kernel_len
+       relocate_kernel_len:
+               .quad   relocate_kernel_end - relocate_kernel
diff --git a/arch/s390/kernel/relocate_kernel64.S b/arch/s390/kernel/relocate_kernel64.S
new file mode 100644 (file)
index 0000000..96290cc
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * arch/s390/kernel/relocate_kernel64.S
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *
+ */
+
+/*
+ * moves the new kernel to its destination...
+ * %r2 = pointer to first kimage_entry_t
+ * %r3 = start address - where to jump to after the job is done...
+ *
+ * %r5 will be used as temp. storage
+ * %r6 holds the destination address
+ * %r7 = PAGE_SIZE
+ * %r8 holds the source address
+ * %r9 = PAGE_SIZE
+ *
+ * 0xf000 is a page_mask
+ */
+
+       .text
+       .globl          relocate_kernel
+       relocate_kernel:
+               basr    %r13,0          #base address
+       .base:
+               spx     zero64-.base(%r13)      #absolute addressing mode
+               stnsm   sys_msk-.base(%r13),0xf8        #disable DAT and IRQ (external)
+       .top:
+               lghi    %r7,4096        #load PAGE_SIZE in r7
+               lghi    %r9,4096        #load PAGE_SIZE in r9
+               lg      %r5,0(%r2)      #read another word for indirection page
+               aghi    %r2,8           #increment pointer
+               tml     %r5,0x1         #is it a destination page?
+               je      .indir_check    #NO, goto "indir_check"
+               lgr     %r6,%r5         #r6 = r5
+               nill    %r6,0xf000      #mask it out and...
+               j       .top            #...next iteration
+       .indir_check:
+               tml     %r5,0x2         #is it a indirection page?
+               je      .done_test      #NO, goto "done_test"
+               nill    %r5,0xf000      #YES, mask out,
+               lgr     %r2,%r5         #move it into the right register,
+               j       .top            #and read next...
+       .done_test:
+               tml     %r5,0x4         #is it the done indicator?
+               je      .source_test    #NO! Well, then it should be the source indicator...
+               j       .done           #ok, lets finish it here...
+       .source_test:
+               tml     %r5,0x8         #it should be a source indicator...
+               je      .top            #NO, ignore it...
+               lgr     %r8,%r5         #r8 = r5
+               nill    %r8,0xf000      #masking
+       0:      mvcle   %r6,%r8,0x0     #copy PAGE_SIZE bytes from r8 to r6 - pad with 0
+               jo      0b
+               j       .top
+       .done:
+               sgr     %r0,%r0         #clear register r0
+               la      %r4,load_psw-.base(%r13)        #load psw-address into the register
+               o       %r3,4(%r4)      #or load address into psw
+               st      %r3,4(%r4)
+               mvc     0(8,%r0),0(%r4) #copy psw to absolute address 0
+               sam31                   #31 bit mode
+               sr      %r1,%r1         #erase register r1
+               sr      %r2,%r2         #erase register r2
+               sigp    %r1,%r2,0x12    #set cpuid to zero
+               lpsw    0               #hopefully start new kernel...
+
+               .align  8
+       zero64:
+               .quad   0
+       load_psw:
+               .long   0x00080000,0x80000000
+       sys_msk:
+               .quad   0
+       relocate_kernel_end:
+       .globl  relocate_kernel_len
+       relocate_kernel_len:
+               .quad   relocate_kernel_end - relocate_kernel
+
index df83215beac34740263366f121b14d1ce6a0738c..b6d740ac0e6eedb8f0d1d7255b4d872463acc702 100644 (file)
@@ -198,11 +198,11 @@ static void __init conmode_default(void)
        char *ptr;
 
         if (MACHINE_IS_VM) {
-               __cpcmd("QUERY CONSOLE", query_buffer, 1024);
+               __cpcmd("QUERY CONSOLE", query_buffer, 1024, NULL);
                console_devno = simple_strtoul(query_buffer + 5, NULL, 16);
                ptr = strstr(query_buffer, "SUBCHANNEL =");
                console_irq = simple_strtoul(ptr + 13, NULL, 16);
-               __cpcmd("QUERY TERM", query_buffer, 1024);
+               __cpcmd("QUERY TERM", query_buffer, 1024, NULL);
                ptr = strstr(query_buffer, "CONMODE");
                /*
                 * Set the conmode to 3215 so that the device recognition 
@@ -211,7 +211,7 @@ static void __init conmode_default(void)
                 * 3215 and the 3270 driver will try to access the console
                 * device (3215 as console and 3270 as normal tty).
                 */
-               __cpcmd("TERM CONMODE 3215", NULL, 0);
+               __cpcmd("TERM CONMODE 3215", NULL, 0, NULL);
                if (ptr == NULL) {
 #if defined(CONFIG_SCLP_CONSOLE)
                        SET_CONSOLE_SCLP;
@@ -414,7 +414,8 @@ setup_lowcore(void)
        lc->program_new_psw.mask = PSW_KERNEL_BITS;
        lc->program_new_psw.addr =
                PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
-       lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
+       lc->mcck_new_psw.mask =
+               PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
        lc->mcck_new_psw.addr =
                PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
        lc->io_new_psw.mask = PSW_KERNEL_BITS;
@@ -424,12 +425,18 @@ setup_lowcore(void)
        lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
        lc->async_stack = (unsigned long)
                __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
-#ifdef CONFIG_CHECK_STACK
        lc->panic_stack = (unsigned long)
                __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE;
-#endif
        lc->current_task = (unsigned long) init_thread_union.thread_info.task;
        lc->thread_info = (unsigned long) &init_thread_union;
+#ifndef CONFIG_ARCH_S390X
+       if (MACHINE_HAS_IEEE) {
+               lc->extended_save_area_addr = (__u32)
+                       __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
+               /* enable extended save area */
+               ctl_set_bit(14, 29);
+       }
+#endif
 #ifdef CONFIG_ARCH_S390X
        if (MACHINE_HAS_DIAG44)
                lc->diag44_opcode = 0x83000044;
index fdfcf0488b49b3b8d94d21afaa7442b828565739..642572a8e334d435e988c935673437b666ceda95 100644 (file)
@@ -284,7 +284,7 @@ static void do_machine_restart(void * __unused)
         * locks are always held disabled).
         */
        if (MACHINE_IS_VM)
-               cpcmd ("IPL", NULL, 0);
+               cpcmd ("IPL", NULL, 0, NULL);
        else
                reipl (0x10000 | S390_lowcore.ipl_device);
 }
@@ -313,7 +313,7 @@ static void do_machine_halt(void * __unused)
        if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid) == 0) {
                smp_send_stop();
                if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
-                       cpcmd(vmhalt_cmd, NULL, 0);
+                       cpcmd(vmhalt_cmd, NULL, 0, NULL);
                signal_processor(smp_processor_id(),
                                 sigp_stop_and_store_status);
        }
@@ -332,7 +332,7 @@ static void do_machine_power_off(void * __unused)
        if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid) == 0) {
                smp_send_stop();
                if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
-                       cpcmd(vmpoff_cmd, NULL, 0);
+                       cpcmd(vmpoff_cmd, NULL, 0, NULL);
                signal_processor(smp_processor_id(),
                                 sigp_stop_and_store_status);
        }
@@ -679,12 +679,14 @@ __cpu_disable(void)
 {
        unsigned long flags;
        ec_creg_mask_parms cr_parms;
+       int cpu = smp_processor_id();
 
        spin_lock_irqsave(&smp_reserve_lock, flags);
-       if (smp_cpu_reserved[smp_processor_id()] != 0) {
+       if (smp_cpu_reserved[cpu] != 0) {
                spin_unlock_irqrestore(&smp_reserve_lock, flags);
                return -EBUSY;
        }
+       cpu_clear(cpu, cpu_online_map);
 
 #ifdef CONFIG_PFAULT
        /* Disable pfault pseudo page faults on this cpu. */
@@ -771,13 +773,24 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 
                *(lowcore_ptr[i]) = S390_lowcore;
                lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE);
-#ifdef CONFIG_CHECK_STACK
                stack = __get_free_pages(GFP_KERNEL,0);
                if (stack == 0ULL)
                        panic("smp_boot_cpus failed to allocate memory\n");
                lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE);
+#ifndef __s390x__
+               if (MACHINE_HAS_IEEE) {
+                       lowcore_ptr[i]->extended_save_area_addr =
+                               (__u32) __get_free_pages(GFP_KERNEL,0);
+                       if (lowcore_ptr[i]->extended_save_area_addr == 0)
+                               panic("smp_boot_cpus failed to "
+                                     "allocate memory\n");
+               }
 #endif
        }
+#ifndef __s390x__
+       if (MACHINE_HAS_IEEE)
+               ctl_set_bit(14, 29); /* enable extended save area */
+#endif
        set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]);
 
        for_each_cpu(cpu)
index 515938628f82c75a7d80367568e933cfc4e0783c..a8668afb5f87d2b5b3324a8dae1802eab7aedcdf 100644 (file)
@@ -285,7 +285,7 @@ SYSCALL(sys_mq_timedsend,sys_mq_timedsend,compat_sys_mq_timedsend_wrapper)
 SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive_wrapper)
 SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify_wrapper) /* 275 */
 SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr_wrapper)
-NI_SYSCALL                                                     /* reserved for kexec */
+SYSCALL(sys_kexec_load,sys_kexec_load,compat_sys_kexec_load_wrapper)
 SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper)
 SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper)
 SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl)               /* 280 */
index ca34b6f34b38e9efc78fc2a418d8390d9174233f..bc7b7be7acbe7b9858992e75fcc86309d59de79b 100644 (file)
@@ -735,7 +735,7 @@ void __init trap_init(void)
                                                    &ext_int_pfault);
 #endif
 #ifndef CONFIG_ARCH_S390X
-               cpcmd("SET PAGEX ON", NULL, 0);
+               cpcmd("SET PAGEX ON", NULL, 0, NULL);
 #endif
        }
 }
index 648deed17e25f8c2e39e97f01141bc0e09d496a2..c5348108ca3ce23e8da4a6681c32330ebad73122 100644 (file)
@@ -576,8 +576,8 @@ segment_save(char *name)
                        segtype_string[seg->range[i].start & 0xff]);
        }
        sprintf(cmd2, "SAVESEG %s", name);
-       cpcmd(cmd1, NULL, 0);
-       cpcmd(cmd2, NULL, 0);
+       cpcmd(cmd1, NULL, 0, NULL);
+       cpcmd(cmd2, NULL, 0, NULL);
        spin_unlock(&dcss_lock);
 }
 
index 262e13d086fefdb23c63e73ac89c28fb619b2e82..7a117ef473c5f46c64d711a2753c1e7a1abf5327 100644 (file)
@@ -270,66 +270,10 @@ endmenu
 
 source "drivers/Kconfig"
 
-config PRINTER
-       tristate "Parallel printer support"
-       depends on PARPORT
-       ---help---
-         If you intend to attach a printer to the parallel port of your Linux
-         box (as opposed to using a serial printer; if the connector at the
-         printer has 9 or 25 holes ["female"], then it's serial), say Y.
-         Also read the Printing-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         It is possible to share one parallel port among several devices
-         (e.g. printer and ZIP drive) and it is safe to compile the
-         corresponding drivers into the kernel.  If you want to compile this
-         driver as a module however, choose M here and read
-         <file:Documentation/parport.txt>.  The module will be called lp.
-
-         If you have several parallel ports, you can specify which ports to
-         use with the "lp" kernel command line option.  (Try "man bootparam"
-         or see the documentation of your boot loader (silo) about how to pass
-         options to the kernel at boot time.)  The syntax of the "lp" command
-         line option can be found in <file:drivers/char/lp.c>.
-
-         If you have more than 8 printers, you need to increase the LP_NO
-         macro in lp.c and the PARPORT_MAX macro in parport.h.
-
-source "mm/Kconfig"
-
-endmenu
-
-source "drivers/base/Kconfig"
-
-source "drivers/video/Kconfig"
-
-source "drivers/mtd/Kconfig"
-
-source "drivers/serial/Kconfig"
-
 if !SUN4
 source "drivers/sbus/char/Kconfig"
 endif
 
-source "drivers/block/Kconfig"
-
-# Don't frighten a common SBus user
-if PCI
-
-source "drivers/ide/Kconfig"
-
-endif
-
-source "drivers/isdn/Kconfig"
-
-source "drivers/scsi/Kconfig"
-
-source "drivers/fc4/Kconfig"
-
-source "drivers/md/Kconfig"
-
-source "net/Kconfig"
-
 # This one must be before the filesystem configs. -DaveM
 
 menu "Unix98 PTY support"
index a0716ccc2f4a2227c211f19a77017b2790379a31..8852c20c8d9928e8d09bf7a35f4a76a0f2d4b71a 100644 (file)
@@ -16,7 +16,7 @@
 #include <asm/ebus.h>
 #include <asm/auxio.h>
 
-/* This cannot be static, as it is referenced in entry.S */
+/* This cannot be static, as it is referenced in irq.c */
 void __iomem *auxio_register = NULL;
 
 enum auxio_type {
index a47f2d0b1a29b326df9c813f53f455c4a5074c25..eee516a71c14b73bb103ef33a91dd3029f41e64f 100644 (file)
@@ -271,8 +271,9 @@ cplus_fptrap_insn_1:
        fmuld           %f0, %f2, %f26
        faddd           %f0, %f2, %f28
        fmuld           %f0, %f2, %f30
+       membar          #Sync
        b,pt            %xcc, fpdis_exit
-        membar         #Sync
+        nop
 2:     andcc           %g5, FPRS_DU, %g0
        bne,pt          %icc, 3f
         fzero          %f32
@@ -301,8 +302,9 @@ cplus_fptrap_insn_2:
        fmuld           %f32, %f34, %f58
        faddd           %f32, %f34, %f60
        fmuld           %f32, %f34, %f62
+       membar          #Sync
        ba,pt           %xcc, fpdis_exit
-        membar         #Sync
+        nop
 3:     mov             SECONDARY_CONTEXT, %g3
        add             %g6, TI_FPREGS, %g1
        ldxa            [%g3] ASI_DMMU, %g5
@@ -699,116 +701,6 @@ utrap_ill:
        ba,pt           %xcc, rtrap
         clr            %l6
 
-#ifdef CONFIG_BLK_DEV_FD
-       .globl          floppy_hardint
-floppy_hardint:
-       wr              %g0, (1 << 11), %clear_softint
-       sethi           %hi(doing_pdma), %g1
-       ld              [%g1 + %lo(doing_pdma)], %g2
-       brz,pn          %g2, floppy_dosoftint
-        sethi          %hi(fdc_status), %g3
-       ldx             [%g3 + %lo(fdc_status)], %g3
-       sethi           %hi(pdma_vaddr), %g5
-       ldx             [%g5 + %lo(pdma_vaddr)], %g4
-       sethi           %hi(pdma_size), %g5
-       ldx             [%g5 + %lo(pdma_size)], %g5
-
-next_byte:
-       lduba           [%g3] ASI_PHYS_BYPASS_EC_E, %g7
-       andcc           %g7, 0x80, %g0
-       be,pn           %icc, floppy_fifo_emptied
-        andcc          %g7, 0x20, %g0
-       be,pn           %icc, floppy_overrun
-        andcc          %g7, 0x40, %g0
-       be,pn           %icc, floppy_write
-        sub            %g5, 1, %g5
-
-       inc             %g3
-       lduba           [%g3] ASI_PHYS_BYPASS_EC_E, %g7
-       dec             %g3
-       orcc            %g0, %g5, %g0
-       stb             %g7, [%g4]
-       bne,pn          %xcc, next_byte
-        add            %g4, 1, %g4
-
-       b,pt            %xcc, floppy_tdone
-        nop
-
-floppy_write:
-       ldub            [%g4], %g7
-       orcc            %g0, %g5, %g0
-       inc             %g3
-       stba            %g7, [%g3] ASI_PHYS_BYPASS_EC_E
-       dec             %g3
-       bne,pn          %xcc, next_byte
-        add            %g4, 1, %g4
-
-floppy_tdone:
-       sethi           %hi(pdma_vaddr), %g1
-       stx             %g4, [%g1 + %lo(pdma_vaddr)]
-       sethi           %hi(pdma_size), %g1
-       stx             %g5, [%g1 + %lo(pdma_size)]
-       sethi           %hi(auxio_register), %g1
-       ldx             [%g1 + %lo(auxio_register)], %g7
-       lduba           [%g7] ASI_PHYS_BYPASS_EC_E, %g5
-       or              %g5, AUXIO_AUX1_FTCNT, %g5
-/*     andn            %g5, AUXIO_AUX1_MASK, %g5 */
-       stba            %g5, [%g7] ASI_PHYS_BYPASS_EC_E
-       andn            %g5, AUXIO_AUX1_FTCNT, %g5
-/*     andn            %g5, AUXIO_AUX1_MASK, %g5 */
-
-       nop; nop;  nop; nop;  nop; nop;
-       nop; nop;  nop; nop;  nop; nop;
-
-       stba            %g5, [%g7] ASI_PHYS_BYPASS_EC_E
-       sethi           %hi(doing_pdma), %g1
-       b,pt            %xcc, floppy_dosoftint
-        st             %g0, [%g1 + %lo(doing_pdma)]
-
-floppy_fifo_emptied:
-       sethi           %hi(pdma_vaddr), %g1
-       stx             %g4, [%g1 + %lo(pdma_vaddr)]
-       sethi           %hi(pdma_size), %g1
-       stx             %g5, [%g1 + %lo(pdma_size)]
-       sethi           %hi(irq_action), %g1
-       or              %g1, %lo(irq_action), %g1
-       ldx             [%g1 + (11 << 3)], %g3          ! irqaction[floppy_irq]
-       ldx             [%g3 + 0x08], %g4               ! action->flags>>48==ino
-       sethi           %hi(ivector_table), %g3
-       srlx            %g4, 48, %g4
-       or              %g3, %lo(ivector_table), %g3
-       sllx            %g4, 5, %g4
-       ldx             [%g3 + %g4], %g4                ! &ivector_table[ino]
-       ldx             [%g4 + 0x10], %g4               ! bucket->iclr
-       stwa            %g0, [%g4] ASI_PHYS_BYPASS_EC_E ! ICLR_IDLE
-       membar          #Sync                           ! probably not needed...
-       retry
-
-floppy_overrun:
-       sethi           %hi(pdma_vaddr), %g1
-       stx             %g4, [%g1 + %lo(pdma_vaddr)]
-       sethi           %hi(pdma_size), %g1
-       stx             %g5, [%g1 + %lo(pdma_size)]
-       sethi           %hi(doing_pdma), %g1
-       st              %g0, [%g1 + %lo(doing_pdma)]
-
-floppy_dosoftint:
-       rdpr            %pil, %g2
-       wrpr            %g0, 15, %pil
-       sethi           %hi(109f), %g7
-       b,pt            %xcc, etrap_irq
-109:    or             %g7, %lo(109b), %g7
-
-       mov             11, %o0
-       mov             0, %o1
-       call            sparc_floppy_irq
-        add            %sp, PTREGS_OFF, %o2
-
-       b,pt            %xcc, rtrap_irq
-        nop
-
-#endif /* CONFIG_BLK_DEV_FD */
-
        /* XXX Here is stuff we still need to write... -DaveM XXX */
        .globl          netbsd_syscall
 netbsd_syscall:
index 4dcb8af94090cfc490da271877561d988b3a2aea..424712577307d07e0cab4a2e92b07e8cc58b45fe 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/uaccess.h>
 #include <asm/cache.h>
 #include <asm/cpudata.h>
+#include <asm/auxio.h>
 
 #ifdef CONFIG_SMP
 static void distribute_irqs(void);
@@ -834,137 +835,65 @@ void handler_irq(int irq, struct pt_regs *regs)
 }
 
 #ifdef CONFIG_BLK_DEV_FD
-extern void floppy_interrupt(int irq, void *dev_cookie, struct pt_regs *regs);
+extern irqreturn_t floppy_interrupt(int, void *, struct pt_regs *);;
 
-void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
-{
-       struct irqaction *action = *(irq + irq_action);
-       struct ino_bucket *bucket;
-       int cpu = smp_processor_id();
-
-       irq_enter();
-       kstat_this_cpu.irqs[irq]++;
-
-       *(irq_work(cpu, irq)) = 0;
-       bucket = get_ino_in_irqaction(action) + ivector_table;
-
-       bucket->flags |= IBF_INPROGRESS;
-
-       floppy_interrupt(irq, dev_cookie, regs);
-       upa_writel(ICLR_IDLE, bucket->iclr);
-
-       bucket->flags &= ~IBF_INPROGRESS;
-
-       irq_exit();
-}
-#endif
-
-/* The following assumes that the branch lies before the place we
- * are branching to.  This is the case for a trap vector...
- * You have been warned.
- */
-#define SPARC_BRANCH(dest_addr, inst_addr) \
-          (0x10800000 | ((((dest_addr)-(inst_addr))>>2)&0x3fffff))
-
-#define SPARC_NOP (0x01000000)
+/* XXX No easy way to include asm/floppy.h XXX */
+extern unsigned char *pdma_vaddr;
+extern unsigned long pdma_size;
+extern volatile int doing_pdma;
+extern unsigned long fdc_status;
 
-static void install_fast_irq(unsigned int cpu_irq,
-                            irqreturn_t (*handler)(int, void *, struct pt_regs *))
+irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
 {
-       extern unsigned long sparc64_ttable_tl0;
-       unsigned long ttent = (unsigned long) &sparc64_ttable_tl0;
-       unsigned int *insns;
-
-       ttent += 0x820;
-       ttent += (cpu_irq - 1) << 5;
-       insns = (unsigned int *) ttent;
-       insns[0] = SPARC_BRANCH(((unsigned long) handler),
-                               ((unsigned long)&insns[0]));
-       insns[1] = SPARC_NOP;
-       __asm__ __volatile__("membar #StoreStore; flush %0" : : "r" (ttent));
-}
-
-int request_fast_irq(unsigned int irq,
-                    irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                    unsigned long irqflags, const char *name, void *dev_id)
-{
-       struct irqaction *action;
-       struct ino_bucket *bucket = __bucket(irq);
-       unsigned long flags;
-
-       /* No pil0 dummy buckets allowed here. */
-       if (bucket < &ivector_table[0] ||
-           bucket >= &ivector_table[NUM_IVECS]) {
-               unsigned int *caller;
-
-               __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-               printk(KERN_CRIT "request_fast_irq: Old style IRQ registry attempt "
-                      "from %p, irq %08x.\n", caller, irq);
-               return -EINVAL;
-       }       
-       
-       if (!handler)
-               return -EINVAL;
+       if (likely(doing_pdma)) {
+               void __iomem *stat = (void __iomem *) fdc_status;
+               unsigned char *vaddr = pdma_vaddr;
+               unsigned long size = pdma_size;
+               u8 val;
+
+               while (size) {
+                       val = readb(stat);
+                       if (unlikely(!(val & 0x80))) {
+                               pdma_vaddr = vaddr;
+                               pdma_size = size;
+                               return IRQ_HANDLED;
+                       }
+                       if (unlikely(!(val & 0x20))) {
+                               pdma_vaddr = vaddr;
+                               pdma_size = size;
+                               doing_pdma = 0;
+                               goto main_interrupt;
+                       }
+                       if (val & 0x40) {
+                               /* read */
+                               *vaddr++ = readb(stat + 1);
+                       } else {
+                               unsigned char data = *vaddr++;
 
-       if ((bucket->pil == 0) || (bucket->pil == 14)) {
-               printk("request_fast_irq: Trying to register shared IRQ 0 or 14.\n");
-               return -EBUSY;
-       }
+                               /* write */
+                               writeb(data, stat + 1);
+                       }
+                       size--;
+               }
 
-       spin_lock_irqsave(&irq_action_lock, flags);
+               pdma_vaddr = vaddr;
+               pdma_size = size;
 
-       action = *(bucket->pil + irq_action);
-       if (action) {
-               if (action->flags & SA_SHIRQ)
-                       panic("Trying to register fast irq when already shared.\n");
-               if (irqflags & SA_SHIRQ)
-                       panic("Trying to register fast irq as shared.\n");
-               printk("request_fast_irq: Trying to register yet already owned.\n");
-               spin_unlock_irqrestore(&irq_action_lock, flags);
-               return -EBUSY;
-       }
+               /* Send Terminal Count pulse to floppy controller. */
+               val = readb(auxio_register);
+               val |= AUXIO_AUX1_FTCNT;
+               writeb(val, auxio_register);
+               val &= AUXIO_AUX1_FTCNT;
+               writeb(val, auxio_register);
 
-       /*
-        * We do not check for SA_SAMPLE_RANDOM in this path. Neither do we
-        * support smp intr affinity in this path.
-        */
-       if (irqflags & SA_STATIC_ALLOC) {
-               if (static_irq_count < MAX_STATIC_ALLOC)
-                       action = &static_irqaction[static_irq_count++];
-               else
-                       printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed "
-                              "using kmalloc\n", bucket->pil, name);
-       }
-       if (action == NULL)
-               action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
-                                                    GFP_ATOMIC);
-       if (!action) {
-               spin_unlock_irqrestore(&irq_action_lock, flags);
-               return -ENOMEM;
+               doing_pdma = 0;
        }
-       install_fast_irq(bucket->pil, handler);
 
-       bucket->irq_info = action;
-       bucket->flags |= IBF_ACTIVE;
-
-       action->handler = handler;
-       action->flags = irqflags;
-       action->dev_id = NULL;
-       action->name = name;
-       action->next = NULL;
-       put_ino_in_irqaction(action, irq);
-       put_smpaff_in_irqaction(action, CPU_MASK_NONE);
-
-       *(bucket->pil + irq_action) = action;
-       enable_irq(irq);
-
-       spin_unlock_irqrestore(&irq_action_lock, flags);
-
-#ifdef CONFIG_SMP
-       distribute_irqs();
-#endif
-       return 0;
+main_interrupt:
+       return floppy_interrupt(irq, dev_cookie, regs);
 }
+EXPORT_SYMBOL(sparc_floppy_irq);
+#endif
 
 /* We really don't need these at all on the Sparc.  We only have
  * stubs here because they are exported to modules.
index 63496c43fe1736861e36edeeff29a28335fb18c0..a809e63f03ef8f63f37ece764d1ee26a3db297b1 100644 (file)
@@ -32,8 +32,9 @@ static __inline__ int __sem_update_count(struct semaphore *sem, int incr)
 "      add     %1, %4, %1\n"
 "      cas     [%3], %0, %1\n"
 "      cmp     %0, %1\n"
+"      membar  #StoreLoad | #StoreStore\n"
 "      bne,pn  %%icc, 1b\n"
-"       membar #StoreLoad | #StoreStore\n"
+"       nop\n"
        : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
        : "r" (&sem->count), "r" (incr), "m" (sem->count)
        : "cc");
@@ -71,8 +72,9 @@ void up(struct semaphore *sem)
 "      cmp     %%g1, %%g7\n"
 "      bne,pn  %%icc, 1b\n"
 "       addcc  %%g7, 1, %%g0\n"
+"      membar  #StoreLoad | #StoreStore\n"
 "      ble,pn  %%icc, 3f\n"
-"       membar #StoreLoad | #StoreStore\n"
+"       nop\n"
 "2:\n"
 "      .subsection 2\n"
 "3:    mov     %0, %%g1\n"
@@ -128,8 +130,9 @@ void __sched down(struct semaphore *sem)
 "      cmp     %%g1, %%g7\n"
 "      bne,pn  %%icc, 1b\n"
 "       cmp    %%g7, 1\n"
+"      membar  #StoreLoad | #StoreStore\n"
 "      bl,pn   %%icc, 3f\n"
-"       membar #StoreLoad | #StoreStore\n"
+"       nop\n"
 "2:\n"
 "      .subsection 2\n"
 "3:    mov     %0, %%g1\n"
@@ -233,8 +236,9 @@ int __sched down_interruptible(struct semaphore *sem)
 "      cmp     %%g1, %%g7\n"
 "      bne,pn  %%icc, 1b\n"
 "       cmp    %%g7, 1\n"
+"      membar  #StoreLoad | #StoreStore\n"
 "      bl,pn   %%icc, 3f\n"
-"       membar #StoreLoad | #StoreStore\n"
+"       nop\n"
 "2:\n"
 "      .subsection 2\n"
 "3:    mov     %2, %%g1\n"
index e78cc53594fa5bfbfc480ba874a24047f7f2b508..56cd96f4a5cdbd29a4ae17eabb6d2673f4cb76a9 100644 (file)
@@ -227,7 +227,6 @@ EXPORT_SYMBOL(__flush_dcache_range);
 
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mstk48t02_regs);
-EXPORT_SYMBOL(request_fast_irq);
 #ifdef CONFIG_SUN_AUXIO
 EXPORT_SYMBOL(auxio_set_led);
 EXPORT_SYMBOL(auxio_set_lte);
index 2c8f9344b4eeac3af10732e1bdd8d6f76de9eb0a..3a145fc39cf2d4b4b619bbb1038e50bd383f2bd1 100644 (file)
@@ -98,8 +98,9 @@ startup_continue:
 
        sethi           %hi(prom_entry_lock), %g2
 1:     ldstub          [%g2 + %lo(prom_entry_lock)], %g1
+       membar          #StoreLoad | #StoreStore
        brnz,pn         %g1, 1b
-        membar         #StoreLoad | #StoreStore
+        nop
 
        sethi           %hi(p1275buf), %g2
        or              %g2, %lo(p1275buf), %g2
index da9b520c71894488d844ff71f69c015766ac16ef..bafd2fc07acb181b7861459b721fd8722eb66969 100644 (file)
 #define LOOP_CHUNK3(src, dest, len, branch_dest)               \
        MAIN_LOOP_CHUNK(src, dest, f32, f48, len, branch_dest)
 
+#define DO_SYNC                        membar  #Sync;
 #define STORE_SYNC(dest, fsrc)                         \
        EX_ST(STORE_BLK(%fsrc, %dest));                 \
-       add                     %dest, 0x40, %dest;
+       add                     %dest, 0x40, %dest;     \
+       DO_SYNC
 
 #define STORE_JUMP(dest, fsrc, target)                 \
        EX_ST(STORE_BLK(%fsrc, %dest));                 \
        add                     %dest, 0x40, %dest;     \
-       ba,pt                   %xcc, target;
+       ba,pt                   %xcc, target;           \
+        nop;
 
 #define FINISH_VISCHUNK(dest, f0, f1, left)    \
        subcc                   %left, 8, %left;\
@@ -239,17 +242,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f0, %f2, %f48
 1:     FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)
-       STORE_JUMP(o0, f48, 40f) membar #Sync
+       STORE_JUMP(o0, f48, 40f)
 2:     FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16)
-       STORE_JUMP(o0, f48, 48f) membar #Sync
+       STORE_JUMP(o0, f48, 48f)
 3:     FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
-       STORE_JUMP(o0, f48, 56f) membar #Sync
+       STORE_JUMP(o0, f48, 56f)
 
 1:     FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
        LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -260,17 +263,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f2, %f4, %f48
 1:     FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)
-       STORE_JUMP(o0, f48, 41f) membar #Sync
+       STORE_JUMP(o0, f48, 41f)
 2:     FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
-       STORE_JUMP(o0, f48, 49f) membar #Sync
+       STORE_JUMP(o0, f48, 49f)
 3:     FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34)
-       STORE_JUMP(o0, f48, 57f) membar #Sync
+       STORE_JUMP(o0, f48, 57f)
 
 1:     FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
        LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -281,17 +284,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f4, %f6, %f48
 1:     FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)
-       STORE_JUMP(o0, f48, 42f) membar #Sync
+       STORE_JUMP(o0, f48, 42f)
 2:     FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
-       STORE_JUMP(o0, f48, 50f) membar #Sync
+       STORE_JUMP(o0, f48, 50f)
 3:     FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36)
-       STORE_JUMP(o0, f48, 58f) membar #Sync
+       STORE_JUMP(o0, f48, 58f)
 
 1:     FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
        LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -302,17 +305,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f6, %f8, %f48
 1:     FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6)
-       STORE_JUMP(o0, f48, 43f) membar #Sync
+       STORE_JUMP(o0, f48, 43f)
 2:     FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
-       STORE_JUMP(o0, f48, 51f) membar #Sync
+       STORE_JUMP(o0, f48, 51f)
 3:     FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38)
-       STORE_JUMP(o0, f48, 59f) membar #Sync
+       STORE_JUMP(o0, f48, 59f)
 
 1:     FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
        LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -323,17 +326,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f8, %f10, %f48
 1:     FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)
-       STORE_JUMP(o0, f48, 44f) membar #Sync
+       STORE_JUMP(o0, f48, 44f)
 2:     FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
-       STORE_JUMP(o0, f48, 52f) membar #Sync
+       STORE_JUMP(o0, f48, 52f)
 3:     FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40)
-       STORE_JUMP(o0, f48, 60f) membar #Sync
+       STORE_JUMP(o0, f48, 60f)
 
 1:     FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
        LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -344,17 +347,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f10, %f12, %f48
 1:     FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10)
-       STORE_JUMP(o0, f48, 45f) membar #Sync
+       STORE_JUMP(o0, f48, 45f)
 2:     FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
-       STORE_JUMP(o0, f48, 53f) membar #Sync
+       STORE_JUMP(o0, f48, 53f)
 3:     FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42)
-       STORE_JUMP(o0, f48, 61f) membar #Sync
+       STORE_JUMP(o0, f48, 61f)
 
 1:     FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
        LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -365,17 +368,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f12, %f14, %f48
 1:     FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12)
-       STORE_JUMP(o0, f48, 46f) membar #Sync
+       STORE_JUMP(o0, f48, 46f)
 2:     FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
-       STORE_JUMP(o0, f48, 54f) membar #Sync
+       STORE_JUMP(o0, f48, 54f)
 3:     FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44)
-       STORE_JUMP(o0, f48, 62f) membar #Sync
+       STORE_JUMP(o0, f48, 62f)
 
 1:     FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
        LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -386,17 +389,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f14, %f16, %f48
 1:     FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14)
-       STORE_JUMP(o0, f48, 47f) membar #Sync
+       STORE_JUMP(o0, f48, 47f)
 2:     FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
-       STORE_JUMP(o0, f48, 55f) membar #Sync
+       STORE_JUMP(o0, f48, 55f)
 3:     FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
-       STORE_JUMP(o0, f48, 63f) membar #Sync
+       STORE_JUMP(o0, f48, 63f)
 
 40:    FINISH_VISCHUNK(o0, f0,  f2,  g3)
 41:    FINISH_VISCHUNK(o0, f2,  f4,  g3)
index 65e328d600a840af2063ff740589172e7c2bbd0a..4e18989bd60299e67b693f7e2d9070b52d0cb190 100644 (file)
@@ -72,7 +72,11 @@ vis1:        ldub            [%g6 + TI_FPSAVED], %g3
 
        stda            %f48, [%g3 + %g1] ASI_BLK_P
 5:     membar          #Sync
-       jmpl            %g7 + %g0, %g0
+       ba,pt           %xcc, 80f
+        nop
+
+       .align          32
+80:    jmpl            %g7 + %g0, %g0
         nop
 
 6:     ldub            [%g3 + TI_FPSAVED], %o5
@@ -87,8 +91,11 @@ vis1:        ldub            [%g6 + TI_FPSAVED], %g3
        stda            %f32, [%g2 + %g1] ASI_BLK_P
        stda            %f48, [%g3 + %g1] ASI_BLK_P
        membar          #Sync
-       jmpl            %g7 + %g0, %g0
+       ba,pt           %xcc, 80f
+        nop
 
+       .align          32
+80:    jmpl            %g7 + %g0, %g0
         nop
 
        .align          32
@@ -126,6 +133,10 @@ VISenterhalf:
        stda            %f0, [%g2 + %g1] ASI_BLK_P
        stda            %f16, [%g3 + %g1] ASI_BLK_P
        membar          #Sync
+       ba,pt           %xcc, 4f
+        nop
+
+       .align          32
 4:     and             %o5, FPRS_DU, %o5
        jmpl            %g7 + %g0, %g0
         wr             %o5, FPRS_FEF, %fprs
index e528b8d1a3e69fc8d57128df8f8d7654a1ef8ab6..faf87c31598bc30f44a42d5a76079db4322096a7 100644 (file)
@@ -7,18 +7,6 @@
 #include <linux/config.h>
 #include <asm/asi.h>
 
-       /* On SMP we need to use memory barriers to ensure
-        * correct memory operation ordering, nop these out
-        * for uniprocessor.
-        */
-#ifdef CONFIG_SMP
-#define ATOMIC_PRE_BARRIER     membar #StoreLoad | #LoadLoad
-#define ATOMIC_POST_BARRIER    membar #StoreLoad | #StoreStore
-#else
-#define ATOMIC_PRE_BARRIER     nop
-#define ATOMIC_POST_BARRIER    nop
-#endif
-
        .text
 
        /* Two versions of the atomic routines, one that
@@ -52,6 +40,24 @@ atomic_sub: /* %o0 = decrement, %o1 = atomic_ptr */
         nop
        .size   atomic_sub, .-atomic_sub
 
+       /* On SMP we need to use memory barriers to ensure
+        * correct memory operation ordering, nop these out
+        * for uniprocessor.
+        */
+#ifdef CONFIG_SMP
+
+#define ATOMIC_PRE_BARRIER     membar #StoreLoad | #LoadLoad;
+#define ATOMIC_POST_BARRIER    \
+       ba,pt %xcc, 80b;        \
+       membar #StoreLoad | #StoreStore
+
+80:    retl
+        nop
+#else
+#define ATOMIC_PRE_BARRIER
+#define ATOMIC_POST_BARRIER
+#endif
+
        .globl  atomic_add_ret
        .type   atomic_add_ret,#function
 atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
@@ -62,9 +68,10 @@ atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
        cmp     %g1, %g7
        bne,pn  %icc, 1b
         add    %g7, %o0, %g7
+       sra     %g7, 0, %o0
        ATOMIC_POST_BARRIER
        retl
-        sra    %g7, 0, %o0
+        nop
        .size   atomic_add_ret, .-atomic_add_ret
 
        .globl  atomic_sub_ret
@@ -77,9 +84,10 @@ atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
        cmp     %g1, %g7
        bne,pn  %icc, 1b
         sub    %g7, %o0, %g7
+       sra     %g7, 0, %o0
        ATOMIC_POST_BARRIER
        retl
-        sra    %g7, 0, %o0
+        nop
        .size   atomic_sub_ret, .-atomic_sub_ret
 
        .globl  atomic64_add
@@ -118,9 +126,10 @@ atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
        cmp     %g1, %g7
        bne,pn  %xcc, 1b
         add    %g7, %o0, %g7
+       mov     %g7, %o0
        ATOMIC_POST_BARRIER
        retl
-        mov    %g7, %o0
+        nop
        .size   atomic64_add_ret, .-atomic64_add_ret
 
        .globl  atomic64_sub_ret
@@ -133,7 +142,8 @@ atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
        cmp     %g1, %g7
        bne,pn  %xcc, 1b
         sub    %g7, %o0, %g7
+       mov     %g7, %o0
        ATOMIC_POST_BARRIER
        retl
-        mov    %g7, %o0
+        nop
        .size   atomic64_sub_ret, .-atomic64_sub_ret
index 886dcd2b376a0e9d1359b35b04da1124db7746b8..31afbfe6c1e86864242f7e5bc75f5902a4da4387 100644 (file)
@@ -7,20 +7,26 @@
 #include <linux/config.h>
 #include <asm/asi.h>
 
+       .text
+
        /* On SMP we need to use memory barriers to ensure
         * correct memory operation ordering, nop these out
         * for uniprocessor.
         */
+
 #ifdef CONFIG_SMP
 #define BITOP_PRE_BARRIER      membar #StoreLoad | #LoadLoad
-#define BITOP_POST_BARRIER     membar #StoreLoad | #StoreStore
+#define BITOP_POST_BARRIER     \
+       ba,pt   %xcc, 80b;      \
+       membar #StoreLoad | #StoreStore
+
+80:    retl
+        nop
 #else
-#define BITOP_PRE_BARRIER      nop
-#define BITOP_POST_BARRIER     nop
+#define BITOP_PRE_BARRIER
+#define BITOP_POST_BARRIER
 #endif
 
-       .text
-
        .globl  test_and_set_bit
        .type   test_and_set_bit,#function
 test_and_set_bit:      /* %o0=nr, %o1=addr */
@@ -37,10 +43,11 @@ test_and_set_bit:   /* %o0=nr, %o1=addr */
        cmp     %g7, %g1
        bne,pn  %xcc, 1b
         and    %g7, %o2, %g2
-       BITOP_POST_BARRIER
        clr     %o0
+       movrne  %g2, 1, %o0
+       BITOP_POST_BARRIER
        retl
-        movrne %g2, 1, %o0
+        nop
        .size   test_and_set_bit, .-test_and_set_bit
 
        .globl  test_and_clear_bit
@@ -59,10 +66,11 @@ test_and_clear_bit: /* %o0=nr, %o1=addr */
        cmp     %g7, %g1
        bne,pn  %xcc, 1b
         and    %g7, %o2, %g2
-       BITOP_POST_BARRIER
        clr     %o0
+       movrne  %g2, 1, %o0
+       BITOP_POST_BARRIER
        retl
-        movrne %g2, 1, %o0
+        nop
        .size   test_and_clear_bit, .-test_and_clear_bit
 
        .globl  test_and_change_bit
@@ -81,10 +89,11 @@ test_and_change_bit:        /* %o0=nr, %o1=addr */
        cmp     %g7, %g1
        bne,pn  %xcc, 1b
         and    %g7, %o2, %g2
-       BITOP_POST_BARRIER
        clr     %o0
+       movrne  %g2, 1, %o0
+       BITOP_POST_BARRIER
        retl
-        movrne %g2, 1, %o0
+        nop
        .size   test_and_change_bit, .-test_and_change_bit
 
        .globl  set_bit
index c421e0c653253270c9b5edda838a22134e803c5d..f03344cf784e1785efbef5e0b195d89a568549b3 100644 (file)
@@ -252,8 +252,9 @@ wlock_again:
 "              andn    %%g1, %%g3, %%g7\n"
 "              casx    [%0], %%g1, %%g7\n"
 "              cmp     %%g1, %%g7\n"
+"              membar  #StoreLoad | #StoreStore\n"
 "              bne,pn  %%xcc, 1b\n"
-"               membar #StoreLoad | #StoreStore"
+"               nop"
                : /* no outputs */
                : "r" (&(rw->lock))
                : "g3", "g1", "g7", "cc", "memory");
@@ -351,8 +352,9 @@ int _do_write_trylock (rwlock_t *rw, char *str)
 "              andn    %%g1, %%g3, %%g7\n"
 "              casx    [%0], %%g1, %%g7\n"
 "              cmp     %%g1, %%g7\n"
+"              membar  #StoreLoad | #StoreStore\n"
 "              bne,pn  %%xcc, 1b\n"
-"               membar #StoreLoad | #StoreStore"
+"               nop"
                : /* no outputs */
                : "r" (&(rw->lock))
                : "g3", "g1", "g7", "cc", "memory");
index 7e6fdaebedbab9bf088170e40420307f8f730ed7..8ee288dd0afc87d9eb18ba92f193f51e2fd9f46b 100644 (file)
@@ -48,8 +48,9 @@ start_to_zero:
 #endif
 to_zero:
        ldstub  [%o1], %g3
+       membar  #StoreLoad | #StoreStore
        brnz,pn %g3, spin_on_lock
-        membar #StoreLoad | #StoreStore
+        nop
 loop2: cas     [%o0], %g2, %g7         /* ASSERT(g7 == 0) */
        cmp     %g2, %g7
 
@@ -71,8 +72,9 @@ loop2:        cas     [%o0], %g2, %g7         /* ASSERT(g7 == 0) */
         nop
 spin_on_lock:
        ldub    [%o1], %g3
+       membar  #LoadLoad
        brnz,pt %g3, spin_on_lock
-        membar #LoadLoad
+        nop
        ba,pt   %xcc, to_zero
         nop
        nop
index 174ff7b9164c5493f2062967fdd6ecc165746051..75f0e6b951d61b9ff5ef5ecf4187bac65ea785bf 100644 (file)
@@ -17,8 +17,9 @@ __down_read:
        bne,pn          %icc, 1b
         add            %g7, 1, %g7
        cmp             %g7, 0
+       membar          #StoreLoad | #StoreStore
        bl,pn           %icc, 3f
-        membar         #StoreLoad | #StoreStore
+        nop
 2:
        retl
         nop
@@ -57,8 +58,9 @@ __down_write:
        cmp             %g3, %g7
        bne,pn          %icc, 1b
         cmp            %g7, 0
+       membar          #StoreLoad | #StoreStore
        bne,pn          %icc, 3f
-        membar         #StoreLoad | #StoreStore
+        nop
 2:     retl
         nop
 3:
@@ -97,8 +99,9 @@ __up_read:
        cmp             %g1, %g7
        bne,pn          %icc, 1b
         cmp            %g7, 0
+       membar          #StoreLoad | #StoreStore
        bl,pn           %icc, 3f
-        membar         #StoreLoad | #StoreStore
+        nop
 2:     retl
         nop
 3:     sethi           %hi(RWSEM_ACTIVE_MASK), %g1
@@ -126,8 +129,9 @@ __up_write:
        bne,pn          %icc, 1b
         sub            %g7, %g1, %g7
        cmp             %g7, 0
+       membar          #StoreLoad | #StoreStore
        bl,pn           %icc, 3f
-        membar         #StoreLoad | #StoreStore
+        nop
 2:
        retl
         nop
@@ -151,8 +155,9 @@ __downgrade_write:
        bne,pn          %icc, 1b
         sub            %g7, %g1, %g7
        cmp             %g7, 0
+       membar          #StoreLoad | #StoreStore
        bl,pn           %icc, 3f
-        membar         #StoreLoad | #StoreStore
+        nop
 2:
        retl
         nop
index 9c5222075da93ac61018cb996f32008178dffcbd..8fc413cb6acd9116763ce2eb4edcf12d0d765f3c 100644 (file)
@@ -136,8 +136,9 @@ static __inline__ void set_dcache_dirty(struct page *page, int this_cpu)
                             "or        %%g1, %0, %%g1\n\t"
                             "casx      [%2], %%g7, %%g1\n\t"
                             "cmp       %%g7, %%g1\n\t"
+                            "membar    #StoreLoad | #StoreStore\n\t"
                             "bne,pn    %%xcc, 1b\n\t"
-                            " membar   #StoreLoad | #StoreStore"
+                            " nop"
                             : /* no outputs */
                             : "r" (mask), "r" (non_cpu_bits), "r" (&page->flags)
                             : "g1", "g7");
@@ -157,8 +158,9 @@ static __inline__ void clear_dcache_dirty_cpu(struct page *page, unsigned long c
                             " andn     %%g7, %1, %%g1\n\t"
                             "casx      [%2], %%g7, %%g1\n\t"
                             "cmp       %%g7, %%g1\n\t"
+                            "membar    #StoreLoad | #StoreStore\n\t"
                             "bne,pn    %%xcc, 1b\n\t"
-                            " membar   #StoreLoad | #StoreStore\n"
+                            " nop\n"
                             "2:"
                             : /* no outputs */
                             : "r" (cpu), "r" (mask), "r" (&page->flags),
index 7a0934321010afbd603fb46378102b17bcc01bba..7a2431d3abc7e9057d862add7040d97f56849d91 100644 (file)
@@ -266,8 +266,9 @@ __cheetah_flush_tlb_pending:        /* 22 insns */
         andn           %o3, 1, %o3
        stxa            %g0, [%o3] ASI_IMMU_DEMAP
 2:     stxa            %g0, [%o3] ASI_DMMU_DEMAP       
+       membar          #Sync
        brnz,pt         %o1, 1b
-        membar         #Sync
+        nop
        stxa            %g2, [%o4] ASI_DMMU
        flush           %g6
        wrpr            %g0, 0, %tl
index cf15b4a8b517556c1f498822b24c0a8af79d57a7..c1b03f7c1daa962195a6e8ee26d09580abfab615 100644 (file)
@@ -157,9 +157,9 @@ static void daemon_remove(void *data)
 
        os_close_file(pri->fd);
        os_close_file(pri->control);
-       if(pri->data_addr != NULL) kfree(pri->data_addr);
-       if(pri->ctl_addr != NULL) kfree(pri->ctl_addr);
-       if(pri->local_addr != NULL) kfree(pri->local_addr);
+       kfree(pri->data_addr);
+       kfree(pri->ctl_addr);
+       kfree(pri->local_addr);
 }
 
 int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri)
index 0f59736db329587d079b910279a035d409f4e884..2bb4c4f5dec4f08cd420caaf19d0bf75dcd77bef 100644 (file)
@@ -602,11 +602,26 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
        return n;
 }
 
-int line_remove(struct line *lines, unsigned int num, char *str)
+int line_id(char **str, int *start_out, int *end_out)
+{
+       char *end;
+        int n;
+
+       n = simple_strtoul(*str, &end, 0);
+       if((*end != '\0') || (end == *str))
+                return -1;
+
+        *str = end;
+        *start_out = n;
+        *end_out = n;
+        return n;
+}
+
+int line_remove(struct line *lines, unsigned int num, int n)
 {
        char config[sizeof("conxxxx=none\0")];
 
-       sprintf(config, "%s=none", str);
+       sprintf(config, "%d=none", n);
        return !line_setup(lines, num, config, 0);
 }
 
index d7c7adcc0a6731a2acec59eceffdb18a949ffcad..404de41a4f677cf664b740ff38a3a2e327e42a4e 100644 (file)
@@ -419,8 +419,9 @@ void mconsole_config(struct mc_request *req)
 void mconsole_remove(struct mc_request *req)
 {
        struct mc_device *dev;  
-       char *ptr = req->request.data;
-       int err;
+       char *ptr = req->request.data, *err_msg = "";
+        char error[256];
+       int err, start, end, n;
 
        ptr += strlen("remove");
        while(isspace(*ptr)) ptr++;
@@ -429,8 +430,35 @@ void mconsole_remove(struct mc_request *req)
                mconsole_reply(req, "Bad remove option", 1, 0);
                return;
        }
-       err = (*dev->remove)(&ptr[strlen(dev->name)]);
-       mconsole_reply(req, "", err, 0);
+
+        ptr = &ptr[strlen(dev->name)];
+
+        err = 1;
+        n = (*dev->id)(&ptr, &start, &end);
+        if(n < 0){
+                err_msg = "Couldn't parse device number";
+                goto out;
+        }
+        else if((n < start) || (n > end)){
+                sprintf(error, "Invalid device number - must be between "
+                        "%d and %d", start, end);
+                err_msg = error;
+                goto out;
+        }
+
+       err = (*dev->remove)(n);
+        switch(err){
+        case -ENODEV:
+                err_msg = "Device doesn't exist";
+                break;
+        case -EBUSY:
+                err_msg = "Device is currently open";
+                break;
+        default:
+                break;
+        }
+ out:
+       mconsole_reply(req, err_msg, err, 0);
 }
 
 #ifdef CONFIG_MAGIC_SYSRQ
index 5388a7428691a2c4c12791b0e5370cd0b31685ba..1495007bf6c07df5061526d554382287d95e27e2 100644 (file)
@@ -612,25 +612,35 @@ static int net_config(char *str)
        return(err);
 }
 
-static int net_remove(char *str)
+static int net_id(char **str, int *start_out, int *end_out)
+{
+        char *end;
+        int n;
+
+       n = simple_strtoul(*str, &end, 0);
+       if((*end != '\0') || (end == *str))
+               return -1;
+
+        *start_out = n;
+        *end_out = n;
+        *str = end;
+        return n;
+}
+
+static int net_remove(int n)
 {
        struct uml_net *device;
        struct net_device *dev;
        struct uml_net_private *lp;
-       char *end;
-       int n;
-
-       n = simple_strtoul(str, &end, 0);
-       if((*end != '\0') || (end == str))
-               return(-1);
 
        device = find_device(n);
        if(device == NULL)
-               return(0);
+               return -ENODEV;
 
        dev = device->dev;
        lp = dev->priv;
-       if(lp->fd > 0) return(-1);
+       if(lp->fd > 0)
+                return -EBUSY;
        if(lp->remove != NULL) (*lp->remove)(&lp->user);
        unregister_netdev(dev);
        platform_device_unregister(&device->pdev);
@@ -638,13 +648,14 @@ static int net_remove(char *str)
        list_del(&device->list);
        kfree(device);
        free_netdev(dev);
-       return(0);
+       return 0;
 }
 
 static struct mc_device net_mc = {
        .name           = "eth",
        .config         = net_config,
        .get_config     = NULL,
+        .id            = net_id,
        .remove         = net_remove,
 };
 
index b32a77010fbe5743aace38839dcf21f477c7da25..62e04ecfada85746c044a381724902d9440a4757 100644 (file)
@@ -49,7 +49,7 @@ static struct chan_opts opts = {
 
 static int ssl_config(char *str);
 static int ssl_get_config(char *dev, char *str, int size, char **error_out);
-static int ssl_remove(char *str);
+static int ssl_remove(int n);
 
 static struct line_driver driver = {
        .name                   = "UML serial line",
@@ -69,6 +69,7 @@ static struct line_driver driver = {
                .name           = "ssl",
                .config         = ssl_config,
                .get_config     = ssl_get_config,
+                .id            = line_id,
                .remove         = ssl_remove,
        },
 };
@@ -94,10 +95,10 @@ static int ssl_get_config(char *dev, char *str, int size, char **error_out)
                               str, size, error_out));
 }
 
-static int ssl_remove(char *str)
+static int ssl_remove(int n)
 {
-       return(line_remove(serial_lines, 
-                          sizeof(serial_lines)/sizeof(serial_lines[0]), str));
+        return line_remove(serial_lines,
+                           sizeof(serial_lines)/sizeof(serial_lines[0]), n);
 }
 
 int ssl_open(struct tty_struct *tty, struct file *filp)
index afbe1e71ed8310f36b2be4f8f633b61ca84af0a2..005aa6333b6e5ff59d957e201b8a6df15175888b 100644 (file)
@@ -55,7 +55,7 @@ static struct chan_opts opts = {
 
 static int con_config(char *str);
 static int con_get_config(char *dev, char *str, int size, char **error_out);
-static int con_remove(char *str);
+static int con_remove(int n);
 
 static struct line_driver driver = {
        .name                   = "UML console",
@@ -75,6 +75,7 @@ static struct line_driver driver = {
                .name           = "con",
                .config         = con_config,
                .get_config     = con_get_config,
+                .id            = line_id,
                .remove         = con_remove,
        },
 };
@@ -99,9 +100,9 @@ static int con_get_config(char *dev, char *str, int size, char **error_out)
                               size, error_out));
 }
 
-static int con_remove(char *str)
+static int con_remove(int n)
 {
-       return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str));
+        return line_remove(vts, sizeof(vts)/sizeof(vts[0]), n);
 }
 
 static int con_open(struct tty_struct *tty, struct file *filp)
index 2a7f6892c55c203d66c03640acdccb8a3655b8e3..344b24d09a7c07a773f81ab99ab6b4688675b6d9 100644 (file)
@@ -754,24 +754,34 @@ static int ubd_get_config(char *name, char *str, int size, char **error_out)
        return(len);
 }
 
-static int ubd_remove(char *str)
+static int ubd_id(char **str, int *start_out, int *end_out)
+{
+        int n;
+
+       n = parse_unit(str);
+        *start_out = 0;
+        *end_out = MAX_DEV - 1;
+        return n;
+}
+
+static int ubd_remove(int n)
 {
        struct ubd *dev;
-       int n, err = -ENODEV;
+       int err = -ENODEV;
 
-       n = parse_unit(&str);
+       spin_lock(&ubd_lock);
 
-       if((n < 0) || (n >= MAX_DEV))
-               return(err);
+       if(ubd_gendisk[n] == NULL)
+               goto out;
 
        dev = &ubd_dev[n];
-       if(dev->count > 0)
-               return(-EBUSY); /* you cannot remove a open disk */
 
-       err = 0;
-       spin_lock(&ubd_lock);
+       if(dev->file == NULL)
+               goto out;
 
-       if(ubd_gendisk[n] == NULL)
+       /* you cannot remove a open disk */
+       err = -EBUSY;
+       if(dev->count > 0)
                goto out;
 
        del_gendisk(ubd_gendisk[n]);
@@ -787,15 +797,16 @@ static int ubd_remove(char *str)
        platform_device_unregister(&dev->pdev);
        *dev = ((struct ubd) DEFAULT_UBD);
        err = 0;
- out:
-       spin_unlock(&ubd_lock);
-       return(err);
+out:
+       spin_unlock(&ubd_lock);
+       return err;
 }
 
 static struct mc_device ubd_mc = {
        .name           = "ubd",
        .config         = ubd_config,
        .get_config     = ubd_get_config,
+       .id             = ubd_id,
        .remove         = ubd_remove,
 };
 
index 4c5e92c04ccba6c6471befbc835293155322d308..5323d22a6ca701c97e6fcfc163ce8102890c0901 100644 (file)
@@ -101,7 +101,8 @@ extern void lines_init(struct line *lines, int nlines);
 extern void close_lines(struct line *lines, int nlines);
 
 extern int line_config(struct line *lines, unsigned int sizeof_lines, char *str);
-extern int line_remove(struct line *lines, unsigned int sizeof_lines, char *str);
+extern int line_id(char **str, int *start_out, int *end_out);
+extern int line_remove(struct line *lines, unsigned int sizeof_lines, int n);
 extern int line_get_config(char *dev, struct line *lines, unsigned int sizeof_lines, char *str,
                           int size, char **error_out);
 
index 61c274fcee5d539e6062023d013bd1b7aa51ae8a..d86ee14260ce463e44a965725d995c2ad8a9e069 100644 (file)
@@ -20,7 +20,8 @@ struct mc_device {
        char *name;
        int (*config)(char *);
        int (*get_config)(char *, char *, int, char **);
-       int (*remove)(char *);
+        int (*id)(char **, int *, int *);
+       int (*remove)(int);
 };
 
 #define CONFIG_CHUNK(str, size, current, chunk, end) \
index 6793a2fcd0aeed91c48d3182515bd09c2d1e45d6..f64ef77019a33af160e919baee0632a7e0957c4d 100644 (file)
@@ -8,11 +8,11 @@
 
 extern void timer(void);
 extern void switch_timers(int to_real);
-extern void set_interval(int timer_type);
 extern void idle_sleep(int secs);
 extern void enable_timer(void);
 extern void disable_timer(void);
 extern unsigned long time_lock(void);
 extern void time_unlock(unsigned long);
+extern void user_time_init(void);
 
 #endif
index e59f581526782adca0763540a98bc80505a7a79a..1e1a87f1c510cbc7a2d3a4ea472bd6395f6e4bb2 100644 (file)
@@ -69,7 +69,6 @@ static __init void do_uml_initcalls(void)
 
 static void last_ditch_exit(int sig)
 {
-        kmalloc_ok = 0;
        signal(SIGINT, SIG_DFL);
        signal(SIGTERM, SIG_DFL);
        signal(SIGHUP, SIG_DFL);
index 157584ae4792b46176031ac54e1437f7d43c317a..d4036ed680bcd408e82f1afd6871d77915792939 100644 (file)
@@ -96,8 +96,8 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 
        current->thread.request.u.thread.proc = fn;
        current->thread.request.u.thread.arg = arg;
-       pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, NULL, 0, NULL,
-                     NULL);
+       pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0,
+                     &current->thread.regs, 0, NULL, NULL);
        if(pid < 0)
                panic("do_fork failed in kernel_thread, errno = %d", pid);
        return(pid);
@@ -169,7 +169,7 @@ int current_pid(void)
 
 void default_idle(void)
 {
-       uml_idle_timer();
+       CHOOSE_MODE(uml_idle_timer(), (void) 0);
 
        atomic_inc(&init_mm.mm_count);
        current->mm = &init_mm;
index 207f89d749080a596954a6ac7adbf2fd68fd88cb..fcec51da1d3771abe84944ca1138853417df6bec 100644 (file)
@@ -38,14 +38,14 @@ static void kill_off_processes(void)
 
 void uml_cleanup(void)
 {
-       kill_off_processes();
+        kmalloc_ok = 0;
        do_uml_exitcalls();
+       kill_off_processes();
 }
 
 void machine_restart(char * __unused)
 {
-       do_uml_exitcalls();
-       kill_off_processes();
+        uml_cleanup();
        CHOOSE_MODE(reboot_tt(), reboot_skas());
 }
 
@@ -53,8 +53,7 @@ EXPORT_SYMBOL(machine_restart);
 
 void machine_power_off(void)
 {
-       do_uml_exitcalls();
-       kill_off_processes();
+        uml_cleanup();
        CHOOSE_MODE(halt_tt(), halt_skas());
 }
 
index d37d1bfcd6f73916266be72a6fd733d3443d0239..ff69c4b312c0c01bf471df0ebc2ee406bb2f7e13 100644 (file)
@@ -4,10 +4,10 @@
 #
 
 obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
-       syscall_kern.o syscall_user.o time.o tlb.o trap_user.o uaccess.o \
+       syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \
 
 subdir- := util
 
-USER_OBJS := process.o time.o
+USER_OBJS := process.o
 
 include arch/um/scripts/Makefile.rules
index c1e33bd788dbff1524dc77b0e891b5e3b7322ff6..bcd26a6a3888cce3a09df6f4fb9f8177d4d71219 100644 (file)
@@ -13,7 +13,6 @@ extern unsigned long exec_fp_regs[];
 extern unsigned long exec_fpx_regs[];
 extern int have_fpx_regs;
 
-extern void user_time_init_skas(void);
 extern void sig_handler_common_skas(int sig, void *sc_ptr);
 extern void halt_skas(void);
 extern void reboot_skas(void);
index fc71ef295782296d10d118f3cc95b336e6b01fcb..0a7b8aa55db8342b905a6f8b6f395e2a4a9ad9dd 100644 (file)
@@ -111,8 +111,7 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
        void (*handler)(int);
 
        if(current->thread.forking){
-               memcpy(&p->thread.regs.regs.skas, 
-                      &current->thread.regs.regs.skas, 
+               memcpy(&p->thread.regs.regs.skas, &regs->regs.skas,
                       sizeof(p->thread.regs.regs.skas));
                REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0);
                if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
@@ -181,7 +180,6 @@ int start_uml_skas(void)
        start_userspace(0);
 
        init_new_thread_signals(1);
-       uml_idle_timer();
 
        init_task.thread.request.u.thread.proc = start_kernel_proc;
        init_task.thread.request.u.thread.arg = NULL;
@@ -201,14 +199,3 @@ int thread_pid_skas(struct task_struct *task)
 #warning Need to look up userspace_pid by cpu
        return(userspace_pid[0]);
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/time.c b/arch/um/kernel/skas/time.c
deleted file mode 100644 (file)
index 9809149..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* 
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <sys/signal.h>
-#include <sys/time.h>
-#include "time_user.h"
-#include "process.h"
-#include "user.h"
-
-void user_time_init_skas(void)
-{
-        if(signal(SIGALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
-                panic("Couldn't set SIGALRM handler");
-       if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
-               panic("Couldn't set SIGVTALRM handler");
-       set_interval(ITIMER_VIRTUAL);
-}
-
-/*
- * 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 b7a55251e89727d44cf7ba841b309091034edcdb..8e1a3501ff46362814c0bb83b974951cbafbe9e2 100644 (file)
@@ -31,7 +31,8 @@ long sys_fork(void)
        long ret;
 
        current->thread.forking = 1;
-        ret = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL);
+       ret = do_fork(SIGCHLD, UPT_SP(&current->thread.regs.regs),
+                     &current->thread.regs, 0, NULL, NULL);
        current->thread.forking = 0;
        return(ret);
 }
@@ -41,8 +42,9 @@ long sys_vfork(void)
        long ret;
 
        current->thread.forking = 1;
-       ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL,
-                     NULL);
+       ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
+                     UPT_SP(&current->thread.regs.regs),
+                     &current->thread.regs, 0, NULL, NULL);
        current->thread.forking = 0;
        return(ret);
 }
@@ -162,14 +164,3 @@ int next_syscall_index(int limit)
        spin_unlock(&syscall_lock);
        return(ret);
 }
-
-/*
- * 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 c40c86a3f918b491b04e1d1f05e235fedf22c599..f829b309b63c7d7c27dd36ba87363130695ca887 100644 (file)
@@ -33,7 +33,7 @@ void timer(void)
        timeradd(&xtime, &local_offset, &xtime);
 }
 
-void set_interval(int timer_type)
+static void set_interval(int timer_type)
 {
        int usec = 1000000/hz();
        struct itimerval interval = ((struct itimerval) { { 0, usec },
@@ -45,12 +45,7 @@ void set_interval(int timer_type)
 
 void enable_timer(void)
 {
-       int usec = 1000000/hz();
-       struct itimerval enable = ((struct itimerval) { { 0, usec },
-                                                       { 0, usec }});
-       if(setitimer(ITIMER_VIRTUAL, &enable, NULL))
-               printk("enable_timer - setitimer failed, errno = %d\n",
-                      errno);
+       set_interval(ITIMER_VIRTUAL);
 }
 
 void disable_timer(void)
@@ -155,13 +150,15 @@ void idle_sleep(int secs)
        nanosleep(&ts, NULL);
 }
 
-/*
- * 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:
- */
+/* XXX This partly duplicates init_irq_signals */
+
+void user_time_init(void)
+{
+       set_handler(SIGVTALRM, (__sighandler_t) alarm_handler,
+                   SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH,
+                   SIGALRM, SIGUSR2, -1);
+       set_handler(SIGALRM, (__sighandler_t) alarm_handler,
+                   SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH,
+                   SIGVTALRM, SIGUSR2, -1);
+       set_interval(ITIMER_VIRTUAL);
+}
index 6516fc52afe01f23ecfbe0365cb251e9d3c8635d..a8b4ef601f5964d236360e8ae5bb1d4f49dbc56d 100644 (file)
@@ -162,7 +162,7 @@ int __init timer_init(void)
 {
        int err;
 
-       CHOOSE_MODE(user_time_init_tt(), user_time_init_skas());
+       user_time_init();
        err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL);
        if(err != 0)
                printk(KERN_ERR "timer_init : request_irq failed - "
index 3fd2554e60b6e58ff35b7af3b4141421f69ef1f1..6939e5af8472ceecf90fa878c72a4b0e927ec76e 100644 (file)
@@ -4,11 +4,11 @@
 #
 
 obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
-       syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \
+       syscall_kern.o syscall_user.o tlb.o tracer.o trap_user.o \
        uaccess.o uaccess_user.o
 
 obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/
 
-USER_OBJS := gdb.o time.o tracer.o
+USER_OBJS := gdb.o tracer.o
 
 include arch/um/scripts/Makefile.rules
index 19a0ad7b35b3c0d7a819e540c288f546ac5efbec..37e22d71a0d9d5c546326e5a19276ec54524ac14 100644 (file)
@@ -153,10 +153,10 @@ void remove_gdb_cb(void *unused)
        exit_debugger_cb(NULL);
 }
 
-int gdb_remove(char *unused)
+int gdb_remove(int unused)
 {
        initial_thread_cb(remove_gdb_cb, NULL);
-       return(0);
+        return 0;
 }
 
 void signal_usr1(int sig)
index 93fb121f86af5c34213d44c430b398f027c227b1..26506388a6aa66cbc64552153ccd822f33c81cf3 100644 (file)
@@ -10,7 +10,7 @@
 #ifdef CONFIG_MCONSOLE
 
 extern int gdb_config(char *str);
-extern int gdb_remove(char *unused);
+extern int gdb_remove(int n);
 
 static struct mc_device gdb_mc = {
        .name           = "gdb",
index 8eff674107cac331259fcc8387cebfb77ce941bb..738435461e137ddf51ec54ca395677b5965ef037 100644 (file)
@@ -4,8 +4,8 @@
  * Licensed under the GPL
  */
 
-#ifndef __DEBUG_H
-#define __DEBUG_H
+#ifndef __UML_TT_DEBUG_H
+#define __UML_TT_DEBUG_H
 
 extern int debugger_proxy(int status, pid_t pid);
 extern void child_proxy(pid_t pid, int status);
@@ -13,17 +13,6 @@ extern void init_proxy (pid_t pid, int waiting, int status);
 extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd);
 extern void fake_child_exit(void);
 extern int gdb_config(char *str);
-extern int gdb_remove(char *unused);
+extern int gdb_remove(int unused);
 
 #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 efe4620190699cda8c9274d4838e98890b249dd0..e171e15fead527e0f37a8d52ab9cdff939e58dc7 100644 (file)
@@ -13,7 +13,6 @@ enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
 extern int tracing_pid;
 
 extern int tracer(int (*init_proc)(void *), void *sp);
-extern void user_time_init_tt(void);
 extern void sig_handler_common_tt(int sig, void *sc);
 extern void syscall_handler_tt(int sig, union uml_pt_regs *regs);
 extern void reboot_tt(void);
index 776310fd5b8b7e34d4b651b5fd2216a27b0a8935..a189a2b92935973123f8a855ca75832e4651e78c 100644 (file)
@@ -266,10 +266,10 @@ int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
        }
 
        if(current->thread.forking){
-               sc_to_sc(UPT_SC(&p->thread.regs.regs), 
-                        UPT_SC(&current->thread.regs.regs));
+               sc_to_sc(UPT_SC(&p->thread.regs.regs), UPT_SC(&regs->regs));
                SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0);
-               if(sp != 0) SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
+               if(sp != 0)
+                       SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
        }
        p->thread.mode.tt.extern_pid = new_pid;
 
@@ -459,14 +459,3 @@ int is_valid_pid(int pid)
        read_unlock(&tasklist_lock);
        return(0);
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/tt/time.c b/arch/um/kernel/tt/time.c
deleted file mode 100644 (file)
index 8565b71..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* 
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <signal.h>
-#include <sys/time.h>
-#include <time_user.h>
-#include "process.h"
-#include "user.h"
-
-void user_time_init_tt(void)
-{
-       if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
-               panic("Couldn't set SIGVTALRM handler");
-       set_interval(ITIMER_VIRTUAL);
-}
-
-/*
- * 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 03913ca5d256ac2f7c699e57dde29523dd51b52b..4efc69a039d70022592cec5430a46a1c9a08c826 100644 (file)
@@ -312,7 +312,7 @@ long sys_sigreturn(struct pt_regs regs)
        unsigned long __user *extramask = frame->extramask;
        int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
 
-       if(copy_from_user(&set.sig[0], oldmask, sizeof(&set.sig[0])) ||
+       if(copy_from_user(&set.sig[0], oldmask, sizeof(set.sig[0])) ||
           copy_from_user(&set.sig[1], extramask, sig_size))
                goto segfault;
 
index 335e2d89504d8992f6f12f784bf325cec48ab081..83e9be820a86991b50ccf25de396c5f0cd626088 100644 (file)
@@ -69,15 +69,11 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp,
 {
        long ret;
 
-       /* XXX: normal arch do here this pass, and also pass the regs to
-        * do_fork, instead of NULL. Currently the arch-independent code
-        * ignores these values, while the UML code (actually it's
-        * copy_thread) does the right thing. But this should change,
-        probably. */
-       /*if (!newsp)
-               newsp = UPT_SP(current->thread.regs);*/
+       if (!newsp)
+               newsp = UPT_SP(&current->thread.regs.regs);
        current->thread.forking = 1;
-       ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
+       ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
+                     child_tid);
        current->thread.forking = 0;
        return(ret);
 }
@@ -197,14 +193,3 @@ long sys_sigaction(int sig, const struct old_sigaction __user *act,
 
        return ret;
 }
-
-/*
- * 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 6f44f40204ed0947ffe93f6358a0a517649b6fd8..3259a4db453462e0d50b438ae295ff8cf9568326 100644 (file)
@@ -174,26 +174,11 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp,
 {
        long ret;
 
-       /* XXX: normal arch do here this pass, and also pass the regs to
-        * do_fork, instead of NULL. Currently the arch-independent code
-        * ignores these values, while the UML code (actually it's
-        * copy_thread) does the right thing. But this should change,
-        probably. */
-       /*if (!newsp)
-               newsp = UPT_SP(current->thread.regs);*/
+       if (!newsp)
+               newsp = UPT_SP(&current->thread.regs.regs);
        current->thread.forking = 1;
-       ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
+       ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
+                     child_tid);
        current->thread.forking = 0;
        return(ret);
 }
-
-/*
- * 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 db259757dc8a4f97af912c8d56f5e0ae8d4ab81a..d09437b5c48f06f2b7d22fc801db069402183738 100644 (file)
@@ -207,33 +207,6 @@ config SMP
 
          If you don't know what to do here, say N.
 
-config PREEMPT
-       bool "Preemptible Kernel"
-       ---help---
-         This option reduces the latency of the kernel when reacting to
-         real-time or interactive events by allowing a low priority process to
-         be preempted even if it is in kernel mode executing a system call.
-         This allows applications to run more reliably even when the system is
-         under load. On contrary it may also break your drivers and add
-         priority inheritance problems to your system. Don't select it if
-         you rely on a stable system or have slightly obscure hardware.
-         It's also not very well tested on x86-64 currently.
-         You have been warned.
-
-         Say Y here if you are feeling brave and building a kernel for a
-         desktop, embedded or real-time system.  Say N if you are unsure.
-
-config PREEMPT_BKL
-       bool "Preempt The Big Kernel Lock"
-       depends on PREEMPT
-       default y
-       help
-         This option reduces the latency of the kernel by making the
-         big kernel lock preemptible.
-
-         Say Y here if you are building a kernel for a desktop system.
-         Say N if you are unsure.
-
 config SCHED_SMT
        bool "SMT (Hyperthreading) scheduler support"
        depends on SMP
@@ -244,6 +217,8 @@ config SCHED_SMT
          cost of slightly increased overhead in some places. If unsure say
          N here.
 
+source "kernel/Kconfig.preempt"
+
 config K8_NUMA
        bool "K8 NUMA support"
        select NUMA
@@ -313,6 +288,15 @@ config NR_CPUS
          This is purely to save memory - each supported CPU requires
          memory in the static kernel configuration.
 
+config HOTPLUG_CPU
+       bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
+       depends on SMP && HOTPLUG && EXPERIMENTAL
+       help
+               Say Y here to experiment with turning CPUs off and on.  CPUs
+               can be controlled through /sys/devices/system/cpu/cpu#.
+               Say N if you want to disable CPU hotplug.
+
+
 config HPET_TIMER
        bool
        default y
@@ -385,6 +369,34 @@ config X86_MCE_INTEL
           Additional support for intel specific MCE features such as
           the thermal monitor.
 
+config PHYSICAL_START
+       hex "Physical address where the kernel is loaded" if EMBEDDED
+       default "0x100000"
+       help
+         This gives the physical address where the kernel is loaded.
+         Primarily used in the case of kexec on panic where the
+         fail safe kernel needs to run at a different address than
+         the panic-ed kernel.
+
+         Don't change this unless you know what you are doing.
+
+config KEXEC
+       bool "kexec system call (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       help
+         kexec is a system call that implements the ability to shutdown your
+         current kernel, and to start another kernel.  It is like a reboot
+         but it is indepedent of the system firmware.   And like a reboot
+         you can start any kernel with it, not just Linux.
+
+         The name comes from the similiarity to the exec system call.
+
+         It is an ongoing process to be certain the hardware in a machine
+         is properly shutdown, so do not be surprised if this code does not
+         initially work for you.  It may help to enable device hotplugging
+         support.  As of this writing the exact hardware interface is
+         strongly in flux, so no good recommendation can be made.
+
 config SECCOMP
        bool "Enable seccomp to safely compute untrusted bytecode"
        depends on PROC_FS
index 6f90c246c4189989d6fcaadc7cff0e9ed18cd905..8a73794f9b9022dba5b6085fab84a81556dc8d0c 100644 (file)
@@ -35,7 +35,7 @@ export IA32_CC IA32_LD IA32_AS IA32_OBJCOPY IA32_CPP
 
 LDFLAGS                := -m elf_x86_64
 OBJCOPYFLAGS   := -O binary -R .note -R .comment -S
-LDFLAGS_vmlinux := -e stext
+LDFLAGS_vmlinux :=
 
 CHECKFLAGS      += -D__x86_64__ -m64
 
index 27264dbd575c222f0fd02c8758d7edf459e34adb..6f55565e4d4213cbfd295000bc88b70f742f8425 100644 (file)
@@ -2,8 +2,6 @@
  *  linux/boot/head.S
  *
  *  Copyright (C) 1991, 1992, 1993  Linus Torvalds
- *
- *  $Id: head.S,v 1.3 2001/04/20 00:59:28 ak Exp $                     
  */
 
 /*
  */
 
 /*
- * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996    
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  */
 .code32
 .text
 
 #include <linux/linkage.h>
 #include <asm/segment.h>
+#include <asm/page.h>
 
        .code32
        .globl startup_32
@@ -77,7 +76,7 @@ startup_32:
        jnz  3f
        addl $8,%esp
        xorl %ebx,%ebx
-       ljmp $(__KERNEL_CS), $0x100000
+       ljmp $(__KERNEL_CS), $__PHYSICAL_START
 
 /*
  * We come here, if we were loaded high.
@@ -103,7 +102,7 @@ startup_32:
        popl %ecx       # lcount
        popl %edx       # high_buffer_start
        popl %eax       # hcount
-       movl $0x100000,%edi
+       movl $__PHYSICAL_START,%edi
        cli             # make sure we don't get interrupted
        ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine
 
@@ -128,7 +127,7 @@ move_routine_start:
        movsl
        movl %ebx,%esi  # Restore setup pointer
        xorl %ebx,%ebx
-       ljmp $(__KERNEL_CS), $0x100000
+       ljmp $(__KERNEL_CS), $__PHYSICAL_START
 move_routine_end:
 
 
index c8b9216f9e634c365dc49eaf25ef96f234544249..b38d5b8b5fb844ebf92ed2221faa1bcf2d274e6a 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "miscsetup.h"
 #include <asm/io.h>
+#include <asm/page.h>
 
 /*
  * gzip declarations
@@ -92,8 +93,11 @@ static unsigned long output_ptr = 0;
 static void *malloc(int size);
 static void free(void *where);
  
+void* memset(void* s, int c, unsigned n);
+void* memcpy(void* dest, const void* src, unsigned n);
+
 static void putstr(const char *);
-  
+
 extern int end;
 static long free_mem_ptr = (long)&end;
 static long free_mem_end_ptr;
@@ -284,7 +288,7 @@ void setup_normal_output_buffer(void)
 #else
        if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory");
 #endif
-       output_data = (char *)0x100000; /* Points to 1M */
+       output_data = (char *)__PHYSICAL_START; /* Normally Points to 1M */
        free_mem_end_ptr = (long)real_mode;
 }
 
@@ -307,8 +311,8 @@ void setup_output_buffer_if_we_run_high(struct moveparams *mv)
        low_buffer_size = low_buffer_end - LOW_BUFFER_START;
        high_loaded = 1;
        free_mem_end_ptr = (long)high_buffer_start;
-       if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) {
-               high_buffer_start = (uch *)(0x100000 + low_buffer_size);
+       if ( (__PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) {
+               high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size);
                mv->hcount = 0; /* say: we need not to move high_buffer */
        }
        else mv->hcount = -1;
index f17b40dfc0f4bde512541ded9c67a88570eb3460..198af15a77586c1abb2cd9c0159cb3e0e0da1643 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh
 #
-# arch/i386/boot/install.sh
+# arch/x86_64/boot/install.sh
 #
 # 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
index 75d4d2ad93b363a83f3a66346644a8ea716ea64f..ff58b2832b75d5b54df35e57a60fc9dd398c16cd 100644 (file)
@@ -33,7 +33,7 @@
  * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
  * <stiker@northlink.com>
  *
- * Fix to work around buggy BIOSes which dont use carry bit correctly
+ * Fix to work around buggy BIOSes which don't use carry bit correctly
  * and/or report extended memory in CX/DX for e801h memory size detection 
  * call.  As a result the kernel got wrong figures.  The int15/e801h docs
  * from Ralf Brown interrupt list seem to indicate AX/BX should be used
@@ -383,7 +383,7 @@ sse_ok:
 # a whole bunch of different types, and allows memory holes and
 # everything.  We scan through this memory map and build a list
 # of the first 32 memory areas, which we return at [E820MAP].
-# This is documented at http://www.teleport.com/~acpi/acpihtml/topic245.htm
+# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification.
 
 #define SMAP  0x534d4150
 
@@ -436,7 +436,7 @@ bail820:
 
 meme801:
        stc                                     # fix to work around buggy
-       xorw    %cx,%cx                         # BIOSes which dont clear/set
+       xorw    %cx,%cx                         # BIOSes which don't clear/set
        xorw    %dx,%dx                         # carry on pass/error of
                                                # e801h memory size call
                                                # or merely pass cx,dx though
@@ -733,7 +733,7 @@ flush_instr:
 #
 #      but we yet haven't reloaded the CS register, so the default size 
 #      of the target offset still is 16 bit.
-#       However, using an operant prefix (0x66), the CPU will properly
+#      However, using an operand prefix (0x66), the CPU will properly
 #      take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
 #      Manual, Mixing 16-bit and 32-bit code, page 16-6)
 
index c2fa66313170767827c6a2af0afeedca9b813ce2..18b5bac1c4282fb94a8bb71afbc79a383164246a 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  $Id: build.c,v 1.3 2001/06/26 15:14:50 pavel Exp $
- *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1997 Martin Mares
  */
@@ -8,7 +6,8 @@
 /*
  * This file builds a disk-image from three different files:
  *
- * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
+ * - bootsect: compatibility mbr which prints an error message if
+ *             someone tries to boot the kernel directly.
  * - setup: 8086 machine code, sets up system parm
  * - system: 80386 code for actual system
  *
index f3ca0db85b5b54b286fc5e72aa75e559bedbb61c..cc935427d532355672d06034a644bcbc142e4342 100644 (file)
@@ -589,7 +589,7 @@ ia32_sys_call_table:
        .quad compat_sys_mq_timedreceive        /* 280 */
        .quad compat_sys_mq_notify
        .quad compat_sys_mq_getsetattr
-       .quad quiet_ni_syscall          /* reserved for kexec */
+       .quad compat_sys_kexec_load     /* reserved for kexec */
        .quad compat_sys_waitid
        .quad quiet_ni_syscall          /* sys_altroot */
        .quad sys_add_key
index 5ca4a4598fdad807b5aa0e8143c2aa55525fced2..48f9e2c19cd6f78a4cdc21efdec7afec0da19277 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_SMP)             += smp.o smpboot.o trampoline.o
 obj-$(CONFIG_X86_LOCAL_APIC)   += apic.o  nmi.o
 obj-$(CONFIG_X86_IO_APIC)      += io_apic.o mpparse.o \
                genapic.o genapic_cluster.o genapic_flat.o
+obj-$(CONFIG_KEXEC)            += machine_kexec.o relocate_kernel.o crash.o
 obj-$(CONFIG_PM)               += suspend.o
 obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend_asm.o
 obj-$(CONFIG_CPU_FREQ)         += cpufreq/
index a4c630034cd43041f9e10614b040512cc345fa95..185faa911db592b26483bda86a6760a9fd044d63 100644 (file)
@@ -67,7 +67,7 @@ wakeup_code:
        shll    $4, %eax
        addl    $(gdta - wakeup_code), %eax
        movl    %eax, gdt_48a +2 - wakeup_code
-       lgdt    %ds:gdt_48a - wakeup_code               # load gdt with whatever is
+       lgdtl   %ds:gdt_48a - wakeup_code       # load gdt with whatever is
                                                # appropriate
 
        movl    $1, %eax                        # protected mode (PE) bit
index f8e6cc4fecd4887acc244fee292f401a96aac59b..375d369570ca3dbbb365b363585d5b6ecff1ef57 100644 (file)
@@ -133,7 +133,7 @@ void __init connect_bsp_APIC(void)
        }
 }
 
-void disconnect_bsp_APIC(void)
+void disconnect_bsp_APIC(int virt_wire_setup)
 {
        if (pic_mode) {
                /*
@@ -146,6 +146,42 @@ void disconnect_bsp_APIC(void)
                outb(0x70, 0x22);
                outb(0x00, 0x23);
        }
+       else {
+               /* Go back to Virtual Wire compatibility mode */
+               unsigned long value;
+
+               /* For the spurious interrupt use vector F, and enable it */
+               value = apic_read(APIC_SPIV);
+               value &= ~APIC_VECTOR_MASK;
+               value |= APIC_SPIV_APIC_ENABLED;
+               value |= 0xf;
+               apic_write_around(APIC_SPIV, value);
+
+               if (!virt_wire_setup) {
+                       /* For LVT0 make it edge triggered, active high, external and enabled */
+                       value = apic_read(APIC_LVT0);
+                       value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
+                               APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
+                               APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED );
+                       value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
+                       value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);
+                       apic_write_around(APIC_LVT0, value);
+               }
+               else {
+                       /* Disable LVT0 */
+                       apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
+               }
+
+               /* For LVT1 make it edge triggered, active high, nmi and enabled */
+               value = apic_read(APIC_LVT1);
+               value &= ~(
+                       APIC_MODE_MASK | APIC_SEND_PENDING |
+                       APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
+                       APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
+               value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
+               value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
+               apic_write_around(APIC_LVT1, value);
+       }
 }
 
 void disable_local_APIC(void)
@@ -285,7 +321,7 @@ void __init init_bsp_APIC(void)
        apic_write_around(APIC_LVT1, value);
 }
 
-void __init setup_local_APIC (void)
+void __cpuinit setup_local_APIC (void)
 {
        unsigned int value, ver, maxlvt;
 
@@ -534,7 +570,7 @@ static struct sys_device device_lapic = {
        .cls            = &lapic_sysclass,
 };
 
-static void __init apic_pm_activate(void)
+static void __cpuinit apic_pm_activate(void)
 {
        apic_pm_state.active = 1;
 }
@@ -774,14 +810,14 @@ void __init setup_boot_APIC_clock (void)
        local_irq_enable();
 }
 
-void __init setup_secondary_APIC_clock(void)
+void __cpuinit setup_secondary_APIC_clock(void)
 {
        local_irq_disable(); /* FIXME: Do we need this? --RR */
        setup_APIC_timer(calibration_result);
        local_irq_enable();
 }
 
-void __init disable_APIC_timer(void)
+void __cpuinit disable_APIC_timer(void)
 {
        if (using_apic_timer) {
                unsigned long v;
diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash.c
new file mode 100644 (file)
index 0000000..d7fa424
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Architecture specific (x86_64) functions for kexec based crash dumps.
+ *
+ * Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2004. All rights reserved.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/irq.h>
+#include <linux/reboot.h>
+#include <linux/kexec.h>
+
+#include <asm/processor.h>
+#include <asm/hardirq.h>
+#include <asm/nmi.h>
+#include <asm/hw_irq.h>
+
+note_buf_t crash_notes[NR_CPUS];
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+       /* This function is only called after the system
+        * has paniced or is otherwise in a critical state.
+        * The minimum amount of code to allow a kexec'd kernel
+        * to run successfully needs to happen here.
+        *
+        * In practice this means shooting down the other cpus in
+        * an SMP system.
+        */
+}
index 7c154dfff64aa406b15294236eee46a738837ee8..6ded3a50dfe63682174470acc3e78e2cfdbfd8b5 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/bootmem.h>
 #include <linux/ioport.h>
 #include <linux/string.h>
+#include <linux/kexec.h>
 #include <asm/page.h>
 #include <asm/e820.h>
 #include <asm/proto.h>
@@ -191,8 +192,6 @@ void __init e820_reserve_resources(void)
        int i;
        for (i = 0; i < e820.nr_map; i++) {
                struct resource *res;
-               if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL)
-                       continue;
                res = alloc_bootmem_low(sizeof(struct resource));
                switch (e820.map[i].type) {
                case E820_RAM:  res->name = "System RAM"; break;
@@ -212,6 +211,9 @@ void __init e820_reserve_resources(void)
                         */
                        request_resource(res, &code_resource);
                        request_resource(res, &data_resource);
+#ifdef CONFIG_KEXEC
+                       request_resource(res, &crashk_res);
+#endif
                }
        }
 }
index b4cbbad0422624aca80206bb15b89f826a8014dd..282846965080ee90ac4388618de7a4b2a2fbedae 100644 (file)
@@ -7,6 +7,8 @@
  * Hacked for x86-64 by James Cleverdon from i386 architecture code by
  * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
  * James Cleverdon.
+ * Ashok Raj <ashok.raj@intel.com>
+ *     Removed IPI broadcast shortcut to support CPU hotplug
  */
 #include <linux/config.h>
 #include <linux/threads.h>
 #include <asm/smp.h>
 #include <asm/ipi.h>
 
+/*
+ * The following permit choosing broadcast IPI shortcut v.s sending IPI only
+ * to online cpus via the send_IPI_mask varient.
+ * The mask version is my preferred option, since it eliminates a lot of
+ * other extra code that would need to be written to cleanup intrs sent
+ * to a CPU while offline.
+ *
+ * Sending broadcast introduces lots of trouble in CPU hotplug situations.
+ * These IPI's are delivered to cpu's irrespective of their offline status
+ * and could pickup stale intr data when these CPUS are turned online.
+ *
+ * Not using broadcast is a cleaner approach IMO, but Andi Kleen disagrees with
+ * the idea of not using broadcast IPI's anymore. Hence the run time check
+ * is introduced, on his request so we can choose an alternate mechanism.
+ *
+ * Initial wacky performance tests that collect cycle counts show
+ * no increase in using mask v.s broadcast version. In fact they seem
+ * identical in terms of cycle counts.
+ *
+ * if we need to use broadcast, we need to do the following.
+ *
+ * cli;
+ * hold call_lock;
+ * clear any pending IPI, just ack and clear all pending intr
+ * set cpu_online_map;
+ * release call_lock;
+ * sti;
+ *
+ * The complicated dummy irq processing shown above is not required if
+ * we didnt sent IPI's to wrong CPU's in the first place.
+ *
+ * - Ashok Raj <ashok.raj@intel.com>
+ */
+#ifdef CONFIG_HOTPLUG_CPU
+#define DEFAULT_SEND_IPI       (1)
+#else
+#define DEFAULT_SEND_IPI       (0)
+#endif
+
+static int no_broadcast=DEFAULT_SEND_IPI;
 
 static cpumask_t flat_target_cpus(void)
 {
@@ -45,22 +87,6 @@ static void flat_init_apic_ldr(void)
        apic_write_around(APIC_LDR, val);
 }
 
-static void flat_send_IPI_allbutself(int vector)
-{
-       /*
-        * if there are no other CPUs in the system then
-        * we get an APIC send error if we try to broadcast.
-        * thus we have to avoid sending IPIs in this case.
-        */
-       if (num_online_cpus() > 1)
-               __send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL);
-}
-
-static void flat_send_IPI_all(int vector)
-{
-       __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
-}
-
 static void flat_send_IPI_mask(cpumask_t cpumask, int vector)
 {
        unsigned long mask = cpus_addr(cpumask)[0];
@@ -93,6 +119,39 @@ static void flat_send_IPI_mask(cpumask_t cpumask, int vector)
        local_irq_restore(flags);
 }
 
+static inline void __local_flat_send_IPI_allbutself(int vector)
+{
+       if (no_broadcast) {
+               cpumask_t mask = cpu_online_map;
+               int this_cpu = get_cpu();
+
+               cpu_clear(this_cpu, mask);
+               flat_send_IPI_mask(mask, vector);
+               put_cpu();
+       }
+       else
+               __send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL);
+}
+
+static inline void __local_flat_send_IPI_all(int vector)
+{
+       if (no_broadcast)
+               flat_send_IPI_mask(cpu_online_map, vector);
+       else
+               __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
+}
+
+static void flat_send_IPI_allbutself(int vector)
+{
+       if (((num_online_cpus()) - 1) >= 1)
+               __local_flat_send_IPI_allbutself(vector);
+}
+
+static void flat_send_IPI_all(int vector)
+{
+       __local_flat_send_IPI_all(vector);
+}
+
 static int flat_apic_id_registered(void)
 {
        return physid_isset(GET_APIC_ID(apic_read(APIC_ID)), phys_cpu_present_map);
@@ -111,6 +170,16 @@ static unsigned int phys_pkg_id(int index_msb)
        return ((ebx >> 24) & 0xFF) >> index_msb;
 }
 
+static __init int no_ipi_broadcast(char *str)
+{
+       get_option(&str, &no_broadcast);
+       printk ("Using %s mode\n", no_broadcast ? "No IPI Broadcast" :
+                                                                                       "IPI Broadcast");
+       return 1;
+}
+
+__setup("no_ipi_broadcast", no_ipi_broadcast);
+
 struct genapic apic_flat =  {
        .name = "flat",
        .int_delivery_mode = dest_LowestPrio,
@@ -125,3 +194,12 @@ struct genapic apic_flat =  {
        .cpu_mask_to_apicid = flat_cpu_mask_to_apicid,
        .phys_pkg_id = phys_pkg_id,
 };
+
+static int __init print_ipi_mode(void)
+{
+       printk ("Using IPI %s mode\n", no_broadcast ? "No-Shortcut" :
+                                                                                       "Shortcut");
+       return 0;
+}
+
+late_initcall(print_ipi_mode);
index 9bd2e7a4b81e196d89856871397d6300c2e4d2bb..8d765aa77a266e980c8edaae33a8c11ffdd42e9c 100644 (file)
@@ -248,23 +248,23 @@ ENTRY(_stext)
         */
 .org 0x1000
 ENTRY(init_level4_pgt)
-       .quad   0x0000000000102007              /* -> level3_ident_pgt */
+       .quad   0x0000000000002007 + __PHYSICAL_START   /* -> level3_ident_pgt */
        .fill   255,8,0
-       .quad   0x000000000010a007
+       .quad   0x000000000000a007 + __PHYSICAL_START
        .fill   254,8,0
        /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
-       .quad   0x0000000000103007              /* -> level3_kernel_pgt */
+       .quad   0x0000000000003007 + __PHYSICAL_START   /* -> level3_kernel_pgt */
 
 .org 0x2000
 ENTRY(level3_ident_pgt)
-       .quad   0x0000000000104007
+       .quad   0x0000000000004007 + __PHYSICAL_START
        .fill   511,8,0
 
 .org 0x3000
 ENTRY(level3_kernel_pgt)
        .fill   510,8,0
        /* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
-       .quad   0x0000000000105007              /* -> level2_kernel_pgt */
+       .quad   0x0000000000005007 + __PHYSICAL_START   /* -> level2_kernel_pgt */
        .fill   1,8,0
 
 .org 0x4000
@@ -337,17 +337,17 @@ ENTRY(empty_bad_pmd_table)
 
 .org 0xa000
 ENTRY(level3_physmem_pgt)
-       .quad   0x0000000000105007              /* -> level2_kernel_pgt (so that __va works even before pagetable_init) */
+       .quad   0x0000000000005007 + __PHYSICAL_START   /* -> level2_kernel_pgt (so that __va works even before pagetable_init) */
 
        .org 0xb000
 #ifdef CONFIG_ACPI_SLEEP
 ENTRY(wakeup_level4_pgt)
-       .quad   0x0000000000102007              /* -> level3_ident_pgt */
+       .quad   0x0000000000002007 + __PHYSICAL_START   /* -> level3_ident_pgt */
        .fill   255,8,0
-       .quad   0x000000000010a007
+       .quad   0x000000000000a007 + __PHYSICAL_START
        .fill   254,8,0
        /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
-       .quad   0x0000000000103007              /* -> level3_kernel_pgt */
+       .quad   0x0000000000003007 + __PHYSICAL_START   /* -> level3_kernel_pgt */
 #endif
 
        .data
index ba139cac57cef085252f30c97d7296fd87c8210e..d9b22b633e390c0739fdd33ba64b121982b8925f 100644 (file)
@@ -42,7 +42,7 @@ void mxcsr_feature_mask_init(void)
  * Called at bootup to set up the initial FPU state that is later cloned
  * into all processes.
  */
-void __init fpu_init(void)
+void __cpuinit fpu_init(void)
 {
        unsigned long oldcr0 = read_cr0();
        extern void __bad_fxsave_alignment(void);
index 19eafa0aa95c4dc1aa822f44fac760c8e2e15ef4..a891690951299912495b8da4915210e73b524988 100644 (file)
@@ -414,10 +414,22 @@ static int i8259A_suspend(struct sys_device *dev, pm_message_t state)
        return 0;
 }
 
+static int i8259A_shutdown(struct sys_device *dev)
+{
+       /* Put the i8259A into a quiescent state that
+        * the kernel initialization code can get it
+        * out of.
+        */
+       outb(0xff, 0x21);       /* mask all of 8259A-1 */
+       outb(0xff, 0xA1);       /* mask all of 8259A-1 */
+       return 0;
+}
+
 static struct sysdev_class i8259_sysdev_class = {
        set_kset_name("i8259"),
        .suspend = i8259A_suspend,
        .resume = i8259A_resume,
+       .shutdown = i8259A_shutdown,
 };
 
 static struct sys_device device_i8259A = {
index afd87e64d0a870c43eaab0a6a99882c9d1c12281..d206d7e49cf5a5381e0c72c96d202bb77c677020 100644 (file)
@@ -330,7 +330,7 @@ static int find_irq_entry(int apic, int pin, int type)
 /*
  * Find the pin to which IRQ[irq] (ISA) is connected
  */
-static int __init find_isa_irq_pin(int irq, int type)
+static int find_isa_irq_pin(int irq, int type)
 {
        int i;
 
@@ -1064,7 +1064,6 @@ void print_all_local_APICs (void)
 
 void __apicdebuginit print_PIC(void)
 {
-       extern spinlock_t i8259A_lock;
        unsigned int v;
        unsigned long flags;
 
@@ -1132,12 +1131,44 @@ static void __init enable_IO_APIC(void)
  */
 void disable_IO_APIC(void)
 {
+       int pin;
        /*
         * Clear the IO-APIC before rebooting:
         */
        clear_IO_APIC();
 
-       disconnect_bsp_APIC();
+       /*
+        * If the i82559 is routed through an IOAPIC
+        * Put that IOAPIC in virtual wire mode
+        * so legacy interrups can be delivered.
+        */
+       pin = find_isa_irq_pin(0, mp_ExtINT);
+       if (pin != -1) {
+               struct IO_APIC_route_entry entry;
+               unsigned long flags;
+
+               memset(&entry, 0, sizeof(entry));
+               entry.mask            = 0; /* Enabled */
+               entry.trigger         = 0; /* Edge */
+               entry.irr             = 0;
+               entry.polarity        = 0; /* High */
+               entry.delivery_status = 0;
+               entry.dest_mode       = 0; /* Physical */
+               entry.delivery_mode   = 7; /* ExtInt */
+               entry.vector          = 0;
+               entry.dest.physical.physical_dest = 0;
+
+
+               /*
+                * Add it to the IO-APIC irq-routing table:
+                */
+               spin_lock_irqsave(&ioapic_lock, flags);
+               io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
+               io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
+               spin_unlock_irqrestore(&ioapic_lock, flags);
+       }
+
+       disconnect_bsp_APIC(pin != -1);
 }
 
 /*
index 62b112e4deb40aa873f7782babe5782a8955e191..cc3fb85f51459141be2519243b8e752d5371f3d9 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
 #include <linux/module.h>
+#include <linux/delay.h>
 #include <asm/uaccess.h>
 #include <asm/io_apic.h>
 
@@ -106,3 +107,31 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
        return 1;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+void fixup_irqs(cpumask_t map)
+{
+       unsigned int irq;
+       static int warned;
+
+       for (irq = 0; irq < NR_IRQS; irq++) {
+               cpumask_t mask;
+               if (irq == 2)
+                       continue;
+
+               cpus_and(mask, irq_affinity[irq], map);
+               if (any_online_cpu(mask) == NR_CPUS) {
+                       printk("Breaking affinity for irq %i\n", irq);
+                       mask = map;
+               }
+               if (irq_desc[irq].handler->set_affinity)
+                       irq_desc[irq].handler->set_affinity(irq, mask);
+               else if (irq_desc[irq].action && !(warned++))
+                       printk("Cannot set affinity for irq %i\n", irq);
+       }
+
+       /* That doesn't seem sufficient.  Give it 1ms. */
+       local_irq_enable();
+       mdelay(1);
+       local_irq_disable();
+}
+#endif
index 4e680f87a75f739729427a4b6027714e1c7f93f5..acd2a778ebe6ddafeb7d036f370e2ef2bca9c849 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/preempt.h>
-#include <linux/moduleloader.h>
+
 #include <asm/cacheflush.h>
 #include <asm/pgtable.h>
 #include <asm/kdebug.h>
@@ -51,8 +51,6 @@ static struct kprobe *kprobe_prev;
 static unsigned long kprobe_status_prev, kprobe_old_rflags_prev, kprobe_saved_rflags_prev;
 static struct pt_regs jprobe_saved_regs;
 static long *jprobe_saved_rsp;
-static kprobe_opcode_t *get_insn_slot(void);
-static void free_insn_slot(kprobe_opcode_t *slot);
 void jprobe_return_end(void);
 
 /* copy of the kernel stack at the probe fire time */
@@ -274,48 +272,23 @@ static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
                regs->rip = (unsigned long)p->ainsn.insn;
 }
 
-struct task_struct  *arch_get_kprobe_task(void *ptr)
-{
-       return ((struct thread_info *) (((unsigned long) ptr) &
-                                       (~(THREAD_SIZE -1))))->task;
-}
-
 void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
 {
        unsigned long *sara = (unsigned long *)regs->rsp;
-       struct kretprobe_instance *ri;
-       static void *orig_ret_addr;
+        struct kretprobe_instance *ri;
+
+        if ((ri = get_free_rp_inst(rp)) != NULL) {
+                ri->rp = rp;
+                ri->task = current;
+               ri->ret_addr = (kprobe_opcode_t *) *sara;
 
-       /*
-        * Save the return address when the return probe hits
-        * the first time, and use it to populate the (krprobe
-        * instance)->ret_addr for subsequent return probes at
-        * the same addrress since stack address would have
-        * the kretprobe_trampoline by then.
-        */
-       if (((void*) *sara) != kretprobe_trampoline)
-               orig_ret_addr = (void*) *sara;
-
-       if ((ri = get_free_rp_inst(rp)) != NULL) {
-               ri->rp = rp;
-               ri->stack_addr = sara;
-               ri->ret_addr = orig_ret_addr;
-               add_rp_inst(ri);
                /* Replace the return addr with trampoline addr */
                *sara = (unsigned long) &kretprobe_trampoline;
-       } else {
-               rp->nmissed++;
-       }
-}
 
-void arch_kprobe_flush_task(struct task_struct *tk)
-{
-       struct kretprobe_instance *ri;
-       while ((ri = get_rp_inst_tsk(tk)) != NULL) {
-               *((unsigned long *)(ri->stack_addr)) =
-                                       (unsigned long) ri->ret_addr;
-               recycle_rp_inst(ri);
-       }
+                add_rp_inst(ri);
+        } else {
+                rp->nmissed++;
+        }
 }
 
 /*
@@ -428,36 +401,59 @@ no_kprobe:
  */
 int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 {
-       struct task_struct *tsk;
-       struct kretprobe_instance *ri;
-       struct hlist_head *head;
-       struct hlist_node *node;
-       unsigned long *sara = (unsigned long *)regs->rsp - 1;
-
-       tsk = arch_get_kprobe_task(sara);
-       head = kretprobe_inst_table_head(tsk);
-
-       hlist_for_each_entry(ri, node, head, hlist) {
-               if (ri->stack_addr == sara && ri->rp) {
-                       if (ri->rp->handler)
-                               ri->rp->handler(ri, regs);
-               }
-       }
-       return 0;
-}
+        struct kretprobe_instance *ri = NULL;
+        struct hlist_head *head;
+        struct hlist_node *node, *tmp;
+       unsigned long orig_ret_address = 0;
+       unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
 
-void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs,
-                                               unsigned long flags)
-{
-       struct kretprobe_instance *ri;
-       /* RA already popped */
-       unsigned long *sara = ((unsigned long *)regs->rsp) - 1;
+        head = kretprobe_inst_table_head(current);
 
-       while ((ri = get_rp_inst(sara))) {
-               regs->rip = (unsigned long)ri->ret_addr;
+       /*
+        * It is possible to have multiple instances associated with a given
+        * task either because an multiple functions in the call path
+        * have a return probe installed on them, and/or more then one return
+        * return probe was registered for a target function.
+        *
+        * We can handle this because:
+        *     - instances are always inserted at the head of the list
+        *     - when multiple return probes are registered for the same
+         *       function, the first instance's ret_addr will point to the
+        *       real return address, and all the rest will point to
+        *       kretprobe_trampoline
+        */
+       hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+                if (ri->task != current)
+                       /* another task is sharing our hash bucket */
+                        continue;
+
+               if (ri->rp && ri->rp->handler)
+                       ri->rp->handler(ri, regs);
+
+               orig_ret_address = (unsigned long)ri->ret_addr;
                recycle_rp_inst(ri);
+
+               if (orig_ret_address != trampoline_address)
+                       /*
+                        * This is the real return address. Any other
+                        * instances associated with this task are for
+                        * other calls deeper on the call stack
+                        */
+                       break;
        }
-       regs->eflags &= ~TF_MASK;
+
+       BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+       regs->rip = orig_ret_address;
+
+       unlock_kprobes();
+       preempt_enable_no_resched();
+
+        /*
+         * By returning a non-zero value, we are telling
+         * kprobe_handler() that we have handled unlocking
+         * and re-enabling preemption.
+         */
+        return 1;
 }
 
 /*
@@ -550,8 +546,7 @@ int post_kprobe_handler(struct pt_regs *regs)
                current_kprobe->post_handler(current_kprobe, regs, 0);
        }
 
-       if (current_kprobe->post_handler != trampoline_post_handler)
-               resume_execution(current_kprobe, regs);
+       resume_execution(current_kprobe, regs);
        regs->eflags |= kprobe_saved_rflags;
 
        /* Restore the original saved kprobes variables and continue. */
@@ -682,111 +677,12 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
        return 0;
 }
 
-/*
- * kprobe->ainsn.insn points to the copy of the instruction to be single-stepped.
- * By default on x86_64, pages we get from kmalloc or vmalloc are not
- * executable.  Single-stepping an instruction on such a page yields an
- * oops.  So instead of storing the instruction copies in their respective
- * kprobe objects, we allocate a page, map it executable, and store all the
- * instruction copies there.  (We can allocate additional pages if somebody
- * inserts a huge number of probes.)  Each page can hold up to INSNS_PER_PAGE
- * instruction slots, each of which is MAX_INSN_SIZE*sizeof(kprobe_opcode_t)
- * bytes.
- */
-#define INSNS_PER_PAGE (PAGE_SIZE/(MAX_INSN_SIZE*sizeof(kprobe_opcode_t)))
-struct kprobe_insn_page {
-       struct hlist_node hlist;
-       kprobe_opcode_t *insns;         /* page of instruction slots */
-       char slot_used[INSNS_PER_PAGE];
-       int nused;
+static struct kprobe trampoline_p = {
+       .addr = (kprobe_opcode_t *) &kretprobe_trampoline,
+       .pre_handler = trampoline_probe_handler
 };
 
-static struct hlist_head kprobe_insn_pages;
-
-/**
- * get_insn_slot() - Find a slot on an executable page for an instruction.
- * We allocate an executable page if there's no room on existing ones.
- */
-static kprobe_opcode_t *get_insn_slot(void)
-{
-       struct kprobe_insn_page *kip;
-       struct hlist_node *pos;
-
-       hlist_for_each(pos, &kprobe_insn_pages) {
-               kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
-               if (kip->nused < INSNS_PER_PAGE) {
-                       int i;
-                       for (i = 0; i < INSNS_PER_PAGE; i++) {
-                               if (!kip->slot_used[i]) {
-                                       kip->slot_used[i] = 1;
-                                       kip->nused++;
-                                       return kip->insns + (i*MAX_INSN_SIZE);
-                               }
-                       }
-                       /* Surprise!  No unused slots.  Fix kip->nused. */
-                       kip->nused = INSNS_PER_PAGE;
-               }
-       }
-
-       /* All out of space.  Need to allocate a new page. Use slot 0.*/
-       kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL);
-       if (!kip) {
-               return NULL;
-       }
-
-       /*
-        * For the %rip-relative displacement fixups to be doable, we
-        * need our instruction copy to be within +/- 2GB of any data it
-        * might access via %rip.  That is, within 2GB of where the
-        * kernel image and loaded module images reside.  So we allocate
-        * a page in the module loading area.
-        */
-       kip->insns = module_alloc(PAGE_SIZE);
-       if (!kip->insns) {
-               kfree(kip);
-               return NULL;
-       }
-       INIT_HLIST_NODE(&kip->hlist);
-       hlist_add_head(&kip->hlist, &kprobe_insn_pages);
-       memset(kip->slot_used, 0, INSNS_PER_PAGE);
-       kip->slot_used[0] = 1;
-       kip->nused = 1;
-       return kip->insns;
-}
-
-/**
- * free_insn_slot() - Free instruction slot obtained from get_insn_slot().
- */
-static void free_insn_slot(kprobe_opcode_t *slot)
+int __init arch_init(void)
 {
-       struct kprobe_insn_page *kip;
-       struct hlist_node *pos;
-
-       hlist_for_each(pos, &kprobe_insn_pages) {
-               kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
-               if (kip->insns <= slot
-                   && slot < kip->insns+(INSNS_PER_PAGE*MAX_INSN_SIZE)) {
-                       int i = (slot - kip->insns) / MAX_INSN_SIZE;
-                       kip->slot_used[i] = 0;
-                       kip->nused--;
-                       if (kip->nused == 0) {
-                               /*
-                                * Page is no longer in use.  Free it unless
-                                * it's the last one.  We keep the last one
-                                * so as not to have to set it up again the
-                                * next time somebody inserts a probe.
-                                */
-                               hlist_del(&kip->hlist);
-                               if (hlist_empty(&kprobe_insn_pages)) {
-                                       INIT_HLIST_NODE(&kip->hlist);
-                                       hlist_add_head(&kip->hlist,
-                                               &kprobe_insn_pages);
-                               } else {
-                                       module_free(NULL, kip->insns);
-                                       kfree(kip);
-                               }
-                       }
-                       return;
-               }
-       }
+       return register_kprobe(&trampoline_p);
 }
diff --git a/arch/x86_64/kernel/machine_kexec.c b/arch/x86_64/kernel/machine_kexec.c
new file mode 100644 (file)
index 0000000..60d1eff
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * machine_kexec.c - handle transition of Linux booting another kernel
+ * Copyright (C) 2002-2005 Eric Biederman  <ebiederm@xmission.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/reboot.h>
+#include <asm/pda.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/apic.h>
+#include <asm/cpufeature.h>
+#include <asm/hw_irq.h>
+
+#define LEVEL0_SIZE (1UL << 12UL)
+#define LEVEL1_SIZE (1UL << 21UL)
+#define LEVEL2_SIZE (1UL << 30UL)
+#define LEVEL3_SIZE (1UL << 39UL)
+#define LEVEL4_SIZE (1UL << 48UL)
+
+#define L0_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define L1_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_PSE)
+#define L2_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define L3_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+static void init_level2_page(u64 *level2p, unsigned long addr)
+{
+       unsigned long end_addr;
+
+       addr &= PAGE_MASK;
+       end_addr = addr + LEVEL2_SIZE;
+       while (addr < end_addr) {
+               *(level2p++) = addr | L1_ATTR;
+               addr += LEVEL1_SIZE;
+       }
+}
+
+static int init_level3_page(struct kimage *image, u64 *level3p,
+                               unsigned long addr, unsigned long last_addr)
+{
+       unsigned long end_addr;
+       int result;
+
+       result = 0;
+       addr &= PAGE_MASK;
+       end_addr = addr + LEVEL3_SIZE;
+       while ((addr < last_addr) && (addr < end_addr)) {
+               struct page *page;
+               u64 *level2p;
+
+               page = kimage_alloc_control_pages(image, 0);
+               if (!page) {
+                       result = -ENOMEM;
+                       goto out;
+               }
+               level2p = (u64 *)page_address(page);
+               init_level2_page(level2p, addr);
+               *(level3p++) = __pa(level2p) | L2_ATTR;
+               addr += LEVEL2_SIZE;
+       }
+       /* clear the unused entries */
+       while (addr < end_addr) {
+               *(level3p++) = 0;
+               addr += LEVEL2_SIZE;
+       }
+out:
+       return result;
+}
+
+
+static int init_level4_page(struct kimage *image, u64 *level4p,
+                               unsigned long addr, unsigned long last_addr)
+{
+       unsigned long end_addr;
+       int result;
+
+       result = 0;
+       addr &= PAGE_MASK;
+       end_addr = addr + LEVEL4_SIZE;
+       while ((addr < last_addr) && (addr < end_addr)) {
+               struct page *page;
+               u64 *level3p;
+
+               page = kimage_alloc_control_pages(image, 0);
+               if (!page) {
+                       result = -ENOMEM;
+                       goto out;
+               }
+               level3p = (u64 *)page_address(page);
+               result = init_level3_page(image, level3p, addr, last_addr);
+               if (result) {
+                       goto out;
+               }
+               *(level4p++) = __pa(level3p) | L3_ATTR;
+               addr += LEVEL3_SIZE;
+       }
+       /* clear the unused entries */
+       while (addr < end_addr) {
+               *(level4p++) = 0;
+               addr += LEVEL3_SIZE;
+       }
+out:
+       return result;
+}
+
+
+static int init_pgtable(struct kimage *image, unsigned long start_pgtable)
+{
+       u64 *level4p;
+       level4p = (u64 *)__va(start_pgtable);
+       return init_level4_page(image, level4p, 0, end_pfn << PAGE_SHIFT);
+}
+
+static void set_idt(void *newidt, u16 limit)
+{
+       unsigned char curidt[10];
+
+       /* x86-64 supports unaliged loads & stores */
+       (*(u16 *)(curidt)) = limit;
+       (*(u64 *)(curidt +2)) = (unsigned long)(newidt);
+
+       __asm__ __volatile__ (
+               "lidt %0\n"
+               : "=m" (curidt)
+               );
+};
+
+
+static void set_gdt(void *newgdt, u16 limit)
+{
+       unsigned char curgdt[10];
+
+       /* x86-64 supports unaligned loads & stores */
+       (*(u16 *)(curgdt)) = limit;
+       (*(u64 *)(curgdt +2)) = (unsigned long)(newgdt);
+
+       __asm__ __volatile__ (
+               "lgdt %0\n"
+               : "=m" (curgdt)
+               );
+};
+
+static void load_segments(void)
+{
+       __asm__ __volatile__ (
+               "\tmovl $"STR(__KERNEL_DS)",%eax\n"
+               "\tmovl %eax,%ds\n"
+               "\tmovl %eax,%es\n"
+               "\tmovl %eax,%ss\n"
+               "\tmovl %eax,%fs\n"
+               "\tmovl %eax,%gs\n"
+               );
+#undef STR
+#undef __STR
+}
+
+typedef NORET_TYPE void (*relocate_new_kernel_t)(unsigned long indirection_page,
+                                       unsigned long control_code_buffer,
+                                       unsigned long start_address,
+                                       unsigned long pgtable) ATTRIB_NORET;
+
+const extern unsigned char relocate_new_kernel[];
+const extern unsigned long relocate_new_kernel_size;
+
+int machine_kexec_prepare(struct kimage *image)
+{
+       unsigned long start_pgtable, control_code_buffer;
+       int result;
+
+       /* Calculate the offsets */
+       start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT;
+       control_code_buffer = start_pgtable + 4096UL;
+
+       /* Setup the identity mapped 64bit page table */
+       result = init_pgtable(image, start_pgtable);
+       if (result)
+               return result;
+
+       /* Place the code in the reboot code buffer */
+       memcpy(__va(control_code_buffer), relocate_new_kernel,
+                                               relocate_new_kernel_size);
+
+       return 0;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+       return;
+}
+
+/*
+ * Do not allocate memory (or fail in any way) in machine_kexec().
+ * We are past the point of no return, committed to rebooting now.
+ */
+NORET_TYPE void machine_kexec(struct kimage *image)
+{
+       unsigned long page_list;
+       unsigned long control_code_buffer;
+       unsigned long start_pgtable;
+       relocate_new_kernel_t rnk;
+
+       /* Interrupts aren't acceptable while we reboot */
+       local_irq_disable();
+
+       /* Calculate the offsets */
+       page_list = image->head;
+       start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT;
+       control_code_buffer = start_pgtable + 4096UL;
+
+       /* Set the low half of the page table to my identity mapped
+        * page table for kexec.  Leave the high half pointing at the
+        * kernel pages.   Don't bother to flush the global pages
+        * as that will happen when I fully switch to my identity mapped
+        * page table anyway.
+        */
+       memcpy(__va(read_cr3()), __va(start_pgtable), PAGE_SIZE/2);
+       __flush_tlb();
+
+
+       /* The segment registers are funny things, they are
+        * automatically loaded from a table, in memory wherever you
+        * set them to a specific selector, but this table is never
+        * accessed again unless you set the segment to a different selector.
+        *
+        * The more common model are caches where the behide
+        * the scenes work is done, but is also dropped at arbitrary
+        * times.
+        *
+        * I take advantage of this here by force loading the
+        * segments, before I zap the gdt with an invalid value.
+        */
+       load_segments();
+       /* The gdt & idt are now invalid.
+        * If you want to load them you must set up your own idt & gdt.
+        */
+       set_gdt(phys_to_virt(0),0);
+       set_idt(phys_to_virt(0),0);
+       /* now call it */
+       rnk = (relocate_new_kernel_t) control_code_buffer;
+       (*rnk)(page_list, control_code_buffer, image->start, start_pgtable);
+}
index 3a89d735a4f60f7203d8b0d2e5df2d2685d299fa..21e70625a4953e26361c060c432f1803393952c5 100644 (file)
@@ -327,7 +327,7 @@ static void mce_init(void *dummy)
 }
 
 /* Add per CPU specific workarounds here */
-static void __init mce_cpu_quirks(struct cpuinfo_x86 *c) 
+static void __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
 { 
        /* This should be disabled by the BIOS, but isn't always */
        if (c->x86_vendor == X86_VENDOR_AMD && c->x86 == 15) {
@@ -337,7 +337,7 @@ static void __init mce_cpu_quirks(struct cpuinfo_x86 *c)
        }
 }                      
 
-static void __init mce_cpu_features(struct cpuinfo_x86 *c)
+static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c)
 {
        switch (c->x86_vendor) {
        case X86_VENDOR_INTEL:
@@ -352,7 +352,7 @@ static void __init mce_cpu_features(struct cpuinfo_x86 *c)
  * Called for each booted CPU to set up machine checks.
  * Must be called with preempt off. 
  */
-void __init mcheck_init(struct cpuinfo_x86 *c)
+void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
 {
        static cpumask_t mce_cpus __initdata = CPU_MASK_NONE;
 
@@ -411,7 +411,7 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff
        memset(mcelog.entry, 0, next * sizeof(struct mce));
        mcelog.next = 0;
 
-       synchronize_kernel();   
+       synchronize_sched();
 
        /* Collect entries that were still getting written before the synchronize. */
 
@@ -542,7 +542,7 @@ ACCESSOR(bank4ctl,bank[4],mce_restart())
 ACCESSOR(tolerant,tolerant,)
 ACCESSOR(check_interval,check_interval,mce_restart())
 
-static __init int mce_init_device(void)
+static __cpuinit int mce_init_device(void)
 {
        int err;
        if (!mce_available(&boot_cpu_data))
index 4db9a640069fe02def836ef0f14340b92c55b84d..0be0a795981418750d322dced63743ee97b4e201 100644 (file)
@@ -42,7 +42,7 @@ done:
        irq_exit();
 }
 
-static void __init intel_init_thermal(struct cpuinfo_x86 *c)
+static void __cpuinit intel_init_thermal(struct cpuinfo_x86 *c)
 {
        u32 l, h;
        int tm2 = 0;
@@ -93,7 +93,7 @@ static void __init intel_init_thermal(struct cpuinfo_x86 *c)
        return;
 }
 
-void __init mce_intel_feature_init(struct cpuinfo_x86 *c)
+void __cpuinit mce_intel_feature_init(struct cpuinfo_x86 *c)
 {
        intel_init_thermal(c);
 }
index 31c0f2e6ac916c8f1cd93f025cf3182b92f1fa3e..4e44d6e6b7e52f35d55993ea9616d4ef39a165fa 100644 (file)
@@ -98,7 +98,7 @@ static unsigned int nmi_p4_cccr_val;
        (P4_CCCR_OVF_PMI0|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT|     \
         P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE)
 
-static __init inline int nmi_known_cpu(void)
+static __cpuinit inline int nmi_known_cpu(void)
 {
        switch (boot_cpu_data.x86_vendor) {
        case X86_VENDOR_AMD:
@@ -110,7 +110,7 @@ static __init inline int nmi_known_cpu(void)
 }
 
 /* Run after command line and cpu_init init, but before all other checks */
-void __init nmi_watchdog_default(void)
+void __cpuinit nmi_watchdog_default(void)
 {
        if (nmi_watchdog != NMI_DEFAULT)
                return;
index e59d1f9d616396172129d91524196d4551324f1f..7577f9d7a75d8373f1a79be83c4e30c63b867f19 100644 (file)
@@ -8,7 +8,8 @@
  * 
  *  X86-64 port
  *     Andi Kleen.
- * 
+ *
+ *     CPU hotplug support - ashok.raj@intel.com
  *  $Id: process.c,v 1.38 2002/01/15 10:08:03 ak Exp $
  */
 
@@ -18,6 +19,7 @@
 
 #include <stdarg.h>
 
+#include <linux/cpu.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -154,6 +156,29 @@ void cpu_idle_wait(void)
 }
 EXPORT_SYMBOL_GPL(cpu_idle_wait);
 
+#ifdef CONFIG_HOTPLUG_CPU
+DECLARE_PER_CPU(int, cpu_state);
+
+#include <asm/nmi.h>
+/* We don't actually take CPU down, just spin without interrupts. */
+static inline void play_dead(void)
+{
+       idle_task_exit();
+       wbinvd();
+       mb();
+       /* Ack it */
+       __get_cpu_var(cpu_state) = CPU_DEAD;
+
+       while (1)
+               safe_halt();
+}
+#else
+static inline void play_dead(void)
+{
+       BUG();
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 /*
  * The idle thread. There's no useful work to be
  * done, so just try to conserve power and have a
@@ -174,6 +199,8 @@ void cpu_idle (void)
                        idle = pm_idle;
                        if (!idle)
                                idle = default_idle;
+                       if (cpu_is_offline(smp_processor_id()))
+                               play_dead();
                        idle();
                }
 
@@ -204,7 +231,7 @@ static void mwait_idle(void)
        }
 }
 
-void __init select_idle_routine(const struct cpuinfo_x86 *c)
+void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
 {
        static int printed;
        if (cpu_has(c, X86_FEATURE_MWAIT)) {
@@ -454,6 +481,33 @@ out:
        return err;
 }
 
+/*
+ * This function selects if the context switch from prev to next
+ * has to tweak the TSC disable bit in the cr4.
+ */
+static inline void disable_tsc(struct task_struct *prev_p,
+                              struct task_struct *next_p)
+{
+       struct thread_info *prev, *next;
+
+       /*
+        * gcc should eliminate the ->thread_info dereference if
+        * has_secure_computing returns 0 at compile time (SECCOMP=n).
+        */
+       prev = prev_p->thread_info;
+       next = next_p->thread_info;
+
+       if (has_secure_computing(prev) || has_secure_computing(next)) {
+               /* slow path here */
+               if (has_secure_computing(prev) &&
+                   !has_secure_computing(next)) {
+                       write_cr4(read_cr4() & ~X86_CR4_TSD);
+               } else if (!has_secure_computing(prev) &&
+                          has_secure_computing(next))
+                       write_cr4(read_cr4() | X86_CR4_TSD);
+       }
+}
+
 /*
  * This special macro can be used to load a debugging register
  */
@@ -572,6 +626,8 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct *
                }
        }
 
+       disable_tsc(prev_p, next_p);
+
        return prev_p;
 }
 
index be4b36f762cf42adb461ec5ea51ea75da45e0e02..57e71dbdfd69952732a24fa8c4ac54a234e49d80 100644 (file)
@@ -66,41 +66,47 @@ static int __init reboot_setup(char *str)
 
 __setup("reboot=", reboot_setup);
 
-#ifdef CONFIG_SMP
-static void smp_halt(void)
+static inline void kb_wait(void)
 {
-       int cpuid = safe_smp_processor_id(); 
-       static int first_entry = 1;
+       int i;
 
-       if (reboot_force)
-               return;
+       for (i=0; i<0x10000; i++)
+               if ((inb_p(0x64) & 0x02) == 0)
+                       break;
+}
 
-       if (first_entry) {
-               first_entry = 0;
-               smp_call_function((void *)machine_restart, NULL, 1, 0);
-       }
-                       
-       smp_stop_cpu(); 
+void machine_shutdown(void)
+{
+       /* Stop the cpus and apics */
+#ifdef CONFIG_SMP
+       int reboot_cpu_id;
 
-       /* AP calling this. Just halt */
-       if (cpuid != boot_cpu_id) { 
-               for (;;) 
-                       asm("hlt");
+       /* The boot cpu is always logical cpu 0 */
+       reboot_cpu_id = 0;
+
+       /* Make certain the cpu I'm about to reboot on is online */
+       if (!cpu_isset(reboot_cpu_id, cpu_online_map)) {
+               reboot_cpu_id = smp_processor_id();
        }
 
-       /* Wait for all other CPUs to have run smp_stop_cpu */
-       while (!cpus_empty(cpu_online_map))
-               rep_nop(); 
-}
+       /* Make certain I only run on the appropriate processor */
+       set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
+
+       /* O.K Now that I'm on the appropriate processor,
+        * stop all of the others.
+        */
+       smp_send_stop();
 #endif
 
-static inline void kb_wait(void)
-{
-       int i;
+       local_irq_disable();
 
-       for (i=0; i<0x10000; i++)
-               if ((inb_p(0x64) & 0x02) == 0)
-                       break;
+#ifndef CONFIG_SMP
+       disable_local_APIC();
+#endif
+
+       disable_IO_APIC();
+
+       local_irq_enable();
 }
 
 void machine_restart(char * __unused)
@@ -109,9 +115,7 @@ void machine_restart(char * __unused)
 
        printk("machine restart\n");
 
-#ifdef CONFIG_SMP
-       smp_halt(); 
-#endif
+       machine_shutdown();
 
        if (!reboot_force) {
                local_irq_disable();
diff --git a/arch/x86_64/kernel/relocate_kernel.S b/arch/x86_64/kernel/relocate_kernel.S
new file mode 100644 (file)
index 0000000..d24fa9b
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * relocate_kernel.S - put the kernel image in place to boot
+ * Copyright (C) 2002-2005 Eric Biederman  <ebiederm@xmission.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <linux/linkage.h>
+
+       /*
+        * Must be relocatable PIC code callable as a C function, that once
+        * it starts can not use the previous processes stack.
+        */
+       .globl relocate_new_kernel
+       .code64
+relocate_new_kernel:
+       /* %rdi page_list
+        * %rsi reboot_code_buffer
+        * %rdx start address
+        * %rcx page_table
+        * %r8  arg5
+        * %r9  arg6
+        */
+
+       /* zero out flags, and disable interrupts */
+       pushq $0
+       popfq
+
+       /* set a new stack at the bottom of our page... */
+       lea   4096(%rsi), %rsp
+
+       /* store the parameters back on the stack */
+       pushq   %rdx /* store the start address */
+
+       /* Set cr0 to a known state:
+        * 31 1 == Paging enabled
+        * 18 0 == Alignment check disabled
+        * 16 0 == Write protect disabled
+        * 3  0 == No task switch
+        * 2  0 == Don't do FP software emulation.
+        * 0  1 == Proctected mode enabled
+        */
+       movq    %cr0, %rax
+       andq    $~((1<<18)|(1<<16)|(1<<3)|(1<<2)), %rax
+       orl     $((1<<31)|(1<<0)), %eax
+       movq    %rax, %cr0
+
+       /* Set cr4 to a known state:
+        * 10 0 == xmm exceptions disabled
+        * 9  0 == xmm registers instructions disabled
+        * 8  0 == performance monitoring counter disabled
+        * 7  0 == page global disabled
+        * 6  0 == machine check exceptions disabled
+        * 5  1 == physical address extension enabled
+        * 4  0 == page size extensions disabled
+        * 3  0 == Debug extensions disabled
+        * 2  0 == Time stamp disable (disabled)
+        * 1  0 == Protected mode virtual interrupts disabled
+        * 0  0 == VME disabled
+        */
+
+       movq    $((1<<5)), %rax
+       movq    %rax, %cr4
+
+       jmp 1f
+1:
+
+       /* Switch to the identity mapped page tables,
+        * and flush the TLB.
+       */
+       movq    %rcx, %cr3
+
+       /* Do the copies */
+       movq    %rdi, %rcx      /* Put the page_list in %rcx */
+       xorq    %rdi, %rdi
+       xorq    %rsi, %rsi
+       jmp     1f
+
+0:     /* top, read another word for the indirection page */
+
+       movq    (%rbx), %rcx
+       addq    $8,     %rbx
+1:
+       testq   $0x1,   %rcx  /* is it a destination page? */
+       jz      2f
+       movq    %rcx,   %rdi
+       andq    $0xfffffffffffff000, %rdi
+       jmp     0b
+2:
+       testq   $0x2,   %rcx  /* is it an indirection page? */
+       jz      2f
+       movq    %rcx,   %rbx
+       andq    $0xfffffffffffff000, %rbx
+       jmp     0b
+2:
+       testq   $0x4,   %rcx  /* is it the done indicator? */
+       jz      2f
+       jmp     3f
+2:
+       testq   $0x8,   %rcx  /* is it the source indicator? */
+       jz      0b            /* Ignore it otherwise */
+       movq    %rcx,   %rsi  /* For ever source page do a copy */
+       andq    $0xfffffffffffff000, %rsi
+
+       movq    $512,   %rcx
+       rep ; movsq
+       jmp     0b
+3:
+
+       /* To be certain of avoiding problems with self-modifying code
+        * I need to execute a serializing instruction here.
+        * So I flush the TLB by reloading %cr3 here, it's handy,
+        * and not processor dependent.
+        */
+       movq    %cr3, %rax
+       movq    %rax, %cr3
+
+       /* set all of the registers to known values */
+       /* leave %rsp alone */
+
+       xorq    %rax, %rax
+       xorq    %rbx, %rbx
+       xorq    %rcx, %rcx
+       xorq    %rdx, %rdx
+       xorq    %rsi, %rsi
+       xorq    %rdi, %rdi
+       xorq    %rbp, %rbp
+       xorq    %r8,  %r8
+       xorq    %r9,  %r9
+       xorq    %r10, %r9
+       xorq    %r11, %r11
+       xorq    %r12, %r12
+       xorq    %r13, %r13
+       xorq    %r14, %r14
+       xorq    %r15, %r15
+
+       ret
+relocate_new_kernel_end:
+
+       .globl relocate_new_kernel_size
+relocate_new_kernel_size:
+       .quad relocate_new_kernel_end - relocate_new_kernel
index 000015dd5a8be5770bb3d845cda66b716d6fe5a8..b02d921da4f72267cf9e7fb534fccf5a33001456 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/kallsyms.h>
 #include <linux/edd.h>
 #include <linux/mmzone.h>
+#include <linux/kexec.h>
 
 #include <asm/mtrr.h>
 #include <asm/uaccess.h>
@@ -367,6 +368,27 @@ static __init void parse_cmdline_early (char ** cmdline_p)
                if (!memcmp(from, "noexec=", 7))
                        nonx_setup(from + 7);
 
+#ifdef CONFIG_KEXEC
+               /* crashkernel=size@addr specifies the location to reserve for
+                * a crash kernel.  By reserving this memory we guarantee
+                * that linux never set's it up as a DMA target.
+                * Useful for holding code to do something appropriate
+                * after a kernel panic.
+                */
+               else if (!memcmp(from, "crashkernel=", 12)) {
+                       unsigned long size, base;
+                       size = memparse(from+12, &from);
+                       if (*from == '@') {
+                               base = memparse(from+1, &from);
+                               /* FIXME: Do I want a sanity check
+                                * to validate the memory range?
+                                */
+                               crashk_res.start = base;
+                               crashk_res.end   = base + size - 1;
+                       }
+               }
+#endif
+
        next_char:
                c = *(from++);
                if (!c)
@@ -625,6 +647,13 @@ void __init setup_arch(char **cmdline_p)
 #endif
 
        sparse_init();
+
+#ifdef CONFIG_KEXEC
+       if (crashk_res.start != crashk_res.end) {
+               reserve_bootmem(crashk_res.start,
+                       crashk_res.end - crashk_res.start + 1);
+       }
+#endif
        paging_init();
 
        check_ioapic();
@@ -676,7 +705,7 @@ void __init setup_arch(char **cmdline_p)
 #endif
 }
 
-static int __init get_model_name(struct cpuinfo_x86 *c)
+static int __cpuinit get_model_name(struct cpuinfo_x86 *c)
 {
        unsigned int *v;
 
@@ -692,7 +721,7 @@ static int __init get_model_name(struct cpuinfo_x86 *c)
 }
 
 
-static void __init display_cacheinfo(struct cpuinfo_x86 *c)
+static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
 {
        unsigned int n, dummy, eax, ebx, ecx, edx;
 
@@ -803,7 +832,7 @@ static int __init init_amd(struct cpuinfo_x86 *c)
        return r;
 }
 
-static void __init detect_ht(struct cpuinfo_x86 *c)
+static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_SMP
        u32     eax, ebx, ecx, edx;
@@ -864,7 +893,7 @@ static void __init detect_ht(struct cpuinfo_x86 *c)
 /*
  * find out the number of processor cores on the die
  */
-static int __init intel_num_cpu_cores(struct cpuinfo_x86 *c)
+static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
 {
        unsigned int eax;
 
@@ -882,7 +911,7 @@ static int __init intel_num_cpu_cores(struct cpuinfo_x86 *c)
                return 1;
 }
 
-static void __init init_intel(struct cpuinfo_x86 *c)
+static void __cpuinit init_intel(struct cpuinfo_x86 *c)
 {
        /* Cache sizes */
        unsigned n;
@@ -902,7 +931,7 @@ static void __init init_intel(struct cpuinfo_x86 *c)
        c->x86_num_cores = intel_num_cpu_cores(c);
 }
 
-void __init get_cpu_vendor(struct cpuinfo_x86 *c)
+void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
 {
        char *v = c->x86_vendor_id;
 
@@ -923,7 +952,7 @@ struct cpu_model_info {
 /* Do some early cpuid on the boot CPU to get some parameter that are
    needed before check_bugs. Everything advanced is in identify_cpu
    below. */
-void __init early_identify_cpu(struct cpuinfo_x86 *c)
+void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
 {
        u32 tfms;
 
@@ -977,7 +1006,7 @@ void __init early_identify_cpu(struct cpuinfo_x86 *c)
 /*
  * This does the hard work of actually picking apart the CPU stuff...
  */
-void __init identify_cpu(struct cpuinfo_x86 *c)
+void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
 {
        int i;
        u32 xlvl;
@@ -1054,7 +1083,7 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
 }
  
 
-void __init print_cpu_info(struct cpuinfo_x86 *c)
+void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
 {
        if (c->x86_model_id[0])
                printk("%s", c->x86_model_id);
index 678b7ac33b8b3cbf6a824750fc42b982dc50e79f..f2b9c6bc999a09753d75bd6e07390913f88e8702 100644 (file)
@@ -29,7 +29,7 @@
 
 char x86_boot_params[BOOT_PARAM_SIZE] __initdata = {0,};
 
-cpumask_t cpu_initialized __initdata = CPU_MASK_NONE;
+cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
 
 struct x8664_pda cpu_pda[NR_CPUS] __cacheline_aligned; 
 
@@ -171,7 +171,7 @@ void syscall_init(void)
        wrmsrl(MSR_SYSCALL_MASK, EF_TF|EF_DF|EF_IE|0x3000); 
 }
 
-void __init check_efer(void)
+void __cpuinit check_efer(void)
 {
        unsigned long efer;
 
@@ -188,7 +188,7 @@ void __init check_efer(void)
  * 'CPU state barrier', nothing should get across.
  * A lot of state is already set up in PDA init.
  */
-void __init cpu_init (void)
+void __cpuinit cpu_init (void)
 {
 #ifdef CONFIG_SMP
        int cpu = stack_smp_processor_id();
index 98b7ba95d581519edb84a263d5f18f8cca8e12df..98590a989f3d759311935f6142191761bd42c376 100644 (file)
@@ -425,7 +425,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
        if (!user_mode(regs))
                return 1;
 
-       if (try_to_freeze(0))
+       if (try_to_freeze())
                goto no_signal;
 
        if (!oldset)
index 1e379ed17b1d7549a3bf48f8c772d4751e516baa..ccae392886af214cdb5c54f8dc261798ac0fe0b2 100644 (file)
@@ -283,6 +283,16 @@ struct call_data_struct {
 
 static struct call_data_struct * call_data;
 
+void lock_ipi_call_lock(void)
+{
+       spin_lock_irq(&call_lock);
+}
+
+void unlock_ipi_call_lock(void)
+{
+       spin_unlock_irq(&call_lock);
+}
+
 /*
  * this function sends a 'generic call function' IPI to all other CPUs
  * in the system.
index f1ec0f34594124f73feb76dcf0f270dc420dfca5..b969ee12872847024e7e32ef96776485a99f501f 100644 (file)
@@ -34,6 +34,7 @@
  *      Andi Kleen              :       Converted to new state machine.
  *                                     Various cleanups.
  *                                     Probably mostly hotplug CPU ready now.
+ *     Ashok Raj                       : CPU hotplug support
  */
 
 
 #include <asm/proto.h>
 #include <asm/nmi.h>
 
-/* Change for real CPU hotplug. Note other files need to be fixed
-   first too. */
-#define __cpuinit __init
-#define __cpuinitdata __initdata
-
 /* Number of siblings per CPU package */
 int smp_num_siblings = 1;
 /* Package ID of each logical CPU */
@@ -103,6 +99,37 @@ EXPORT_SYMBOL(cpu_core_map);
 extern unsigned char trampoline_data[];
 extern unsigned char trampoline_end[];
 
+/* State of each CPU */
+DEFINE_PER_CPU(int, cpu_state) = { 0 };
+
+/*
+ * Store all idle threads, this can be reused instead of creating
+ * a new thread. Also avoids complicated thread destroy functionality
+ * for idle threads.
+ */
+struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ;
+
+#define get_idle_for_cpu(x)     (idle_thread_array[(x)])
+#define set_idle_for_cpu(x,p)   (idle_thread_array[(x)] = (p))
+
+/*
+ * cpu_possible_map should be static, it cannot change as cpu's
+ * are onlined, or offlined. The reason is per-cpu data-structures
+ * are allocated by some modules at init time, and dont expect to
+ * do this dynamically on cpu arrival/departure.
+ * cpu_present_map on the other hand can change dynamically.
+ * In case when cpu_hotplug is not compiled, then we resort to current
+ * behaviour, which is cpu_possible == cpu_present.
+ * If cpu-hotplug is supported, then we need to preallocate for all
+ * those NR_CPUS, hence cpu_possible_map represents entire NR_CPUS range.
+ * - Ashok Raj
+ */
+#ifdef CONFIG_HOTPLUG_CPU
+#define fixup_cpu_possible_map(x)      cpu_set((x), cpu_possible_map)
+#else
+#define fixup_cpu_possible_map(x)
+#endif
+
 /*
  * Currently trivial. Write the real->protected mode
  * bootstrap into the page concerned. The caller
@@ -418,6 +445,33 @@ void __cpuinit smp_callin(void)
        cpu_set(cpuid, cpu_callin_map);
 }
 
+static inline void set_cpu_sibling_map(int cpu)
+{
+       int i;
+
+       if (smp_num_siblings > 1) {
+               for_each_cpu(i) {
+                       if (cpu_core_id[cpu] == cpu_core_id[i]) {
+                               cpu_set(i, cpu_sibling_map[cpu]);
+                               cpu_set(cpu, cpu_sibling_map[i]);
+                       }
+               }
+       } else {
+               cpu_set(cpu, cpu_sibling_map[cpu]);
+       }
+
+       if (current_cpu_data.x86_num_cores > 1) {
+               for_each_cpu(i) {
+                       if (phys_proc_id[cpu] == phys_proc_id[i]) {
+                               cpu_set(i, cpu_core_map[cpu]);
+                               cpu_set(cpu, cpu_core_map[i]);
+                       }
+               }
+       } else {
+               cpu_core_map[cpu] = cpu_sibling_map[cpu];
+       }
+}
+
 /*
  * Setup code on secondary processor (after comming out of the trampoline)
  */
@@ -447,10 +501,29 @@ void __cpuinit start_secondary(void)
 
        enable_APIC_timer();
 
+       /*
+        * The sibling maps must be set before turing the online map on for
+        * this cpu
+        */
+       set_cpu_sibling_map(smp_processor_id());
+
+       /*
+        * We need to hold call_lock, so there is no inconsistency
+        * between the time smp_call_function() determines number of
+        * IPI receipients, and the time when the determination is made
+        * for which cpus receive the IPI in genapic_flat.c. Holding this
+        * lock helps us to not include this cpu in a currently in progress
+        * smp_call_function().
+        */
+       lock_ipi_call_lock();
+
        /*
         * Allow the master to continue.
         */
        cpu_set(smp_processor_id(), cpu_online_map);
+       per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+       unlock_ipi_call_lock();
+
        mb();
 
        /* Wait for TSC sync to not schedule things before.
@@ -628,33 +701,77 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
        return (send_status | accept_status);
 }
 
+struct create_idle {
+       struct task_struct *idle;
+       struct completion done;
+       int cpu;
+};
+
+void do_fork_idle(void *_c_idle)
+{
+       struct create_idle *c_idle = _c_idle;
+
+       c_idle->idle = fork_idle(c_idle->cpu);
+       complete(&c_idle->done);
+}
+
 /*
  * Boot one CPU.
  */
 static int __cpuinit do_boot_cpu(int cpu, int apicid)
 {
-       struct task_struct *idle;
        unsigned long boot_error;
        int timeout;
        unsigned long start_rip;
+       struct create_idle c_idle = {
+               .cpu = cpu,
+               .done = COMPLETION_INITIALIZER(c_idle.done),
+       };
+       DECLARE_WORK(work, do_fork_idle, &c_idle);
+
+       c_idle.idle = get_idle_for_cpu(cpu);
+
+       if (c_idle.idle) {
+               c_idle.idle->thread.rsp = (unsigned long) (((struct pt_regs *)
+                       (THREAD_SIZE + (unsigned long) c_idle.idle->thread_info)) - 1);
+               init_idle(c_idle.idle, cpu);
+               goto do_rest;
+       }
+
        /*
-        * We can't use kernel_thread since we must avoid to
-        * reschedule the child.
+        * During cold boot process, keventd thread is not spun up yet.
+        * When we do cpu hot-add, we create idle threads on the fly, we should
+        * not acquire any attributes from the calling context. Hence the clean
+        * way to create kernel_threads() is to do that from keventd().
+        * We do the current_is_keventd() due to the fact that ACPI notifier
+        * was also queuing to keventd() and when the caller is already running
+        * in context of keventd(), we would end up with locking up the keventd
+        * thread.
         */
-       idle = fork_idle(cpu);
-       if (IS_ERR(idle)) {
+       if (!keventd_up() || current_is_keventd())
+               work.func(work.data);
+       else {
+               schedule_work(&work);
+               wait_for_completion(&c_idle.done);
+       }
+
+       if (IS_ERR(c_idle.idle)) {
                printk("failed fork for CPU %d\n", cpu);
-               return PTR_ERR(idle);
+               return PTR_ERR(c_idle.idle);
        }
 
-       cpu_pda[cpu].pcurrent = idle;
+       set_idle_for_cpu(cpu, c_idle.idle);
+
+do_rest:
+
+       cpu_pda[cpu].pcurrent = c_idle.idle;
 
        start_rip = setup_trampoline();
 
-       init_rsp = idle->thread.rsp;
+       init_rsp = c_idle.idle->thread.rsp;
        per_cpu(init_tss,cpu).rsp0 = init_rsp;
        initial_code = start_secondary;
-       clear_ti_thread_flag(idle->thread_info, TIF_FORK);
+       clear_ti_thread_flag(c_idle.idle->thread_info, TIF_FORK);
 
        printk(KERN_INFO "Booting processor %d/%d rip %lx rsp %lx\n", cpu, apicid,
               start_rip, init_rsp);
@@ -745,51 +862,6 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid)
 cycles_t cacheflush_time;
 unsigned long cache_decay_ticks;
 
-/*
- * Construct cpu_sibling_map[], so that we can tell the sibling CPU
- * on SMT systems efficiently.
- */
-static __cpuinit void detect_siblings(void)
-{
-       int cpu;
-
-       for (cpu = 0; cpu < NR_CPUS; cpu++) {
-               cpus_clear(cpu_sibling_map[cpu]);
-               cpus_clear(cpu_core_map[cpu]);
-       }
-
-       for_each_online_cpu (cpu) {
-               struct cpuinfo_x86 *c = cpu_data + cpu;
-               int siblings = 0;
-               int i;
-               if (smp_num_siblings > 1) {
-                       for_each_online_cpu (i) {
-                               if (cpu_core_id[cpu] == cpu_core_id[i]) {
-                                       siblings++;
-                                       cpu_set(i, cpu_sibling_map[cpu]);
-                               }
-                       }
-               } else {
-                       siblings++;
-                       cpu_set(cpu, cpu_sibling_map[cpu]);
-               }
-
-               if (siblings != smp_num_siblings) {
-                       printk(KERN_WARNING
-              "WARNING: %d siblings found for CPU%d, should be %d\n",
-                              siblings, cpu, smp_num_siblings);
-                       smp_num_siblings = siblings;
-               }
-               if (c->x86_num_cores > 1) {
-                       for_each_online_cpu(i) {
-                               if (phys_proc_id[cpu] == phys_proc_id[i])
-                                       cpu_set(i, cpu_core_map[cpu]);
-                       }
-               } else
-                       cpu_core_map[cpu] = cpu_sibling_map[cpu];
-       }
-}
-
 /*
  * Cleanup possible dangling ends...
  */
@@ -823,7 +895,7 @@ static __cpuinit void smp_cleanup_boot(void)
  *
  * RED-PEN audit/test this more. I bet there is more state messed up here.
  */
-static __cpuinit void disable_smp(void)
+static __init void disable_smp(void)
 {
        cpu_present_map = cpumask_of_cpu(0);
        cpu_possible_map = cpumask_of_cpu(0);
@@ -838,7 +910,7 @@ static __cpuinit void disable_smp(void)
 /*
  * Handle user cpus=... parameter.
  */
-static __cpuinit void enforce_max_cpus(unsigned max_cpus)
+static __init void enforce_max_cpus(unsigned max_cpus)
 {
        int i, k;
        k = 0;
@@ -855,7 +927,7 @@ static __cpuinit void enforce_max_cpus(unsigned max_cpus)
 /*
  * Various sanity checks.
  */
-static int __cpuinit smp_sanity_check(unsigned max_cpus)
+static int __init smp_sanity_check(unsigned max_cpus)
 {
        if (!physid_isset(hard_smp_processor_id(), phys_cpu_present_map)) {
                printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
@@ -913,7 +985,7 @@ static int __cpuinit smp_sanity_check(unsigned max_cpus)
  * Prepare for SMP bootup.  The MP table or ACPI has been read
  * earlier.  Just do some sanity checking here and enable APIC mode.
  */
-void __cpuinit smp_prepare_cpus(unsigned int max_cpus)
+void __init smp_prepare_cpus(unsigned int max_cpus)
 {
        int i;
 
@@ -930,10 +1002,9 @@ void __cpuinit smp_prepare_cpus(unsigned int max_cpus)
                int apicid = cpu_present_to_apicid(i);
                if (physid_isset(apicid, phys_cpu_present_map)) {
                        cpu_set(i, cpu_present_map);
-                       /* possible map would be different if we supported real
-                          CPU hotplug. */
                        cpu_set(i, cpu_possible_map);
                }
+               fixup_cpu_possible_map(i);
        }
 
        if (smp_sanity_check(max_cpus) < 0) {
@@ -978,13 +1049,13 @@ void __init smp_prepare_boot_cpu(void)
        int me = smp_processor_id();
        cpu_set(me, cpu_online_map);
        cpu_set(me, cpu_callout_map);
+       cpu_set(0, cpu_sibling_map[0]);
+       cpu_set(0, cpu_core_map[0]);
+       per_cpu(cpu_state, me) = CPU_ONLINE;
 }
 
 /*
  * Entry point to boot a CPU.
- *
- * This is all __cpuinit, not __devinit for now because we don't support
- * CPU hotplug (yet).
  */
 int __cpuinit __cpu_up(unsigned int cpu)
 {
@@ -1001,6 +1072,15 @@ int __cpuinit __cpu_up(unsigned int cpu)
                return -EINVAL;
        }
 
+       /*
+        * Already booted CPU?
+        */
+       if (cpu_isset(cpu, cpu_callin_map)) {
+               Dprintk("do_boot_cpu %d Already started\n", cpu);
+               return -ENOSYS;
+       }
+
+       per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
        /* Boot it! */
        err = do_boot_cpu(cpu, apicid);
        if (err < 0) {
@@ -1013,23 +1093,118 @@ int __cpuinit __cpu_up(unsigned int cpu)
 
        while (!cpu_isset(cpu, cpu_online_map))
                cpu_relax();
-       return 0;
+       err = 0;
+
+       return err;
 }
 
 /*
  * Finish the SMP boot.
  */
-void __cpuinit smp_cpus_done(unsigned int max_cpus)
+void __init smp_cpus_done(unsigned int max_cpus)
 {
+#ifndef CONFIG_HOTPLUG_CPU
        zap_low_mappings();
+#endif
        smp_cleanup_boot();
 
 #ifdef CONFIG_X86_IO_APIC
        setup_ioapic_dest();
 #endif
 
-       detect_siblings();
        time_init_gtod();
 
        check_nmi_watchdog();
 }
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+static void remove_siblinginfo(int cpu)
+{
+       int sibling;
+
+       for_each_cpu_mask(sibling, cpu_sibling_map[cpu])
+               cpu_clear(cpu, cpu_sibling_map[sibling]);
+       for_each_cpu_mask(sibling, cpu_core_map[cpu])
+               cpu_clear(cpu, cpu_core_map[sibling]);
+       cpus_clear(cpu_sibling_map[cpu]);
+       cpus_clear(cpu_core_map[cpu]);
+       phys_proc_id[cpu] = BAD_APICID;
+       cpu_core_id[cpu] = BAD_APICID;
+}
+
+void remove_cpu_from_maps(void)
+{
+       int cpu = smp_processor_id();
+
+       cpu_clear(cpu, cpu_callout_map);
+       cpu_clear(cpu, cpu_callin_map);
+       clear_bit(cpu, &cpu_initialized); /* was set by cpu_init() */
+}
+
+int __cpu_disable(void)
+{
+       int cpu = smp_processor_id();
+
+       /*
+        * Perhaps use cpufreq to drop frequency, but that could go
+        * into generic code.
+        *
+        * We won't take down the boot processor on i386 due to some
+        * interrupts only being able to be serviced by the BSP.
+        * Especially so if we're not using an IOAPIC   -zwane
+        */
+       if (cpu == 0)
+               return -EBUSY;
+
+       disable_APIC_timer();
+
+       /*
+        * HACK:
+        * Allow any queued timer interrupts to get serviced
+        * This is only a temporary solution until we cleanup
+        * fixup_irqs as we do for IA64.
+        */
+       local_irq_enable();
+       mdelay(1);
+
+       local_irq_disable();
+       remove_siblinginfo(cpu);
+
+       /* It's now safe to remove this processor from the online map */
+       cpu_clear(cpu, cpu_online_map);
+       remove_cpu_from_maps();
+       fixup_irqs(cpu_online_map);
+       return 0;
+}
+
+void __cpu_die(unsigned int cpu)
+{
+       /* We don't do anything here: idle task is faking death itself. */
+       unsigned int i;
+
+       for (i = 0; i < 10; i++) {
+               /* They ack this in play_dead by setting CPU_DEAD */
+               if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
+                       printk ("CPU %d is now offline\n", cpu);
+                       return;
+               }
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(HZ/10);
+       }
+       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 */
index ebaa1e37d6579b7e0912e093fc1daa4fc186646d..6c0f402e3a889c9b7234a6ed8de80b259bd12a38 100644 (file)
@@ -44,7 +44,6 @@ void __save_processor_state(struct saved_context *ctxt)
         */
        asm volatile ("sgdt %0" : "=m" (ctxt->gdt_limit));
        asm volatile ("sidt %0" : "=m" (ctxt->idt_limit));
-       asm volatile ("sldt %0" : "=m" (ctxt->ldt));
        asm volatile ("str %0"  : "=m" (ctxt->tr));
 
        /* XMM0..XMM15 should be handled by kernel_fpu_begin(). */
@@ -69,6 +68,7 @@ void __save_processor_state(struct saved_context *ctxt)
        asm volatile ("movq %%cr2, %0" : "=r" (ctxt->cr2));
        asm volatile ("movq %%cr3, %0" : "=r" (ctxt->cr3));
        asm volatile ("movq %%cr4, %0" : "=r" (ctxt->cr4));
+       asm volatile ("movq %%cr8, %0" : "=r" (ctxt->cr8));
 }
 
 void save_processor_state(void)
@@ -90,11 +90,19 @@ void __restore_processor_state(struct saved_context *ctxt)
        /*
         * control registers
         */
+       asm volatile ("movq %0, %%cr8" :: "r" (ctxt->cr8));
        asm volatile ("movq %0, %%cr4" :: "r" (ctxt->cr4));
        asm volatile ("movq %0, %%cr3" :: "r" (ctxt->cr3));
        asm volatile ("movq %0, %%cr2" :: "r" (ctxt->cr2));
        asm volatile ("movq %0, %%cr0" :: "r" (ctxt->cr0));
 
+       /*
+        * now restore the descriptor tables to their proper values
+        * ltr is done i fix_processor_context().
+        */
+       asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit));
+       asm volatile ("lidt %0" :: "m" (ctxt->idt_limit));
+
        /*
         * segment registers
         */
@@ -108,14 +116,6 @@ void __restore_processor_state(struct saved_context *ctxt)
        wrmsrl(MSR_GS_BASE, ctxt->gs_base);
        wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
 
-       /*
-        * now restore the descriptor tables to their proper values
-        * ltr is done i fix_processor_context().
-        */
-       asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit));
-       asm volatile ("lidt %0" :: "m" (ctxt->idt_limit));
-       asm volatile ("lldt %0" :: "m" (ctxt->ldt));
-
        fix_processor_context();
 
        do_fpu_end();
index 121646fc43f62e399cc39a87d397e6ae4948b944..1027366300022f8846f9bd9a573d0c528f4261e0 100644 (file)
@@ -586,11 +586,17 @@ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
 asmlinkage void default_do_nmi(struct pt_regs *regs)
 {
        unsigned char reason = 0;
+       int cpu;
+
+       cpu = smp_processor_id();
 
        /* Only the BSP gets external NMIs from the system.  */
-       if (!smp_processor_id())
+       if (!cpu)
                reason = get_nmi_reason();
 
+       if (!cpu_online(cpu))
+               return;
+
        if (!(reason & 0xc0)) {
                if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT)
                                                                == NOTIFY_STOP)
index 59ebd5beda8743b6937ca6897d987a9d2ad78b02..73389f51c4e5b2d841619e22e3e27af9ddbbdf24 100644 (file)
@@ -2,7 +2,10 @@
  * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
  */
 
+#define LOAD_OFFSET __START_KERNEL_map
+
 #include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
 #include <linux/config.h>
 
 OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
@@ -11,28 +14,30 @@ ENTRY(phys_startup_64)
 jiffies_64 = jiffies;
 SECTIONS
 {
-  . = 0xffffffff80100000;
+  . = __START_KERNEL;
   phys_startup_64 = startup_64 - LOAD_OFFSET;
   _text = .;                   /* Text and read-only data */
-  .text : {
+  .text :  AT(ADDR(.text) - LOAD_OFFSET) {
        *(.text)
        SCHED_TEXT
        LOCK_TEXT
        *(.fixup)
        *(.gnu.warning)
        } = 0x9090
-  .text.lock : { *(.text.lock) }       /* out-of-line lock text */
+                               /* out-of-line lock text */
+  .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) { *(.text.lock) }
 
   _etext = .;                  /* End of text section */
 
   . = ALIGN(16);               /* Exception table */
   __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
+  __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) }
   __stop___ex_table = .;
 
   RODATA
 
-  .data : {                    /* Data */
+                               /* Data */
+  .data : AT(ADDR(.data) - LOAD_OFFSET) {
        *(.data)
        CONSTRUCTORS
        }
@@ -40,62 +45,95 @@ SECTIONS
   _edata = .;                  /* End of data section */
 
   __bss_start = .;             /* BSS */
-  .bss : {
+  .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
        *(.bss.page_aligned)    
        *(.bss)
        }
   __bss_end = .;
 
+  . = ALIGN(PAGE_SIZE);
   . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+  .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
+       *(.data.cacheline_aligned)
+  }
+
+#define VSYSCALL_ADDR (-10*1024*1024)
+#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.cacheline_aligned) + SIZEOF(.data.cacheline_aligned) + 4095) & ~(4095))
+#define VSYSCALL_VIRT_ADDR ((ADDR(.data.cacheline_aligned) + SIZEOF(.data.cacheline_aligned) + 4095) & ~(4095))
+
+#define VLOAD_OFFSET (VSYSCALL_ADDR - VSYSCALL_PHYS_ADDR)
+#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET)
+
+#define VVIRT_OFFSET (VSYSCALL_ADDR - VSYSCALL_VIRT_ADDR)
+#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET)
 
-#define AFTER(x)      BINALIGN(LOADADDR(x) + SIZEOF(x), 16)
-#define BINALIGN(x,y) (((x) + (y) - 1)  & ~((y) - 1))
-#define CACHE_ALIGN(x) BINALIGN(x, CONFIG_X86_L1_CACHE_BYTES)
+  . = VSYSCALL_ADDR;
+  .vsyscall_0 :         AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) }
+  __vsyscall_0 = VSYSCALL_VIRT_ADDR;
 
-  .vsyscall_0 -10*1024*1024: AT ((LOADADDR(.data.cacheline_aligned) + SIZEOF(.data.cacheline_aligned) + 4095) & ~(4095)) { *(.vsyscall_0) }
-  __vsyscall_0 = LOADADDR(.vsyscall_0);
   . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
-  .xtime_lock : AT CACHE_ALIGN(AFTER(.vsyscall_0)) { *(.xtime_lock) }
-  xtime_lock = LOADADDR(.xtime_lock);
-  .vxtime : AT AFTER(.xtime_lock) { *(.vxtime) }
-  vxtime = LOADADDR(.vxtime);
-  .wall_jiffies : AT AFTER(.vxtime) { *(.wall_jiffies) }
-  wall_jiffies = LOADADDR(.wall_jiffies);
-  .sys_tz : AT AFTER(.wall_jiffies) { *(.sys_tz) }
-  sys_tz = LOADADDR(.sys_tz);
-  .sysctl_vsyscall : AT AFTER(.sys_tz) { *(.sysctl_vsyscall) }
-  sysctl_vsyscall = LOADADDR(.sysctl_vsyscall); 
-  .xtime : AT AFTER(.sysctl_vsyscall) { *(.xtime) }
-  xtime = LOADADDR(.xtime);
+  .xtime_lock : AT(VLOAD(.xtime_lock)) { *(.xtime_lock) }
+  xtime_lock = VVIRT(.xtime_lock);
+
+  .vxtime : AT(VLOAD(.vxtime)) { *(.vxtime) }
+  vxtime = VVIRT(.vxtime);
+
+  .wall_jiffies : AT(VLOAD(.wall_jiffies)) { *(.wall_jiffies) }
+  wall_jiffies = VVIRT(.wall_jiffies);
+
+  .sys_tz : AT(VLOAD(.sys_tz)) { *(.sys_tz) }
+  sys_tz = VVIRT(.sys_tz);
+
+  .sysctl_vsyscall : AT(VLOAD(.sysctl_vsyscall)) { *(.sysctl_vsyscall) }
+  sysctl_vsyscall = VVIRT(.sysctl_vsyscall);
+
+  .xtime : AT(VLOAD(.xtime)) { *(.xtime) }
+  xtime = VVIRT(.xtime);
+
   . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
-  .jiffies : AT CACHE_ALIGN(AFTER(.xtime)) { *(.jiffies) }
-  jiffies = LOADADDR(.jiffies);
-  .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT (LOADADDR(.vsyscall_0) + 1024) { *(.vsyscall_1) }
-  . = LOADADDR(.vsyscall_0) + 4096;
+  .jiffies : AT(VLOAD(.jiffies)) { *(.jiffies) }
+  jiffies = VVIRT(.jiffies);
+
+  .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) { *(.vsyscall_1) }
+  .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2)) { *(.vsyscall_2) }
+  .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) { *(.vsyscall_3) }
+
+  . = VSYSCALL_VIRT_ADDR + 4096;
+
+#undef VSYSCALL_ADDR
+#undef VSYSCALL_PHYS_ADDR
+#undef VSYSCALL_VIRT_ADDR
+#undef VLOAD_OFFSET
+#undef VLOAD
+#undef VVIRT_OFFSET
+#undef VVIRT
 
   . = ALIGN(8192);             /* init_task */
-  .data.init_task : { *(.data.init_task) }
+  .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
+       *(.data.init_task)
+  }
 
   . = ALIGN(4096);
-  .data.page_aligned : { *(.data.page_aligned) }
+  .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+       *(.data.page_aligned)
+  }
 
   . = ALIGN(4096);             /* Init code and data */
   __init_begin = .;
-  .init.text : 
+  .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
        _sinittext = .;
        *(.init.text)
        _einittext = .;
   }
   __initdata_begin = .;
-  .init.data : { *(.init.data) }
+  .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) }
   __initdata_end = .;
   . = ALIGN(16);
   __setup_start = .;
-  .init.setup : { *(.init.setup) }
+  .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : {
+  .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
        *(.initcall1.init) 
        *(.initcall2.init) 
        *(.initcall3.init) 
@@ -106,32 +144,38 @@ SECTIONS
   }
   __initcall_end = .;
   __con_initcall_start = .;
-  .con_initcall.init : { *(.con_initcall.init) }
+  .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
+       *(.con_initcall.init)
+  }
   __con_initcall_end = .;
   SECURITY_INIT
   . = ALIGN(8);
   __alt_instructions = .;
-  .altinstructions : { *(.altinstructions) } 
+  .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
+       *(.altinstructions)
+  }
   __alt_instructions_end = .; 
- .altinstr_replacement : { *(.altinstr_replacement) }
+  .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
+       *(.altinstr_replacement)
+  }
   /* .exit.text is discard at runtime, not link time, to deal with references
      from .altinstructions and .eh_frame */
-  .exit.text : { *(.exit.text) }
-  .exit.data : { *(.exit.data) }       
+  .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) }
+  .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) }
   . = ALIGN(4096);
   __initramfs_start = .;
-  .init.ramfs : { *(.init.ramfs) }
+  .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) }
   __initramfs_end = .; 
   . = ALIGN(32);
   __per_cpu_start = .;
-  .data.percpu  : { *(.data.percpu) }
+  .data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) }
   __per_cpu_end = .;
   . = ALIGN(4096);
   __init_end = .;
 
   . = ALIGN(4096);
   __nosave_begin = .;
-  .data_nosave : { *(.data.nosave) }
+  .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) }
   . = ALIGN(4096);
   __nosave_end = .;
 
index 84cde796ecb133ebfaf145262323d7ab20379482..ac61c186eb0218862f59e8638bef6ef918e11064 100644 (file)
@@ -251,7 +251,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
        setup_node_bootmem(0, start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
 }
 
-__init void numa_add_cpu(int cpu)
+__cpuinit void numa_add_cpu(int cpu)
 {
        /* BP is initialized elsewhere */
        if (cpu) 
index b693c232fd0737c18af22dae138dfb93754f040e..657e88aa09022ba67df0fcc8dca7d20e44ecef53 100644 (file)
@@ -7,25 +7,50 @@
 
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/acpi.h>
 #include "pci.h"
 
 #define MMCONFIG_APER_SIZE (256*1024*1024)
 
-/* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
-u32 pci_mmcfg_base_addr;
-
 /* Static virtual mapping of the MMCONFIG aperture */
-char *pci_mmcfg_virt;
+struct mmcfg_virt {
+       struct acpi_table_mcfg_config *cfg;
+       char *virt;
+};
+static struct mmcfg_virt *pci_mmcfg_virt;
 
-static inline char *pci_dev_base(unsigned int bus, unsigned int devfn)
+static char *get_virt(unsigned int seg, int bus)
 {
-       return pci_mmcfg_virt + ((bus << 20) | (devfn << 12));
+       int cfg_num = -1;
+       struct acpi_table_mcfg_config *cfg;
+
+       while (1) {
+               ++cfg_num;
+               if (cfg_num >= pci_mmcfg_config_num) {
+                       /* something bad is going on, no cfg table is found. */
+                       /* so we fall back to the old way we used to do this */
+                       /* and just rely on the first entry to be correct. */
+                       return pci_mmcfg_virt[0].virt;
+               }
+               cfg = pci_mmcfg_virt[cfg_num].cfg;
+               if (cfg->pci_segment_group_number != seg)
+                       continue;
+               if ((cfg->start_bus_number <= bus) &&
+                   (cfg->end_bus_number >= bus))
+                       return pci_mmcfg_virt[cfg_num].virt;
+       }
+}
+
+static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
+{
+
+       return get_virt(seg, bus) + ((bus << 20) | (devfn << 12));
 }
 
 static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
                          unsigned int devfn, int reg, int len, u32 *value)
 {
-       char *addr = pci_dev_base(bus, devfn); 
+       char *addr = pci_dev_base(seg, bus, devfn);
 
        if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
                return -EINVAL;
@@ -48,7 +73,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
 static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
                           unsigned int devfn, int reg, int len, u32 value)
 {
-       char *addr = pci_dev_base(bus,devfn);
+       char *addr = pci_dev_base(seg, bus, devfn);
 
        if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
                return -EINVAL;
@@ -75,9 +100,15 @@ static struct pci_raw_ops pci_mmcfg = {
 
 static int __init pci_mmcfg_init(void)
 {
+       int i;
+
        if ((pci_probe & PCI_PROBE_MMCONF) == 0)
                return 0;
-       if (!pci_mmcfg_base_addr)
+
+       acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+       if ((pci_mmcfg_config_num == 0) ||
+           (pci_mmcfg_config == NULL) ||
+           (pci_mmcfg_config[0].base_address == 0))
                return 0;
 
        /* Kludge for now. Don't use mmconfig on AMD systems because
@@ -88,13 +119,22 @@ static int __init pci_mmcfg_init(void)
                return 0; 
 
        /* RED-PEN i386 doesn't do _nocache right now */
-       pci_mmcfg_virt = ioremap_nocache(pci_mmcfg_base_addr, MMCONFIG_APER_SIZE);
-       if (!pci_mmcfg_virt) { 
-               printk("PCI: Cannot map mmconfig aperture\n");
+       pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL);
+       if (pci_mmcfg_virt == NULL) {
+               printk("PCI: Can not allocate memory for mmconfig structures\n");
                return 0;
-       }       
+       }
+       for (i = 0; i < pci_mmcfg_config_num; ++i) {
+               pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
+               pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, MMCONFIG_APER_SIZE);
+               if (!pci_mmcfg_virt[i].virt) {
+                       printk("PCI: Cannot map mmconfig aperture for segment %d\n",
+                              pci_mmcfg_config[i].pci_segment_group_number);
+                       return 0;
+               }
+               printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
+       }
 
-       printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_base_addr);
        raw_pci_ops = &pci_mmcfg;
        pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
 
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
new file mode 100644 (file)
index 0000000..c9b5d29
--- /dev/null
@@ -0,0 +1,260 @@
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/config-language.txt.
+
+mainmenu "Linux/Xtensa Kernel Configuration"
+
+config FRAME_POINTER
+       bool
+       default n
+
+config XTENSA
+       bool
+       default y
+       help
+         Xtensa processors are 32-bit RISC machines designed by Tensilica
+         primarily for embedded systems.  These processors are both
+         configurable and extensible.  The Linux port to the Xtensa
+         architecture supports all processor configurations and extensions,
+         with reasonable minimum requirements.  The Xtensa Linux project has
+         a home page at <http://xtensa.sourceforge.net/>.
+
+config UID16
+       bool
+       default n
+
+config RWSEM_XCHGADD_ALGORITHM
+       bool
+       default y
+
+config HAVE_DEC_LOCK
+       bool
+       default y
+
+config GENERIC_HARDIRQS
+       bool
+       default y
+
+source "init/Kconfig"
+
+menu "Processor type and features"
+
+choice
+       prompt "Xtensa Processor Configuration"
+       default XTENSA_CPU_LINUX_BE
+
+config XTENSA_CPU_LINUX_BE
+       bool "linux_be"
+       ---help---
+         The linux_be processor configuration is the baseline Xtensa
+         configurations included in this kernel and also used by
+         binutils, gcc, and gdb. It contains no TIE, no coprocessors,
+         and the following configuration options:
+
+         Code Density Option                2 Misc Special Registers
+         NSA/NSAU Instructions              128-bit Data Bus Width
+         Processor ID                       8K, 2-way I and D Caches
+         Zero-Overhead Loops                2 Inst Address Break Registers
+         Big Endian                         2 Data Address Break Registers
+         64 General-Purpose Registers       JTAG Interface and Trace Port
+         17 Interrupts                      MMU w/ TLBs and Autorefill
+         3 Interrupt Levels                 8 Autorefill Ways (I/D TLBs)
+         3 Timers                           Unaligned Exceptions
+endchoice
+
+config MMU
+       bool
+       default y
+
+config XTENSA_UNALIGNED_USER
+       bool "Unaligned memory access in use space"
+       ---help---
+          The Xtensa architecture currently does not handle unaligned
+          memory accesses in hardware but through an exception handler.
+          Per default, unaligned memory accesses are disabled in user space.
+
+          Say Y here to enable unaligned memory access in user space.
+
+config PREEMPT
+       bool "Preemptible Kernel"
+       ---help---
+           This option reduces the latency of the kernel when reacting to
+           real-time or interactive events by allowing a low priority process to
+           be preempted even if it is in kernel mode executing a system call.
+           Unfortunately the kernel code has some race conditions if both
+           CONFIG_SMP and CONFIG_PREEMPT are enabled, so this option is
+           currently disabled if you are building an SMP kernel.
+
+           Say Y here if you are building a kernel for a desktop, embedded
+           or real-time system.  Say N if you are unsure.
+
+config MATH_EMULATION
+       bool "Math emulation"
+       help
+       Can we use information of configuration file?
+
+config HIGHMEM
+       bool "High memory support"
+
+endmenu
+
+menu "Platform options"
+
+choice
+       prompt "Xtensa System Type"
+       default XTENSA_PLATFORM_ISS
+
+config XTENSA_PLATFORM_ISS
+       bool "ISS"
+       help
+         ISS is an acronym for Tensilica's Instruction Set Simulator.
+
+config XTENSA_PLATFORM_XT2000
+       bool "XT2000"
+       help
+         XT2000 is the name of Tensilica's feature-rich emulation platform.
+         This hardware is capable of running a full Linux distribution.
+
+endchoice
+
+
+config XTENSA_CALIBRATE_CCOUNT
+       bool "Auto calibration of the CPU clock rate"
+       ---help---
+         On some platforms (XT2000, for example), the CPU clock rate can
+         vary.  The frequency can be determined, however, by measuring
+         against a well known, fixed frequency, such as an UART oscillator.
+
+config XTENSA_CPU_CLOCK
+       int "CPU clock rate [MHz]"
+       depends on !XTENSA_CALIBRATE_CCOUNT
+       default "16"
+
+config GENERIC_CALIBRATE_DELAY
+       bool "Auto calibration of the BogoMIPS value"
+       ---help---
+         The BogoMIPS value can easily be derived from the CPU frequency.
+
+config CMDLINE_BOOL
+       bool "Default bootloader kernel arguments"
+
+config CMDLINE
+       string "Initial kernel command string"
+       depends on CMDLINE_BOOL
+       default "console=ttyS0,38400 root=/dev/ram"
+       help
+         On some architectures (EBSA110 and CATS), there is currently no way
+         for the boot loader to pass arguments to the kernel. For these
+         architectures, you should supply some command-line options at build
+         time by entering them here. As a minimum, you should specify the
+         memory size and the root device (e.g., mem=64M root=/dev/nfs).
+
+config SERIAL_CONSOLE
+       bool
+       depends on XTENSA_PLATFORM_ISS
+       default y
+
+config XTENSA_ISS_NETWORK
+       bool
+       depends on XTENSA_PLATFORM_ISS
+       default y
+
+source "mm/Kconfig"
+
+endmenu
+
+menu "Bus options"
+
+config PCI
+       bool "PCI support" if !XTENSA_PLATFORM_ISS
+       depends on !XTENSA_PLATFORM_ISS
+       default y
+       help
+         Find out whether you have a PCI motherboard. PCI is the name of a
+         bus system, i.e. the way the CPU talks to the other stuff inside
+         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
+
+       bool "Support for hot-pluggable devices"
+       ---help---
+       Say Y here if you want to plug devices into your computer while
+       the system is running, and be able to use them quickly.  In many
+       cases, the devices can likewise be unplugged at any time too.
+
+       One well known example of this is PCMCIA- or PC-cards, credit-card
+       size devices such as network cards, modems or hard drives which are
+       plugged into slots found on all modern laptop computers.  Another
+       example, used on modern desktops as well as laptops, is USB.
+
+       Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
+       software (at <http://linux-hotplug.sourceforge.net/>) and install it.
+       Then your kernel will automatically call out to a user mode "policy
+       agent" (/sbin/hotplug) to load modules and set up software needed
+       to use devices as you hotplug them.
+
+source "drivers/pcmcia/Kconfig"
+
+source "drivers/pci/hotplug/Kconfig"
+
+endmenu
+
+menu "Exectuable file formats"
+
+# only elf supported
+config KCORE_ELF
+        bool
+        depends on PROC_FS
+        default y
+        help
+          If you enabled support for /proc file system then the file
+          /proc/kcore will contain the kernel core image in ELF format. This
+          can be used in gdb:
+
+          $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+          This is especially useful if you have compiled the kernel with the
+          "-g" option to preserve debugging information. It is mainly used
+         for examining kernel data structures on the live kernel.
+
+source "fs/Kconfig.binfmt"
+
+endmenu
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+menu "Xtensa initrd options"
+       depends on BLK_DEV_INITRD
+
+       config EMBEDDED_RAMDISK
+       bool "Embed root filesystem ramdisk into the kernel"
+
+config EMBEDDED_RAMDISK_IMAGE
+       string "Filename of gziped ramdisk image"
+       depends on EMBEDDED_RAMDISK
+       default "ramdisk.gz"
+       help
+         This is the filename of the ramdisk image to be built into the
+         kernel.  Relative pathnames are relative to arch/xtensa/boot/ramdisk/.
+         The ramdisk image is not part of the kernel distribution; you must
+         provide one yourself.
+endmenu
+
+source "arch/xtensa/Kconfig.debug"
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
+
+
diff --git a/arch/xtensa/Kconfig.debug b/arch/xtensa/Kconfig.debug
new file mode 100644 (file)
index 0000000..11c5852
--- /dev/null
@@ -0,0 +1,7 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+endmenu
+
+
diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile
new file mode 100644 (file)
index 0000000..27847e4
--- /dev/null
@@ -0,0 +1,104 @@
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 2001 - 2005  Tensilica Inc.
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+
+# Core configuration.
+# (Use CPU=<xtensa_config> to use another default compiler.)
+
+cpu-$(CONFIG_XTENSA_CPU_LINUX_BE)      := linux_be
+cpu-$(CONFIG_XTENSA_CPU_LINUX_CUSTOM)  := linux_custom
+
+CPU = $(cpu-y)
+export CPU
+
+# Platform configuration
+
+platform-$(CONFIG_XTENSA_PLATFORM_XT2000)      := xt2000
+platform-$(CONFIG_XTENSA_PLATFORM_ISS)         := iss
+
+PLATFORM = $(platform-y)
+export PLATFORM
+
+CPPFLAGS       += $(if $(KBUILD_SRC),-I$(srctree)/include/asm-xtensa/)
+CPPFLAGS       += -Iinclude/asm
+CFLAGS         += -pipe -mlongcalls
+
+KBUILD_DEFCONFIG := iss_defconfig
+
+# ramdisk/initrd support
+# You need a compressed ramdisk image, named ramdisk.gz in
+# arch/xtensa/boot/ramdisk
+
+core-$(CONFIG_EMBEDDED_RAMDISK)        += arch/xtensa/boot/ramdisk/
+
+# Test for cross compiling
+
+ifneq ($(CPU),)
+  COMPILE_ARCH = $(shell uname -m)
+
+  ifneq ($(COMPILE_ARCH), xtensa)
+    ifndef CROSS_COMPILE
+      CROSS_COMPILE = xtensa_$(CPU)-
+    endif
+  endif
+endif
+
+#
+
+LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+
+head-y         := arch/xtensa/kernel/head.o
+core-y         += arch/xtensa/kernel/ arch/xtensa/mm/
+ifneq ($(PLATFORM),)
+core-y         += arch/xtensa/platform-$(PLATFORM)/
+endif
+libs-y         += arch/xtensa/lib/ $(LIBGCC)
+
+boot           := arch/xtensa/boot
+
+archinc                := include/asm-xtensa
+
+arch/xtensa/kernel/asm-offsets.s: \
+       arch/xtensa/kernel/asm-offsets.c $(archinc)/.platform
+
+include/asm-xtensa/offsets.h: arch/xtensa/kernel/asm-offsets.s
+       $(call filechk,gen-asm-offsets)
+
+prepare: $(archinc)/.platform $(archinc)/offsets.h
+
+# Update machine cpu and platform symlinks if something which affects
+# them changed.
+
+$(archinc)/.platform: $(wildcard include/config/arch/*.h) include/config/MARKER
+       @echo '  SYMLINK $(archinc)/xtensa/config -> $(archinc)/xtensa/config-$(CPU)'
+       $(Q)mkdir -p $(archinc)
+       $(Q)mkdir -p $(archinc)/xtensa
+       $(Q)ln -fsn $(srctree)/$(archinc)/xtensa/config-$(CPU) $(archinc)/xtensa/config
+       @echo '  SYMLINK $(archinc)/platform -> $(archinc)/platform-$(PLATFORM)'
+       $(Q)ln -fsn $(srctree)/$(archinc)/platform-$(PLATFORM) $(archinc)/platform
+       @touch $@
+
+
+all: zImage
+
+bzImage : zImage
+
+zImage zImage.initrd: vmlinux
+       $(Q)$(MAKE) $(build)=$(boot) $@
+
+CLEAN_FILES    += arch/xtensa/vmlinux.lds $(archinc)/offset.h \
+                  $(archinc)/platform $(archinc)/xtensa/config \
+                  $(archinc)/.platform
+
+define archhelp
+  @echo '* zImage      - Compressed kernel image (arch/xtensa/boot/images/zImage.*)'
+endef
+
diff --git a/arch/xtensa/boot/Makefile b/arch/xtensa/boot/Makefile
new file mode 100644 (file)
index 0000000..820b31d
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# arch/xtensa/boot/Makefile
+#
+# 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.
+#
+#
+
+
+CFLAGS                 += -fno-builtin -Iarch/$(ARCH)/boot/include
+HOSTFLAGS      += -Iarch/$(ARCH)/boot/include
+
+BIG_ENDIAN     := $(shell echo -e __XTENSA_EB__ | $(CC) -E - | grep -v "\#")
+
+export CFLAGS
+export AFLAGS
+export BIG_ENDIAN
+
+subdir-y       := lib
+
+# Subdirs for the boot loader(s)
+
+bootdir-$(CONFIG_XTENSA_PLATFORM_ISS)   += boot-elf
+bootdir-$(CONFIG_XTENSA_PLATFORM_XT2000) += boot-redboot boot-elf
+
+
+zImage zImage.initrd Image Image.initrd: $(bootdir-y)
+
+$(bootdir-y): $(addprefix $(obj)/,$(subdir-y)) \
+             $(addprefix $(obj)/,$(host-progs))
+       $(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS)
+
diff --git a/arch/xtensa/boot/boot-elf/Makefile b/arch/xtensa/boot/boot-elf/Makefile
new file mode 100644 (file)
index 0000000..734db7f
--- /dev/null
@@ -0,0 +1,52 @@
+#
+# 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.
+#
+
+GZIP = gzip
+GZIP_FLAGS = -v9fc
+
+ifeq ($(BIG_ENDIAN),1)
+OBJCOPY_ARGS    := -O elf32-xtensa-be
+else
+OBJCOPY_ARGS    := -O elf32-xtensa-le
+endif
+
+export OBJCOPY_ARGS
+
+boot-y         := bootstrap.o
+
+OBJS           := $(addprefix $(obj)/,$(boot-y))
+
+Image: vmlinux $(OBJS)
+       $(OBJCOPY) --strip-all -R .comment -R .xt.insn -O binary \
+               vmlinux vmlinux.tmp
+       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+               --add-section image=vmlinux.tmp \
+               --set-section-flags image=contents,alloc,load,load,data \
+               $(OBJS) $@.tmp
+       $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) \
+               -T $(srctree)/arch/$(ARCH)/boot/boot-elf/boot.ld \
+               -o arch/$(ARCH)/boot/$@.elf $@.tmp
+       rm -f $@.tmp vmlinux.tmp
+
+Image.initrd:  vmlinux $(OBJS)
+       $(OBJCOPY) --strip-all -R .comment -R .xt.insn -O binary \
+               --add-section .initrd=arch/$(ARCH)/boot/ramdisk \
+               --set-section-flags .initrd=contents,alloc,load,load,data \
+               vmlinux vmlinux.tmp
+       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+               --add-section image=vmlinux.tmp \
+               --set-section-flags image=contents,alloc,load,load,data \
+               $(OBJS) $@.tmp
+       $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) \
+               -T $(srctree)/arch/$(ARCH)/boot/boot-elf/boot.ld \
+               -o arch/$(ARCH)/boot/$@.elf $@.tmp
+       rm -f $@.tmp vmlinux.tmp
+
+
+zImage:        Image
+
+zImage.initrd: Image.initrd
+
diff --git a/arch/xtensa/boot/boot-elf/boot.ld b/arch/xtensa/boot/boot-elf/boot.ld
new file mode 100644 (file)
index 0000000..4ab06a0
--- /dev/null
@@ -0,0 +1,71 @@
+OUTPUT_ARCH(xtensa)
+
+SECTIONS
+{
+       .start 0xD0000000 : { *(.start) }
+
+       .text 0xD0000000:
+       {
+               __reloc_start = . ;
+               _text_start = . ;
+               *(.literal .text.literal .text)
+               _text_end = . ;
+       }
+
+       .rodata ALIGN(0x04):
+       {
+               *(.rodata)
+               *(.rodata1)
+       }
+
+       .data ALIGN(0x04):
+       {
+               *(.data)
+               *(.data1)
+               *(.sdata)
+               *(.sdata2)
+               *(.got.plt)
+               *(.got)
+               *(.dynamic)
+       }
+
+       __reloc_end = . ;
+
+       .initrd ALIGN(0x10) :
+       {
+               boot_initrd_start = . ;
+               *(.initrd)
+               boot_initrd_end = .;
+       }
+
+       . = ALIGN(0x10);
+       __image_load = . ;
+       .image 0xd0001000:
+       {
+               _image_start = .;
+               *(image)
+               . = (. + 3) & ~ 3;
+               _image_end = .  ;
+       }
+
+
+       .bss ((LOADADDR(.image) + SIZEOF(.image) + 3) & ~ 3):
+       {
+               __bss_start = .;
+               *(.sbss)
+               *(.scommon)
+               *(.dynbss)
+               *(.bss)
+               __bss_end = .;
+       }
+       _end = .;
+       _param_start = .;
+
+       .ResetVector.text 0xfe000020 :
+       {
+               *(.ResetVector.text)
+       }
+
+
+       PROVIDE (end = .);
+}
diff --git a/arch/xtensa/boot/boot-elf/bootstrap.S b/arch/xtensa/boot/boot-elf/bootstrap.S
new file mode 100644 (file)
index 0000000..7cba94a
--- /dev/null
@@ -0,0 +1,37 @@
+
+#include <xtensa/config/specreg.h>
+#include <xtensa/config/core.h>
+
+#include <linux/config.h>
+#include <asm/bootparam.h>
+
+
+/* ResetVector
+ */
+       .section        .ResetVector.text, "ax"
+       .global         _ResetVector
+_ResetVector:
+       _j reset
+       .align 4
+RomInitAddr:
+       .word 0xd0001000
+RomBootParam:
+       .word _bootparam
+reset:
+       l32r    a0, RomInitAddr
+       l32r    a2, RomBootParam
+       movi    a3, 0
+       movi    a4, 0
+       jx      a0
+
+       .align 4
+       .section .bootstrap.data, "aw"
+
+       .globl _bootparam
+_bootparam:
+       .short  BP_TAG_FIRST
+       .short  4
+       .long   BP_VERSION
+       .short  BP_TAG_LAST
+       .short  0
+       .long   0
diff --git a/arch/xtensa/boot/boot-redboot/Makefile b/arch/xtensa/boot/boot-redboot/Makefile
new file mode 100644 (file)
index 0000000..f53262c
--- /dev/null
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+
+GZIP = gzip
+GZIP_FLAGS = -v9fc
+ifeq ($(BIG_ENDIAN),1)
+OBJCOPY_ARGS   := -O elf32-xtensa-be
+else
+OBJCOPY_ARGS   := -O elf32-xtensa-le
+endif
+
+LD_ARGS        = -T $(srctree)/$(obj)/boot.ld
+
+boot-y := bootstrap.o
+
+OBJS   := $(addprefix $(obj)/,$(boot-y))
+LIBS   := arch/xtensa/boot/lib/lib.a arch/xtensa/lib/lib.a
+
+LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+
+zImage: vmlinux $(OBJS) $(LIBS)
+       $(OBJCOPY) --strip-all -R .comment -R .xt.insn -O binary \
+               vmlinux vmlinux.tmp
+       gzip -vf9 vmlinux.tmp
+       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+               --add-section image=vmlinux.tmp.gz \
+               --set-section-flags image=contents,alloc,load,load,data \
+               $(OBJS) $@.tmp
+       $(LD) $(LD_ARGS) -o $@.elf $@.tmp $(LIBS) -L/xtensa-elf/lib $(LIBGCC)
+       $(OBJCOPY) -S -O binary $@.elf arch/$(ARCH)/boot/$@.redboot
+       rm -f $@.tmp $@.elf vmlinux.tmp.gz
+
diff --git a/arch/xtensa/boot/boot-redboot/boot.ld b/arch/xtensa/boot/boot-redboot/boot.ld
new file mode 100644 (file)
index 0000000..65b7264
--- /dev/null
@@ -0,0 +1,66 @@
+OUTPUT_ARCH(xtensa)
+
+SECTIONS
+{
+       .start 0xD0200000 : { *(.start) }
+
+       .text :
+       {
+               __reloc_start = . ;
+               _text_start = . ;
+               *(.literal .text.literal .text)
+               _text_end = . ;
+       }
+
+       .rodata ALIGN(0x04):
+       {
+               *(.rodata)
+               *(.rodata1)
+       }
+
+       .data ALIGN(0x04):
+       {
+               *(.data)
+               *(.data1)
+               *(.sdata)
+               *(.sdata2)
+               *(.got.plt)
+               *(.got)
+               *(.dynamic)
+       }
+
+       __reloc_end = . ;
+
+       .initrd ALIGN(0x10) :
+       {
+               boot_initrd_start = . ;
+               *(.initrd)
+               boot_initrd_end = .;
+       }
+
+       . = ALIGN(0x10);
+       __image_load = . ;
+       .image 0xd0001000: AT(__image_load)
+       {
+               _image_start = .;
+               *(image)
+               . = (. + 3) & ~ 3;
+               _image_end = .  ;
+       }
+
+
+       .bss ((LOADADDR(.image) + SIZEOF(.image) + 3) & ~ 3):
+       {
+               __bss_start = .;
+               *(.sbss)
+               *(.scommon)
+               *(.dynbss)
+               *(.bss)
+               __bss_end = .;
+       }
+       _end = .;
+       _param_start = .;
+
+
+       PROVIDE (end = .);
+}
diff --git a/arch/xtensa/boot/boot-redboot/bootstrap.S b/arch/xtensa/boot/boot-redboot/bootstrap.S
new file mode 100644 (file)
index 0000000..ee636b0
--- /dev/null
@@ -0,0 +1,246 @@
+
+#define _ASMLANGUAGE
+#include <xtensa/config/specreg.h>
+#include <xtensa/config/core.h>
+#include <xtensa/cacheasm.h>
+
+       /*
+        * RB-Data: RedBoot data/bss
+        * P:       Boot-Parameters
+        * L:       Kernel-Loader
+        *
+        * The Linux-Kernel image including the loader must be loaded
+        * to a position so that the kernel and the boot parameters
+        * can fit in the space before the load address.
+        *  ______________________________________________________
+        * |_RB-Data_|_P_|__________|_L_|___Linux-Kernel___|______|
+        *                          ^
+        *                          ^ Load address
+        *  ______________________________________________________
+        * |___Linux-Kernel___|_P_|_L_|___________________________|
+        *
+        * The loader copies the parameter to the position that will
+        * be the end of the kernel and itself to the end of the
+        * parameter list.
+        */
+
+/* Make sure we have enough space for the 'uncompressor' */
+
+#define STACK_SIZE 32768
+#define HEAP_SIZE (131072*4)
+
+       # a2: Parameter list
+       # a3: Size of parameter list
+
+       .section .start, "ax"
+
+       .globl __start
+       /* this must be the first byte of the loader! */
+__start:
+       entry   sp, 32          # we do not intend to return
+       _call0  _start
+__start_a0:
+       .align 4
+
+       .section .text, "ax"
+       .begin literal_prefix .text
+
+       /* put literals in here! */
+
+       .globl _start
+_start:
+
+       /* 'reset' window registers */
+
+       movi    a4, 1
+       wsr     a4, PS
+       rsync
+
+       rsr     a5, WINDOWBASE
+       ssl     a5
+       sll     a4, a4
+       wsr     a4, WINDOWSTART
+       rsync
+
+       movi    a4, 0x00040000
+       wsr     a4, PS
+       rsync
+
+       /* copy the loader to its address
+        * Note: The loader itself is a very small piece, so we assume we
+        *       don't partially overlap. We also assume (even more important)
+        *       that the kernel image is out of the way. Usually, when the
+        *       load address of this image is not at an arbitrary address,
+        *       but aligned to some 10K's we shouldn't overlap.
+        */
+
+       /* Note: The assembler cannot relax "addi a0, a0, ..." to an
+          l32r, so we load to a4 first. */
+
+       addi    a4, a0, __start - __start_a0
+       mov     a0, a4
+       movi    a4, __start
+       movi    a5, __reloc_end
+
+       # a0: address where this code has been loaded
+       # a4: compiled address of __start
+       # a5: compiled end address
+
+       mov.n   a7, a0
+       mov.n   a8, a4
+
+1:
+       l32i    a10, a7, 0
+       l32i    a11, a7, 4
+       s32i    a10, a8, 0
+       s32i    a11, a8, 4
+       l32i    a10, a7, 8
+       l32i    a11, a7, 12
+       s32i    a10, a8, 8
+       s32i    a11, a8, 12
+       addi    a8, a8, 16
+       addi    a7, a7, 16
+       blt     a8, a5, 1b
+
+
+       /* We have to flush and invalidate the caches here before we jump. */
+
+#if XCHAL_DCACHE_IS_WRITEBACK
+       dcache_writeback_all  a5, a6
+#endif
+       icache_invalidate_all a5, a6
+
+       movi    a11, _reloc
+       jx      a11
+
+       .globl _reloc
+_reloc:
+
+       /* RedBoot is now at the end of the memory, so we don't have
+        * to copy the parameter list. Keep the code around; in case
+        * we need it again. */
+#if 0
+       # a0: load address
+       # a2: start address of parameter list
+       # a3: length of parameter list
+       # a4: __start
+
+       /* copy the parameter list out of the way */
+
+       movi    a6, _param_start
+       add     a3, a2, a3
+2:
+       l32i    a8, a2, 0
+       s32i    a8, a6, 0
+       addi    a2, a2, 4
+       addi    a6, a6, 4
+       blt     a2, a3, 2b
+#endif
+
+       /* clear BSS section */
+       movi    a6, __bss_start
+       movi    a7, __bss_end
+       movi.n  a5, 0
+3:
+       s32i    a5, a6, 0
+       addi    a6, a6, 4
+       blt     a6, a7, 3b
+
+       movi    a5, -16
+       movi    a1, _stack + STACK_SIZE
+       and     a1, a1, a5
+
+       /* Uncompress the kernel */
+
+       # a0: load address
+       # a2: boot parameter
+       # a4: __start
+
+       movi    a3, __image_load
+       sub     a4, a3, a4
+       add     a8, a0, a4
+
+       # a1  Stack
+       # a8(a4)  Load address of the image
+
+       movi    a6, _image_start
+       movi    a10, _image_end
+       movi    a7, 0x1000000
+       sub     a11, a10, a6
+       movi    a9, complen
+       s32i    a11, a9, 0
+
+       movi    a0, 0
+
+       # a6 destination
+       # a7 maximum size of destination
+       # a8 source
+       # a9 ptr to length
+
+       .extern gunzip
+       movi    a4, gunzip
+       beqz    a4, 1f
+
+       callx4  a4
+
+       j       2f
+
+
+       # a6 destination start
+       # a7 maximum size of destination
+       # a8 source start
+       # a9 ptr to length
+       # a10 destination end
+
+1:
+        l32i    a9, a8, 0
+        l32i    a11, a8, 4
+        s32i    a9, a6, 0
+        s32i    a11, a6, 4
+        l32i    a9, a8, 8
+        l32i    a11, a8, 12
+        s32i    a9, a6, 8
+        s32i    a11, a6, 12
+        addi    a6, a6, 16
+        addi    a8, a8, 16
+        blt     a6, a10, 1b
+
+
+       /* jump to the kernel */
+2:
+#if XCHAL_DCACHE_IS_WRITEBACK
+       dcache_writeback_all a5, a6
+#endif
+       icache_invalidate_all a5, a6
+
+       movi    a5, __start
+       movi    a3, boot_initrd_start
+       movi    a4, boot_initrd_end
+       sub     a3, a3, a5
+       sub     a4, a4, a5
+       add     a3, a0, a3
+       add     a4, a0, a4
+
+       # a2  Boot parameter list
+       # a3  initrd_start (virtual load address)
+       # a4  initrd_end   (virtual load address)
+
+       movi    a0, _image_start
+       jx      a0
+
+       .align 16
+       .data
+       .globl avail_ram
+avail_ram:
+       .long   _heap
+       .globl end_avail
+end_avail:
+       .long   _heap + HEAP_SIZE
+
+       .comm _stack, STACK_SIZE
+       .comm _heap, HEAP_SIZE
+
+       .globl end_avail
+       .comm complen, 4
+
+       .end    literal_prefix
diff --git a/arch/xtensa/boot/lib/Makefile b/arch/xtensa/boot/lib/Makefile
new file mode 100644 (file)
index 0000000..9e73bb8
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# Makefile for some libs needed by zImage.
+#
+
+zlib   := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
+
+lib-y  += $(zlib:.c=.o) zmem.o
+
+EXTRA_CFLAGS   += -Ilib/zlib_inflate
+
+quiet_cmd_copy_zlib = COPY    $@
+      cmd_copy_zlib = cat $< > $@
+
+$(addprefix $(obj)/,$(zlib)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
+       $(call cmd,copy_zlib)
+
+clean-files    := $(zlib)
diff --git a/arch/xtensa/boot/lib/zmem.c b/arch/xtensa/boot/lib/zmem.c
new file mode 100644 (file)
index 0000000..d9862aa
--- /dev/null
@@ -0,0 +1,79 @@
+#include <linux/zlib.h>
+
+/* bits taken from ppc */
+
+extern void *avail_ram, *end_avail;
+
+void exit (void)
+{
+  for (;;);
+}
+
+void *zalloc(unsigned size)
+{
+        void *p = avail_ram;
+
+        size = (size + 7) & -8;
+        avail_ram += size;
+        if (avail_ram > end_avail) {
+                //puts("oops... out of memory\n");
+                //pause();
+                exit ();
+        }
+        return p;
+}
+
+#define HEAD_CRC        2
+#define EXTRA_FIELD     4
+#define ORIG_NAME       8
+#define COMMENT         0x10
+#define RESERVED        0xe0
+
+#define DEFLATED        8
+
+void gunzip (void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+       z_stream s;
+       int r, i, flags;
+
+        /* skip header */
+        i = 10;
+        flags = src[3];
+        if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+                //puts("bad gzipped data\n");
+                exit();
+        }
+        if ((flags & EXTRA_FIELD) != 0)
+                i = 12 + src[10] + (src[11] << 8);
+        if ((flags & ORIG_NAME) != 0)
+                while (src[i++] != 0)
+                        ;
+        if ((flags & COMMENT) != 0)
+                while (src[i++] != 0)
+                        ;
+        if ((flags & HEAD_CRC) != 0)
+                i += 2;
+        if (i >= *lenp) {
+                //puts("gunzip: ran out of data in header\n");
+                exit();
+        }
+
+       s.workspace = zalloc(zlib_inflate_workspacesize());
+        r = zlib_inflateInit2(&s, -MAX_WBITS);
+        if (r != Z_OK) {
+                //puts("inflateInit2 returned "); puthex(r); puts("\n");
+                exit();
+        }
+        s.next_in = src + i;
+        s.avail_in = *lenp - i;
+        s.next_out = dst;
+        s.avail_out = dstlen;
+        r = zlib_inflate(&s, Z_FINISH);
+        if (r != Z_OK && r != Z_STREAM_END) {
+                //puts("inflate returned "); puthex(r); puts("\n");
+                exit();
+        }
+        *lenp = s.next_out - (unsigned char *) dst;
+        zlib_inflateEnd(&s);
+}
+
diff --git a/arch/xtensa/boot/ramdisk/Makefile b/arch/xtensa/boot/ramdisk/Makefile
new file mode 100644 (file)
index 0000000..b12f763
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# Makefile for a ramdisk image
+#
+
+BIG_ENDIAN     := $(shell echo -e "\#ifdef __XTENSA_EL__\nint little;\n\#else\nint big;\n\#endif" | $(CC) -E -|grep -c big)
+
+ifeq ($(BIG_ENDIAN),1)
+OBJCOPY_ARGS    := -O elf32-xtensa-be
+else
+OBJCOPY_ARGS    := -O elf32-xtensa-le
+endif
+
+obj-y = ramdisk.o
+
+RAMDISK_IMAGE = arch/$(ARCH)/boot/ramdisk/$(CONFIG_EMBEDDED_RAMDISK_IMAGE)
+
+arch/$(ARCH)/boot/ramdisk/ramdisk.o:
+       $(Q)echo -e "dummy:" | $(AS) -o $@;
+       $(Q)$(OBJCOPY) $(OBJCOPY_ARGS)                                      \
+               --add-section .initrd=$(RAMDISK_IMAGE)                      \
+               --set-section-flags .initrd=contents,alloc,load,load,data   \
+               arch/$(ARCH)/boot/ramdisk/ramdisk.o $@
+
diff --git a/arch/xtensa/configs/common_defconfig b/arch/xtensa/configs/common_defconfig
new file mode 100644 (file)
index 0000000..1d230ee
--- /dev/null
@@ -0,0 +1,662 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-rc2
+# Tue Mar  1 16:36:53 2005
+#
+# CONFIG_FRAME_POINTER is not set
+CONFIG_XTENSA=y
+# CONFIG_UID16 is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+
+#
+# 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
+
+#
+# Processor type and features
+#
+CONFIG_XTENSA_ARCH_LINUX_BE=y
+# CONFIG_XTENSA_ARCH_LINUX_LE is not set
+# CONFIG_XTENSA_ARCH_LINUX_TEST is not set
+# CONFIG_XTENSA_ARCH_S5 is not set
+# CONFIG_XTENSA_CUSTOM is not set
+CONFIG_MMU=y
+# CONFIG_XTENSA_UNALIGNED_USER is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_HIGHMEM is not set
+
+#
+# Platform options
+#
+# CONFIG_XTENSA_PLATFORM_ISS is not set
+CONFIG_XTENSA_PLATFORM_XT2000=y
+CONFIG_XTENSA_CALIBRATE_CCOUNT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,38400 ip=bootp root=nfs nfsroot=/opt/montavista/pro/devkit/xtensa/linux_be/target"
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+# CONFIG_PCI_NAMES is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Exectuable file formats
+#
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# 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
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+# CONFIG_NET_SCH_HFSC is not set
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+CONFIG_XT2000_SONIC=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+CONFIG_STRIP=m
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_HERMES=m
+# CONFIG_PLX_HERMES is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_PCI_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+# CONFIG_PRISM54 is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+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
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+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 is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_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
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_SYSFS=y
+CONFIG_DEVFS_FS=y
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/xtensa/configs/iss_defconfig b/arch/xtensa/configs/iss_defconfig
new file mode 100644 (file)
index 0000000..802621d
--- /dev/null
@@ -0,0 +1,531 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-rc2
+# Fri Feb 25 19:21:24 2005
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_XTENSA=y
+# CONFIG_UID16 is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_KOBJECT_UEVENT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Processor type and features
+#
+CONFIG_XTENSA_ARCH_LINUX_BE=y
+# CONFIG_XTENSA_ARCH_LINUX_LE is not set
+# CONFIG_XTENSA_ARCH_LINUX_TEST is not set
+# CONFIG_XTENSA_ARCH_S5 is not set
+# CONFIG_XTENSA_CUSTOM is not set
+CONFIG_MMU=y
+# CONFIG_XTENSA_UNALIGNED_USER is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_HIGHMEM is not set
+
+#
+# Platform options
+#
+CONFIG_XTENSA_PLATFORM_ISS=y
+# CONFIG_XTENSA_PLATFORM_XT2000 is not set
+# CONFIG_XTENSA_PLATFORM_ARUBA is not set
+# CONFIG_XTENSA_CALIBRATE_CCOUNT is not set
+CONFIG_XTENSA_CPU_CLOCK=10
+# CONFIG_GENERIC_CALIBRATE_DELAY is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,38400 eth0=tuntap,,tap0 ip=192.168.168.5:192.168.168.1 root=nfs nfsroot=192.168.168.1:/opt/montavista/pro/devkit/xtensa/linux_be/target"
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_XTENSA_ISS_NETWORK=y
+
+#
+# Bus options
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Exectuable file formats
+#
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+# CONFIG_SCTP_HMAC_MD5 is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_SCH_CLK_JIFFIES is not set
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_NETDEVICES is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+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=y
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=y
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+CONFIG_NFS_DIRECTIO=y
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile
new file mode 100644 (file)
index 0000000..d573017
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for the Linux/Xtensa kernel.
+#
+
+extra-y := head.o vmlinux.lds
+
+
+obj-y := align.o entry.o irq.o coprocessor.o process.o ptrace.o semaphore.o  \
+        setup.o signal.o syscalls.o time.o traps.o vectors.o platform.o  \
+        pci-dma.o
+
+## windowspill.o
+
+obj-$(CONFIG_KGDB) += xtensa-stub.o
+obj-$(CONFIG_PCI) += pci.o
+obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o
+
+
diff --git a/arch/xtensa/kernel/align.S b/arch/xtensa/kernel/align.S
new file mode 100644 (file)
index 0000000..74b1e90
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * arch/xtensa/kernel/align.S
+ *
+ * Handle unalignment exceptions in kernel space.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica, Inc.
+ *
+ * Rewritten by Chris Zankel <chris@zankel.net>
+ *
+ * Based on work from Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * and Marc Gauthier <marc@tensilica.com, marc@alimni.uwaterloo.ca>
+ */
+
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+#include <asm/ptrace.h>
+#include <asm/current.h>
+#include <asm/offsets.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/thread_info.h>
+
+#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
+
+/*  First-level exception handler for unaligned exceptions.
+ *
+ *  Note: This handler works only for kernel exceptions.  Unaligned user
+ *        access should get a seg fault.
+ */
+
+/* Big and little endian 16-bit values are located in
+ * different halves of a register.  HWORD_START helps to
+ * abstract the notion of extracting a 16-bit value from a
+ * register.
+ * We also have to define new shifting instructions because
+ * lsb and msb are on 'opposite' ends in a register for
+ * different endian machines.
+ *
+ * Assume a memory region in ascending address:
+ *     0 1 2 3|4 5 6 7
+ *
+ * When loading one word into a register, the content of that register is:
+ *  LE 3 2 1 0, 7 6 5 4
+ *  BE  0 1 2 3, 4 5 6 7
+ *
+ * Masking the bits of the higher/lower address means:
+ *  LE  X X 0 0, 0 0 X X
+ *  BE 0 0 X X, X X 0 0
+ *
+ * Shifting to higher/lower addresses, means:
+ *  LE  shift left / shift right
+ *  BE  shift right / shift left
+ *
+ * Extracting 16 bits from a 32 bit reg. value to higher/lower address means:
+ *  LE  mask 0 0 X X / shift left
+ *  BE  shift left / mask 0 0 X X
+ */
+
+#define UNALIGNED_USER_EXCEPTION
+
+#if XCHAL_HAVE_BE
+
+#define HWORD_START    16
+#define        INSN_OP0        28
+#define        INSN_T          24
+#define        INSN_OP1        16
+
+.macro __src_b r, w0, w1;      src     \r, \w0, \w1;   .endm
+.macro __ssa8  r;              ssa8b   \r;             .endm
+.macro __ssa8r r;              ssa8l   \r;             .endm
+.macro __sh    r, s;           srl     \r, \s;         .endm
+.macro __sl    r, s;           sll     \r, \s;         .endm
+.macro __exth  r, s;           extui   \r, \s, 0, 16;  .endm
+.macro __extl  r, s;           slli    \r, \s, 16;     .endm
+
+#else
+
+#define HWORD_START    0
+#define        INSN_OP0        0
+#define        INSN_T          4
+#define        INSN_OP1        12
+
+.macro __src_b r, w0, w1;      src     \r, \w1, \w0;   .endm
+.macro __ssa8  r;              ssa8l   \r;             .endm
+.macro __ssa8r r;              ssa8b   \r;             .endm
+.macro __sh    r, s;           sll     \r, \s;         .endm
+.macro __sl    r, s;           srl     \r, \s;         .endm
+.macro __exth  r, s;           slli    \r, \s, 16;     .endm
+.macro __extl  r, s;           extui   \r, \s, 0, 16;  .endm
+
+#endif
+
+/*
+ *     xxxx xxxx = imm8 field
+ *          yyyy = imm4 field
+ *          ssss = s field
+ *          tttt = t field
+ *
+ *                      16                 0
+ *                       -------------------
+ *     L32I.N            yyyy ssss tttt 1000
+ *     S32I.N            yyyy ssss tttt 1001
+ *
+ *            23                           0
+ *             -----------------------------
+ *     res               0000           0010
+ *     L16UI   xxxx xxxx 0001 ssss tttt 0010
+ *     L32I    xxxx xxxx 0010 ssss tttt 0010
+ *     XXX               0011 ssss tttt 0010
+ *     XXX               0100 ssss tttt 0010
+ *     S16I    xxxx xxxx 0101 ssss tttt 0010
+ *     S32I    xxxx xxxx 0110 ssss tttt 0010
+ *     XXX               0111 ssss tttt 0010
+ *     XXX               1000 ssss tttt 0010
+ *     L16SI   xxxx xxxx 1001 ssss tttt 0010
+ *     XXX               1010           0010
+ *      **L32AI        xxxx xxxx 1011 ssss tttt 0010 unsupported
+ *     XXX               1100           0010
+ *     XXX               1101           0010
+ *     XXX               1110           0010
+ *     **S32RI xxxx xxxx 1111 ssss tttt 0010 unsupported
+ *             -----------------------------
+ *                           ^         ^    ^
+ *    sub-opcode (NIBBLE_R) -+         |    |
+ *       t field (NIBBLE_T) -----------+    |
+ *  major opcode (NIBBLE_OP0) --------------+
+ */
+
+#define OP0_L32I_N     0x8             /* load immediate narrow */
+#define OP0_S32I_N     0x9             /* store immediate narrow */
+#define OP1_SI_MASK    0x4             /* OP1 bit set for stores */
+#define OP1_SI_BIT     2               /* OP1 bit number for stores */
+
+#define OP1_L32I       0x2
+#define OP1_L16UI      0x1
+#define OP1_L16SI      0x9
+#define OP1_L32AI      0xb
+
+#define OP1_S32I       0x6
+#define OP1_S16I       0x5
+#define OP1_S32RI      0xf
+
+/*
+ * Entry condition:
+ *
+ *   a0:       trashed, original value saved on stack (PT_AREG0)
+ *   a1:       a1
+ *   a2:       new stack pointer, original in DEPC
+ *   a3:       dispatch table
+ *   depc:     a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:        a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+
+ENTRY(fast_unaligned)
+
+       /* Note: We don't expect the address to be aligned on a word
+        *       boundary. After all, the processor generated that exception
+        *       and it would be a hardware fault.
+        */
+
+       /* Save some working register */
+
+       s32i    a4, a2, PT_AREG4
+       s32i    a5, a2, PT_AREG5
+       s32i    a6, a2, PT_AREG6
+       s32i    a7, a2, PT_AREG7
+       s32i    a8, a2, PT_AREG8
+
+       rsr     a0, DEPC
+       xsr     a3, EXCSAVE_1
+       s32i    a0, a2, PT_AREG2
+       s32i    a3, a2, PT_AREG3
+
+       /* Keep value of SAR in a0 */
+
+       rsr     a0, SAR
+       rsr     a8, EXCVADDR            # load unaligned memory address
+
+       /* Now, identify one of the following load/store instructions.
+        *
+        * The only possible danger of a double exception on the
+        * following l32i instructions is kernel code in vmalloc
+        * memory. The processor was just executing at the EPC_1
+        * address, and indeed, already fetched the instruction.  That
+        * guarantees a TLB mapping, which hasn't been replaced by
+        * this unaligned exception handler that uses only static TLB
+        * mappings. However, high-level interrupt handlers might
+        * modify TLB entries, so for the generic case, we register a
+        * TABLE_FIXUP handler here, too.
+        */
+
+       /* a3...a6 saved on stack, a2 = SP */
+
+       /* Extract the instruction that caused the unaligned access. */
+
+       rsr     a7, EPC_1       # load exception address
+       movi    a3, ~3
+       and     a3, a3, a7      # mask lower bits
+
+       l32i    a4, a3, 0       # load 2 words
+       l32i    a5, a3, 4
+
+       __ssa8  a7
+       __src_b a4, a4, a5      # a4 has the instruction
+
+       /* Analyze the instruction (load or store?). */
+
+       extui   a5, a4, INSN_OP0, 4     # get insn.op0 nibble
+
+#if XCHAL_HAVE_NARROW
+       _beqi   a5, OP0_L32I_N, .Lload  # L32I.N, jump
+       addi    a6, a5, -OP0_S32I_N
+       _beqz   a6, .Lstore             # S32I.N, do a store
+#endif
+       /* 'store indicator bit' not set, jump */
+       _bbci.l a4, OP1_SI_BIT + INSN_OP1, .Lload
+
+       /* Store: Jump to table entry to get the value in the source register.*/
+
+.Lstore:movi   a5, .Lstore_table       # table
+       extui   a6, a4, INSN_T, 4       # get source register
+       addx8   a5, a6, a5
+       jx      a5                      # jump into table
+
+       /* Invalid instruction, CRITICAL! */
+.Linvalid_instruction_load:
+       j       .Linvalid_instruction
+
+       /* Load: Load memory address. */
+
+.Lload: movi   a3, ~3
+       and     a3, a3, a8              # align memory address
+
+       __ssa8  a8
+#ifdef UNALIGNED_USER_EXCEPTION
+       addi    a3, a3, 8
+       l32e    a5, a3, -8
+       l32e    a6, a3, -4
+#else
+       l32i    a5, a3, 0
+       l32i    a6, a3, 4
+#endif
+       __src_b a3, a5, a6              # a3 has the data word
+
+#if XCHAL_HAVE_NARROW
+       addi    a7, a7, 2               # increment PC (assume 16-bit insn)
+
+       extui   a5, a4, INSN_OP0, 4
+       _beqi   a5, OP0_L32I_N, 1f      # l32i.n: jump
+
+       addi    a7, a7, 1
+#else
+       addi    a7, a7, 3
+#endif
+
+       extui   a5, a4, INSN_OP1, 4
+       _beqi   a5, OP1_L32I, 1f        # l32i: jump
+
+       extui   a3, a3, 0, 16           # extract lower 16 bits
+       _beqi   a5, OP1_L16UI, 1f
+       addi    a5, a5, -OP1_L16SI
+       _bnez   a5, .Linvalid_instruction_load
+
+       /* sign extend value */
+
+       slli    a3, a3, 16
+       srai    a3, a3, 16
+
+       /* Set target register. */
+
+1:
+
+#if XCHAL_HAVE_LOOP
+       rsr     a3, LEND                # check if we reached LEND
+       bne     a7, a3, 1f
+       rsr     a3, LCOUNT              # and LCOUNT != 0
+       beqz    a3, 1f
+       addi    a3, a3, -1              # decrement LCOUNT and set
+       rsr     a7, LBEG                # set PC to LBEGIN
+       wsr     a3, LCOUNT
+#endif
+
+1:     wsr     a7, EPC_1               # skip load instruction
+       extui   a4, a4, INSN_T, 4       # extract target register
+       movi    a5, .Lload_table
+       addx8   a4, a4, a5
+       jx      a4                      # jump to entry for target register
+
+       .align  8
+.Lload_table:
+       s32i    a3, a2, PT_AREG0;       _j .Lexit;      .align 8
+       mov     a1, a3;                 _j .Lexit;      .align 8 # fishy??
+       s32i    a3, a2, PT_AREG2;       _j .Lexit;      .align 8
+       s32i    a3, a2, PT_AREG3;       _j .Lexit;      .align 8
+       s32i    a3, a2, PT_AREG4;       _j .Lexit;      .align 8
+       s32i    a3, a2, PT_AREG5;       _j .Lexit;      .align 8
+       s32i    a3, a2, PT_AREG6;       _j .Lexit;      .align 8
+       s32i    a3, a2, PT_AREG7;       _j .Lexit;      .align 8
+       s32i    a3, a2, PT_AREG8;       _j .Lexit;      .align 8
+       mov     a9, a3          ;       _j .Lexit;      .align 8
+       mov     a10, a3         ;       _j .Lexit;      .align 8
+       mov     a11, a3         ;       _j .Lexit;      .align 8
+       mov     a12, a3         ;       _j .Lexit;      .align 8
+       mov     a13, a3         ;       _j .Lexit;      .align 8
+       mov     a14, a3         ;       _j .Lexit;      .align 8
+       mov     a15, a3         ;       _j .Lexit;      .align 8
+
+.Lstore_table:
+       l32i    a3, a2, PT_AREG0;       _j 1f;  .align 8
+       mov     a3, a1;                 _j 1f;  .align 8        # fishy??
+       l32i    a3, a2, PT_AREG2;       _j 1f;  .align 8
+       l32i    a3, a2, PT_AREG3;       _j 1f;  .align 8
+       l32i    a3, a2, PT_AREG4;       _j 1f;  .align 8
+       l32i    a3, a2, PT_AREG5;       _j 1f;  .align 8
+       l32i    a3, a2, PT_AREG6;       _j 1f;  .align 8
+       l32i    a3, a2, PT_AREG7;       _j 1f;  .align 8
+       l32i    a3, a2, PT_AREG8;       _j 1f;  .align 8
+       mov     a3, a9          ;       _j 1f;  .align 8
+       mov     a3, a10         ;       _j 1f;  .align 8
+       mov     a3, a11         ;       _j 1f;  .align 8
+       mov     a3, a12         ;       _j 1f;  .align 8
+       mov     a3, a13         ;       _j 1f;  .align 8
+       mov     a3, a14         ;       _j 1f;  .align 8
+       mov     a3, a15         ;       _j 1f;  .align 8
+
+1:     # a7: instruction pointer, a4: instruction, a3: value
+
+       movi    a6, 0                   # mask: ffffffff:00000000
+
+#if XCHAL_HAVE_NARROW
+       addi    a7, a7, 2               # incr. PC,assume 16-bit instruction
+
+       extui   a5, a4, INSN_OP0, 4     # extract OP0
+       addi    a5, a5, -OP0_S32I_N
+       _beqz   a5, 1f                  # s32i.n: jump
+
+       addi    a7, a7, 1               # increment PC, 32-bit instruction
+#else
+       addi    a7, a7, 3               # increment PC, 32-bit instruction
+#endif
+
+       extui   a5, a4, INSN_OP1, 4     # extract OP1
+       _beqi   a5, OP1_S32I, 1f        # jump if 32 bit store
+       _bnei   a5, OP1_S16I, .Linvalid_instruction_store
+
+       movi    a5, -1
+       __extl  a3, a3                  # get 16-bit value
+       __exth  a6, a5                  # get 16-bit mask ffffffff:ffff0000
+
+       /* Get memory address */
+
+1:
+#if XCHAL_HAVE_LOOP
+       rsr     a3, LEND                # check if we reached LEND
+       bne     a7, a3, 1f
+       rsr     a3, LCOUNT              # and LCOUNT != 0
+       beqz    a3, 1f
+       addi    a3, a3, -1              # decrement LCOUNT and set
+       rsr     a7, LBEG                # set PC to LBEGIN
+       wsr     a3, LCOUNT
+#endif
+
+1:     wsr     a7, EPC_1               # skip store instruction
+       movi    a4, ~3
+       and     a4, a4, a8              # align memory address
+
+       /* Insert value into memory */
+
+       movi    a5, -1                  # mask: ffffffff:XXXX0000
+#ifdef UNALIGNED_USER_EXCEPTION
+       addi    a4, a4, 8
+#endif
+
+       __ssa8r a8
+       __src_b a7, a5, a6              # lo-mask  F..F0..0 (BE) 0..0F..F (LE)
+       __src_b a6, a6, a5              # hi-mask  0..0F..F (BE) F..F0..0 (LE)
+#ifdef UNALIGNED_USER_EXCEPTION
+       l32e    a5, a4, -8
+#else
+       l32i    a5, a4, 0               # load lower address word
+#endif
+       and     a5, a5, a7              # mask
+       __sh    a7, a3                  # shift value
+       or      a5, a5, a7              # or with original value
+#ifdef UNALIGNED_USER_EXCEPTION
+       s32e    a5, a4, -8
+       l32e    a7, a4, -4
+#else
+       s32i    a5, a4, 0               # store
+       l32i    a7, a4, 4               # same for upper address word
+#endif
+       __sl    a5, a3
+       and     a6, a7, a6
+       or      a6, a6, a5
+#ifdef UNALIGNED_USER_EXCEPTION
+       s32e    a6, a4, -4
+#else
+       s32i    a6, a4, 4
+#endif
+
+       /* Done. restore stack and return */
+
+.Lexit:
+       movi    a4, 0
+       rsr     a3, EXCSAVE_1
+       s32i    a4, a3, EXC_TABLE_FIXUP
+
+       /* Restore working register */
+
+       l32i    a7, a2, PT_AREG7
+       l32i    a6, a2, PT_AREG6
+       l32i    a5, a2, PT_AREG5
+       l32i    a4, a2, PT_AREG4
+       l32i    a3, a2, PT_AREG3
+
+       /* restore SAR and return */
+
+       wsr     a0, SAR
+       l32i    a0, a2, PT_AREG0
+       l32i    a2, a2, PT_AREG2
+       rfe
+
+       /* We cannot handle this exception. */
+
+       .extern _kernel_exception
+.Linvalid_instruction_store:
+.Linvalid_instruction:
+
+       /* Restore a4...a8 and SAR, set SP, and jump to default exception. */
+
+       l32i    a8, a2, PT_AREG8
+       l32i    a7, a2, PT_AREG7
+       l32i    a6, a2, PT_AREG6
+       l32i    a5, a2, PT_AREG5
+       l32i    a4, a2, PT_AREG4
+       wsr     a0, SAR
+       mov     a1, a2
+
+       rsr     a0, PS
+        bbsi.l  a2, PS_UM_SHIFT, 1f     # jump if user mode
+
+       movi    a0, _kernel_exception
+       jx      a0
+
+1:     movi    a0, _user_exception
+       jx      a0
+
+
+#endif /* XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION */
+
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c
new file mode 100644 (file)
index 0000000..840cd9a
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * arch/xtensa/kernel/asm-offsets.c
+ *
+ * Generates definitions from c-type structures used by assembly sources.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ */
+
+#include <asm/processor.h>
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/thread_info.h>
+#include <linux/ptrace.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+
+#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+       /* struct pt_regs */
+       DEFINE(PT_PC, offsetof (struct pt_regs, pc));
+       DEFINE(PT_PS, offsetof (struct pt_regs, ps));
+       DEFINE(PT_DEPC, offsetof (struct pt_regs, depc));
+       DEFINE(PT_EXCCAUSE, offsetof (struct pt_regs, exccause));
+       DEFINE(PT_EXCVADDR, offsetof (struct pt_regs, excvaddr));
+       DEFINE(PT_DEBUGCAUSE, offsetof (struct pt_regs, debugcause));
+       DEFINE(PT_WMASK, offsetof (struct pt_regs, wmask));
+       DEFINE(PT_LBEG, offsetof (struct pt_regs, lbeg));
+       DEFINE(PT_LEND, offsetof (struct pt_regs, lend));
+       DEFINE(PT_LCOUNT, offsetof (struct pt_regs, lcount));
+       DEFINE(PT_SAR, offsetof (struct pt_regs, sar));
+       DEFINE(PT_SYSCALL, offsetof (struct pt_regs, syscall));
+       DEFINE(PT_AREG, offsetof (struct pt_regs, areg[0]));
+       DEFINE(PT_AREG0, offsetof (struct pt_regs, areg[0]));
+       DEFINE(PT_AREG1, offsetof (struct pt_regs, areg[1]));
+       DEFINE(PT_AREG2, offsetof (struct pt_regs, areg[2]));
+       DEFINE(PT_AREG3, offsetof (struct pt_regs, areg[3]));
+       DEFINE(PT_AREG4, offsetof (struct pt_regs, areg[4]));
+       DEFINE(PT_AREG5, offsetof (struct pt_regs, areg[5]));
+       DEFINE(PT_AREG6, offsetof (struct pt_regs, areg[6]));
+       DEFINE(PT_AREG7, offsetof (struct pt_regs, areg[7]));
+       DEFINE(PT_AREG8, offsetof (struct pt_regs, areg[8]));
+       DEFINE(PT_AREG9, offsetof (struct pt_regs, areg[9]));
+       DEFINE(PT_AREG10, offsetof (struct pt_regs, areg[10]));
+       DEFINE(PT_AREG11, offsetof (struct pt_regs, areg[11]));
+       DEFINE(PT_AREG12, offsetof (struct pt_regs, areg[12]));
+       DEFINE(PT_AREG13, offsetof (struct pt_regs, areg[13]));
+       DEFINE(PT_AREG14, offsetof (struct pt_regs, areg[14]));
+       DEFINE(PT_AREG15, offsetof (struct pt_regs, areg[15]));
+       DEFINE(PT_WINDOWBASE, offsetof (struct pt_regs, windowbase));
+       DEFINE(PT_WINDOWSTART, offsetof(struct pt_regs, windowstart));
+       DEFINE(PT_SIZE, sizeof(struct pt_regs));
+       DEFINE(PT_AREG_END, offsetof (struct pt_regs, areg[XCHAL_NUM_AREGS]));
+       DEFINE(PT_USER_SIZE, offsetof(struct pt_regs, areg[XCHAL_NUM_AREGS]));
+       BLANK();
+
+       /* struct task_struct */
+       DEFINE(TASK_PTRACE, offsetof (struct task_struct, ptrace));
+       DEFINE(TASK_MM, offsetof (struct task_struct, mm));
+       DEFINE(TASK_ACTIVE_MM, offsetof (struct task_struct, active_mm));
+       DEFINE(TASK_PID, offsetof (struct task_struct, pid));
+       DEFINE(TASK_THREAD, offsetof (struct task_struct, thread));
+       DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, thread_info));
+       DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct));
+       BLANK();
+
+       /* struct thread_info (offset from start_struct) */
+       DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
+       DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
+       DEFINE(THREAD_CP_SAVE, offsetof (struct task_struct, thread.cp_save));
+       DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds));
+       BLANK();
+
+       /* struct mm_struct */
+       DEFINE(MM_USERS, offsetof(struct mm_struct, mm_users));
+       DEFINE(MM_PGD, offsetof (struct mm_struct, pgd));
+       DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context));
+       BLANK();
+       DEFINE(PT_SINGLESTEP_BIT, PT_SINGLESTEP_BIT);
+       return 0;
+}
+
+
diff --git a/arch/xtensa/kernel/coprocessor.S b/arch/xtensa/kernel/coprocessor.S
new file mode 100644 (file)
index 0000000..356192a
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * arch/xtensa/kernel/coprocessor.S
+ *
+ * Xtensa processor configuration-specific table of coprocessor and
+ * other custom register layout information.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 - 2005 Tensilica Inc.
+ *
+ * Marc Gauthier <marc@tensilica.com> <marc@alumni.uwaterloo.ca>
+ */
+
+/*
+ * This module contains a table that describes the layout of the various
+ * custom registers and states associated with each coprocessor, as well
+ * as those not associated with any coprocessor ("extra state").
+ * This table is included with core dumps and is available via the ptrace
+ * interface, allowing the layout of such register/state information to
+ * be modified in the kernel without affecting the debugger.  Each
+ * register or state is identified using a 32-bit "libdb target number"
+ * assigned when the Xtensa processor is generated.
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/processor.h>
+
+#if XCHAL_HAVE_CP
+
+#define CP_LAST ((XCHAL_CP_MAX - 1) * COPROCESSOR_INFO_SIZE)
+
+ENTRY(release_coprocessors)
+
+       entry   a1, 16
+                                               # a2: task
+       movi    a3, 1 << XCHAL_CP_MAX           # a3: coprocessor-bit
+       movi    a4, coprocessor_info+CP_LAST    # a4: owner-table
+                                               # a5: tmp
+       movi    a6, 0                           # a6: 0
+       rsil    a7, LOCKLEVEL                   # a7: PS
+
+1:     /* Check if task is coprocessor owner of coprocessor[i]. */
+
+       l32i    a5, a4, COPROCESSOR_INFO_OWNER
+       srli    a3, a3, 1
+       beqz    a3, 1f
+       addi    a4, a4, -8
+       beq     a2, a5, 1b
+
+       /* Found an entry: Clear entry CPENABLE bit to disable CP. */
+
+       rsr     a5, CPENABLE
+       s32i    a6, a4, COPROCESSOR_INFO_OWNER
+       xor     a5, a3, a5
+       wsr     a5, CPENABLE
+
+       bnez    a3, 1b
+
+1:     wsr     a7, PS
+       rsync
+       retw
+
+
+ENTRY(disable_coprocessor)
+       entry   sp, 16
+       rsil    a7, LOCKLEVEL
+       rsr     a3, CPENABLE
+       movi    a4, 1
+       ssl     a2
+       sll     a4, a4
+       and     a4, a3, a4
+       xor     a3, a3, a4
+       wsr     a3, CPENABLE
+       wsr     a7, PS
+       rsync
+       retw
+
+ENTRY(enable_coprocessor)
+       entry   sp, 16
+       rsil    a7, LOCKLEVEL
+       rsr     a3, CPENABLE
+       movi    a4, 1
+       ssl     a2
+       sll     a4, a4
+       or      a3, a3, a4
+       wsr     a3, CPENABLE
+       wsr     a7, PS
+       rsync
+       retw
+
+#endif
+
+ENTRY(save_coprocessor_extra)
+       entry   sp, 16
+       xchal_extra_store_funcbody
+       retw
+
+ENTRY(restore_coprocessor_extra)
+       entry   sp, 16
+       xchal_extra_load_funcbody
+       retw
+
+ENTRY(save_coprocessor_registers)
+       entry   sp, 16
+       xchal_cpi_store_funcbody
+       retw
+
+ENTRY(restore_coprocessor_registers)
+       entry   sp, 16
+       xchal_cpi_load_funcbody
+       retw
+
+
+/*
+ *  The Xtensa compile-time HAL (core.h) XCHAL_*_SA_CONTENTS_LIBDB macros
+ *  describe the contents of coprocessor & extra save areas in terms of
+ *  undefined CONTENTS_LIBDB_{SREG,UREG,REGF} macros.  We define these
+ *  latter macros here; they expand into a table of the format we want.
+ *  The general format is:
+ *
+ *     CONTENTS_LIBDB_SREG(libdbnum, offset, size, align, rsv1, name, sregnum,
+ *                         bitmask, rsv2, rsv3)
+ *     CONTENTS_LIBDB_UREG(libdbnum, offset, size, align, rsv1, name, uregnum,
+ *                         bitmask, rsv2, rsv3)
+ *     CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index,
+ *                         numentries, contentsize, regname_base,
+ *                         regfile_name, rsv2, rsv3)
+ *
+ *  For this table, we only care about the <libdbnum>, <offset> and <size>
+ *  fields.
+ */
+
+/*  Map all XCHAL CONTENTS macros to the reg_entry asm macro defined below:  */
+
+#define CONTENTS_LIBDB_SREG(libdbnum,offset,size,align,rsv1,name,sregnum,     \
+                           bitmask, rsv2, rsv3)                              \
+               reg_entry libdbnum, offset, size ;
+#define CONTENTS_LIBDB_UREG(libdbnum,offset,size,align,rsv1,name,uregnum,     \
+                           bitmask, rsv2, rsv3)                              \
+               reg_entry libdbnum, offset, size ;
+#define CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index, \
+                           numentries, contentsize, regname_base,            \
+                           regfile_name, rsv2, rsv3)                         \
+               reg_entry libdbnum, offset, size ;
+
+/* A single table entry: */
+       .macro  reg_entry       libdbnum, offset, size
+        .ifne  (__last_offset-(__last_group_offset+\offset))
+         /* padding entry */
+         .word (0xFC000000+__last_offset-(__last_group_offset+\offset))
+        .endif
+        .word  \libdbnum                               /* actual entry */
+        .set   __last_offset, __last_group_offset+\offset+\size
+       .endm   /* reg_entry */
+
+
+/* Table entry that marks the beginning of a group (coprocessor or "extra"): */
+       .macro  reg_group       cpnum, num_entries, align
+        .set   __last_group_offset, (__last_offset + \align- 1) & -\align
+        .ifne  \num_entries
+         .word 0xFD000000+(\cpnum<<16)+\num_entries
+        .endif
+       .endm   /* reg_group */
+
+/*
+ * Register info tables.
+ */
+
+       .section .rodata, "a"
+       .globl  _xtensa_reginfo_tables
+       .globl  _xtensa_reginfo_table_size
+       .align  4
+_xtensa_reginfo_table_size:
+       .word   _xtensa_reginfo_table_end - _xtensa_reginfo_tables
+
+_xtensa_reginfo_tables:
+       .set    __last_offset, 0
+       reg_group 0xFF, XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM, XCHAL_EXTRA_SA_ALIGN
+       XCHAL_EXTRA_SA_CONTENTS_LIBDB
+       reg_group 0, XCHAL_CP0_SA_CONTENTS_LIBDB_NUM, XCHAL_CP0_SA_ALIGN
+       XCHAL_CP0_SA_CONTENTS_LIBDB
+       reg_group 1, XCHAL_CP1_SA_CONTENTS_LIBDB_NUM, XCHAL_CP1_SA_ALIGN
+       XCHAL_CP1_SA_CONTENTS_LIBDB
+       reg_group 2, XCHAL_CP2_SA_CONTENTS_LIBDB_NUM, XCHAL_CP2_SA_ALIGN
+       XCHAL_CP2_SA_CONTENTS_LIBDB
+       reg_group 3, XCHAL_CP3_SA_CONTENTS_LIBDB_NUM, XCHAL_CP3_SA_ALIGN
+       XCHAL_CP3_SA_CONTENTS_LIBDB
+       reg_group 4, XCHAL_CP4_SA_CONTENTS_LIBDB_NUM, XCHAL_CP4_SA_ALIGN
+       XCHAL_CP4_SA_CONTENTS_LIBDB
+       reg_group 5, XCHAL_CP5_SA_CONTENTS_LIBDB_NUM, XCHAL_CP5_SA_ALIGN
+       XCHAL_CP5_SA_CONTENTS_LIBDB
+       reg_group 6, XCHAL_CP6_SA_CONTENTS_LIBDB_NUM, XCHAL_CP6_SA_ALIGN
+       XCHAL_CP6_SA_CONTENTS_LIBDB
+       reg_group 7, XCHAL_CP7_SA_CONTENTS_LIBDB_NUM, XCHAL_CP7_SA_ALIGN
+       XCHAL_CP7_SA_CONTENTS_LIBDB
+       .word   0xFC000000      /* invalid register number,marks end of table*/
+_xtensa_reginfo_table_end:
+
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
new file mode 100644 (file)
index 0000000..c64a01f
--- /dev/null
@@ -0,0 +1,1996 @@
+/*
+ * arch/xtensa/kernel/entry.S
+ *
+ * Low-level exception handling
+ *
+ * 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 by Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/offsets.h>
+#include <asm/processor.h>
+#include <asm/thread_info.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+#include <asm/ptrace.h>
+#include <asm/current.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/signal.h>
+#include <xtensa/coreasm.h>
+
+/* Unimplemented features. */
+
+#undef SIGNAL_HANDLING_IN_DOUBLE_EXCEPTION
+#undef KERNEL_STACK_OVERFLOW_CHECK
+#undef PREEMPTIBLE_KERNEL
+#undef ALLOCA_EXCEPTION_IN_IRAM
+
+/* Not well tested.
+ *
+ * - fast_coprocessor
+ */
+
+/*
+ * Macro to find first bit set in WINDOWBASE from the left + 1
+ *
+ * 100....0 -> 1
+ * 010....0 -> 2
+ * 000....1 -> WSBITS
+ */
+
+       .macro ffs_ws bit mask
+
+#if XCHAL_HAVE_NSA
+       nsau    \bit, \mask                     # 32-WSBITS ... 31 (32 iff 0)
+       addi    \bit, \bit, WSBITS - 32 + 1     # uppest bit set -> return 1
+#else
+       movi    \bit, WSBITS
+#if WSBITS > 16
+       _bltui  \mask, 0x10000, 99f
+       addi    \bit, \bit, -16
+       extui   \mask, \mask, 16, 16
+#endif
+#if WSBITS > 8
+99:    _bltui  \mask, 0x100, 99f
+       addi    \bit, \bit, -8
+       srli    \mask, \mask, 8
+#endif
+99:    _bltui  \mask, 0x10, 99f
+       addi    \bit, \bit, -4
+       srli    \mask, \mask, 4
+99:    _bltui  \mask, 0x4, 99f
+       addi    \bit, \bit, -2
+       srli    \mask, \mask, 2
+99:    _bltui  \mask, 0x2, 99f
+       addi    \bit, \bit, -1
+99:
+
+#endif
+       .endm
+
+/* ----------------- DEFAULT FIRST LEVEL EXCEPTION HANDLERS ----------------- */
+
+/*
+ * First-level exception handler for user exceptions.
+ * Save some special registers, extra states and all registers in the AR
+ * register file that were in use in the user task, and jump to the common
+ * exception code.
+ * We save SAR (used to calculate WMASK), and WB and WS (we don't have to
+ * save them for kernel exceptions).
+ *
+ * Entry condition for user_exception:
+ *
+ *   a0:       trashed, original value saved on stack (PT_AREG0)
+ *   a1:       a1
+ *   a2:       new stack pointer, original value in depc
+ *   a3:       dispatch table
+ *   depc:     a2, original value saved on stack (PT_DEPC)
+ *   excsave1: a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ *
+ * Entry condition for _user_exception:
+ *
+ *   a0-a3 and depc have been saved to PT_AREG0...PT_AREG3 and PT_DEPC
+ *   excsave has been restored, and
+ *   stack pointer (a1) has been set.
+ *
+ * Note: _user_exception might be at an odd adress. Don't use call0..call12
+ */
+
+ENTRY(user_exception)
+
+       /* Save a2, a3, and depc, restore excsave_1 and set SP. */
+
+       xsr     a3, EXCSAVE_1
+       rsr     a0, DEPC
+       s32i    a1, a2, PT_AREG1
+       s32i    a0, a2, PT_AREG2
+       s32i    a3, a2, PT_AREG3
+       mov     a1, a2
+
+       .globl _user_exception
+_user_exception:
+
+       /* Save SAR and turn off single stepping */
+
+       movi    a2, 0
+       rsr     a3, SAR
+       wsr     a2, ICOUNTLEVEL
+       s32i    a3, a1, PT_SAR
+
+       /* Rotate ws so that the current windowbase is at bit0. */
+       /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */
+
+       rsr     a2, WINDOWBASE
+       rsr     a3, WINDOWSTART
+       ssr     a2
+       s32i    a2, a1, PT_WINDOWBASE
+       s32i    a3, a1, PT_WINDOWSTART
+       slli    a2, a3, 32-WSBITS
+       src     a2, a3, a2
+       srli    a2, a2, 32-WSBITS
+       s32i    a2, a1, PT_WMASK        # needed for restoring registers
+
+       /* Save only live registers. */
+
+       _bbsi.l a2, 1, 1f
+       s32i    a4, a1, PT_AREG4
+       s32i    a5, a1, PT_AREG5
+       s32i    a6, a1, PT_AREG6
+       s32i    a7, a1, PT_AREG7
+       _bbsi.l a2, 2, 1f
+       s32i    a8, a1, PT_AREG8
+       s32i    a9, a1, PT_AREG9
+       s32i    a10, a1, PT_AREG10
+       s32i    a11, a1, PT_AREG11
+       _bbsi.l a2, 3, 1f
+       s32i    a12, a1, PT_AREG12
+       s32i    a13, a1, PT_AREG13
+       s32i    a14, a1, PT_AREG14
+       s32i    a15, a1, PT_AREG15
+       _bnei   a2, 1, 1f               # only one valid frame?
+
+       /* Only one valid frame, skip saving regs. */
+
+       j       2f
+
+       /* Save the remaining registers.
+        * We have to save all registers up to the first '1' from
+        * the right, except the current frame (bit 0).
+        * Assume a2 is:  001001000110001
+        * All regiser frames starting from the top fiel to the marked '1'
+        * must be saved.
+        */
+
+1:     addi    a3, a2, -1              # eliminate '1' in bit 0: yyyyxxww0
+       neg     a3, a3                  # yyyyxxww0 -> YYYYXXWW1+1
+       and     a3, a3, a2              # max. only one bit is set
+
+       /* Find number of frames to save */
+
+       ffs_ws  a0, a3                  # number of frames to the '1' from left
+
+       /* Store information into WMASK:
+        * bits 0..3: xxx1 masked lower 4 bits of the rotated windowstart,
+        * bits 4...: number of valid 4-register frames
+        */
+
+       slli    a3, a0, 4               # number of frames to save in bits 8..4
+       extui   a2, a2, 0, 4            # mask for the first 16 registers
+       or      a2, a3, a2
+       s32i    a2, a1, PT_WMASK        # needed when we restore the reg-file
+
+       /* Save 4 registers at a time */
+
+1:     rotw    -1
+       s32i    a0, a5, PT_AREG_END - 16
+       s32i    a1, a5, PT_AREG_END - 12
+       s32i    a2, a5, PT_AREG_END - 8
+       s32i    a3, a5, PT_AREG_END - 4
+       addi    a0, a4, -1
+       addi    a1, a5, -16
+       _bnez   a0, 1b
+
+       /* WINDOWBASE still in SAR! */
+
+       rsr     a2, SAR                 # original WINDOWBASE
+       movi    a3, 1
+       ssl     a2
+       sll     a3, a3
+       wsr     a3, WINDOWSTART         # set corresponding WINDOWSTART bit
+       wsr     a2, WINDOWBASE          # and WINDOWSTART
+       rsync
+
+       /* We are back to the original stack pointer (a1) */
+
+2:
+#if XCHAL_EXTRA_SA_SIZE
+
+       /* For user exceptions, save the extra state into the user's TCB.
+        * Note: We must assume that xchal_extra_store_funcbody destroys a2..a15
+        */
+
+       GET_CURRENT(a2,a1)
+       addi    a2, a2, THREAD_CP_SAVE
+       xchal_extra_store_funcbody
+#endif
+
+       /* Now, jump to the common exception handler. */
+
+       j       common_exception
+
+
+/*
+ * First-level exit handler for kernel exceptions
+ * Save special registers and the live window frame.
+ * Note: Even though we changes the stack pointer, we don't have to do a
+ *      MOVSP here, as we do that when we return from the exception.
+ *      (See comment in the kernel exception exit code)
+ *
+ * Entry condition for kernel_exception:
+ *
+ *   a0:       trashed, original value saved on stack (PT_AREG0)
+ *   a1:       a1
+ *   a2:       new stack pointer, original in DEPC
+ *   a3:       dispatch table
+ *   depc:     a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:        a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ *
+ * Entry condition for _kernel_exception:
+ *
+ *   a0-a3 and depc have been saved to PT_AREG0...PT_AREG3 and PT_DEPC
+ *   excsave has been restored, and
+ *   stack pointer (a1) has been set.
+ *
+ * Note: _kernel_exception might be at an odd adress. Don't use call0..call12
+ */
+
+ENTRY(kernel_exception)
+
+       /* Save a0, a2, a3, DEPC and set SP. */
+
+       xsr     a3, EXCSAVE_1           # restore a3, excsave_1
+       rsr     a0, DEPC                # get a2
+       s32i    a1, a2, PT_AREG1
+       s32i    a0, a2, PT_AREG2
+       s32i    a3, a2, PT_AREG3
+       mov     a1, a2
+
+       .globl _kernel_exception
+_kernel_exception:
+
+       /* Save SAR and turn off single stepping */
+
+       movi    a2, 0
+       rsr     a3, SAR
+       wsr     a2, ICOUNTLEVEL
+       s32i    a3, a1, PT_SAR
+
+       /* Rotate ws so that the current windowbase is at bit0. */
+       /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */
+
+       rsr     a2, WINDOWBASE          # don't need to save these, we only
+       rsr     a3, WINDOWSTART         # need shifted windowstart: windowmask
+       ssr     a2
+       slli    a2, a3, 32-WSBITS
+       src     a2, a3, a2
+       srli    a2, a2, 32-WSBITS
+       s32i    a2, a1, PT_WMASK        # needed for kernel_exception_exit
+
+       /* Save only the live window-frame */
+
+       _bbsi.l a2, 1, 1f
+       s32i    a4, a1, PT_AREG4
+       s32i    a5, a1, PT_AREG5
+       s32i    a6, a1, PT_AREG6
+       s32i    a7, a1, PT_AREG7
+       _bbsi.l a2, 2, 1f
+       s32i    a8, a1, PT_AREG8
+       s32i    a9, a1, PT_AREG9
+       s32i    a10, a1, PT_AREG10
+       s32i    a11, a1, PT_AREG11
+       _bbsi.l a2, 3, 1f
+       s32i    a12, a1, PT_AREG12
+       s32i    a13, a1, PT_AREG13
+       s32i    a14, a1, PT_AREG14
+       s32i    a15, a1, PT_AREG15
+
+1:
+
+#ifdef KERNEL_STACK_OVERFLOW_CHECK
+
+       /*  Stack overflow check, for debugging  */
+       extui   a2, a1, TASK_SIZE_BITS,XX
+       movi    a3, SIZE??
+       _bge    a2, a3, out_of_stack_panic
+
+#endif
+
+/*
+ * This is the common exception handler.
+ * We get here from the user exception handler or simply by falling through
+ * from the kernel exception handler.
+ * Save the remaining special registers, switch to kernel mode, and jump
+ * to the second-level exception handler.
+ *
+ */
+
+common_exception:
+
+       /* Save EXCVADDR, DEBUGCAUSE, and PC, and clear LCOUNT */
+
+       rsr     a2, DEBUGCAUSE
+       rsr     a3, EPC_1
+       s32i    a2, a1, PT_DEBUGCAUSE
+       s32i    a3, a1, PT_PC
+
+       rsr     a3, EXCVADDR
+       movi    a2, 0
+       s32i    a3, a1, PT_EXCVADDR
+       xsr     a2, LCOUNT
+       s32i    a2, a1, PT_LCOUNT
+
+       /* It is now save to restore the EXC_TABLE_FIXUP variable. */
+
+       rsr     a0, EXCCAUSE
+       movi    a3, 0
+       rsr     a2, EXCSAVE_1
+       s32i    a0, a1, PT_EXCCAUSE
+       s32i    a3, a2, EXC_TABLE_FIXUP
+
+       /* All unrecoverable states are saved on stack, now, and a1 is valid,
+        * so we can allow exceptions and interrupts (*) again.
+        * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)
+        *
+        * (*) We only allow interrupts if PS.INTLEVEL was not set to 1 before
+        *     (interrupts disabled) and if this exception is not an interrupt.
+        */
+
+       rsr     a3, PS
+       addi    a0, a0, -4
+       movi    a2, 1
+       extui   a3, a3, 0, 1            # a3 = PS.INTLEVEL[0]
+       moveqz  a3, a2, a0              # a3 = 1 iff interrupt exception
+       movi    a2, PS_WOE_MASK
+       or      a3, a3, a2
+       rsr     a0, EXCCAUSE
+       xsr     a3, PS
+
+       s32i    a3, a1, PT_PS           # save ps
+
+       /* Save LBEG, LEND */
+
+       rsr     a2, LBEG
+       rsr     a3, LEND
+       s32i    a2, a1, PT_LBEG
+       s32i    a3, a1, PT_LEND
+
+       /* Go to second-level dispatcher. Set up parameters to pass to the
+        * exception handler and call the exception handler.
+        */
+
+       movi    a4, exc_table
+       mov     a6, a1                  # pass stack frame
+       mov     a7, a0                  # pass EXCCAUSE
+       addx4   a4, a0, a4
+       l32i    a4, a4, EXC_TABLE_DEFAULT               # load handler
+
+       /* Call the second-level handler */
+
+       callx4  a4
+
+       /* Jump here for exception exit */
+
+common_exception_return:
+
+       /* Jump if we are returning from kernel exceptions. */
+
+1:     l32i    a3, a1, PT_PS
+       _bbsi.l a3, PS_UM_SHIFT, 2f
+       j       kernel_exception_exit
+
+       /* Specific to a user exception exit:
+        * We need to check some flags for signal handling and rescheduling,
+        * and have to restore WB and WS, extra states, and all registers
+        * in the register file that were in use in the user task.
+        */
+
+2:     wsr     a3, PS          /* disable interrupts */
+
+       /* Check for signals (keep interrupts disabled while we read TI_FLAGS)
+        * Note: PS.INTLEVEL = 0, PS.EXCM = 1
+        */
+
+       GET_THREAD_INFO(a2,a1)
+       l32i    a4, a2, TI_FLAGS
+
+       /* Enable interrupts again.
+        * Note: When we get here, we certainly have handled any interrupts.
+        *       (Hint: There is only one user exception frame on stack)
+        */
+
+       movi    a3, PS_WOE_MASK
+
+       _bbsi.l a4, TIF_NEED_RESCHED, 3f
+       _bbci.l a4, TIF_SIGPENDING, 4f
+
+#ifndef SIGNAL_HANDLING_IN_DOUBLE_EXCEPTION
+       l32i    a4, a1, PT_DEPC
+       bgeui   a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f
+#endif
+
+       /* Reenable interrupts and call do_signal() */
+
+       wsr     a3, PS
+       movi    a4, do_signal   # int do_signal(struct pt_regs*, sigset_t*)
+       mov     a6, a1
+       movi    a7, 0
+       callx4  a4
+       j       1b
+
+3:     /* Reenable interrupts and reschedule */
+
+       wsr     a3, PS
+       movi    a4, schedule    # void schedule (void)
+       callx4  a4
+       j       1b
+
+       /* Restore the state of the task and return from the exception. */
+
+
+       /* If we are returning from a user exception, and the process
+        * to run next has PT_SINGLESTEP set, we want to setup
+        * ICOUNT and ICOUNTLEVEL to step one instruction.
+        * PT_SINGLESTEP is set by sys_ptrace (ptrace.c)
+        */
+
+4:     /* a2 holds GET_CURRENT(a2,a1)  */
+
+       l32i    a3, a2, TI_TASK
+       l32i    a3, a3, TASK_PTRACE
+       bbci.l  a3, PT_SINGLESTEP_BIT, 1f # jump if single-step flag is not set
+
+       movi    a3, -2                  # PT_SINGLESTEP flag is set,
+       movi    a4, 1                   # icountlevel of 1 means it won't
+       wsr     a3, ICOUNT              # start counting until after rfe
+       wsr     a4, ICOUNTLEVEL         # so setup icount & icountlevel.
+       isync
+
+1:
+
+#if XCHAL_EXTRA_SA_SIZE
+
+       /* For user exceptions, restore the extra state from the user's TCB. */
+
+       /* Note: a2 still contains GET_CURRENT(a2,a1) */
+       addi    a2, a2, THREAD_CP_SAVE
+       xchal_extra_load_funcbody
+
+       /* We must assume that xchal_extra_store_funcbody destroys
+        * registers a2..a15.  FIXME, this list can eventually be
+        * reduced once real register requirements of the macro are
+        * finalized. */
+
+#endif /* XCHAL_EXTRA_SA_SIZE */
+
+
+       /* Switch to the user thread WINDOWBASE. Save SP temporarily in DEPC */
+
+       l32i    a2, a1, PT_WINDOWBASE
+       l32i    a3, a1, PT_WINDOWSTART
+       wsr     a1, DEPC                # use DEPC as temp storage
+       wsr     a3, WINDOWSTART         # restore WINDOWSTART
+       ssr     a2                      # preserve user's WB in the SAR
+       wsr     a2, WINDOWBASE          # switch to user's saved WB
+       rsync
+       rsr     a1, DEPC                # restore stack pointer
+       l32i    a2, a1, PT_WMASK        # register frames saved (in bits 4...9)
+       rotw    -1                      # we restore a4..a7
+       _bltui  a6, 16, 1f              # only have to restore current window?
+
+       /* The working registers are a0 and a3.  We are restoring to
+        * a4..a7.  Be careful not to destroy what we have just restored.
+        * Note: wmask has the format YYYYM:
+        *       Y: number of registers saved in groups of 4
+        *       M: 4 bit mask of first 16 registers
+        */
+
+       mov     a2, a6
+       mov     a3, a5
+
+2:     rotw    -1                      # a0..a3 become a4..a7
+       addi    a3, a7, -4*4            # next iteration
+       addi    a2, a6, -16             # decrementing Y in WMASK
+       l32i    a4, a3, PT_AREG_END + 0
+       l32i    a5, a3, PT_AREG_END + 4
+       l32i    a6, a3, PT_AREG_END + 8
+       l32i    a7, a3, PT_AREG_END + 12
+       _bgeui  a2, 16, 2b
+
+       /* Clear unrestored registers (don't leak anything to user-land */
+
+1:     rsr     a0, WINDOWBASE
+       rsr     a3, SAR
+       sub     a3, a0, a3
+       beqz    a3, 2f
+       extui   a3, a3, 0, WBBITS
+
+1:     rotw    -1
+       addi    a3, a7, -1
+       movi    a4, 0
+       movi    a5, 0
+       movi    a6, 0
+       movi    a7, 0
+       bgei    a3, 1, 1b
+
+       /* We are back were we were when we started.
+        * Note: a2 still contains WMASK (if we've returned to the original
+        *       frame where we had loaded a2), or at least the lower 4 bits
+        *       (if we have restored WSBITS-1 frames).
+        */
+
+2:     j       common_exception_exit
+
+       /* This is the kernel exception exit.
+        * We avoided to do a MOVSP when we entered the exception, but we
+        * have to do it here.
+        */
+
+kernel_exception_exit:
+
+       /* Disable interrupts (a3 holds PT_PS) */
+
+       wsr     a3, PS
+
+#ifdef PREEMPTIBLE_KERNEL
+
+#ifdef CONFIG_PREEMPT
+
+       /*
+        * Note: We've just returned from a call4, so we have
+        * at least 4 addt'l regs.
+        */
+
+       /* Check current_thread_info->preempt_count */
+
+       GET_THREAD_INFO(a2)
+       l32i    a3, a2, TI_PREEMPT
+       bnez    a3, 1f
+
+       l32i    a2, a2, TI_FLAGS
+
+1:
+
+#endif
+
+#endif
+
+       /* Check if we have to do a movsp.
+        *
+        * We only have to do a movsp if the previous window-frame has
+        * been spilled to the *temporary* exception stack instead of the
+        * task's stack. This is the case if the corresponding bit in
+        * WINDOWSTART for the previous window-frame was set before
+        * (not spilled) but is zero now (spilled).
+        * If this bit is zero, all other bits except the one for the
+        * current window frame are also zero. So, we can use a simple test:
+        * 'and' WINDOWSTART and WINDOWSTART-1:
+        *
+        *  (XXXXXX1[0]* - 1) AND XXXXXX1[0]* = XXXXXX0[0]*
+        *
+        * The result is zero only if one bit was set.
+        *
+        * (Note: We might have gone through several task switches before
+        *        we come back to the current task, so WINDOWBASE might be
+        *        different from the time the exception occurred.)
+        */
+
+       /* Test WINDOWSTART before and after the exception.
+        * We actually have WMASK, so we only have to test if it is 1 or not.
+        */
+
+       l32i    a2, a1, PT_WMASK
+       _beqi   a2, 1, common_exception_exit    # Spilled before exception,jump
+
+       /* Test WINDOWSTART now. If spilled, do the movsp */
+
+       rsr     a3, WINDOWSTART
+       addi    a0, a3, -1
+       and     a3, a3, a0
+       _bnez   a3, common_exception_exit
+
+       /* Do a movsp (we returned from a call4, so we have at least a0..a7) */
+
+       addi    a0, a1, -16
+       l32i    a3, a0, 0
+       l32i    a4, a0, 4
+       s32i    a3, a1, PT_SIZE+0
+       s32i    a4, a1, PT_SIZE+4
+       l32i    a3, a0, 8
+       l32i    a4, a0, 12
+       s32i    a3, a1, PT_SIZE+8
+       s32i    a4, a1, PT_SIZE+12
+
+       /* Common exception exit.
+        * We restore the special register and the current window frame, and
+        * return from the exception.
+        *
+        * Note: We expect a2 to hold PT_WMASK
+        */
+
+common_exception_exit:
+
+       _bbsi.l a2, 1, 1f
+       l32i    a4,  a1, PT_AREG4
+       l32i    a5,  a1, PT_AREG5
+       l32i    a6,  a1, PT_AREG6
+       l32i    a7,  a1, PT_AREG7
+       _bbsi.l a2, 2, 1f
+       l32i    a8,  a1, PT_AREG8
+       l32i    a9,  a1, PT_AREG9
+       l32i    a10, a1, PT_AREG10
+       l32i    a11, a1, PT_AREG11
+       _bbsi.l a2, 3, 1f
+       l32i    a12, a1, PT_AREG12
+       l32i    a13, a1, PT_AREG13
+       l32i    a14, a1, PT_AREG14
+       l32i    a15, a1, PT_AREG15
+
+       /* Restore PC, SAR */
+
+1:     l32i    a2, a1, PT_PC
+       l32i    a3, a1, PT_SAR
+       wsr     a2, EPC_1
+       wsr     a3, SAR
+
+       /* Restore LBEG, LEND, LCOUNT */
+
+       l32i    a2, a1, PT_LBEG
+       l32i    a3, a1, PT_LEND
+       wsr     a2, LBEG
+       l32i    a2, a1, PT_LCOUNT
+       wsr     a3, LEND
+       wsr     a2, LCOUNT
+
+       /* Check if it was double exception. */
+
+       l32i    a0, a1, PT_DEPC
+       l32i    a3, a1, PT_AREG3
+       l32i    a2, a1, PT_AREG2
+       _bgeui  a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
+
+       /* Restore a0...a3 and return */
+
+       l32i    a0, a1, PT_AREG0
+       l32i    a1, a1, PT_AREG1
+       rfe
+
+1:     wsr     a0, DEPC
+       l32i    a0, a1, PT_AREG0
+       l32i    a1, a1, PT_AREG1
+       rfde
+
+/*
+ * Debug exception handler.
+ *
+ * Currently, we don't support KGDB, so only user application can be debugged.
+ *
+ * When we get here,  a0 is trashed and saved to excsave[debuglevel]
+ */
+
+ENTRY(debug_exception)
+
+       rsr     a0, EPS + XCHAL_DEBUGLEVEL
+       bbsi.l  a0, PS_EXCM_SHIFT, 1f   # exception mode
+
+       /* Set EPC_1 and EXCCAUSE */
+
+       wsr     a2, DEPC                # save a2 temporarily
+       rsr     a2, EPC + XCHAL_DEBUGLEVEL
+       wsr     a2, EPC_1
+
+       movi    a2, EXCCAUSE_MAPPED_DEBUG
+       wsr     a2, EXCCAUSE
+
+       /* Restore PS to the value before the debug exc but with PS.EXCM set.*/
+
+       movi    a2, 1 << PS_EXCM_SHIFT
+       or      a2, a0, a2
+       movi    a0, debug_exception     # restore a3, debug jump vector
+       wsr     a2, PS
+       xsr     a0, EXCSAVE + XCHAL_DEBUGLEVEL
+
+       /* Switch to kernel/user stack, restore jump vector, and save a0 */
+
+       bbsi.l  a2, PS_UM_SHIFT, 2f     # jump if user mode
+
+       addi    a2, a1, -16-PT_SIZE     # assume kernel stack
+       s32i    a0, a2, PT_AREG0
+       movi    a0, 0
+       s32i    a1, a2, PT_AREG1
+       s32i    a0, a2, PT_DEPC         # mark it as a regular exception
+       xsr     a0, DEPC
+       s32i    a3, a2, PT_AREG3
+       s32i    a0, a2, PT_AREG2
+       mov     a1, a2
+       j       _kernel_exception
+
+2:     rsr     a2, EXCSAVE_1
+       l32i    a2, a2, EXC_TABLE_KSTK  # load kernel stack pointer
+       s32i    a0, a2, PT_AREG0
+       movi    a0, 0
+       s32i    a1, a2, PT_AREG1
+       s32i    a0, a2, PT_DEPC
+       xsr     a0, DEPC
+       s32i    a3, a2, PT_AREG3
+       s32i    a0, a2, PT_AREG2
+       mov     a1, a2
+       j       _user_exception
+
+       /* Debug exception while in exception mode. */
+1:     j       1b      // FIXME!!
+
+
+/*
+ * We get here in case of an unrecoverable exception.
+ * The only thing we can do is to be nice and print a panic message.
+ * We only produce a single stack frame for panic, so ???
+ *
+ *
+ * Entry conditions:
+ *
+ *   - a0 contains the caller address; original value saved in excsave1.
+ *   - the original a0 contains a valid return address (backtrace) or 0.
+ *   - a2 contains a valid stackpointer
+ *
+ * Notes:
+ *
+ *   - If the stack pointer could be invalid, the caller has to setup a
+ *     dummy stack pointer (e.g. the stack of the init_task)
+ *
+ *   - If the return address could be invalid, the caller has to set it
+ *     to 0, so the backtrace would stop.
+ *
+ */
+       .align 4
+unrecoverable_text:
+       .ascii "Unrecoverable error in exception handler\0"
+
+ENTRY(unrecoverable_exception)
+
+       movi    a0, 1
+       movi    a1, 0
+
+       wsr     a0, WINDOWSTART
+       wsr     a1, WINDOWBASE
+       rsync
+
+       movi    a1, PS_WOE_MASK | 1
+       wsr     a1, PS
+       rsync
+
+       movi    a1, init_task
+       movi    a0, 0
+       addi    a1, a1, PT_REGS_OFFSET
+
+       movi    a4, panic
+       movi    a6, unrecoverable_text
+
+       callx4  a4
+
+1:     j       1b
+
+
+/* -------------------------- FAST EXCEPTION HANDLERS ----------------------- */
+
+/*
+ * Fast-handler for alloca exceptions
+ *
+ *  The ALLOCA handler is entered when user code executes the MOVSP
+ *  instruction and the caller's frame is not in the register file.
+ *  In this case, the caller frame's a0..a3 are on the stack just
+ *  below sp (a1), and this handler moves them.
+ *
+ *  For "MOVSP <ar>,<as>" without destination register a1, this routine
+ *  simply moves the value from <as> to <ar> without moving the save area.
+ *
+ * Entry condition:
+ *
+ *   a0:       trashed, original value saved on stack (PT_AREG0)
+ *   a1:       a1
+ *   a2:       new stack pointer, original in DEPC
+ *   a3:       dispatch table
+ *   depc:     a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:        a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+#if XCHAL_HAVE_BE
+#define _EXTUI_MOVSP_SRC(ar)   extui ar, ar, 4, 4
+#define _EXTUI_MOVSP_DST(ar)   extui ar, ar, 0, 4
+#else
+#define _EXTUI_MOVSP_SRC(ar)   extui ar, ar, 0, 4
+#define _EXTUI_MOVSP_DST(ar)   extui ar, ar, 4, 4
+#endif
+
+ENTRY(fast_alloca)
+
+       /* We shouldn't be in a double exception. */
+
+       l32i    a0, a2, PT_DEPC
+       _bgeui  a0, VALID_DOUBLE_EXCEPTION_ADDRESS, .Lunhandled_double
+
+       rsr     a0, DEPC                # get a2
+       s32i    a4, a2, PT_AREG4        # save a4 and
+       s32i    a0, a2, PT_AREG2        # a2 to stack
+
+       /* Exit critical section. */
+
+       movi    a0, 0
+       s32i    a0, a3, EXC_TABLE_FIXUP
+
+       /* Restore a3, excsave_1 */
+
+       xsr     a3, EXCSAVE_1           # make sure excsave_1 is valid for dbl.
+       rsr     a4, EPC_1               # get exception address
+       s32i    a3, a2, PT_AREG3        # save a3 to stack
+
+#ifdef ALLOCA_EXCEPTION_IN_IRAM
+#error iram not supported
+#else
+       /* Note: l8ui not allowed in IRAM/IROM!! */
+       l8ui    a0, a4, 1               # read as(src) from MOVSP instruction
+#endif
+       movi    a3, .Lmovsp_src
+       _EXTUI_MOVSP_SRC(a0)            # extract source register number
+       addx8   a3, a0, a3
+       jx      a3
+
+.Lunhandled_double:
+       wsr     a0, EXCSAVE_1
+       movi    a0, unrecoverable_exception
+       callx0  a0
+
+       .align 8
+.Lmovsp_src:
+       l32i    a3, a2, PT_AREG0;       _j 1f;  .align 8
+       mov     a3, a1;                 _j 1f;  .align 8
+       l32i    a3, a2, PT_AREG2;       _j 1f;  .align 8
+       l32i    a3, a2, PT_AREG3;       _j 1f;  .align 8
+       l32i    a3, a2, PT_AREG4;       _j 1f;  .align 8
+       mov     a3, a5;                 _j 1f;  .align 8
+       mov     a3, a6;                 _j 1f;  .align 8
+       mov     a3, a7;                 _j 1f;  .align 8
+       mov     a3, a8;                 _j 1f;  .align 8
+       mov     a3, a9;                 _j 1f;  .align 8
+       mov     a3, a10;                _j 1f;  .align 8
+       mov     a3, a11;                _j 1f;  .align 8
+       mov     a3, a12;                _j 1f;  .align 8
+       mov     a3, a13;                _j 1f;  .align 8
+       mov     a3, a14;                _j 1f;  .align 8
+       mov     a3, a15;                _j 1f;  .align 8
+
+1:
+
+#ifdef ALLOCA_EXCEPTION_IN_IRAM
+#error iram not supported
+#else
+       l8ui    a0, a4, 0               # read ar(dst) from MOVSP instruction
+#endif
+       addi    a4, a4, 3               # step over movsp
+       _EXTUI_MOVSP_DST(a0)            # extract destination register
+       wsr     a4, EPC_1               # save new epc_1
+
+       _bnei   a0, 1, 1f               # no 'movsp a1, ax': jump
+
+        /* Move the save area. This implies the use of the L32E
+        * and S32E instructions, because this move must be done with
+        * the user's PS.RING privilege levels, not with ring 0
+        * (kernel's) privileges currently active with PS.EXCM
+        * set. Note that we have stil registered a fixup routine with the
+        * double exception vector in case a double exception occurs.
+        */
+
+       /* a0,a4:avail a1:old user stack a2:exc. stack a3:new user stack. */
+
+       l32e    a0, a1, -16
+       l32e    a4, a1, -12
+       s32e    a0, a3, -16
+       s32e    a4, a3, -12
+       l32e    a0, a1, -8
+       l32e    a4, a1, -4
+       s32e    a0, a3, -8
+       s32e    a4, a3, -4
+
+       /* Restore stack-pointer and all the other saved registers. */
+
+       mov     a1, a3
+
+       l32i    a4, a2, PT_AREG4
+       l32i    a3, a2, PT_AREG3
+       l32i    a0, a2, PT_AREG0
+       l32i    a2, a2, PT_AREG2
+       rfe
+
+       /*  MOVSP <at>,<as>  was invoked with <at> != a1.
+        *  Because the stack pointer is not being modified,
+        *  we should be able to just modify the pointer
+        *  without moving any save area.
+        *  The processor only traps these occurrences if the
+        *  caller window isn't live, so unfortunately we can't
+        *  use this as an alternate trap mechanism.
+        *  So we just do the move.  This requires that we
+        *  resolve the destination register, not just the source,
+        *  so there's some extra work.
+        *  (PERHAPS NOT REALLY NEEDED, BUT CLEANER...)
+        */
+
+       /* a0 dst-reg, a1 user-stack, a2 stack, a3 value of src reg. */
+
+1:     movi    a4, .Lmovsp_dst
+       addx8   a4, a0, a4
+       jx      a4
+
+       .align 8
+.Lmovsp_dst:
+       s32i    a3, a2, PT_AREG0;       _j 1f;  .align 8
+       mov     a1, a3;                 _j 1f;  .align 8
+       s32i    a3, a2, PT_AREG2;       _j 1f;  .align 8
+       s32i    a3, a2, PT_AREG3;       _j 1f;  .align 8
+       s32i    a3, a2, PT_AREG4;       _j 1f;  .align 8
+       mov     a5, a3;                 _j 1f;  .align 8
+       mov     a6, a3;                 _j 1f;  .align 8
+       mov     a7, a3;                 _j 1f;  .align 8
+       mov     a8, a3;                 _j 1f;  .align 8
+       mov     a9, a3;                 _j 1f;  .align 8
+       mov     a10, a3;                _j 1f;  .align 8
+       mov     a11, a3;                _j 1f;  .align 8
+       mov     a12, a3;                _j 1f;  .align 8
+       mov     a13, a3;                _j 1f;  .align 8
+       mov     a14, a3;                _j 1f;  .align 8
+       mov     a15, a3;                _j 1f;  .align 8
+
+1:     l32i    a4, a2, PT_AREG4
+       l32i    a3, a2, PT_AREG3
+       l32i    a0, a2, PT_AREG0
+       l32i    a2, a2, PT_AREG2
+       rfe
+
+
+/*
+ * fast system calls.
+ *
+ * WARNING:  The kernel doesn't save the entire user context before
+ * handling a fast system call.  These functions are small and short,
+ * usually offering some functionality not available to user tasks.
+ *
+ * BE CAREFUL TO PRESERVE THE USER'S CONTEXT.
+ *
+ * Entry condition:
+ *
+ *   a0:       trashed, original value saved on stack (PT_AREG0)
+ *   a1:       a1
+ *   a2:       new stack pointer, original in DEPC
+ *   a3:       dispatch table
+ *   depc:     a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:        a3
+ */
+
+ENTRY(fast_syscall_kernel)
+
+       /* Skip syscall. */
+
+       rsr     a0, EPC_1
+       addi    a0, a0, 3
+       wsr     a0, EPC_1
+
+       l32i    a0, a2, PT_DEPC
+       bgeui   a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_syscall_unrecoverable
+
+       rsr     a0, DEPC                        # get syscall-nr
+       _beqz   a0, fast_syscall_spill_registers
+
+       addi    a0, a0, -__NR_sysxtensa
+       _beqz   a0, fast_syscall_sysxtensa
+
+       j       kernel_exception
+
+
+ENTRY(fast_syscall_user)
+
+       /* Skip syscall. */
+
+       rsr     a0, EPC_1
+       addi    a0, a0, 3
+       wsr     a0, EPC_1
+
+       l32i    a0, a2, PT_DEPC
+       bgeui   a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_syscall_unrecoverable
+
+       rsr     a0, DEPC                        # get syscall-nr
+       _beqz   a0, fast_syscall_spill_registers
+
+       addi    a0, a0, -__NR_sysxtensa
+       _beqz   a0, fast_syscall_sysxtensa
+
+       j       user_exception
+
+ENTRY(fast_syscall_unrecoverable)
+
+        /* Restore all states. */
+
+        l32i    a0, a2, PT_AREG0        # restore a0
+        xsr     a2, DEPC                # restore a2, depc
+        rsr     a3, EXCSAVE_1
+
+        wsr     a0, EXCSAVE_1
+        movi    a0, unrecoverable_exception
+        callx0  a0
+
+
+
+/*
+ * sysxtensa syscall handler
+ *
+ * int sysxtensa (XTENSA_ATOMIC_SET, ptr, val, unused);
+ * int sysxtensa (XTENSA_ATOMIC_ADD, ptr, val, unused);
+ * int sysxtensa (XTENSA_ATOMIC_EXG_ADD, ptr, val, unused);
+ * int sysxtensa (XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval);
+ * a2                    a6              a3    a4      a5
+ *
+ * Entry condition:
+ *
+ *   a0:       trashed, original value saved on stack (PT_AREG0)
+ *   a1:       a1
+ *   a2:       new stack pointer, original in DEPC
+ *   a3:       dispatch table
+ *   depc:     a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:        a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ *
+ * Note: we don't have to save a2; a2 holds the return value
+ *
+ * We use the two macros TRY and CATCH:
+ *
+ * TRY  adds an entry to the __ex_table fixup table for the immediately
+ *      following instruction.
+ *
+ * CATCH catches any exception that occurred at one of the preceeding TRY
+ *       statements and continues from there
+ *
+ * Usage TRY   l32i    a0, a1, 0
+ *             <other code>
+ *      done:  rfe
+ *      CATCH  <set return code>
+ *             j done
+ */
+
+#define TRY                                                            \
+       .section __ex_table, "a";                                       \
+       .word   66f, 67f;                                               \
+       .text;                                                          \
+66:
+
+#define CATCH                                                          \
+67:
+
+ENTRY(fast_syscall_sysxtensa)
+
+       _beqz   a6, 1f
+       _blti   a6, SYSXTENSA_COUNT, 2f
+
+1:     j       user_exception
+
+2:     xsr     a3, EXCSAVE_1           # restore a3, excsave1
+       s32i    a7, a2, PT_AREG7
+
+       movi    a7, 4                   # sizeof(unsigned int)
+       verify_area a3, a7, a0, a2, .Leac
+
+       _beqi   a6, SYSXTENSA_ATOMIC_SET, .Lset
+       _beqi   a6, SYSXTENSA_ATOMIC_EXG_ADD, .Lexg
+       _beqi   a6, SYSXTENSA_ATOMIC_ADD, .Ladd
+
+       /* Fall through for SYSXTENSA_ATOMIC_CMP_SWP */
+
+.Lswp: /* Atomic compare and swap */
+
+TRY    l32i    a7, a3, 0               # read old value
+       bne     a7, a4, 1f              # same as old value? jump
+       s32i    a5, a3, 0               # different, modify value
+       movi    a7, 1                   # and return 1
+       j       .Lret
+
+1:     movi    a7, 0                   # same values: return 0
+       j       .Lret
+
+.Ladd: /* Atomic add */
+.Lexg: /* Atomic (exchange) add */
+
+TRY    l32i    a7, a3, 0
+       add     a4, a4, a7
+       s32i    a4, a3, 0
+       j       .Lret
+
+.Lset: /* Atomic set */
+
+TRY    l32i    a7, a3, 0               # read old value as return value
+       s32i    a4, a3, 0               # write new value
+
+.Lret: mov     a0, a2
+       mov     a2, a7
+       l32i    a7, a0, PT_AREG7
+       l32i    a3, a0, PT_AREG3
+       l32i    a0, a0, PT_AREG0
+       rfe
+
+CATCH
+.Leac: movi    a7, -EFAULT
+       j       .Lret
+
+
+
+/* fast_syscall_spill_registers.
+ *
+ * Entry condition:
+ *
+ *   a0:       trashed, original value saved on stack (PT_AREG0)
+ *   a1:       a1
+ *   a2:       new stack pointer, original in DEPC
+ *   a3:       dispatch table
+ *   depc:     a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:        a3
+ *
+ * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler.
+ * Note: We don't need to save a2 in depc (return value)
+ */
+
+ENTRY(fast_syscall_spill_registers)
+
+       /* Register a FIXUP handler (pass current wb as a parameter) */
+
+       movi    a0, fast_syscall_spill_registers_fixup
+       s32i    a0, a3, EXC_TABLE_FIXUP
+       rsr     a0, WINDOWBASE
+       s32i    a0, a3, EXC_TABLE_PARAM
+
+       /* Save a3 and SAR on stack. */
+
+       rsr     a0, SAR
+       xsr     a3, EXCSAVE_1           # restore a3 and excsave_1
+       s32i    a0, a2, PT_AREG4        # store SAR to PT_AREG4
+       s32i    a3, a2, PT_AREG3
+
+       /* The spill routine might clobber a7, a11, and a15. */
+
+       s32i    a7, a2, PT_AREG5
+       s32i    a11, a2, PT_AREG6
+       s32i    a15, a2, PT_AREG7
+
+       call0   _spill_registers        # destroys a3, DEPC, and SAR
+
+       /* Advance PC, restore registers and SAR, and return from exception. */
+
+       l32i    a3, a2, PT_AREG4
+       l32i    a0, a2, PT_AREG0
+       wsr     a3, SAR
+       l32i    a3, a2, PT_AREG3
+
+       /* Restore clobbered registers. */
+
+       l32i    a7, a2, PT_AREG5
+       l32i    a11, a2, PT_AREG6
+       l32i    a15, a2, PT_AREG7
+
+       movi    a2, 0
+       rfe
+
+/* Fixup handler.
+ *
+ * We get here if the spill routine causes an exception, e.g. tlb miss.
+ * We basically restore WINDOWBASE and WINDOWSTART to the condition when
+ * we entered the spill routine and jump to the user exception handler.
+ *
+ * a0: value of depc, original value in depc
+ * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
+ * a3: exctable, original value in excsave1
+ */
+
+fast_syscall_spill_registers_fixup:
+
+       rsr     a2, WINDOWBASE  # get current windowbase (a2 is saved)
+       xsr     a0, DEPC        # restore depc and a0
+       ssl     a2              # set shift (32 - WB)
+
+       /* We need to make sure the current registers (a0-a3) are preserved.
+        * To do this, we simply set the bit for the current window frame
+        * in WS, so that the exception handlers save them to the task stack.
+        */
+
+       rsr     a3, EXCSAVE_1   # get spill-mask
+       slli    a2, a3, 1       # shift left by one
+
+       slli    a3, a2, 32-WSBITS
+       src     a2, a2, a3      # a1 = xxwww1yyxxxwww1yy......
+       wsr     a2, WINDOWSTART # set corrected windowstart
+
+       movi    a3, exc_table
+       l32i    a2, a3, EXC_TABLE_DOUBLE_SAVE   # restore a2
+       l32i    a3, a3, EXC_TABLE_PARAM # original WB (in user task)
+
+       /* Return to the original (user task) WINDOWBASE.
+        * We leave the following frame behind:
+        * a0, a1, a2   same
+        * a3:          trashed (saved in excsave_1)
+        * depc:        depc (we have to return to that address)
+        * excsave_1:   a3
+        */
+
+       wsr     a3, WINDOWBASE
+       rsync
+
+       /* We are now in the original frame when we entered _spill_registers:
+        *  a0: return address
+        *  a1: used, stack pointer
+        *  a2: kernel stack pointer
+        *  a3: available, saved in EXCSAVE_1
+        *  depc: exception address
+        *  excsave: a3
+        * Note: This frame might be the same as above.
+        */
+
+#ifdef SIGNAL_HANDLING_IN_DOUBLE_EXCEPTION
+       /* Restore registers we precautiously saved.
+        * We have the value of the 'right' a3
+        */
+
+       l32i    a7, a2, PT_AREG5
+       l32i    a11, a2, PT_AREG6
+       l32i    a15, a2, PT_AREG7
+#endif
+
+       /* Setup stack pointer. */
+
+       addi    a2, a2, -PT_USER_SIZE
+       s32i    a0, a2, PT_AREG0
+
+       /* Make sure we return to this fixup handler. */
+
+       movi    a3, fast_syscall_spill_registers_fixup_return
+       s32i    a3, a2, PT_DEPC         # setup depc
+
+       /* Jump to the exception handler. */
+
+       movi    a3, exc_table
+       rsr     a0, EXCCAUSE
+        addx4   a0, a0, a3                     # find entry in table
+        l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
+        jx      a0
+
+fast_syscall_spill_registers_fixup_return:
+
+       /* When we return here, all registers have been restored (a2: DEPC) */
+
+       wsr     a2, DEPC                # exception address
+
+       /* Restore fixup handler. */
+
+       xsr     a3, EXCSAVE_1
+       movi    a2, fast_syscall_spill_registers_fixup
+       s32i    a2, a3, EXC_TABLE_FIXUP
+       rsr     a2, WINDOWBASE
+       s32i    a2, a3, EXC_TABLE_PARAM
+       l32i    a2, a3, EXC_TABLE_KSTK
+
+#ifdef SIGNAL_HANDLING_IN_DOUBLE_EXCEPTION
+       /* Save registers again that might be clobbered. */
+
+       s32i    a7, a2, PT_AREG5
+       s32i    a11, a2, PT_AREG6
+       s32i    a15, a2, PT_AREG7
+#endif
+
+       /* Load WB at the time the exception occurred. */
+
+       rsr     a3, SAR                 # WB is still in SAR
+       neg     a3, a3
+       wsr     a3, WINDOWBASE
+       rsync
+
+       /* Restore a3 and return. */
+
+       movi    a3, exc_table
+       xsr     a3, EXCSAVE_1
+
+       rfde
+
+
+/*
+ * spill all registers.
+ *
+ * This is not a real function. The following conditions must be met:
+ *
+ *  - must be called with call0.
+ *  - uses DEPC, a3 and SAR.
+ *  - the last 'valid' register of each frame are clobbered.
+ *  - the caller must have registered a fixup handler
+ *    (or be inside a critical section)
+ *  - PS_EXCM must be set (PS_WOE cleared?)
+ */
+
+ENTRY(_spill_registers)
+
+       /*
+        * Rotate ws so that the current windowbase is at bit 0.
+        * Assume ws = xxxwww1yy (www1 current window frame).
+        * Rotate ws right so that a2 = yyxxxwww1.
+        */
+
+       wsr     a2, DEPC                # preserve a2
+       rsr     a2, WINDOWBASE
+       rsr     a3, WINDOWSTART
+       ssr     a2                      # holds WB
+       slli    a2, a3, WSBITS
+       or      a3, a3, a2              # a2 = xxxwww1yyxxxwww1yy
+       srl     a3, a3
+
+       /* We are done if there are no more than the current register frame. */
+
+       extui   a3, a3, 1, WSBITS-2     # a3 = 0yyxxxwww
+       movi    a2, (1 << (WSBITS-1))
+       _beqz   a3, .Lnospill           # only one active frame? jump
+
+       /* We want 1 at the top, so that we return to the current windowbase */
+
+       or      a3, a3, a2              # 1yyxxxwww
+
+       /* Skip empty frames - get 'oldest' WINDOWSTART-bit. */
+
+       wsr     a3, WINDOWSTART         # save shifted windowstart
+       neg     a2, a3
+       and     a3, a2, a3              # first bit set from right: 000010000
+
+       ffs_ws  a2, a3                  # a2: shifts to skip empty frames
+       movi    a3, WSBITS
+       sub     a2, a3, a2              # WSBITS-a2:number of 0-bits from right
+       ssr     a2                      # save in SAR for later.
+
+       rsr     a3, WINDOWBASE
+       add     a3, a3, a2
+       rsr     a2, DEPC                # restore a2
+       wsr     a3, WINDOWBASE
+       rsync
+
+       rsr     a3, WINDOWSTART
+       srl     a3, a3                  # shift windowstart
+
+       /* WB is now just one frame below the oldest frame in the register
+          window. WS is shifted so the oldest frame is in bit 0, thus, WB
+          and WS differ by one 4-register frame. */
+
+       /* Save frames. Depending what call was used (call4, call8, call12),
+        * we have to save 4,8. or 12 registers.
+        */
+
+       _bbsi.l a3, 1, .Lc4
+       _bbsi.l a3, 2, .Lc8
+
+       /* Special case: we have a call12-frame starting at a4. */
+
+       _bbci.l a3, 3, .Lc12    # bit 3 shouldn't be zero! (Jump to Lc12 first)
+
+       s32e    a4, a1, -16     # a1 is valid with an empty spill area
+       l32e    a4, a5, -12
+       s32e    a8, a4, -48
+       mov     a8, a4
+       l32e    a4, a1, -16
+       j       .Lc12c
+
+.Lloop: _bbsi.l        a3, 1, .Lc4
+       _bbci.l a3, 2, .Lc12
+
+.Lc8:  s32e    a4, a13, -16
+       l32e    a4, a5, -12
+       s32e    a8, a4, -32
+       s32e    a5, a13, -12
+       s32e    a6, a13, -8
+       s32e    a7, a13, -4
+       s32e    a9, a4, -28
+       s32e    a10, a4, -24
+       s32e    a11, a4, -20
+
+       srli    a11, a3, 2              # shift windowbase by 2
+       rotw    2
+       _bnei   a3, 1, .Lloop
+
+.Lexit: /* Done. Do the final rotation, set WS, and return. */
+
+       rotw    1
+       rsr     a3, WINDOWBASE
+       ssl     a3
+       movi    a3, 1
+       sll     a3, a3
+       wsr     a3, WINDOWSTART
+
+.Lnospill:
+       jx      a0
+
+.Lc4:  s32e    a4, a9, -16
+       s32e    a5, a9, -12
+       s32e    a6, a9, -8
+       s32e    a7, a9, -4
+
+       srli    a7, a3, 1
+       rotw    1
+       _bnei   a3, 1, .Lloop
+       j       .Lexit
+
+.Lc12: _bbci.l a3, 3, .Linvalid_mask   # bit 2 shouldn't be zero!
+
+       /* 12-register frame (call12) */
+
+       l32e    a2, a5, -12
+       s32e    a8, a2, -48
+       mov     a8, a2
+
+.Lc12c: s32e   a9, a8, -44
+       s32e    a10, a8, -40
+       s32e    a11, a8, -36
+       s32e    a12, a8, -32
+       s32e    a13, a8, -28
+       s32e    a14, a8, -24
+       s32e    a15, a8, -20
+       srli    a15, a3, 3
+
+       /* The stack pointer for a4..a7 is out of reach, so we rotate the
+        * window, grab the stackpointer, and rotate back.
+        * Alternatively, we could also use the following approach, but that
+        * makes the fixup routine much more complicated:
+        * rotw 1
+        * s32e a0, a13, -16
+        * ...
+        * rotw 2
+        */
+
+       rotw    1
+       mov     a5, a13
+       rotw    -1
+
+       s32e    a4, a9, -16
+       s32e    a5, a9, -12
+       s32e    a6, a9, -8
+       s32e    a7, a9, -4
+
+       rotw    3
+
+       _beqi   a3, 1, .Lexit
+       j       .Lloop
+
+.Linvalid_mask:
+
+       /* We get here because of an unrecoverable error in the window
+        * registers. If we are in user space, we kill the application,
+        * however, this condition is unrecoverable in kernel space.
+        */
+
+       rsr     a0, PS
+       _bbci.l a0, PS_UM_SHIFT, 1f
+
+       /* User space: Setup a dummy frame and kill application.
+        * Note: We assume EXC_TABLE_KSTK contains a valid stack pointer.
+        */
+
+       movi    a0, 1
+       movi    a1, 0
+
+       wsr     a0, WINDOWSTART
+       wsr     a1, WINDOWBASE
+       rsync
+
+       movi    a0, 0
+
+       movi    a3, exc_table
+       l32i    a1, a3, EXC_TABLE_KSTK
+       wsr     a3, EXCSAVE_1
+
+       movi    a4, PS_WOE_MASK | 1
+       wsr     a4, PS
+       rsync
+
+       movi    a6, SIGSEGV
+       movi    a4, do_exit
+       callx4  a4
+
+1:     /* Kernel space: PANIC! */
+
+       wsr     a0, EXCSAVE_1
+       movi    a0, unrecoverable_exception
+       callx0  a0              # should not return
+1:     j       1b
+
+/*
+ * We should never get here. Bail out!
+ */
+
+ENTRY(fast_second_level_miss_double_kernel)
+
+1:     movi    a0, unrecoverable_exception
+       callx0  a0              # should not return
+1:     j       1b
+
+/* First-level entry handler for user, kernel, and double 2nd-level
+ * TLB miss exceptions.  Note that for now, user and kernel miss
+ * exceptions share the same entry point and are handled identically.
+ *
+ * An old, less-efficient C version of this function used to exist.
+ * We include it below, interleaved as comments, for reference.
+ *
+ * Entry condition:
+ *
+ *   a0:       trashed, original value saved on stack (PT_AREG0)
+ *   a1:       a1
+ *   a2:       new stack pointer, original in DEPC
+ *   a3:       dispatch table
+ *   depc:     a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:        a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+ENTRY(fast_second_level_miss)
+
+       /* Save a1. Note: we don't expect a double exception. */
+
+       s32i    a1, a2, PT_AREG1
+
+       /* We need to map the page of PTEs for the user task.  Find
+        * the pointer to that page.  Also, it's possible for tsk->mm
+        * to be NULL while tsk->active_mm is nonzero if we faulted on
+        * a vmalloc address.  In that rare case, we must use
+        * active_mm instead to avoid a fault in this handler.  See
+        *
+        * http://mail.nl.linux.org/linux-mm/2002-08/msg00258.html
+        *   (or search Internet on "mm vs. active_mm")
+        *
+        *      if (!mm)
+        *              mm = tsk->active_mm;
+        *      pgd = pgd_offset (mm, regs->excvaddr);
+        *      pmd = pmd_offset (pgd, regs->excvaddr);
+        *      pmdval = *pmd;
+        */
+
+       GET_CURRENT(a1,a2)
+       l32i    a0, a1, TASK_MM         # tsk->mm
+       beqz    a0, 9f
+
+8:     rsr     a1, EXCVADDR            # fault address
+       _PGD_OFFSET(a0, a1, a1)
+       l32i    a0, a0, 0               # read pmdval
+       //beqi  a0, _PAGE_USER, 2f
+       beqz    a0, 2f
+
+       /* Read ptevaddr and convert to top of page-table page.
+        *
+        *      vpnval = read_ptevaddr_register() & PAGE_MASK;
+        *      vpnval += DTLB_WAY_PGTABLE;
+        *      pteval = mk_pte (virt_to_page(pmd_val(pmdval)), PAGE_KERNEL);
+        *      write_dtlb_entry (pteval, vpnval);
+        *
+        * The messy computation for 'pteval' above really simplifies
+        * into the following:
+        *
+        * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_KERNEL
+        */
+
+       movi    a1, -PAGE_OFFSET
+       add     a0, a0, a1              # pmdval - PAGE_OFFSET
+       extui   a1, a0, 0, PAGE_SHIFT   # ... & PAGE_MASK
+       xor     a0, a0, a1
+
+
+       movi    a1, PAGE_DIRECTORY
+       or      a0, a0, a1              # ... | PAGE_DIRECTORY
+
+       rsr     a1, PTEVADDR
+       srli    a1, a1, PAGE_SHIFT
+       slli    a1, a1, PAGE_SHIFT      # ptevaddr & PAGE_MASK
+       addi    a1, a1, DTLB_WAY_PGTABLE        # ... + way_number
+
+       wdtlb   a0, a1
+       dsync
+
+       /* Exit critical section. */
+
+       movi    a0, 0
+       s32i    a0, a3, EXC_TABLE_FIXUP
+
+       /* Restore the working registers, and return. */
+
+       l32i    a0, a2, PT_AREG0
+       l32i    a1, a2, PT_AREG1
+       l32i    a2, a2, PT_DEPC
+       xsr     a3, EXCSAVE_1
+
+       bgeui   a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
+
+       /* Restore excsave1 and return. */
+
+       rsr     a2, DEPC
+       rfe
+
+       /* Return from double exception. */
+
+1:     xsr     a2, DEPC
+       esync
+       rfde
+
+9:     l32i    a0, a1, TASK_ACTIVE_MM  # unlikely case mm == 0
+       j       8b
+
+2:     /* Invalid PGD, default exception handling */
+
+       rsr     a1, DEPC
+       xsr     a3, EXCSAVE_1
+       s32i    a1, a2, PT_AREG2
+       s32i    a3, a2, PT_AREG3
+       mov     a1, a2
+
+       rsr     a2, PS
+       bbsi.l  a2, PS_UM_SHIFT, 1f
+       j       _kernel_exception
+1:     j       _user_exception
+
+
+/*
+ * StoreProhibitedException
+ *
+ * Update the pte and invalidate the itlb mapping for this pte.
+ *
+ * Entry condition:
+ *
+ *   a0:       trashed, original value saved on stack (PT_AREG0)
+ *   a1:       a1
+ *   a2:       new stack pointer, original in DEPC
+ *   a3:       dispatch table
+ *   depc:     a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:        a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+ENTRY(fast_store_prohibited)
+
+       /* Save a1 and a4. */
+
+       s32i    a1, a2, PT_AREG1
+       s32i    a4, a2, PT_AREG4
+
+       GET_CURRENT(a1,a2)
+       l32i    a0, a1, TASK_MM         # tsk->mm
+       beqz    a0, 9f
+
+8:     rsr     a1, EXCVADDR            # fault address
+       _PGD_OFFSET(a0, a1, a4)
+       l32i    a0, a0, 0
+       //beqi  a0, _PAGE_USER, 2f      # FIXME use _PAGE_INVALID
+       beqz    a0, 2f
+
+       _PTE_OFFSET(a0, a1, a4)
+       l32i    a4, a0, 0               # read pteval
+       movi    a1, _PAGE_VALID | _PAGE_RW
+       bnall   a4, a1, 2f
+
+       movi    a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_WRENABLE
+       or      a4, a4, a1
+       rsr     a1, EXCVADDR
+       s32i    a4, a0, 0
+
+       /* We need to flush the cache if we have page coloring. */
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+       dhwb    a0, 0
+#endif
+       pdtlb   a0, a1
+       beqz    a0, 1f
+       idtlb   a0              // FIXME do we need this?
+       wdtlb   a4, a0
+1:
+
+       /* Exit critical section. */
+
+       movi    a0, 0
+       s32i    a0, a3, EXC_TABLE_FIXUP
+
+       /* Restore the working registers, and return. */
+
+       l32i    a4, a2, PT_AREG4
+       l32i    a1, a2, PT_AREG1
+       l32i    a0, a2, PT_AREG0
+       l32i    a2, a2, PT_DEPC
+
+       /* Restore excsave1 and a3. */
+
+       xsr     a3, EXCSAVE_1
+       bgeui   a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
+
+       rsr     a2, DEPC
+       rfe
+
+       /* Double exception. Restore FIXUP handler and return. */
+
+1:     xsr     a2, DEPC
+       esync
+       rfde
+
+9:     l32i    a0, a1, TASK_ACTIVE_MM  # unlikely case mm == 0
+       j       8b
+
+2:     /* If there was a problem, handle fault in C */
+
+       rsr     a4, DEPC        # still holds a2
+       xsr     a3, EXCSAVE_1
+       s32i    a4, a2, PT_AREG2
+       s32i    a3, a2, PT_AREG3
+       l32i    a4, a2, PT_AREG4
+       mov     a1, a2
+
+       rsr     a2, PS
+       bbsi.l  a2, PS_UM_SHIFT, 1f
+       j       _kernel_exception
+1:     j       _user_exception
+
+
+#if XCHAL_EXTRA_SA_SIZE
+
+#warning fast_coprocessor untested
+
+/*
+ * Entry condition:
+ *
+ *   a0:       trashed, original value saved on stack (PT_AREG0)
+ *   a1:       a1
+ *   a2:       new stack pointer, original in DEPC
+ *   a3:       dispatch table
+ *   depc:     a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:        a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+ENTRY(fast_coprocessor_double)
+       wsr     a0, EXCSAVE_1
+       movi    a0, unrecoverable_exception
+       callx0  a0
+
+ENTRY(fast_coprocessor)
+
+       /* Fatal if we are in a double exception. */
+
+       l32i    a0, a2, PT_DEPC
+       _bgeui  a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_coprocessor_double
+
+       /* Save some registers a1, a3, a4, SAR */
+
+       xsr     a3, EXCSAVE_1
+       s32i    a3, a2, PT_AREG3
+       rsr     a3, SAR
+       s32i    a4, a2, PT_AREG4
+       s32i    a1, a2, PT_AREG1
+       s32i    a5, a1, PT_AREG5
+       s32i    a3, a2, PT_SAR
+       mov     a1, a2
+
+       /* Currently, the HAL macros only guarantee saving a0 and a1.
+        * These can and will be refined in the future, but for now,
+        * just save the remaining registers of a2...a15.
+        */
+       s32i    a6, a1, PT_AREG6
+       s32i    a7, a1, PT_AREG7
+       s32i    a8, a1, PT_AREG8
+       s32i    a9, a1, PT_AREG9
+       s32i    a10, a1, PT_AREG10
+       s32i    a11, a1, PT_AREG11
+       s32i    a12, a1, PT_AREG12
+       s32i    a13, a1, PT_AREG13
+       s32i    a14, a1, PT_AREG14
+       s32i    a15, a1, PT_AREG15
+
+       /* Find coprocessor number. Subtract first CP EXCCAUSE from EXCCAUSE */
+
+       rsr     a0, EXCCAUSE
+       addi    a3, a0, -XCHAL_EXCCAUSE_COPROCESSOR0_DISABLED
+
+       /* Set corresponding CPENABLE bit */
+
+       movi    a4, 1
+       ssl     a3                      # SAR: 32 - coprocessor_number
+       rsr     a5, CPENABLE
+       sll     a4, a4
+       or      a4, a5, a4
+       wsr     a4, CPENABLE
+       rsync
+       movi    a5, coprocessor_info    # list of owner and offset into cp_save
+       addx8   a0, a4, a5              # entry for CP
+
+       bne     a4, a5, .Lload          # bit wasn't set before, cp not in use
+
+       /* Now compare the current task with the owner of the coprocessor.
+        * If they are the same, there is no reason to save or restore any
+        * coprocessor state. Having already enabled the coprocessor,
+        * branch ahead to return.
+        */
+       GET_CURRENT(a5,a1)
+       l32i    a4, a0, COPROCESSOR_INFO_OWNER  # a4: current owner for this CP
+       beq     a4, a5, .Ldone
+
+       /* Find location to dump current coprocessor state:
+        *  task_struct->task_cp_save_offset + coprocessor_offset[coprocessor]
+        *
+        * Note: a0 pointer to the entry in the coprocessor owner table,
+        *       a3 coprocessor number,
+         *      a4 current owner of coprocessor.
+        */
+       l32i    a5, a0, COPROCESSOR_INFO_OFFSET
+       addi    a2, a4, THREAD_CP_SAVE
+       add     a2, a2, a5
+
+       /* Store current coprocessor states. (a5 still has CP number) */
+
+       xchal_cpi_store_funcbody
+
+       /* The macro might have destroyed a3 (coprocessor number), but
+        * SAR still has 32 - coprocessor_number!
+        */
+       movi    a3, 32
+       rsr     a4, SAR
+       sub     a3, a3, a4
+
+.Lload:        /* A new task now owns the corpocessors. Save its TCB pointer into
+        * the coprocessor owner table.
+        *
+        * Note: a0 pointer to the entry in the coprocessor owner table,
+        *       a3 coprocessor number.
+        */
+       GET_CURRENT(a4,a1)
+       s32i    a4, a0, 0
+
+       /* Find location from where to restore the current coprocessor state.*/
+
+       l32i    a5, a0, COPROCESSOR_INFO_OFFSET
+       addi    a2, a4, THREAD_CP_SAVE
+       add     a2, a2, a4
+
+       xchal_cpi_load_funcbody
+
+       /* We must assume that the xchal_cpi_store_funcbody macro destroyed
+        * registers a2..a15.
+        */
+
+.Ldone:        l32i    a15, a1, PT_AREG15
+       l32i    a14, a1, PT_AREG14
+       l32i    a13, a1, PT_AREG13
+       l32i    a12, a1, PT_AREG12
+       l32i    a11, a1, PT_AREG11
+       l32i    a10, a1, PT_AREG10
+       l32i    a9, a1, PT_AREG9
+       l32i    a8, a1, PT_AREG8
+       l32i    a7, a1, PT_AREG7
+       l32i    a6, a1, PT_AREG6
+       l32i    a5, a1, PT_AREG5
+       l32i    a4, a1, PT_AREG4
+       l32i    a3, a1, PT_AREG3
+       l32i    a2, a1, PT_AREG2
+       l32i    a0, a1, PT_AREG0
+       l32i    a1, a1, PT_AREG1
+
+       rfe
+
+#endif /* XCHAL_EXTRA_SA_SIZE */
+
+/*
+ * Task switch.
+ *
+ * struct task*  _switch_to (struct task* prev, struct task* next)
+ *         a2                              a2                 a3
+ */
+
+ENTRY(_switch_to)
+
+       entry   a1, 16
+
+       mov     a4, a3                  # preserve a3
+
+       s32i    a0, a2, THREAD_RA       # save return address
+       s32i    a1, a2, THREAD_SP       # save stack pointer
+
+       /* Disable ints while we manipulate the stack pointer; spill regs. */
+
+       movi    a5, PS_EXCM_MASK | LOCKLEVEL
+       xsr     a5, PS
+       rsr     a3, EXCSAVE_1
+       rsync
+       s32i    a3, a3, EXC_TABLE_FIXUP /* enter critical section */
+
+       call0   _spill_registers
+
+       /* Set kernel stack (and leave critical section)
+        * Note: It's save to set it here. The stack will not be overwritten
+        *       because the kernel stack will only be loaded again after
+        *       we return from kernel space.
+        */
+
+       l32i    a0, a4, TASK_THREAD_INFO
+       rsr     a3, EXCSAVE_1           # exc_table
+       movi    a1, 0
+       addi    a0, a0, PT_REGS_OFFSET
+       s32i    a1, a3, EXC_TABLE_FIXUP
+       s32i    a0, a3, EXC_TABLE_KSTK
+
+       /* restore context of the task that 'next' addresses */
+
+       l32i    a0, a4, THREAD_RA       /* restore return address */
+       l32i    a1, a4, THREAD_SP       /* restore stack pointer */
+
+       wsr     a5, PS
+       rsync
+
+       retw
+
+
+ENTRY(ret_from_fork)
+
+       /* void schedule_tail (struct task_struct *prev)
+        * Note: prev is still in a6 (return value from fake call4 frame)
+        */
+       movi    a4, schedule_tail
+       callx4  a4
+
+       movi    a4, do_syscall_trace
+       callx4  a4
+
+       j       common_exception_return
+
+
+
+/*
+ * Table of syscalls
+ */
+
+.data
+.align  4
+.global sys_call_table
+sys_call_table:
+
+#define SYSCALL(call, narg) .word call
+#include "syscalls.h"
+
+/*
+ * Number of arguments of each syscall
+ */
+
+.global sys_narg_table
+sys_narg_table:
+
+#undef SYSCALL
+#define SYSCALL(call, narg) .byte narg
+#include "syscalls.h"
+
diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S
new file mode 100644 (file)
index 0000000..6e9b522
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * arch/xtensa/kernel/head.S
+ *
+ * Xtensa Processor startup code.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Kevin Chea
+ */
+
+#include <xtensa/cacheasm.h>
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+
+/*
+ * This module contains the entry code for kernel images. It performs the
+ * minimal setup needed to call the generic C routines.
+ *
+ * Prerequisites:
+ *
+ * - The kernel image has been loaded to the actual address where it was
+ *   compiled to.
+ * - a2 contains either 0 or a pointer to a list of boot parameters.
+ *   (see setup.c for more details)
+ *
+ */
+
+       .macro  iterate from, to , cmd
+               .ifeq   ((\to - \from) & ~0xfff)
+                       \cmd    \from
+                       iterate "(\from+1)", \to, \cmd
+               .endif
+       .endm
+
+/*
+ *  _start
+ *
+ *  The bootloader passes a pointer to a list of boot parameters in a2.
+ */
+
+       /* The first bytes of the kernel image must be an instruction, so we
+        * manually allocate and define the literal constant we need for a jx
+        * instruction.
+        */
+
+       .section .head.text, "ax"
+       .globl _start
+_start:        _j      2f
+       .align  4
+1:     .word   _startup
+2:     l32r    a0, 1b
+       jx      a0
+
+       .text
+       .align 4
+_startup:
+
+       /* Disable interrupts and exceptions. */
+
+       movi    a0, XCHAL_PS_EXCM_MASK
+       wsr     a0, PS
+
+       /* Preserve the pointer to the boot parameter list in EXCSAVE_1 */
+
+       wsr     a2, EXCSAVE_1
+
+       /* Start with a fresh windowbase and windowstart.  */
+
+       movi    a1, 1
+       movi    a0, 0
+       wsr     a1, WINDOWSTART
+       wsr     a0, WINDOWBASE
+       rsync
+
+       /* Set a0 to 0 for the remaining initialization. */
+
+       movi    a0, 0
+
+       /* Clear debugging registers. */
+
+#if XCHAL_HAVE_DEBUG
+       wsr     a0, IBREAKENABLE
+       wsr     a0, ICOUNT
+       movi    a1, 15
+       wsr     a0, ICOUNTLEVEL
+
+       .macro reset_dbreak num
+       wsr     a0, DBREAKC + \num
+       .endm
+
+        iterate 0, XCHAL_NUM_IBREAK-1, reset_dbreak
+#endif
+
+       /* Clear CCOUNT (not really necessary, but nice) */
+
+       wsr     a0, CCOUNT      # not really necessary, but nice
+
+       /* Disable zero-loops. */
+
+#if XCHAL_HAVE_LOOPS
+       wsr     a0, LCOUNT
+#endif
+
+       /* Disable all timers. */
+
+       .macro  reset_timer     num
+       wsr     a0, CCOMPARE_0 + \num
+       .endm
+       iterate 0, XCHAL_NUM_TIMERS-1, reset_timer
+
+       /* Interrupt initialization. */
+
+       movi    a2, XCHAL_INTTYPE_MASK_SOFTWARE | XCHAL_INTTYPE_MASK_EXTERN_EDGE
+       wsr     a0, INTENABLE
+       wsr     a2, INTCLEAR
+
+       /* Disable coprocessors. */
+
+#if XCHAL_CP_NUM > 0
+       wsr     a0, CPENABLE
+#endif
+
+       /* Set PS.INTLEVEL=1, PS.WOE=0, kernel stack, PS.EXCM=0
+        *
+        * Note: PS.EXCM must be cleared before using any loop
+        *       instructions; otherwise, they are silently disabled, and
+        *       at most one iteration of the loop is executed.
+        */
+
+       movi    a1, 1
+       wsr     a1, PS
+       rsync
+
+       /*  Initialize the caches.
+        *  Does not include flushing writeback d-cache.
+        *  a6, a7 are just working registers (clobbered).
+        */
+
+       icache_reset  a2, a3
+       dcache_reset  a2, a3
+
+       /* Unpack data sections
+        *
+        * The linker script used to build the Linux kernel image
+        * creates a table located at __boot_reloc_table_start
+        * that contans the information what data needs to be unpacked.
+        *
+        * Uses a2-a7.
+        */
+
+       movi    a2, __boot_reloc_table_start
+       movi    a3, __boot_reloc_table_end
+
+1:     beq     a2, a3, 3f      # no more entries?
+       l32i    a4, a2, 0       # start destination (in RAM)
+       l32i    a5, a2, 4       # end desination (in RAM)
+       l32i    a6, a2, 8       # start source (in ROM)
+       addi    a2, a2, 12      # next entry
+       beq     a4, a5, 1b      # skip, empty entry
+       beq     a4, a6, 1b      # skip, source and dest. are the same
+
+2:     l32i    a7, a6, 0       # load word
+       addi    a6, a6, 4
+       s32i    a7, a4, 0       # store word
+       addi    a4, a4, 4
+       bltu    a4, a5, 2b
+       j       1b
+
+3:
+       /* All code and initialized data segments have been copied.
+        * Now clear the BSS segment.
+        */
+
+       movi    a2, _bss_start  # start of BSS
+       movi    a3, _bss_end    # end of BSS
+
+1:     addi    a2, a2, 4
+       s32i    a0, a2, 0
+       blt     a2, a3, 1b
+
+#if XCHAL_DCACHE_IS_WRITEBACK
+
+       /* After unpacking, flush the writeback cache to memory so the
+        * instructions/data are available.
+        */
+
+       dcache_writeback_all    a2, a3
+#endif
+
+       /* Setup stack and enable window exceptions (keep irqs disabled) */
+
+       movi    a1, init_thread_union
+       addi    a1, a1, KERNEL_STACK_SIZE
+
+       movi    a2, 0x00040001          # WOE=1, INTLEVEL=1, UM=0
+       wsr     a2, PS                  # (enable reg-windows; progmode stack)
+       rsync
+
+       /* Set up EXCSAVE[DEBUGLEVEL] to point to the Debug Exception Handler.*/
+
+       movi    a2, debug_exception
+       wsr     a2, EXCSAVE + XCHAL_DEBUGLEVEL
+
+       /* Set up EXCSAVE[1] to point to the exc_table. */
+
+       movi    a6, exc_table
+       xsr     a6, EXCSAVE_1
+
+       /* init_arch kick-starts the linux kernel */
+
+       movi    a4, init_arch
+       callx4  a4
+
+       movi    a4, start_kernel
+       callx4  a4
+
+should_never_return:
+       j       should_never_return
+
+       /* Define some common data structures here.  We define them
+        * here in this assembly file due to their unusual alignment
+        * requirements.
+        */
+
+       .comm   swapper_pg_dir,PAGE_SIZE,PAGE_SIZE
+       .comm   empty_bad_page_table,PAGE_SIZE,PAGE_SIZE
+       .comm   empty_bad_page,PAGE_SIZE,PAGE_SIZE
+       .comm   empty_zero_page,PAGE_SIZE,PAGE_SIZE
+
diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c
new file mode 100644 (file)
index 0000000..4cbf6d9
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * linux/arch/xtensa/kernel/irq.c
+ *
+ * Xtensa built-in interrupt controller and some generic functions copied
+ * from i386.
+ *
+ * Copyright (C) 2002 - 2005 Tensilica, Inc.
+ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
+ *
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Kevin Chea
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/uaccess.h>
+#include <asm/platform.h>
+
+static void enable_xtensa_irq(unsigned int irq);
+static void disable_xtensa_irq(unsigned int irq);
+static void mask_and_ack_xtensa(unsigned int irq);
+static void end_xtensa_irq(unsigned int irq);
+
+static unsigned int cached_irq_mask;
+
+atomic_t irq_err_count;
+
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves.
+ */
+void ack_bad_irq(unsigned int irq)
+{
+          printk("unexpected IRQ trap at vector %02x\n", irq);
+}
+
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+
+unsigned int  do_IRQ(int irq, struct pt_regs *regs)
+{
+       irq_enter();
+
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+       /* Debugging check for stack overflow: is there less than 1KB free? */
+       {
+               unsigned long sp;
+
+               __asm__ __volatile__ ("mov %0, a1\n" : "=a" (sp));
+               sp &= THREAD_SIZE - 1;
+
+               if (unlikely(sp < (sizeof(thread_info) + 1024)))
+                       printk("Stack overflow in do_IRQ: %ld\n",
+                              sp - sizeof(struct thread_info));
+       }
+#endif
+
+       __do_IRQ(irq, regs);
+
+       irq_exit();
+
+       return 1;
+}
+
+/*
+ * Generic, controller-independent functions:
+ */
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+       int i = *(loff_t *) v, j;
+       struct irqaction * action;
+       unsigned long flags;
+
+       if (i == 0) {
+               seq_printf(p, "           ");
+               for (j=0; j<NR_CPUS; j++)
+                       if (cpu_online(j))
+                               seq_printf(p, "CPU%d       ",j);
+               seq_putc(p, '\n');
+       }
+
+       if (i < NR_IRQS) {
+               spin_lock_irqsave(&irq_desc[i].lock, flags);
+               action = irq_desc[i].action;
+               if (!action)
+                       goto skip;
+               seq_printf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
+               seq_printf(p, "%10u ", kstat_irqs(i));
+#else
+               for (j = 0; j < NR_CPUS; j++)
+                       if (cpu_online(j))
+                               seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+#endif
+               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, "  %s", action->name);
+
+               for (action=action->next; action; action = action->next)
+                       seq_printf(p, ", %s", action->name);
+
+               seq_putc(p, '\n');
+skip:
+               spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+       } else if (i == NR_IRQS) {
+               seq_printf(p, "NMI: ");
+               for (j = 0; j < NR_CPUS; j++)
+                       if (cpu_online(j))
+                               seq_printf(p, "%10u ", nmi_count(j));
+               seq_putc(p, '\n');
+               seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+       }
+       return 0;
+}
+/* shutdown is same as "disable" */
+#define shutdown_xtensa_irq disable_xtensa_irq
+
+static unsigned int startup_xtensa_irq(unsigned int irq)
+{
+       enable_xtensa_irq(irq);
+       return 0;               /* never anything pending */
+}
+
+static struct hw_interrupt_type xtensa_irq_type = {
+       "Xtensa-IRQ",
+       startup_xtensa_irq,
+       shutdown_xtensa_irq,
+       enable_xtensa_irq,
+       disable_xtensa_irq,
+       mask_and_ack_xtensa,
+       end_xtensa_irq
+};
+
+static inline void mask_irq(unsigned int irq)
+{
+       cached_irq_mask &= ~(1 << irq);
+       set_sr (cached_irq_mask, INTENABLE);
+}
+
+static inline void unmask_irq(unsigned int irq)
+{
+       cached_irq_mask |= 1 << irq;
+       set_sr (cached_irq_mask, INTENABLE);
+}
+
+static void disable_xtensa_irq(unsigned int irq)
+{
+       unsigned long flags;
+       local_save_flags(flags);
+       mask_irq(irq);
+       local_irq_restore(flags);
+}
+
+static void enable_xtensa_irq(unsigned int irq)
+{
+       unsigned long flags;
+       local_save_flags(flags);
+       unmask_irq(irq);
+       local_irq_restore(flags);
+}
+
+static void mask_and_ack_xtensa(unsigned int irq)
+{
+        disable_xtensa_irq(irq);
+}
+
+static void end_xtensa_irq(unsigned int irq)
+{
+        enable_xtensa_irq(irq);
+}
+
+
+void __init init_IRQ(void)
+{
+       int i;
+
+       for (i=0; i < XTENSA_NR_IRQS; i++)
+               irq_desc[i].handler = &xtensa_irq_type;
+
+       cached_irq_mask = 0;
+
+       platform_init_irq();
+}
diff --git a/arch/xtensa/kernel/module.c b/arch/xtensa/kernel/module.c
new file mode 100644 (file)
index 0000000..d1683cf
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * arch/xtensa/kernel/platform.c
+ *
+ * Module support.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/cache.h>
+
+LIST_HEAD(module_buf_list);
+
+void *module_alloc(unsigned long size)
+{
+  panic("module_alloc not implemented");
+}
+
+void module_free(struct module *mod, void *module_region)
+{
+  panic("module_free not implemented");
+}
+
+int module_frob_arch_sections(Elf32_Ehdr *hdr,
+                             Elf32_Shdr *sechdrs,
+                             char *secstrings,
+                             struct module *me)
+{
+  panic("module_frob_arch_sections not implemented");
+}
+
+int apply_relocate(Elf32_Shdr *sechdrs,
+                  const char *strtab,
+                  unsigned int symindex,
+                  unsigned int relsec,
+                  struct module *module)
+{
+  panic ("apply_relocate not implemented");
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+                      const char *strtab,
+                      unsigned int symindex,
+                      unsigned int relsec,
+                      struct module *module)
+{
+  panic("apply_relocate_add not implemented");
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+                   const Elf_Shdr *sechdrs,
+                   struct module *me)
+{
+  panic ("module_finalize not implemented");
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+  panic("module_arch_cleanup not implemented");
+}
+
+struct bug_entry *module_find_bug(unsigned long bugaddr)
+{
+  panic("module_find_bug not implemented");
+}
diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c
new file mode 100644 (file)
index 0000000..84fde25
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * arch/xtensa/pci-dma.c
+ *
+ * DMA coherent memory allocation.
+ *
+ * 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.
+ *
+ * Copyright (C) 2002 - 2005 Tensilica Inc.
+ *
+ * Based on version for i386.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+
+/*
+ * Note: We assume that the full memory space is always mapped to 'kseg'
+ *      Otherwise we have to use page attributes (not implemented).
+ */
+
+void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp)
+{
+       void *ret;
+
+       /* ignore region speicifiers */
+       gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
+
+       if (dev == NULL || (*dev->dma_mask < 0xffffffff))
+               gfp |= GFP_DMA;
+       ret = (void *)__get_free_pages(gfp, get_order(size));
+
+       if (ret != NULL) {
+               memset(ret, 0, size);
+               *handle = virt_to_bus(ret);
+       }
+       return (void*) BYPASS_ADDR((unsigned long)ret);
+}
+
+void dma_free_coherent(struct device *hwdev, size_t size,
+                        void *vaddr, dma_addr_t dma_handle)
+{
+       free_pages(CACHED_ADDR((unsigned long)vaddr), get_order(size));
+}
+
+
+void consistent_sync(void *vaddr, size_t size, int direction)
+{
+       switch (direction) {
+       case PCI_DMA_NONE:
+               BUG();
+       case PCI_DMA_FROMDEVICE:        /* invalidate only */
+               __invalidate_dcache_range((unsigned long)vaddr,
+                                         (unsigned long)size);
+               break;
+
+       case PCI_DMA_TODEVICE:          /* writeback only */
+       case PCI_DMA_BIDIRECTIONAL:     /* writeback and invalidate */
+               __flush_invalidate_dcache_range((unsigned long)vaddr,
+                                               (unsigned long)size);
+               break;
+       }
+}
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
new file mode 100644 (file)
index 0000000..09887c9
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * arch/xtensa/pcibios.c
+ *
+ * PCI bios-type initialisation for PCI machines
+ *
+ * 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.
+ *
+ * Copyright (C) 2001-2005 Tensilica Inc.
+ *
+ * Based largely on work from Cort (ppc/kernel/pci.c)
+ * IO functions copied from sparc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/bootmem.h>
+
+#include <asm/pci-bridge.h>
+#include <asm/platform.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* PCI Controller */
+
+
+/*
+ * pcibios_alloc_controller
+ * pcibios_enable_device
+ * pcibios_fixups
+ * pcibios_align_resource
+ * pcibios_fixup_bus
+ * pcibios_setup
+ * pci_bus_add_device
+ * pci_mmap_page_range
+ */
+
+struct pci_controller* pci_ctrl_head;
+struct pci_controller** pci_ctrl_tail = &pci_ctrl_head;
+
+static int pci_bus_count;
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ *
+ * Why? Because some silly external IO cards only decode
+ * the low 10 bits of the IO address. The 0x00-0xff region
+ * is reserved for motherboard devices that decode all 16
+ * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
+ * but we want to try to avoid allocating at 0x2900-0x2bff
+ * which might have be mirrored at 0x0100-0x03ff..
+ */
+void
+pcibios_align_resource(void *data, struct resource *res, unsigned long size,
+                      unsigned long align)
+{
+       struct pci_dev *dev = data;
+
+       if (res->flags & IORESOURCE_IO) {
+               unsigned long start = res->start;
+
+               if (size > 0x100) {
+                       printk(KERN_ERR "PCI: I/O Region %s/%d too large"
+                              " (%ld bytes)\n", pci_name(dev),
+                              dev->resource - res, size);
+               }
+
+               if (start & 0x300) {
+                       start = (start + 0x3ff) & ~0x3ff;
+                       res->start = start;
+               }
+       }
+}
+
+int
+pcibios_enable_resources(struct pci_dev *dev, int mask)
+{
+       u16 cmd, old_cmd;
+       int idx;
+       struct resource *r;
+
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       old_cmd = cmd;
+       for(idx=0; idx<6; idx++) {
+               r = &dev->resource[idx];
+               if (!r->start && r->end) {
+                       printk (KERN_ERR "PCI: Device %s not available because "
+                               "of resource collisions\n", pci_name(dev));
+                       return -EINVAL;
+               }
+               if (r->flags & IORESOURCE_IO)
+                       cmd |= PCI_COMMAND_IO;
+               if (r->flags & IORESOURCE_MEM)
+                       cmd |= PCI_COMMAND_MEMORY;
+       }
+       if (dev->resource[PCI_ROM_RESOURCE].start)
+               cmd |= PCI_COMMAND_MEMORY;
+       if (cmd != old_cmd) {
+               printk("PCI: Enabling device %s (%04x -> %04x)\n",
+                       pci_name(dev), old_cmd, cmd);
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+       return 0;
+}
+
+struct pci_controller * __init pcibios_alloc_controller(void)
+{
+       struct pci_controller *pci_ctrl;
+
+       pci_ctrl = (struct pci_controller *)alloc_bootmem(sizeof(*pci_ctrl));
+       memset(pci_ctrl, 0, sizeof(struct pci_controller));
+
+       *pci_ctrl_tail = pci_ctrl;
+       pci_ctrl_tail = &pci_ctrl->next;
+
+       return pci_ctrl;
+}
+
+static int __init pcibios_init(void)
+{
+       struct pci_controller *pci_ctrl;
+       struct pci_bus *bus;
+       int next_busno = 0, i;
+
+       printk("PCI: Probing PCI hardware\n");
+
+       /* Scan all of the recorded PCI controllers.  */
+       for (pci_ctrl = pci_ctrl_head; pci_ctrl; pci_ctrl = pci_ctrl->next) {
+               pci_ctrl->last_busno = 0xff;
+               bus = pci_scan_bus(pci_ctrl->first_busno, pci_ctrl->ops,
+                                  pci_ctrl);
+               if (pci_ctrl->io_resource.flags) {
+                       unsigned long offs;
+
+                       offs = (unsigned long)pci_ctrl->io_space.base;
+                       pci_ctrl->io_resource.start += offs;
+                       pci_ctrl->io_resource.end += offs;
+                       bus->resource[0] = &pci_ctrl->io_resource;
+               }
+               for (i = 0; i < 3; ++i)
+                       if (pci_ctrl->mem_resources[i].flags)
+                               bus->resource[i+1] =&pci_ctrl->mem_resources[i];
+               pci_ctrl->bus = bus;
+               pci_ctrl->last_busno = bus->subordinate;
+               if (next_busno <= pci_ctrl->last_busno)
+                       next_busno = pci_ctrl->last_busno+1;
+       }
+       pci_bus_count = next_busno;
+
+       return platform_pcibios_fixup();
+}
+
+subsys_initcall(pcibios_init);
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+       struct pci_controller *pci_ctrl = bus->sysdata;
+       struct resource *res;
+       unsigned long io_offset;
+       int i;
+
+       io_offset = (unsigned long)pci_ctrl->io_space.base;
+       if (bus->parent == NULL) {
+               /* this is a host bridge - fill in its resources */
+               pci_ctrl->bus = bus;
+
+               bus->resource[0] = res = &pci_ctrl->io_resource;
+               if (!res->flags) {
+                       if (io_offset)
+                               printk (KERN_ERR "I/O resource not set for host"
+                                       " bridge %d\n", pci_ctrl->index);
+                       res->start = 0;
+                       res->end = IO_SPACE_LIMIT;
+                       res->flags = IORESOURCE_IO;
+               }
+               res->start += io_offset;
+               res->end += io_offset;
+
+               for (i = 0; i < 3; i++) {
+                       res = &pci_ctrl->mem_resources[i];
+                       if (!res->flags) {
+                               if (i > 0)
+                                       continue;
+                               printk(KERN_ERR "Memory resource not set for "
+                                      "host bridge %d\n", pci_ctrl->index);
+                               res->start = 0;
+                               res->end = ~0U;
+                               res->flags = IORESOURCE_MEM;
+                       }
+                       bus->resource[i+1] = res;
+               }
+       } else {
+               /* This is a subordinate bridge */
+               pci_read_bridge_bases(bus);
+
+               for (i = 0; i < 4; i++) {
+                       if ((res = bus->resource[i]) == NULL || !res->flags)
+                               continue;
+                       if (io_offset && (res->flags & IORESOURCE_IO)) {
+                               res->start += io_offset;
+                               res->end += io_offset;
+                       }
+               }
+       }
+}
+
+char __init *pcibios_setup(char *str)
+{
+       return str;
+}
+
+/* the next one is stolen from the alpha port... */
+
+void __init
+pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+       pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+       u16 cmd, old_cmd;
+       int idx;
+       struct resource *r;
+
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       old_cmd = cmd;
+       for (idx=0; idx<6; idx++) {
+               r = &dev->resource[idx];
+               if (!r->start && r->end) {
+                       printk(KERN_ERR "PCI: Device %s not available because "
+                              "of resource collisions\n", pci_name(dev));
+                       return -EINVAL;
+               }
+               if (r->flags & IORESOURCE_IO)
+                       cmd |= PCI_COMMAND_IO;
+               if (r->flags & IORESOURCE_MEM)
+                       cmd |= PCI_COMMAND_MEMORY;
+       }
+       if (cmd != old_cmd) {
+               printk("PCI: Enabling device %s (%04x -> %04x)\n",
+                      pci_name(dev), old_cmd, cmd);
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+
+/*
+ * Return the index of the PCI controller for device pdev.
+ */
+
+int
+pci_controller_num(struct pci_dev *dev)
+{
+       struct pci_controller *pci_ctrl = (struct pci_controller*) dev->sysdata;
+       return pci_ctrl->index;
+}
+
+#endif /* CONFIG_PROC_FS */
+
+/*
+ * Platform support for /proc/bus/pci/X/Y mmap()s,
+ * modelled on the sparc64 implementation by Dave Miller.
+ *  -- paulus.
+ */
+
+/*
+ * Adjust vm_pgoff of VMA such that it is the physical page offset
+ * corresponding to the 32-bit pci bus offset for DEV requested by the user.
+ *
+ * Basically, the user finds the base address for his device which he wishes
+ * to mmap.  They read the 32-bit value from the config space base register,
+ * add whatever PAGE_SIZE multiple offset they wish, and feed this into the
+ * offset parameter of mmap on /proc/bus/pci/XXX for that device.
+ *
+ * Returns negative error code on failure, zero on success.
+ */
+static __inline__ int
+__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
+                      enum pci_mmap_state mmap_state)
+{
+       struct pci_controller *pci_ctrl = (struct pci_controller*) dev->sysdata;
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       unsigned long io_offset = 0;
+       int i, res_bit;
+
+       if (pci_ctrl == 0)
+               return -EINVAL;         /* should never happen */
+
+       /* If memory, add on the PCI bridge address offset */
+       if (mmap_state == pci_mmap_mem) {
+               res_bit = IORESOURCE_MEM;
+       } else {
+               io_offset = (unsigned long)pci_ctrl->io_space.base;
+               offset += io_offset;
+               res_bit = IORESOURCE_IO;
+       }
+
+       /*
+        * Check that the offset requested corresponds to one of the
+        * resources of the device.
+        */
+       for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+               struct resource *rp = &dev->resource[i];
+               int flags = rp->flags;
+
+               /* treat ROM as memory (should be already) */
+               if (i == PCI_ROM_RESOURCE)
+                       flags |= IORESOURCE_MEM;
+
+               /* Active and same type? */
+               if ((flags & res_bit) == 0)
+                       continue;
+
+               /* In the range of this resource? */
+               if (offset < (rp->start & PAGE_MASK) || offset > rp->end)
+                       continue;
+
+               /* found it! construct the final physical address */
+               if (mmap_state == pci_mmap_io)
+                       offset += pci_ctrl->io_space.start - io_offset;
+               vma->vm_pgoff = offset >> PAGE_SHIFT;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+/*
+ * Set vm_flags of VMA, as appropriate for this architecture, for a pci device
+ * mapping.
+ */
+static __inline__ void
+__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,
+                    enum pci_mmap_state mmap_state)
+{
+       vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+}
+
+/*
+ * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
+ * device mapping.
+ */
+static __inline__ void
+__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
+                     enum pci_mmap_state mmap_state, int write_combine)
+{
+       int prot = pgprot_val(vma->vm_page_prot);
+
+       /* Set to write-through */
+       prot &= ~_PAGE_NO_CACHE;
+#if 0
+       if (!write_combine)
+               prot |= _PAGE_WRITETHRU;
+#endif
+       vma->vm_page_prot = __pgprot(prot);
+}
+
+/*
+ * Perform the actual remap of the pages for a PCI device mapping, as
+ * appropriate for this architecture.  The region in the process to map
+ * is described by vm_start and vm_end members of VMA, the base physical
+ * address is found in vm_pgoff.
+ * The pci device structure is provided so that architectures may make mapping
+ * decisions on a per-device or per-bus basis.
+ *
+ * Returns a negative error code on failure, zero on success.
+ */
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+                       enum pci_mmap_state mmap_state,
+                       int write_combine)
+{
+       int ret;
+
+       ret = __pci_mmap_make_offset(dev, vma, mmap_state);
+       if (ret < 0)
+               return ret;
+
+       __pci_mmap_set_flags(dev, vma, mmap_state);
+       __pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
+
+       ret = io_remap_page_range(vma, vma->vm_start, vma->vm_pgoff<<PAGE_SHIFT,
+                              vma->vm_end - vma->vm_start, vma->vm_page_prot);
+
+       return ret;
+}
+
+/*
+ * This probably belongs here rather than ioport.c because
+ * we do not want this crud linked into SBus kernels.
+ * Also, think for a moment about likes of floppy.c that
+ * include architecture specific parts. They may want to redefine ins/outs.
+ *
+ * We do not use horroble macroses here because we want to
+ * advance pointer by sizeof(size).
+ */
+void outsb(unsigned long addr, const void *src, unsigned long count) {
+        while (count) {
+                count -= 1;
+                writeb(*(const char *)src, addr);
+                src += 1;
+                addr += 1;
+        }
+}
+
+void outsw(unsigned long addr, const void *src, unsigned long count) {
+        while (count) {
+                count -= 2;
+                writew(*(const short *)src, addr);
+                src += 2;
+                addr += 2;
+        }
+}
+
+void outsl(unsigned long addr, const void *src, unsigned long count) {
+        while (count) {
+                count -= 4;
+                writel(*(const long *)src, addr);
+                src += 4;
+                addr += 4;
+        }
+}
+
+void insb(unsigned long addr, void *dst, unsigned long count) {
+        while (count) {
+                count -= 1;
+                *(unsigned char *)dst = readb(addr);
+                dst += 1;
+                addr += 1;
+        }
+}
+
+void insw(unsigned long addr, void *dst, unsigned long count) {
+        while (count) {
+                count -= 2;
+                *(unsigned short *)dst = readw(addr);
+                dst += 2;
+                addr += 2;
+        }
+}
+
+void insl(unsigned long addr, void *dst, unsigned long count) {
+        while (count) {
+                count -= 4;
+                /*
+                 * XXX I am sure we are in for an unaligned trap here.
+                 */
+                *(unsigned long *)dst = readl(addr);
+                dst += 4;
+                addr += 4;
+        }
+}
+
+
+
diff --git a/arch/xtensa/kernel/platform.c b/arch/xtensa/kernel/platform.c
new file mode 100644 (file)
index 0000000..cf13627
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * arch/xtensa/kernel/platform.c
+ *
+ * Default platform functions.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <asm/platform.h>
+#include <asm/timex.h>
+
+#define _F(r,f,a,b)                                                    \
+       r __platform_##f a b;                                           \
+       r platform_##f a __attribute__((weak, alias("__platform_"#f)))
+
+/*
+ * Default functions that are used if no platform specific function is defined.
+ * (Please, refer to include/asm-xtensa/platform.h for more information)
+ */
+
+_F(void, setup, (char** cmd), { });
+_F(void, init_irq, (void), { });
+_F(void, restart, (void), { while(1); });
+_F(void, halt, (void), { while(1); });
+_F(void, power_off, (void), { while(1); });
+_F(void, idle, (void), { __asm__ __volatile__ ("waiti 0" ::: "memory"); });
+_F(void, heartbeat, (void), { });
+_F(int,  pcibios_fixup, (void), { return 0; });
+_F(int, get_rtc_time, (time_t* t), { return 0; });
+_F(int, set_rtc_time, (time_t t), { return 0; });
+
+#if CONFIG_XTENSA_CALIBRATE_CCOUNT
+_F(void, calibrate_ccount, (void),
+{
+  printk ("ERROR: Cannot calibrate cpu frequency! Assuming 100MHz.\n");
+  ccount_per_jiffy = 100 * (1000000UL/HZ);
+});
+#endif
+
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
new file mode 100644 (file)
index 0000000..4099703
--- /dev/null
@@ -0,0 +1,482 @@
+// TODO        verify coprocessor handling
+/*
+ * arch/xtensa/kernel/process.c
+ *
+ * Xtensa Processor version.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Chris Zankel <chris@zankel.net>
+ * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Kevin Chea
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/elf.h>
+#include <linux/init.h>
+#include <linux/prctl.h>
+#include <linux/init_task.h>
+#include <linux/module.h>
+#include <linux/mqueue.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/platform.h>
+#include <asm/mmu.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <asm/offsets.h>
+#include <asm/coprocessor.h>
+
+extern void ret_from_fork(void);
+
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+struct mm_struct init_mm = INIT_MM(init_mm);
+EXPORT_SYMBOL(init_mm);
+
+union thread_union init_thread_union
+       __attribute__((__section__(".data.init_task"))) =
+{ INIT_THREAD_INFO(init_task) };
+
+struct task_struct init_task = INIT_TASK(init_task);
+EXPORT_SYMBOL(init_task);
+
+struct task_struct *current_set[NR_CPUS] = {&init_task, };
+
+
+#if XCHAL_CP_NUM > 0
+
+/*
+ * Coprocessor ownership.
+ */
+
+coprocessor_info_t coprocessor_info[] = {
+       { 0, XTENSA_CPE_CP0_OFFSET },
+       { 0, XTENSA_CPE_CP1_OFFSET },
+       { 0, XTENSA_CPE_CP2_OFFSET },
+       { 0, XTENSA_CPE_CP3_OFFSET },
+       { 0, XTENSA_CPE_CP4_OFFSET },
+       { 0, XTENSA_CPE_CP5_OFFSET },
+       { 0, XTENSA_CPE_CP6_OFFSET },
+       { 0, XTENSA_CPE_CP7_OFFSET },
+};
+
+#endif
+
+/*
+ * Powermanagement idle function, if any is provided by the platform.
+ */
+
+void cpu_idle(void)
+{
+       local_irq_enable();
+
+       /* endless idle loop with no priority at all */
+       while (1) {
+               while (!need_resched())
+                       platform_idle();
+               preempt_enable();
+               schedule();
+       }
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+
+void exit_thread(void)
+{
+       release_coprocessors(current);  /* Empty macro if no CPs are defined */
+}
+
+void flush_thread(void)
+{
+       release_coprocessors(current);  /* Empty macro if no CPs are defined */
+}
+
+/*
+ * Copy thread.
+ *
+ * The stack layout for the new thread looks like this:
+ *
+ *     +------------------------+ <- sp in childregs (= tos)
+ *     |       childregs        |
+ *     +------------------------+ <- thread.sp = sp in dummy-frame
+ *     |      dummy-frame       |    (saved in dummy-frame spill-area)
+ *     +------------------------+
+ *
+ * We create a dummy frame to return to ret_from_fork:
+ *   a0 points to ret_from_fork (simulating a call4)
+ *   sp points to itself (thread.sp)
+ *   a2, a3 are unused.
+ *
+ * Note: This is a pristine frame, so we don't need any spill region on top of
+ *       childregs.
+ */
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+               unsigned long unused,
+                struct task_struct * p, struct pt_regs * regs)
+{
+       struct pt_regs *childregs;
+       unsigned long tos;
+       int user_mode = user_mode(regs);
+
+       /* Set up new TSS. */
+       tos = (unsigned long)p->thread_info + THREAD_SIZE;
+       if (user_mode)
+               childregs = (struct pt_regs*)(tos - PT_USER_SIZE);
+       else
+               childregs = (struct pt_regs*)tos - 1;
+
+       *childregs = *regs;
+
+       /* Create a call4 dummy-frame: a0 = 0, a1 = childregs. */
+       *((int*)childregs - 3) = (unsigned long)childregs;
+       *((int*)childregs - 4) = 0;
+
+       childregs->areg[1] = tos;
+       childregs->areg[2] = 0;
+       p->set_child_tid = p->clear_child_tid = NULL;
+       p->thread.ra = MAKE_RA_FOR_CALL((unsigned long)ret_from_fork, 0x1);
+       p->thread.sp = (unsigned long)childregs;
+       if (user_mode(regs)) {
+
+               int len = childregs->wmask & ~0xf;
+               childregs->areg[1] = usp;
+               memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],
+                      &regs->areg[XCHAL_NUM_AREGS - len/4], len);
+
+               if (clone_flags & CLONE_SETTLS)
+                       childregs->areg[2] = childregs->areg[6];
+
+       } else {
+               /* In kernel space, we start a new thread with a new stack. */
+               childregs->wmask = 1;
+       }
+       return 0;
+}
+
+
+/*
+ * Create a kernel thread
+ */
+
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+       long retval;
+       __asm__ __volatile__
+               ("mov           a5, %4\n\t" /* preserve fn in a5 */
+                "mov           a6, %3\n\t" /* preserve and setup arg in a6 */
+                "movi          a2, %1\n\t" /* load __NR_clone for syscall*/
+                "mov           a3, sp\n\t" /* sp check and sys_clone */
+                "mov           a4, %5\n\t" /* load flags for syscall */
+                "syscall\n\t"
+                "beq           a3, sp, 1f\n\t" /* branch if parent */
+                "callx4        a5\n\t"     /* call fn */
+                "movi          a2, %2\n\t" /* load __NR_exit for syscall */
+                "mov           a3, a6\n\t" /* load fn return value */
+                "syscall\n"
+                "1:\n\t"
+                "mov           %0, a2\n\t" /* parent returns zero */
+                :"=r" (retval)
+                :"i" (__NR_clone), "i" (__NR_exit),
+                "r" (arg), "r" (fn),
+                "r" (flags | CLONE_VM)
+                : "a2", "a3", "a4", "a5", "a6" );
+       return retval;
+}
+
+
+/*
+ * These bracket the sleeping functions..
+ */
+
+unsigned long get_wchan(struct task_struct *p)
+{
+       unsigned long sp, pc;
+       unsigned long stack_page = (unsigned long) p->thread_info;
+       int count = 0;
+
+       if (!p || p == current || p->state == TASK_RUNNING)
+               return 0;
+
+       sp = p->thread.sp;
+       pc = MAKE_PC_FROM_RA(p->thread.ra, p->thread.sp);
+
+       do {
+               if (sp < stack_page + sizeof(struct task_struct) ||
+                   sp >= (stack_page + THREAD_SIZE) ||
+                   pc == 0)
+                       return 0;
+               if (!in_sched_functions(pc))
+                       return pc;
+
+               /* Stack layout: sp-4: ra, sp-3: sp' */
+
+               pc = MAKE_PC_FROM_RA(*(unsigned long*)sp - 4, sp);
+               sp = *(unsigned long *)sp - 3;
+       } while (count++ < 16);
+       return 0;
+}
+
+/*
+ * do_copy_regs() gathers information from 'struct pt_regs' and
+ * 'current->thread.areg[]' to fill in the xtensa_gregset_t
+ * structure.
+ *
+ * xtensa_gregset_t and 'struct pt_regs' are vastly different formats
+ * of processor registers.  Besides different ordering,
+ * xtensa_gregset_t contains non-live register information that
+ * 'struct pt_regs' does not.  Exception handling (primarily) uses
+ * 'struct pt_regs'.  Core files and ptrace use xtensa_gregset_t.
+ *
+ */
+
+void do_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs,
+                  struct task_struct *tsk)
+{
+       int i, n, wb_offset;
+
+       elfregs->xchal_config_id0 = XCHAL_HW_CONFIGID0;
+       elfregs->xchal_config_id1 = XCHAL_HW_CONFIGID1;
+
+       __asm__ __volatile__ ("rsr  %0, 176\n" : "=a" (i));
+       elfregs->cpux = i;
+       __asm__ __volatile__ ("rsr  %0, 208\n" : "=a" (i));
+       elfregs->cpuy = i;
+
+       /* Note:  PS.EXCM is not set while user task is running; its
+        * being set in regs->ps is for exception handling convenience.
+        */
+
+       elfregs->pc             = regs->pc;
+       elfregs->ps             = (regs->ps & ~XCHAL_PS_EXCM_MASK);
+       elfregs->exccause       = regs->exccause;
+       elfregs->excvaddr       = regs->excvaddr;
+       elfregs->windowbase     = regs->windowbase;
+       elfregs->windowstart    = regs->windowstart;
+       elfregs->lbeg           = regs->lbeg;
+       elfregs->lend           = regs->lend;
+       elfregs->lcount         = regs->lcount;
+       elfregs->sar            = regs->sar;
+       elfregs->syscall        = regs->syscall;
+
+       /* Copy register file.
+        * The layout looks like this:
+        *
+        * |  a0 ... a15  | Z ... Z |  arX ... arY  |
+        *  current window  unused    saved frames
+        */
+
+       memset (elfregs->ar, 0, sizeof(elfregs->ar));
+
+       wb_offset = regs->windowbase * 4;
+       n = (regs->wmask&1)? 4 : (regs->wmask&2)? 8 : (regs->wmask&4)? 12 : 16;
+
+       for (i = 0; i < n; i++)
+               elfregs->ar[(wb_offset + i) % XCHAL_NUM_AREGS] = regs->areg[i];
+
+       n = (regs->wmask >> 4) * 4;
+
+       for (i = XCHAL_NUM_AREGS - n; n > 0; i++, n--)
+               elfregs->ar[(wb_offset + i) % XCHAL_NUM_AREGS] = regs->areg[i];
+}
+
+void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs)
+{
+       do_copy_regs ((xtensa_gregset_t *)elfregs, regs, current);
+}
+
+
+/* The inverse of do_copy_regs().  No error or sanity checking. */
+
+void do_restore_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs,
+                     struct task_struct *tsk)
+{
+       int i, n, wb_offset;
+
+       /* Note:  PS.EXCM is not set while user task is running; it
+        * needs to be set in regs->ps is for exception handling convenience.
+        */
+
+       regs->pc                = elfregs->pc;
+       regs->ps                = (elfregs->ps | XCHAL_PS_EXCM_MASK);
+       regs->exccause          = elfregs->exccause;
+       regs->excvaddr          = elfregs->excvaddr;
+       regs->windowbase        = elfregs->windowbase;
+       regs->windowstart       = elfregs->windowstart;
+       regs->lbeg              = elfregs->lbeg;
+       regs->lend              = elfregs->lend;
+       regs->lcount            = elfregs->lcount;
+       regs->sar               = elfregs->sar;
+       regs->syscall   = elfregs->syscall;
+
+       /* Clear everything. */
+
+       memset (regs->areg, 0, sizeof(regs->areg));
+
+       /* Copy regs from live window frame. */
+
+       wb_offset = regs->windowbase * 4;
+       n = (regs->wmask&1)? 4 : (regs->wmask&2)? 8 : (regs->wmask&4)? 12 : 16;
+
+       for (i = 0; i < n; i++)
+               regs->areg[(wb_offset+i) % XCHAL_NUM_AREGS] = elfregs->ar[i];
+
+       n = (regs->wmask >> 4) * 4;
+
+       for (i = XCHAL_NUM_AREGS - n; n > 0; i++, n--)
+               regs->areg[(wb_offset+i) % XCHAL_NUM_AREGS] = elfregs->ar[i];
+}
+
+/*
+ * do_save_fpregs() gathers information from 'struct pt_regs' and
+ * 'current->thread' to fill in the elf_fpregset_t structure.
+ *
+ * Core files and ptrace use elf_fpregset_t.
+ */
+
+void do_save_fpregs (elf_fpregset_t *fpregs, struct pt_regs *regs,
+                    struct task_struct *tsk)
+{
+#if XCHAL_HAVE_CP
+
+       extern unsigned char    _xtensa_reginfo_tables[];
+       extern unsigned         _xtensa_reginfo_table_size;
+       int i;
+       unsigned long flags;
+
+       /* Before dumping coprocessor state from memory,
+        * ensure any live coprocessor contents for this
+        * task are first saved to memory:
+        */
+       local_irq_save(flags);
+
+       for (i = 0; i < XCHAL_CP_MAX; i++) {
+               if (tsk == coprocessor_info[i].owner) {
+                       enable_coprocessor(i);
+                       save_coprocessor_registers(
+                           tsk->thread.cp_save+coprocessor_info[i].offset,i);
+                       disable_coprocessor(i);
+               }
+       }
+
+       local_irq_restore(flags);
+
+       /* Now dump coprocessor & extra state: */
+       memcpy((unsigned char*)fpregs,
+               _xtensa_reginfo_tables, _xtensa_reginfo_table_size);
+       memcpy((unsigned char*)fpregs + _xtensa_reginfo_table_size,
+               tsk->thread.cp_save, XTENSA_CP_EXTRA_SIZE);
+#endif
+}
+
+/*
+ * The inverse of do_save_fpregs().
+ * Copies coprocessor and extra state from fpregs into regs and tsk->thread.
+ * Returns 0 on success, non-zero if layout doesn't match.
+ */
+
+int  do_restore_fpregs (elf_fpregset_t *fpregs, struct pt_regs *regs,
+                       struct task_struct *tsk)
+{
+#if XCHAL_HAVE_CP
+
+       extern unsigned char    _xtensa_reginfo_tables[];
+       extern unsigned         _xtensa_reginfo_table_size;
+       int i;
+       unsigned long flags;
+
+       /* Make sure save area layouts match.
+        * FIXME:  in the future we could allow restoring from
+        * a different layout of the same registers, by comparing
+        * fpregs' table with _xtensa_reginfo_tables and matching
+        * entries and copying registers one at a time.
+        * Not too sure yet whether that's very useful.
+        */
+
+       if( memcmp((unsigned char*)fpregs,
+               _xtensa_reginfo_tables, _xtensa_reginfo_table_size) ) {
+           return -1;
+       }
+
+       /* Before restoring coprocessor state from memory,
+        * ensure any live coprocessor contents for this
+        * task are first invalidated.
+        */
+
+       local_irq_save(flags);
+
+       for (i = 0; i < XCHAL_CP_MAX; i++) {
+               if (tsk == coprocessor_info[i].owner) {
+                       enable_coprocessor(i);
+                       save_coprocessor_registers(
+                           tsk->thread.cp_save+coprocessor_info[i].offset,i);
+                       coprocessor_info[i].owner = 0;
+                       disable_coprocessor(i);
+               }
+       }
+
+       local_irq_restore(flags);
+
+       /*  Now restore coprocessor & extra state:  */
+
+       memcpy(tsk->thread.cp_save,
+               (unsigned char*)fpregs + _xtensa_reginfo_table_size,
+               XTENSA_CP_EXTRA_SIZE);
+#endif
+       return 0;
+}
+/*
+ * Fill in the CP structure for a core dump for a particular task.
+ */
+
+int
+dump_task_fpu(struct pt_regs *regs, struct task_struct *task, elf_fpregset_t *r)
+{
+/* see asm/coprocessor.h for this magic number 16 */
+#if TOTAL_CPEXTRA_SIZE > 16
+       do_save_fpregs (r, regs, task);
+
+       /*  For now, bit 16 means some extra state may be present:  */
+// FIXME!! need to track to return more accurate mask
+       return 0x10000 | XCHAL_CP_MASK;
+#else
+       return 0;       /* no coprocessors active on this processor */
+#endif
+}
+
+/*
+ * Fill in the CP structure for a core dump.
+ * This includes any FPU coprocessor.
+ * Here, we dump all coprocessors, and other ("extra") custom state.
+ *
+ * This function is called by elf_core_dump() in fs/binfmt_elf.c
+ * (in which case 'regs' comes from calls to do_coredump, see signals.c).
+ */
+int  dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
+{
+       return dump_task_fpu(regs, current, r);
+}
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
new file mode 100644 (file)
index 0000000..2659efd
--- /dev/null
@@ -0,0 +1,408 @@
+// TODO some minor issues
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005  Tensilica Inc.
+ *
+ * Joe Taylor  <joe@tensilica.com, joetylr@yahoo.com>
+ * Chris Zankel <chris@zankel.net>
+ * Scott Foehner<sfoehner@yahoo.com>,
+ * Kevin Chea
+ * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/security.h>
+#include <linux/signal.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/ptrace.h>
+#include <asm/elf.h>
+
+#define TEST_KERNEL    // verify kernel operations FIXME: remove
+
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+
+void ptrace_disable(struct task_struct *child)
+{
+       /* Nothing to do.. */
+}
+
+int sys_ptrace(long request, long pid, long addr, long data)
+{
+       struct task_struct *child;
+       int ret = -EPERM;
+
+       lock_kernel();
+
+#if 0
+       if ((int)request != 1)
+       printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n",
+              (int) request, (int) pid, (unsigned long) addr,
+              (unsigned long) data);
+#endif
+
+       if (request == PTRACE_TRACEME) {
+
+               /* Are we already being traced? */
+
+               if (current->ptrace & PT_PTRACED)
+                       goto out;
+
+               if ((ret = security_ptrace(current->parent, current)))
+                       goto out;
+
+               /* Set the ptrace bit in the process flags. */
+
+               current->ptrace |= PT_PTRACED;
+               ret = 0;
+               goto out;
+       }
+
+       ret = -ESRCH;
+       read_lock(&tasklist_lock);
+       child = find_task_by_pid(pid);
+       if (child)
+               get_task_struct(child);
+       read_unlock(&tasklist_lock);
+       if (!child)
+               goto out;
+
+       ret = -EPERM;
+       if (pid == 1)           /* you may not mess with init */
+               goto out;
+
+       if (request == PTRACE_ATTACH) {
+               ret = ptrace_attach(child);
+               goto out_tsk;
+       }
+
+       if ((ret = ptrace_check_attach(child, request == PTRACE_KILL)) < 0)
+               goto out_tsk;
+
+       switch (request) {
+       case PTRACE_PEEKTEXT: /* read word at location addr. */
+       case PTRACE_PEEKDATA:
+       {
+               unsigned long tmp;
+               int copied;
+
+               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+               ret = -EIO;
+               if (copied != sizeof(tmp))
+                       break;
+               ret = put_user(tmp,(unsigned long *) data);
+
+               goto out;
+       }
+
+       /* Read the word at location addr in the USER area.  */
+
+       case PTRACE_PEEKUSR:
+               {
+               struct pt_regs *regs;
+               unsigned long tmp;
+
+               regs = xtensa_pt_regs(child);
+               tmp = 0;  /* Default return value. */
+
+               switch(addr) {
+
+               case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
+                       {
+                       int ar = addr - REG_AR_BASE - regs->windowbase * 4;
+                       ar &= (XCHAL_NUM_AREGS - 1);
+                       if (ar < 16 && ar + (regs->wmask >> 4) * 4 >= 0)
+                               tmp = regs->areg[ar];
+                       else
+                               ret = -EIO;
+                       break;
+                       }
+               case REG_A_BASE ... REG_A_BASE + 15:
+                       tmp = regs->areg[addr - REG_A_BASE];
+                       break;
+               case REG_PC:
+                       tmp = regs->pc;
+                       break;
+               case REG_PS:
+                       /* Note:  PS.EXCM is not set while user task is running;
+                        * its being set in regs is for exception handling
+                        * convenience.  */
+                       tmp = (regs->ps & ~XCHAL_PS_EXCM_MASK);
+                       break;
+               case REG_WB:
+                       tmp = regs->windowbase;
+                       break;
+               case REG_WS:
+                       tmp = regs->windowstart;
+                       break;
+               case REG_LBEG:
+                       tmp = regs->lbeg;
+                       break;
+               case REG_LEND:
+                       tmp = regs->lend;
+                       break;
+               case REG_LCOUNT:
+                       tmp = regs->lcount;
+                       break;
+               case REG_SAR:
+                       tmp = regs->sar;
+                       break;
+               case REG_DEPC:
+                       tmp = regs->depc;
+                       break;
+               case REG_EXCCAUSE:
+                       tmp = regs->exccause;
+                       break;
+               case REG_EXCVADDR:
+                       tmp = regs->excvaddr;
+                       break;
+               case SYSCALL_NR:
+                       tmp = regs->syscall;
+                       break;
+               default:
+                       tmp = 0;
+                       ret = -EIO;
+                       goto out;
+               }
+               ret = put_user(tmp, (unsigned long *) data);
+               goto out;
+               }
+
+       case PTRACE_POKETEXT: /* write the word at location addr. */
+       case PTRACE_POKEDATA:
+               if (access_process_vm(child, addr, &data, sizeof(data), 1)
+                   == sizeof(data))
+                       break;
+               ret = -EIO;
+               goto out;
+
+       case PTRACE_POKEUSR:
+               {
+               struct pt_regs *regs;
+               regs = xtensa_pt_regs(child);
+
+               switch (addr) {
+               case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
+                       {
+                       int ar = addr - REG_AR_BASE - regs->windowbase * 4;
+                       if (ar < 16 && ar + (regs->wmask >> 4) * 4 >= 0)
+                               regs->areg[ar & (XCHAL_NUM_AREGS - 1)] = data;
+                       else
+                               ret = -EIO;
+                       break;
+                       }
+               case REG_A_BASE ... REG_A_BASE + 15:
+                       regs->areg[addr - REG_A_BASE] = data;
+                       break;
+               case REG_PC:
+                       regs->pc = data;
+                       break;
+               case SYSCALL_NR:
+                       regs->syscall = data;
+                       break;
+#ifdef TEST_KERNEL
+               case REG_WB:
+                       regs->windowbase = data;
+                       break;
+               case REG_WS:
+                       regs->windowstart = data;
+                       break;
+#endif
+
+               default:
+                       /* The rest are not allowed. */
+                       ret = -EIO;
+                       break;
+               }
+               break;
+               }
+
+       /* continue and stop at next (return from) syscall */
+       case PTRACE_SYSCALL:
+       case PTRACE_CONT: /* restart after signal. */
+       {
+               ret = -EIO;
+               if (!valid_signal(data))
+                       break;
+               if (request == PTRACE_SYSCALL)
+                       set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               else
+                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               child->exit_code = data;
+               /* Make sure the single step bit is not set. */
+               child->ptrace &= ~PT_SINGLESTEP;
+               wake_up_process(child);
+               ret = 0;
+               break;
+       }
+
+       /*
+        * make the child exit.  Best I can do is send it a sigkill.
+        * perhaps it should be put in the status that it wants to
+        * exit.
+        */
+       case PTRACE_KILL:
+               ret = 0;
+               if (child->state == EXIT_ZOMBIE)        /* already dead */
+                       break;
+               child->exit_code = SIGKILL;
+               child->ptrace &= ~PT_SINGLESTEP;
+               wake_up_process(child);
+               break;
+
+       case PTRACE_SINGLESTEP:
+               ret = -EIO;
+               if (!valid_signal(data))
+                       break;
+               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               child->ptrace |= PT_SINGLESTEP;
+               child->exit_code = data;
+               wake_up_process(child);
+               ret = 0;
+               break;
+
+       case PTRACE_GETREGS:
+       {
+               /* 'data' points to user memory in which to write.
+                * Mainly due to the non-live register values, we
+                * reformat the register values into something more
+                * standard.  For convenience, we use the handy
+                * elf_gregset_t format. */
+
+               xtensa_gregset_t format;
+               struct pt_regs *regs = xtensa_pt_regs(child);
+
+               do_copy_regs (&format, regs, child);
+
+               /* Now, copy to user space nice and easy... */
+               ret = 0;
+               if (copy_to_user((void *)data, &format, sizeof(elf_gregset_t)))
+                       ret = -EFAULT;
+               break;
+       }
+
+       case PTRACE_SETREGS:
+       {
+               /* 'data' points to user memory that contains the new
+                * values in the elf_gregset_t format. */
+
+               xtensa_gregset_t format;
+               struct pt_regs *regs = xtensa_pt_regs(child);
+
+               if (copy_from_user(&format,(void *)data,sizeof(elf_gregset_t))){
+                       ret = -EFAULT;
+                       break;
+               }
+
+               /* FIXME: Perhaps we want some sanity checks on
+                * these user-space values?  See ARM version.  Are
+                * debuggers a security concern? */
+
+               do_restore_regs (&format, regs, child);
+
+               ret = 0;
+               break;
+       }
+
+       case PTRACE_GETFPREGS:
+       {
+               /* 'data' points to user memory in which to write.
+                * For convenience, we use the handy
+                * elf_fpregset_t format. */
+
+               elf_fpregset_t fpregs;
+               struct pt_regs *regs = xtensa_pt_regs(child);
+
+               do_save_fpregs (&fpregs, regs, child);
+
+               /* Now, copy to user space nice and easy... */
+               ret = 0;
+               if (copy_to_user((void *)data, &fpregs, sizeof(elf_fpregset_t)))
+                       ret = -EFAULT;
+
+               break;
+       }
+
+       case PTRACE_SETFPREGS:
+       {
+               /* 'data' points to user memory that contains the new
+                * values in the elf_fpregset_t format.
+                */
+               elf_fpregset_t fpregs;
+               struct pt_regs *regs = xtensa_pt_regs(child);
+
+               ret = 0;
+               if (copy_from_user(&fpregs, (void *)data, sizeof(elf_fpregset_t))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               if (do_restore_fpregs (&fpregs, regs, child))
+                       ret = -EIO;
+               break;
+       }
+
+       case PTRACE_GETFPREGSIZE:
+               /* 'data' points to 'unsigned long' set to the size
+                * of elf_fpregset_t
+                */
+               ret = put_user(sizeof(elf_fpregset_t), (unsigned long *) data);
+               break;
+
+       case PTRACE_DETACH: /* detach a process that was attached. */
+               ret = ptrace_detach(child, data);
+               break;
+
+       default:
+               ret = ptrace_request(child, request, addr, data);
+               goto out;
+       }
+out_tsk:
+       put_task_struct(child);
+out:
+       unlock_kernel();
+       return ret;
+}
+
+void do_syscall_trace(void)
+{
+       if (!test_thread_flag(TIF_SYSCALL_TRACE))
+               return;
+
+       if (!(current->ptrace & PT_PTRACED))
+               return;
+
+       /*
+        * The 0x80 provides a way for the tracing parent to distinguish
+        * between a syscall stop and SIGTRAP delivery
+        */
+       ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
+
+       /*
+        * this isn't the same as continuing with a signal, but it will do
+        * for normal use.  strace only continues with a signal if the
+        * stopping signal is not SIGTRAP.  -brl
+        */
+       if (current->exit_code) {
+               send_sig(current->exit_code, current, 1);
+               current->exit_code = 0;
+       }
+}
diff --git a/arch/xtensa/kernel/semaphore.c b/arch/xtensa/kernel/semaphore.c
new file mode 100644 (file)
index 0000000..d40f4b1
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * arch/xtensa/kernel/semaphore.c
+ *
+ * Generic semaphore code. Buyer beware. Do your own specific changes
+ * in <asm/semaphore-helper.h>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Joe Taylor  <joe@tensilica.com, joetylr@yahoo.com>
+ * Chris Zankel        <chris@zankel.net>
+ * Marc Gauthier<marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Kevin Chea
+ */
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/init.h>
+#include <asm/semaphore.h>
+#include <asm/errno.h>
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ */
+
+static __inline__ void wake_one_more(struct semaphore * sem)
+{
+       atomic_inc((atomic_t *)&sem->sleepers);
+}
+
+static __inline__ int waking_non_zero(struct semaphore *sem)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&semaphore_wake_lock, flags);
+       if (sem->sleepers > 0) {
+               sem->sleepers--;
+               ret = 1;
+       }
+       spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+       return ret;
+}
+
+/*
+ * waking_non_zero_interruptible:
+ *     1       got the lock
+ *     0       go to sleep
+ *     -EINTR  interrupted
+ *
+ * We must undo the sem->count down_interruptible() increment while we are
+ * protected by the spinlock in order to make atomic this atomic_inc() with the
+ * atomic_read() in wake_one_more(), otherwise we can race. -arca
+ */
+
+static __inline__ int waking_non_zero_interruptible(struct semaphore *sem,
+                                               struct task_struct *tsk)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&semaphore_wake_lock, flags);
+       if (sem->sleepers > 0) {
+               sem->sleepers--;
+               ret = 1;
+       } else if (signal_pending(tsk)) {
+               atomic_inc(&sem->count);
+               ret = -EINTR;
+       }
+       spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+       return ret;
+}
+
+/*
+ * waking_non_zero_trylock:
+ *     1       failed to lock
+ *     0       got the lock
+ *
+ * We must undo the sem->count down_trylock() increment while we are
+ * protected by the spinlock in order to make atomic this atomic_inc() with the
+ * atomic_read() in wake_one_more(), otherwise we can race. -arca
+ */
+
+static __inline__ int waking_non_zero_trylock(struct semaphore *sem)
+{
+       unsigned long flags;
+       int ret = 1;
+
+       spin_lock_irqsave(&semaphore_wake_lock, flags);
+       if (sem->sleepers <= 0)
+               atomic_inc(&sem->count);
+       else {
+               sem->sleepers--;
+               ret = 0;
+       }
+       spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+       return ret;
+}
+
+spinlock_t semaphore_wake_lock;
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to sleep, while the "waking" variable is
+ * incremented when the "up()" code goes to wake up waiting
+ * processes.
+ *
+ * Notably, the inline "up()" and "down()" functions can
+ * efficiently test if they need to do any extra work (up
+ * needs to do something only if count was negative before
+ * the increment operation.
+ *
+ * waking_non_zero() (from asm/semaphore.h) must execute
+ * atomically.
+ *
+ * When __up() is called, the count was negative before
+ * incrementing it, and we need to wake up somebody.
+ *
+ * This routine adds one to the count of processes that need to
+ * wake up and exit.  ALL waiting processes actually wake up but
+ * only the one that gets to the "waking" field first will gate
+ * through and acquire the semaphore.  The others will go back
+ * to sleep.
+ *
+ * Note that these functions are only called when there is
+ * contention on the lock, and as such all this is the
+ * "non-critical" part of the whole semaphore business. The
+ * critical part is the inline stuff in <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+
+void __up(struct semaphore *sem)
+{
+       wake_one_more(sem);
+       wake_up(&sem->wait);
+}
+
+/*
+ * Perform the "down" function.  Return zero for semaphore acquired,
+ * return negative for signalled out of the function.
+ *
+ * If called from __down, the return is ignored and the wait loop is
+ * not interruptible.  This means that a task waiting on a semaphore
+ * using "down()" cannot be killed until someone does an "up()" on
+ * the semaphore.
+ *
+ * If called from __down_interruptible, the return value gets checked
+ * upon return.  If the return value is negative then the task continues
+ * with the negative value in the return register (it can be tested by
+ * the caller).
+ *
+ * Either form may be used in conjunction with "up()".
+ *
+ */
+
+#define DOWN_VAR                               \
+       struct task_struct *tsk = current;      \
+       wait_queue_t wait;                      \
+       init_waitqueue_entry(&wait, tsk);
+
+#define DOWN_HEAD(task_state)                                          \
+                                                                       \
+                                                                       \
+       tsk->state = (task_state);                                      \
+       add_wait_queue(&sem->wait, &wait);                              \
+                                                                       \
+       /*                                                              \
+        * Ok, we're set up.  sem->count is known to be less than zero  \
+        * so we must wait.                                             \
+        *                                                              \
+        * We can let go the lock for purposes of waiting.              \
+        * We re-acquire it after awaking so as to protect              \
+        * all semaphore operations.                                    \
+        *                                                              \
+        * If "up()" is called before we call waking_non_zero() then    \
+        * we will catch it right away.  If it is called later then     \
+        * we will have to go through a wakeup cycle to catch it.       \
+        *                                                              \
+        * Multiple waiters contend for the semaphore lock to see       \
+        * who gets to gate through and who has to wait some more.      \
+        */                                                             \
+       for (;;) {
+
+#define DOWN_TAIL(task_state)                  \
+               tsk->state = (task_state);      \
+       }                                       \
+       tsk->state = TASK_RUNNING;              \
+       remove_wait_queue(&sem->wait, &wait);
+
+void __sched __down(struct semaphore * sem)
+{
+       DOWN_VAR
+       DOWN_HEAD(TASK_UNINTERRUPTIBLE)
+       if (waking_non_zero(sem))
+               break;
+       schedule();
+       DOWN_TAIL(TASK_UNINTERRUPTIBLE)
+}
+
+int __sched __down_interruptible(struct semaphore * sem)
+{
+       int ret = 0;
+       DOWN_VAR
+       DOWN_HEAD(TASK_INTERRUPTIBLE)
+
+       ret = waking_non_zero_interruptible(sem, tsk);
+       if (ret)
+       {
+               if (ret == 1)
+                       /* ret != 0 only if we get interrupted -arca */
+                       ret = 0;
+               break;
+       }
+       schedule();
+       DOWN_TAIL(TASK_INTERRUPTIBLE)
+       return ret;
+}
+
+int __down_trylock(struct semaphore * sem)
+{
+       return waking_non_zero_trylock(sem);
+}
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
new file mode 100644 (file)
index 0000000..1f5bf5d
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * arch/xtensa/setup.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995  Linus Torvalds
+ * Copyright (C) 2001 - 2005  Tensilica Inc.
+ *
+ * Chris Zankel        <chris@zankel.net>
+ * Joe Taylor  <joe@tensilica.com, joetylr@yahoo.com>
+ * Kevin Chea
+ * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca>
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/tty.h>
+#include <linux/bootmem.h>
+#include <linux/kernel.h>
+
+#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
+# include <linux/console.h>
+#endif
+
+#ifdef CONFIG_RTC
+# include <linux/timex.h>
+#endif
+
+#ifdef CONFIG_PROC_FS
+# include <linux/seq_file.h>
+#endif
+
+#include <asm/system.h>
+#include <asm/bootparam.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/timex.h>
+#include <asm/platform.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+
+#include <xtensa/config/system.h>
+
+#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
+struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16};
+#endif
+
+#ifdef CONFIG_BLK_DEV_FD
+extern struct fd_ops no_fd_ops;
+struct fd_ops *fd_ops;
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+extern struct ide_ops no_ide_ops;
+struct ide_ops *ide_ops;
+#endif
+
+extern struct rtc_ops no_rtc_ops;
+struct rtc_ops *rtc_ops;
+
+#ifdef CONFIG_PC_KEYB
+extern struct kbd_ops no_kbd_ops;
+struct kbd_ops *kbd_ops;
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+extern void *initrd_start;
+extern void *initrd_end;
+extern void *__initrd_start;
+extern void *__initrd_end;
+int initrd_is_mapped = 0;
+extern int initrd_below_start_ok;
+#endif
+
+unsigned char aux_device_present;
+extern unsigned long loops_per_jiffy;
+
+/* Command line specified as configuration option. */
+
+static char command_line[COMMAND_LINE_SIZE];
+
+#ifdef CONFIG_CMDLINE_BOOL
+static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
+#endif
+
+sysmem_info_t __initdata sysmem;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+int initrd_is_mapped;
+#endif
+
+extern void init_mmu(void);
+
+/*
+ * Boot parameter parsing.
+ *
+ * The Xtensa port uses a list of variable-sized tags to pass data to
+ * the kernel. The first tag must be a BP_TAG_FIRST tag for the list
+ * to be recognised. The list is terminated with a zero-sized
+ * BP_TAG_LAST tag.
+ */
+
+typedef struct tagtable {
+       u32 tag;
+       int (*parse)(const bp_tag_t*);
+} tagtable_t;
+
+#define __tagtable(tag, fn) static tagtable_t __tagtable_##fn          \
+       __attribute__((unused, __section__(".taglist"))) = { tag, fn }
+
+/* parse current tag */
+
+static int __init parse_tag_mem(const bp_tag_t *tag)
+{
+       meminfo_t *mi = (meminfo_t*)(tag->data);
+
+       if (mi->type != MEMORY_TYPE_CONVENTIONAL)
+               return -1;
+
+       if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) {
+               printk(KERN_WARNING
+                      "Ignoring memory bank 0x%08lx size %ldKB\n",
+                      (unsigned long)mi->start,
+                      (unsigned long)mi->end - (unsigned long)mi->start);
+               return -EINVAL;
+       }
+       sysmem.bank[sysmem.nr_banks].type  = mi->type;
+       sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(mi->start);
+       sysmem.bank[sysmem.nr_banks].end   = mi->end & PAGE_SIZE;
+       sysmem.nr_banks++;
+
+       return 0;
+}
+
+__tagtable(BP_TAG_MEMORY, parse_tag_mem);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+
+static int __init parse_tag_initrd(const bp_tag_t* tag)
+{
+       meminfo_t* mi;
+       mi = (meminfo_t*)(tag->data);
+       initrd_start = (void*)(mi->start);
+       initrd_end = (void*)(mi->end);
+
+       return 0;
+}
+
+__tagtable(BP_TAG_INITRD, parse_tag_initrd);
+
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+static int __init parse_tag_cmdline(const bp_tag_t* tag)
+{
+       strncpy(command_line, (char*)(tag->data), COMMAND_LINE_SIZE);
+       command_line[COMMAND_LINE_SIZE - 1] = '\0';
+       return 0;
+}
+
+__tagtable(BP_TAG_COMMAND_LINE, parse_tag_cmdline);
+
+static int __init parse_bootparam(const bp_tag_t* tag)
+{
+       extern tagtable_t __tagtable_begin, __tagtable_end;
+       tagtable_t *t;
+
+       /* Boot parameters must start with a BP_TAG_FIRST tag. */
+
+       if (tag->id != BP_TAG_FIRST) {
+               printk(KERN_WARNING "Invalid boot parameters!\n");
+               return 0;
+       }
+
+       tag = (bp_tag_t*)((unsigned long)tag + sizeof(bp_tag_t) + tag->size);
+
+       /* Parse all tags. */
+
+       while (tag != NULL && tag->id != BP_TAG_LAST) {
+               for (t = &__tagtable_begin; t < &__tagtable_end; t++) {
+                       if (tag->id == t->tag) {
+                               t->parse(tag);
+                               break;
+                       }
+               }
+               if (t == &__tagtable_end)
+                       printk(KERN_WARNING "Ignoring tag "
+                              "0x%08x\n", tag->id);
+               tag = (bp_tag_t*)((unsigned long)(tag + 1) + tag->size);
+       }
+
+       return 0;
+}
+
+/*
+ * Initialize architecture. (Early stage)
+ */
+
+void __init init_arch(bp_tag_t *bp_start)
+{
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       initrd_start = &__initrd_start;
+       initrd_end = &__initrd_end;
+#endif
+
+       sysmem.nr_banks = 0;
+
+#ifdef CONFIG_CMDLINE_BOOL
+       strcpy(command_line, default_command_line);
+#endif
+
+       /* Parse boot parameters */
+
+        if (bp_start)
+         parse_bootparam(bp_start);
+
+       if (sysmem.nr_banks == 0) {
+               sysmem.nr_banks = 1;
+               sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START;
+               sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START
+                                    + PLATFORM_DEFAULT_MEM_SIZE;
+       }
+
+       /* Early hook for platforms */
+
+       platform_init(bp_start);
+
+       /* Initialize MMU. */
+
+       init_mmu();
+}
+
+/*
+ * Initialize system. Setup memory and reserve regions.
+ */
+
+extern char _end;
+extern char _stext;
+extern char _WindowVectors_text_start;
+extern char _WindowVectors_text_end;
+extern char _DebugInterruptVector_literal_start;
+extern char _DebugInterruptVector_text_end;
+extern char _KernelExceptionVector_literal_start;
+extern char _KernelExceptionVector_text_end;
+extern char _UserExceptionVector_literal_start;
+extern char _UserExceptionVector_text_end;
+extern char _DoubleExceptionVector_literal_start;
+extern char _DoubleExceptionVector_text_end;
+
+void __init setup_arch(char **cmdline_p)
+{
+       extern int mem_reserve(unsigned long, unsigned long, int);
+       extern void bootmem_init(void);
+
+       memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
+       saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
+       *cmdline_p = command_line;
+
+       /* Reserve some memory regions */
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (initrd_start < initrd_end) {
+               initrd_is_mapped = mem_reserve(__pa(initrd_start),
+                                              __pa(initrd_end), 0);
+               initrd_below_start_ok = 1;
+       } else {
+               initrd_start = 0;
+       }
+#endif
+
+       mem_reserve(__pa(&_stext),__pa(&_end), 1);
+
+       mem_reserve(__pa(&_WindowVectors_text_start),
+                   __pa(&_WindowVectors_text_end), 0);
+
+       mem_reserve(__pa(&_DebugInterruptVector_literal_start),
+                   __pa(&_DebugInterruptVector_text_end), 0);
+
+       mem_reserve(__pa(&_KernelExceptionVector_literal_start),
+                   __pa(&_KernelExceptionVector_text_end), 0);
+
+       mem_reserve(__pa(&_UserExceptionVector_literal_start),
+                   __pa(&_UserExceptionVector_text_end), 0);
+
+       mem_reserve(__pa(&_DoubleExceptionVector_literal_start),
+                   __pa(&_DoubleExceptionVector_text_end), 0);
+
+       bootmem_init();
+
+       platform_setup(cmdline_p);
+
+
+       paging_init();
+
+#ifdef CONFIG_VT
+# if defined(CONFIG_VGA_CONSOLE)
+       conswitchp = &vga_con;
+# elif defined(CONFIG_DUMMY_CONSOLE)
+       conswitchp = &dummy_con;
+# endif
+#endif
+
+#if CONFIG_PCI
+       platform_pcibios_init();
+#endif
+}
+
+void machine_restart(char * cmd)
+{
+       platform_restart();
+}
+
+void machine_halt(void)
+{
+       platform_halt();
+       while (1);
+}
+
+void machine_power_off(void)
+{
+       platform_power_off();
+       while (1);
+}
+#ifdef CONFIG_PROC_FS
+
+/*
+ * Display some core information through /proc/cpuinfo.
+ */
+
+static int
+c_show(struct seq_file *f, void *slot)
+{
+       /* high-level stuff */
+       seq_printf(f,"processor\t: 0\n"
+                    "vendor_id\t: Tensilica\n"
+                    "model\t\t: Xtensa " XCHAL_HW_RELEASE_NAME "\n"
+                    "core ID\t\t: " XCHAL_CORE_ID "\n"
+                    "build ID\t: 0x%x\n"
+                    "byte order\t: %s\n"
+                    "cpu MHz\t\t: %lu.%02lu\n"
+                    "bogomips\t: %lu.%02lu\n",
+                    XCHAL_BUILD_UNIQUE_ID,
+                    XCHAL_HAVE_BE ?  "big" : "little",
+                    CCOUNT_PER_JIFFY/(1000000/HZ),
+                    (CCOUNT_PER_JIFFY/(10000/HZ)) % 100,
+                    loops_per_jiffy/(500000/HZ),
+                    (loops_per_jiffy/(5000/HZ)) % 100);
+
+       seq_printf(f,"flags\t\t: "
+#if XCHAL_HAVE_NMI
+                    "nmi "
+#endif
+#if XCHAL_HAVE_DEBUG
+                    "debug "
+# if XCHAL_HAVE_OCD
+                    "ocd "
+# endif
+#endif
+#if XCHAL_HAVE_DENSITY
+                    "density "
+#endif
+#if XCHAL_HAVE_BOOLEANS
+                    "boolean "
+#endif
+#if XCHAL_HAVE_LOOPS
+                    "loop "
+#endif
+#if XCHAL_HAVE_NSA
+                    "nsa "
+#endif
+#if XCHAL_HAVE_MINMAX
+                    "minmax "
+#endif
+#if XCHAL_HAVE_SEXT
+                    "sext "
+#endif
+#if XCHAL_HAVE_CLAMPS
+                    "clamps "
+#endif
+#if XCHAL_HAVE_MAC16
+                    "mac16 "
+#endif
+#if XCHAL_HAVE_MUL16
+                    "mul16 "
+#endif
+#if XCHAL_HAVE_MUL32
+                    "mul32 "
+#endif
+#if XCHAL_HAVE_MUL32_HIGH
+                    "mul32h "
+#endif
+#if XCHAL_HAVE_FP
+                    "fpu "
+#endif
+                    "\n");
+
+       /* Registers. */
+       seq_printf(f,"physical aregs\t: %d\n"
+                    "misc regs\t: %d\n"
+                    "ibreak\t\t: %d\n"
+                    "dbreak\t\t: %d\n",
+                    XCHAL_NUM_AREGS,
+                    XCHAL_NUM_MISC_REGS,
+                    XCHAL_NUM_IBREAK,
+                    XCHAL_NUM_DBREAK);
+
+
+       /* Interrupt. */
+       seq_printf(f,"num ints\t: %d\n"
+                    "ext ints\t: %d\n"
+                    "int levels\t: %d\n"
+                    "timers\t\t: %d\n"
+                    "debug level\t: %d\n",
+                    XCHAL_NUM_INTERRUPTS,
+                    XCHAL_NUM_EXTINTERRUPTS,
+                    XCHAL_NUM_INTLEVELS,
+                    XCHAL_NUM_TIMERS,
+                    XCHAL_DEBUGLEVEL);
+
+       /* Coprocessors */
+#if XCHAL_HAVE_CP
+       seq_printf(f, "coprocessors\t: %d\n", XCHAL_CP_NUM);
+#else
+       seq_printf(f, "coprocessors\t: none\n");
+#endif
+
+       /* {I,D}{RAM,ROM} and XLMI */
+       seq_printf(f,"inst ROMs\t: %d\n"
+                    "inst RAMs\t: %d\n"
+                    "data ROMs\t: %d\n"
+                    "data RAMs\t: %d\n"
+                    "XLMI ports\t: %d\n",
+                    XCHAL_NUM_IROM,
+                    XCHAL_NUM_IRAM,
+                    XCHAL_NUM_DROM,
+                    XCHAL_NUM_DRAM,
+                    XCHAL_NUM_XLMI);
+
+       /* Cache */
+       seq_printf(f,"icache line size: %d\n"
+                    "icache ways\t: %d\n"
+                    "icache size\t: %d\n"
+                    "icache flags\t: "
+#if XCHAL_ICACHE_LINE_LOCKABLE
+                    "lock"
+#endif
+                    "\n"
+                    "dcache line size: %d\n"
+                    "dcache ways\t: %d\n"
+                    "dcache size\t: %d\n"
+                    "dcache flags\t: "
+#if XCHAL_DCACHE_IS_WRITEBACK
+                    "writeback"
+#endif
+#if XCHAL_DCACHE_LINE_LOCKABLE
+                    "lock"
+#endif
+                    "\n",
+                    XCHAL_ICACHE_LINESIZE,
+                    XCHAL_ICACHE_WAYS,
+                    XCHAL_ICACHE_SIZE,
+                    XCHAL_DCACHE_LINESIZE,
+                    XCHAL_DCACHE_WAYS,
+                    XCHAL_DCACHE_SIZE);
+
+       /* MMU */
+       seq_printf(f,"ASID bits\t: %d\n"
+                    "ASID invalid\t: %d\n"
+                    "ASID kernel\t: %d\n"
+                    "rings\t\t: %d\n"
+                    "itlb ways\t: %d\n"
+                    "itlb AR ways\t: %d\n"
+                    "dtlb ways\t: %d\n"
+                    "dtlb AR ways\t: %d\n",
+                    XCHAL_MMU_ASID_BITS,
+                    XCHAL_MMU_ASID_INVALID,
+                    XCHAL_MMU_ASID_KERNEL,
+                    XCHAL_MMU_RINGS,
+                    XCHAL_ITLB_WAYS,
+                    XCHAL_ITLB_ARF_WAYS,
+                    XCHAL_DTLB_WAYS,
+                    XCHAL_DTLB_ARF_WAYS);
+
+       return 0;
+}
+
+/*
+ * We show only CPU #0 info.
+ */
+static void *
+c_start(struct seq_file *f, loff_t *pos)
+{
+       return (void *) ((*pos == 0) ? (void *)1 : NULL);
+}
+
+static void *
+c_next(struct seq_file *f, void *v, loff_t *pos)
+{
+       return NULL;
+}
+
+static void
+c_stop(struct seq_file *f, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op =
+{
+       start:  c_start,
+       next:   c_next,
+       stop:   c_stop,
+       show:   c_show
+};
+
+#endif /* CONFIG_PROC_FS */
+
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
new file mode 100644 (file)
index 0000000..df6e1e1
--- /dev/null
@@ -0,0 +1,713 @@
+// TODO coprocessor stuff
+/*
+ *  linux/arch/xtensa/kernel/signal.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
+ *
+ *  Joe Taylor <joe@tensilica.com>
+ *  Chris Zankel <chris@zankel.net>
+ *
+ *
+ *
+ */
+
+#include <xtensa/config/core.h>
+#include <xtensa/hal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/personality.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+
+#define DEBUG_SIG  0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options,
+                         struct rusage * ru);
+asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
+
+extern struct task_struct *coproc_owners[];
+
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+
+int sys_sigsuspend(struct pt_regs *regs)
+{
+       old_sigset_t mask = (old_sigset_t) regs->areg[3];
+       sigset_t saveset;
+
+       mask &= _BLOCKABLE;
+       spin_lock_irq(&current->sighand->siglock);
+       saveset = current->blocked;
+       siginitset(&current->blocked, mask);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       regs->areg[2] = -EINTR;
+       while (1) {
+               current->state = TASK_INTERRUPTIBLE;
+               schedule();
+               if (do_signal(regs, &saveset))
+                       return -EINTR;
+       }
+}
+
+asmlinkage int
+sys_rt_sigsuspend(struct pt_regs *regs)
+{
+       sigset_t *unewset = (sigset_t *) regs->areg[4];
+       size_t sigsetsize = (size_t) regs->areg[3];
+       sigset_t saveset, newset;
+       /* XXX: Don't preclude handling different sized sigset_t's.  */
+       if (sigsetsize != sizeof(sigset_t))
+               return -EINVAL;
+
+       if (copy_from_user(&newset, unewset, sizeof(newset)))
+               return -EFAULT;
+       sigdelsetmask(&newset, ~_BLOCKABLE);
+       spin_lock_irq(&current->sighand->siglock);
+       saveset = current->blocked;
+       current->blocked = newset;
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       regs->areg[2] = -EINTR;
+       while (1) {
+               current->state = TASK_INTERRUPTIBLE;
+               schedule();
+               if (do_signal(regs, &saveset))
+                       return -EINTR;
+       }
+}
+
+asmlinkage int
+sys_sigaction(int sig, const struct old_sigaction *act,
+             struct old_sigaction *oact)
+{
+       struct k_sigaction new_ka, old_ka;
+       int ret;
+
+       if (act) {
+               old_sigset_t mask;
+               if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+                   __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+                   __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+                       return -EFAULT;
+               __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+               __get_user(mask, &act->sa_mask);
+               siginitset(&new_ka.sa.sa_mask, mask);
+       }
+
+       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+       if (!ret && oact) {
+               if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+                   __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+                   __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+                       return -EFAULT;
+               __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+               __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+       }
+
+       return ret;
+}
+
+asmlinkage int
+sys_sigaltstack(struct pt_regs *regs)
+{
+       const stack_t *uss = (stack_t *) regs->areg[4];
+       stack_t *uoss = (stack_t *) regs->areg[3];
+
+       if (regs->depc > 64)
+               panic ("Double exception sys_sigreturn\n");
+
+
+       return do_sigaltstack(uss, uoss, regs->areg[1]);
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+struct sigframe
+{
+       struct sigcontext sc;
+       struct _cpstate cpstate;
+       unsigned long extramask[_NSIG_WORDS-1];
+       unsigned char retcode[6];
+       unsigned int reserved[4]; /* Reserved area for chaining */
+       unsigned int window[4]; /* Window of 4 registers for initial context */
+};
+
+struct rt_sigframe
+{
+       struct siginfo info;
+       struct ucontext uc;
+       struct _cpstate cpstate;
+       unsigned char retcode[6];
+       unsigned int reserved[4]; /* Reserved area for chaining */
+       unsigned int window[4]; /* Window of 4 registers for initial context */
+};
+
+extern void release_all_cp (struct task_struct *);
+
+
+// FIXME restore_cpextra
+static inline int
+restore_cpextra (struct _cpstate *buf)
+{
+#if 0
+       /* The signal handler may have used coprocessors in which
+        * case they are still enabled.  We disable them to force a
+        * reloading of the original task's CP state by the lazy
+        * context-switching mechanisms of CP exception handling.
+        * Also, we essentially discard any coprocessor state that the
+        * signal handler created. */
+
+       struct task_struct *tsk = current;
+       release_all_cp(tsk);
+       return __copy_from_user(tsk->thread.cpextra, buf, TOTAL_CPEXTRA_SIZE);
+#endif
+       return 0;
+}
+
+/* Note: We don't copy double exception 'tregs', we have to finish double exc. first before we return to signal handler! This dbl.exc.handler might cause another double exception, but I think we are fine as the situation is the same as if we had returned to the signal handerl and got an interrupt immediately...
+ */
+
+
+static int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
+{
+       struct thread_struct *thread;
+       unsigned int err = 0;
+       unsigned long ps;
+       struct _cpstate *buf;
+
+#define COPY(x)        err |= __get_user(regs->x, &sc->sc_##x)
+       COPY(pc);
+       COPY(depc);
+       COPY(wmask);
+       COPY(lbeg);
+       COPY(lend);
+       COPY(lcount);
+       COPY(sar);
+       COPY(windowbase);
+       COPY(windowstart);
+#undef COPY
+
+       /* For PS, restore only PS.CALLINC.
+        * Assume that all other bits are either the same as for the signal
+        * handler, or the user mode value doesn't matter (e.g. PS.OWB).
+        */
+       err |= __get_user(ps, &sc->sc_ps);
+       regs->ps = (regs->ps & ~XCHAL_PS_CALLINC_MASK)
+               | (ps & XCHAL_PS_CALLINC_MASK);
+
+       /* Additional corruption checks */
+
+       if ((regs->windowbase >= (XCHAL_NUM_AREGS/4))
+       || ((regs->windowstart & ~((1<<(XCHAL_NUM_AREGS/4)) - 1)) != 0) )
+               err = 1;
+       if ((regs->lcount > 0)
+       && ((regs->lbeg > TASK_SIZE) || (regs->lend > TASK_SIZE)) )
+               err = 1;
+
+       /* Restore extended register state.
+        * See struct thread_struct in processor.h.
+        */
+       thread = &current->thread;
+
+       err |= __copy_from_user (regs->areg, sc->sc_areg, XCHAL_NUM_AREGS*4);
+       err |= __get_user(buf, &sc->sc_cpstate);
+       if (buf) {
+               if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+                       goto badframe;
+               err |= restore_cpextra(buf);
+       }
+
+       regs->syscall = -1;             /* disable syscall checks */
+       return err;
+
+badframe:
+       return 1;
+}
+
+static inline void
+flush_my_cpstate(struct task_struct *tsk)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+
+#if 0  // FIXME
+       for (i = 0; i < XCHAL_CP_NUM; i++) {
+               if (tsk == coproc_owners[i]) {
+                       xthal_validate_cp(i);
+                       xthal_save_cpregs(tsk->thread.cpregs_ptr[i], i);
+
+                       /* Invalidate and "disown" the cp to allow
+                        * callers the chance to reset cp state in the
+                        * task_struct. */
+
+                       xthal_invalidate_cp(i);
+                       coproc_owners[i] = 0;
+               }
+       }
+#endif
+       local_irq_restore(flags);
+}
+
+/* Return codes:
+       0:  nothing saved
+       1:  stuff to save, successful
+       -1:  stuff to save, error happened
+*/
+static int
+save_cpextra (struct _cpstate *buf)
+{
+#if (XCHAL_EXTRA_SA_SIZE == 0) && (XCHAL_CP_NUM == 0)
+       return 0;
+#else
+
+       /* FIXME: If a task has never used a coprocessor, there is
+        * no need to save and restore anything.  Tracking this
+        * information would allow us to optimize this section.
+        * Perhaps we can use current->used_math or (current->flags &
+        * PF_USEDFPU) or define a new field in the thread
+        * structure. */
+
+       /* We flush any live, task-owned cp state to the task_struct,
+        * then copy it all to the sigframe.  Then we clear all
+        * cp/extra state in the task_struct, effectively
+        * clearing/resetting all cp/extra state for the signal
+        * handler (cp-exception handling will load these new values
+        * into the cp/extra registers.)  This step is important for
+        * things like a floating-point cp, where the OS must reset
+        * the FCR to the default rounding mode. */
+
+       int err = 0;
+       struct task_struct *tsk = current;
+
+       flush_my_cpstate(tsk);
+       /* Note that we just copy everything: 'extra' and 'cp' state together.*/
+       err |= __copy_to_user(buf, tsk->thread.cp_save, XTENSA_CP_EXTRA_SIZE);
+       memset(tsk->thread.cp_save, 0, XTENSA_CP_EXTRA_SIZE);
+
+#if (XTENSA_CP_EXTRA_SIZE == 0)
+#error Sanity check on memset above, cpextra_size should not be zero.
+#endif
+
+       return err ? -1 : 1;
+#endif
+}
+
+static int
+setup_sigcontext(struct sigcontext *sc, struct _cpstate *cpstate,
+                struct pt_regs *regs, unsigned long mask)
+{
+       struct thread_struct *thread;
+       int err = 0;
+
+//printk("setup_sigcontext\n");
+#define COPY(x)        err |= __put_user(regs->x, &sc->sc_##x)
+       COPY(pc);
+       COPY(ps);
+       COPY(depc);
+       COPY(wmask);
+       COPY(lbeg);
+       COPY(lend);
+       COPY(lcount);
+       COPY(sar);
+       COPY(windowbase);
+       COPY(windowstart);
+#undef COPY
+
+       /* Save extended register state.
+        * See struct thread_struct in processor.h.
+        */
+       thread = &current->thread;
+       err |= __copy_to_user (sc->sc_areg, regs->areg, XCHAL_NUM_AREGS * 4);
+       err |= save_cpextra(cpstate);
+       err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate);
+       /* non-iBCS2 extensions.. */
+       err |= __put_user(mask, &sc->oldmask);
+
+       return err;
+}
+
+asmlinkage int sys_sigreturn(struct pt_regs *regs)
+{
+       struct sigframe *frame = (struct sigframe *)regs->areg[1];
+       sigset_t set;
+       if (regs->depc > 64)
+               panic ("Double exception sys_sigreturn\n");
+
+       if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+               goto badframe;
+
+       if (__get_user(set.sig[0], &frame->sc.oldmask)
+           || (_NSIG_WORDS > 1
+               && __copy_from_user(&set.sig[1], &frame->extramask,
+                                   sizeof(frame->extramask))))
+               goto badframe;
+
+       sigdelsetmask(&set, ~_BLOCKABLE);
+
+       spin_lock_irq(&current->sighand->siglock);
+       current->blocked = set;
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       if (restore_sigcontext(regs, &frame->sc))
+               goto badframe;
+       return regs->areg[2];
+
+badframe:
+       force_sig(SIGSEGV, current);
+       return 0;
+}
+
+asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+{
+       struct rt_sigframe *frame = (struct rt_sigframe *)regs->areg[1];
+       sigset_t set;
+       stack_t st;
+       int ret;
+       if (regs->depc > 64)
+       {
+               printk("!!!!!!! DEPC !!!!!!!\n");
+               return 0;
+       }
+
+       if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+               goto badframe;
+
+       if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+               goto badframe;
+
+       sigdelsetmask(&set, ~_BLOCKABLE);
+       spin_lock_irq(&current->sighand->siglock);
+       current->blocked = set;
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
+               goto badframe;
+       ret = regs->areg[2];
+
+       if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+               goto badframe;
+       /* It is more difficult to avoid calling this function than to
+          call it and ignore errors.  */
+       do_sigaltstack(&st, NULL, regs->areg[1]);
+
+       return ret;
+
+badframe:
+       force_sig(SIGSEGV, current);
+       return 0;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+/*
+ * Determine which stack to use..
+ */
+static inline void *
+get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
+{
+       if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
+               sp = current->sas_ss_sp + current->sas_ss_size;
+
+       return (void *)((sp - frame_size) & -16ul);
+}
+
+#define USE_SIGRETURN          0
+#define USE_RT_SIGRETURN       1
+
+static int
+gen_return_code(unsigned char *codemem, unsigned int use_rt_sigreturn)
+{
+       unsigned int retcall;
+       int err = 0;
+
+#if 0
+       /* Ignoring SA_RESTORER for now; it's supposed to be obsolete,
+        * and the xtensa glibc doesn't use it.
+        */
+       if (ka->sa.sa_flags & SA_RESTORER) {
+               regs->pr = (unsigned long) ka->sa.sa_restorer;
+       } else
+#endif /* 0 */
+       {
+
+#if (__NR_sigreturn > 255) || (__NR_rt_sigreturn > 255)
+
+/* The 12-bit immediate is really split up within the 24-bit MOVI
+ * instruction.  As long as the above system call numbers fit within
+ * 8-bits, the following code works fine. See the Xtensa ISA for
+ * details.
+ */
+
+#error Generating the MOVI instruction below breaks!
+#endif
+
+               retcall = use_rt_sigreturn ? __NR_rt_sigreturn : __NR_sigreturn;
+
+#ifdef __XTENSA_EB__   /* Big Endian version */
+               /* Generate instruction:  MOVI a2, retcall */
+               err |= __put_user(0x22, &codemem[0]);
+               err |= __put_user(0x0a, &codemem[1]);
+               err |= __put_user(retcall, &codemem[2]);
+               /* Generate instruction:  SYSCALL */
+               err |= __put_user(0x00, &codemem[3]);
+               err |= __put_user(0x05, &codemem[4]);
+               err |= __put_user(0x00, &codemem[5]);
+
+#elif defined __XTENSA_EL__   /* Little Endian version */
+               /* Generate instruction:  MOVI a2, retcall */
+               err |= __put_user(0x22, &codemem[0]);
+               err |= __put_user(0xa0, &codemem[1]);
+               err |= __put_user(retcall, &codemem[2]);
+               /* Generate instruction:  SYSCALL */
+               err |= __put_user(0x00, &codemem[3]);
+               err |= __put_user(0x50, &codemem[4]);
+               err |= __put_user(0x00, &codemem[5]);
+#else
+#error Must use compiler for Xtensa processors.
+#endif
+       }
+
+       /* Flush generated code out of the data cache */
+
+       if (err == 0)
+               __flush_invalidate_cache_range((unsigned long)codemem, 6UL);
+
+       return err;
+}
+
+static void
+set_thread_state(struct pt_regs *regs, void *stack, unsigned char *retaddr,
+       void *handler, unsigned long arg1, void *arg2, void *arg3)
+{
+       /* Set up registers for signal handler */
+       start_thread(regs, (unsigned long) handler, (unsigned long) stack);
+
+       /* Set up a stack frame for a call4
+        * Note: PS.CALLINC is set to one by start_thread
+        */
+       regs->areg[4] = (((unsigned long) retaddr) & 0x3fffffff) | 0x40000000;
+       regs->areg[6] = arg1;
+       regs->areg[7] = (unsigned long) arg2;
+       regs->areg[8] = (unsigned long) arg3;
+}
+
+static void setup_frame(int sig, struct k_sigaction *ka,
+                       sigset_t *set, struct pt_regs *regs)
+{
+       struct sigframe *frame;
+       int err = 0;
+       int signal;
+
+       frame = get_sigframe(ka, regs->areg[1], sizeof(*frame));
+       if (regs->depc > 64)
+       {
+               printk("!!!!!!! DEPC !!!!!!!\n");
+               return;
+       }
+
+
+       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+               goto give_sigsegv;
+
+       signal = current_thread_info()->exec_domain
+               && current_thread_info()->exec_domain->signal_invmap
+               && sig < 32
+               ? current_thread_info()->exec_domain->signal_invmap[sig]
+               : sig;
+
+       err |= setup_sigcontext(&frame->sc, &frame->cpstate, regs, set->sig[0]);
+
+       if (_NSIG_WORDS > 1) {
+               err |= __copy_to_user(frame->extramask, &set->sig[1],
+                                     sizeof(frame->extramask));
+       }
+
+       /* Create sys_sigreturn syscall in stack frame */
+       err |= gen_return_code(frame->retcode, USE_SIGRETURN);
+
+       if (err)
+               goto give_sigsegv;
+
+       /* Create signal handler execution context.
+        * Return context not modified until this point.
+        */
+       set_thread_state(regs, frame, frame->retcode,
+               ka->sa.sa_handler, signal, &frame->sc, NULL);
+
+       /* Set access mode to USER_DS.  Nomenclature is outdated, but
+        * functionality is used in uaccess.h
+        */
+       set_fs(USER_DS);
+
+
+#if DEBUG_SIG
+       printk("SIG deliver (%s:%d): signal=%d sp=%p pc=%08x\n",
+               current->comm, current->pid, signal, frame, regs->pc);
+#endif
+
+       return;
+
+give_sigsegv:
+       if (sig == SIGSEGV)
+               ka->sa.sa_handler = SIG_DFL;
+       force_sig(SIGSEGV, current);
+}
+
+static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+                          sigset_t *set, struct pt_regs *regs)
+{
+       struct rt_sigframe *frame;
+       int err = 0;
+       int signal;
+
+       frame = get_sigframe(ka, regs->areg[1], sizeof(*frame));
+       if (regs->depc > 64)
+               panic ("Double exception sys_sigreturn\n");
+
+       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+               goto give_sigsegv;
+
+       signal = current_thread_info()->exec_domain
+               && current_thread_info()->exec_domain->signal_invmap
+               && sig < 32
+               ? current_thread_info()->exec_domain->signal_invmap[sig]
+               : sig;
+
+       err |= copy_siginfo_to_user(&frame->info, info);
+
+       /* Create the ucontext.  */
+       err |= __put_user(0, &frame->uc.uc_flags);
+       err |= __put_user(0, &frame->uc.uc_link);
+       err |= __put_user((void *)current->sas_ss_sp,
+                         &frame->uc.uc_stack.ss_sp);
+       err |= __put_user(sas_ss_flags(regs->areg[1]),
+                         &frame->uc.uc_stack.ss_flags);
+       err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+       err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->cpstate,
+                               regs, set->sig[0]);
+       err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+       /* Create sys_rt_sigreturn syscall in stack frame */
+       err |= gen_return_code(frame->retcode, USE_RT_SIGRETURN);
+
+       if (err)
+               goto give_sigsegv;
+
+       /* Create signal handler execution context.
+        * Return context not modified until this point.
+        */
+       set_thread_state(regs, frame, frame->retcode,
+               ka->sa.sa_handler, signal, &frame->info, &frame->uc);
+
+       /* Set access mode to USER_DS.  Nomenclature is outdated, but
+        * functionality is used in uaccess.h
+        */
+       set_fs(USER_DS);
+
+#if DEBUG_SIG
+       printk("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08x\n",
+               current->comm, current->pid, signal, frame, regs->pc);
+#endif
+
+       return;
+
+give_sigsegv:
+       if (sig == SIGSEGV)
+               ka->sa.sa_handler = SIG_DFL;
+       force_sig(SIGSEGV, current);
+}
+
+
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals that
+ * the kernel can handle, and then we build all the user-level signal handling
+ * stack-frames in one go after that.
+ */
+int do_signal(struct pt_regs *regs, sigset_t *oldset)
+{
+       siginfo_t info;
+       int signr;
+       struct k_sigaction ka;
+
+       if (!oldset)
+               oldset = &current->blocked;
+
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+
+       /* Are we from a system call? */
+       if (regs->syscall >= 0) {
+               /* If so, check system call restarting.. */
+               switch (regs->areg[2]) {
+                       case ERESTARTNOHAND:
+                       case ERESTART_RESTARTBLOCK:
+                               regs->areg[2] = -EINTR;
+                               break;
+
+                       case ERESTARTSYS:
+                               if (!(ka.sa.sa_flags & SA_RESTART)) {
+                                       regs->areg[2] = -EINTR;
+                                       break;
+                               }
+                       /* fallthrough */
+                       case ERESTARTNOINTR:
+                               regs->areg[2] = regs->syscall;
+                               regs->pc -= 3;
+               }
+       }
+
+       if (signr == 0)
+               return 0;               /* no signals delivered */
+
+       /* Whee!  Actually deliver the signal.  */
+
+       /* Set up the stack frame */
+       if (ka.sa.sa_flags & SA_SIGINFO)
+               setup_rt_frame(signr, &ka, &info, oldset, regs);
+       else
+               setup_frame(signr, &ka, oldset, regs);
+
+       if (ka.sa.sa_flags & SA_ONESHOT)
+               ka.sa.sa_handler = SIG_DFL;
+
+       if (!(ka.sa.sa_flags & SA_NODEFER)) {
+               spin_lock_irq(&current->sighand->siglock);
+               sigorsets(&current->blocked, &current->blocked, &ka.sa.sa_mask);
+               sigaddset(&current->blocked, signr);
+               recalc_sigpending();
+               spin_unlock_irq(&current->sighand->siglock);
+       }
+       return 1;
+}
diff --git a/arch/xtensa/kernel/syscalls.c b/arch/xtensa/kernel/syscalls.c
new file mode 100644 (file)
index 0000000..abc8ed6
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ * arch/xtensa/kernel/syscall.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ * Copyright (C) 1995 - 2000 by Ralf Baechle
+ *
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Chris Zankel <chris@zankel.net>
+ * Kevin Chea
+ *
+ */
+
+#define DEBUG  0
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/mman.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/utsname.h>
+#include <linux/unistd.h>
+#include <linux/stringify.h>
+#include <linux/syscalls.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/errno.h>
+#include <asm/ptrace.h>
+#include <asm/signal.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+#include <asm/mman.h>
+#include <asm/shmparam.h>
+#include <asm/page.h>
+#include <asm/ipc.h>
+
+extern void do_syscall_trace(void);
+typedef int (*syscall_t)(void *a0,...);
+extern int (*do_syscalls)(struct pt_regs *regs, syscall_t fun,
+                                    int narg);
+extern syscall_t sys_call_table[];
+extern unsigned char sys_narg_table[];
+
+/*
+ * sys_pipe() is the normal C calling standard for creating a pipe. It's not
+ * the way unix traditional does this, though.
+ */
+
+int sys_pipe(int __user *userfds)
+{
+       int fd[2];
+       int error;
+
+       error = do_pipe(fd);
+       if (!error) {
+               if (copy_to_user(userfds, fd, 2 * sizeof(int)))
+                       error = -EFAULT;
+       }
+       return error;
+}
+
+/*
+ * Common code for old and new mmaps.
+ */
+
+static inline long do_mmap2(unsigned long addr, unsigned long len,
+                           unsigned long prot, unsigned long flags,
+                           unsigned long fd, unsigned long pgoff)
+{
+       int error = -EBADF;
+       struct file * file = NULL;
+
+       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+       if (!(flags & MAP_ANONYMOUS)) {
+               file = fget(fd);
+               if (!file)
+                       goto out;
+       }
+
+       down_write(&current->mm->mmap_sem);
+       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+       up_write(&current->mm->mmap_sem);
+
+       if (file)
+               fput(file);
+out:
+       return error;
+}
+
+unsigned long old_mmap(unsigned long addr, size_t len, int prot,
+                      int flags, int fd, off_t offset)
+{
+       return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+}
+
+long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
+              unsigned long flags, unsigned long fd, unsigned long pgoff)
+{
+       return do_mmap2(addr, len, prot, flags, fd, pgoff);
+}
+
+int sys_fork(struct pt_regs *regs)
+{
+       return do_fork(SIGCHLD, regs->areg[1], regs, 0, NULL, NULL);
+}
+
+int sys_vfork(struct pt_regs *regs)
+{
+       return do_fork(CLONE_VFORK|CLONE_VM|SIGCHLD, regs->areg[1],
+                      regs, 0, NULL, NULL);
+}
+
+int sys_clone(struct pt_regs *regs)
+{
+       unsigned long clone_flags;
+       unsigned long newsp;
+       int __user *parent_tidptr, *child_tidptr;
+       clone_flags = regs->areg[4];
+       newsp = regs->areg[3];
+       parent_tidptr = (int __user *)regs->areg[5];
+       child_tidptr = (int __user *)regs->areg[6];
+       if (!newsp)
+               newsp = regs->areg[1];
+       return do_fork(clone_flags,newsp,regs,0,parent_tidptr,child_tidptr);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+
+int sys_execve(struct pt_regs *regs)
+{
+       int error;
+       char * filename;
+
+       filename = getname((char *) (long)regs->areg[5]);
+       error = PTR_ERR(filename);
+       if (IS_ERR(filename))
+               goto out;
+       error = do_execve(filename, (char **) (long)regs->areg[3],
+                         (char **) (long)regs->areg[4], regs);
+       putname(filename);
+
+out:
+       return error;
+}
+
+int sys_uname(struct old_utsname * name)
+{
+       if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
+               return 0;
+       return -EFAULT;
+}
+
+int sys_olduname(struct oldold_utsname * name)
+{
+       int error;
+
+       if (!name)
+               return -EFAULT;
+       if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+               return -EFAULT;
+
+       error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+       error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
+       error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+       error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
+       error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+       error -= __put_user(0,name->release+__OLD_UTS_LEN);
+       error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+       error -= __put_user(0,name->version+__OLD_UTS_LEN);
+       error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+       error -= __put_user(0,name->machine+__OLD_UTS_LEN);
+
+       return error ? -EFAULT : 0;
+}
+
+
+/*
+ * Build the string table for the builtin "poor man's strace".
+ */
+
+#if DEBUG
+#define SYSCALL(fun, narg) #fun,
+static char *sfnames[] = {
+#include "syscalls.h"
+};
+#undef SYS
+#endif
+
+void system_call (struct pt_regs *regs)
+{
+       syscall_t syscall;
+       unsigned long parm0, parm1, parm2, parm3, parm4, parm5;
+       int nargs, res;
+       unsigned int syscallnr;
+       int ps;
+
+#if DEBUG
+       int i;
+       unsigned long parms[6];
+       char *sysname;
+#endif
+
+       regs->syscall = regs->areg[2];
+
+       do_syscall_trace();
+
+       /* Have to load after syscall_trace because strace
+        * sometimes changes regs->syscall.
+        */
+       syscallnr = regs->syscall;
+
+       parm0 = parm1 = parm2 = parm3 = parm4 = parm5 = 0;
+
+       /* Restore interrupt level to syscall invoker's.
+        * If this were in assembly, we wouldn't disable
+        * interrupts in the first place:
+        */
+       local_save_flags (ps);
+       local_irq_restore((ps & ~XCHAL_PS_INTLEVEL_MASK) |
+                         (regs->ps & XCHAL_PS_INTLEVEL_MASK) );
+
+       if (syscallnr > __NR_Linux_syscalls) {
+               regs->areg[2] = -ENOSYS;
+               return;
+       }
+
+       syscall = sys_call_table[syscallnr];
+       nargs = sys_narg_table[syscallnr];
+
+       if (syscall == NULL) {
+               regs->areg[2] = -ENOSYS;
+               return;
+       }
+
+       /* There shouldn't be more than six arguments in the table! */
+
+       if (nargs > 6)
+               panic("Internal error - too many syscall arguments (%d)!\n",
+                     nargs);
+
+       /* Linux takes system-call arguments in registers.  The ABI
+         * and Xtensa software conventions require the system-call
+         * number in a2.  If an argument exists in a2, we move it to
+         * the next available register.  Note that for improved
+         * efficiency, we do NOT shift all parameters down one
+         * register to maintain the original order.
+        *
+         * At best case (zero arguments), we just write the syscall
+         * number to a2.  At worst case (1 to 6 arguments), we move
+         * the argument in a2 to the next available register, then
+         * write the syscall number to a2.
+        *
+         * For clarity, the following truth table enumerates all
+         * possibilities.
+        *
+         * arguments   syscall number  arg0, arg1, arg2, arg3, arg4, arg5
+         * ---------   --------------  ----------------------------------
+        *      0             a2
+        *      1             a2        a3
+        *      2             a2        a4,   a3
+        *      3             a2        a5,   a3,   a4
+        *      4             a2        a6,   a3,   a4,   a5
+        *      5             a2        a7,   a3,   a4,   a5,   a6
+        *      6             a2        a8,   a3,   a4,   a5,   a6,   a7
+        */
+       if (nargs) {
+               parm0 = regs->areg[nargs+2];
+               parm1 = regs->areg[3];
+               parm2 = regs->areg[4];
+               parm3 = regs->areg[5];
+               parm4 = regs->areg[6];
+               parm5 = regs->areg[7];
+       } else /* nargs == 0 */
+               parm0 = (unsigned long) regs;
+
+#if DEBUG
+       parms[0] = parm0;
+       parms[1] = parm1;
+       parms[2] = parm2;
+       parms[3] = parm3;
+       parms[4] = parm4;
+       parms[5] = parm5;
+
+       sysname = sfnames[syscallnr];
+       if (strncmp(sysname, "sys_", 4) == 0)
+               sysname = sysname + 4;
+
+       printk("\017SYSCALL:I:%x:%d:%s  %s(", regs->pc, current->pid,
+              current->comm, sysname);
+       for (i = 0; i < nargs; i++)
+               printk((i>0) ? ", %#lx" : "%#lx", parms[i]);
+       printk(")\n");
+#endif
+
+       res = syscall((void *)parm0, parm1, parm2, parm3, parm4, parm5);
+
+#if DEBUG
+       printk("\017SYSCALL:O:%d:%s  %s(",current->pid, current->comm, sysname);
+       for (i = 0; i < nargs; i++)
+               printk((i>0) ? ", %#lx" : "%#lx", parms[i]);
+       if (res < 4096)
+               printk(") = %d\n", res);
+       else
+               printk(") = %#x\n", res);
+#endif /* DEBUG */
+
+       regs->areg[2] = res;
+       do_syscall_trace();
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+
+int sys_ipc (uint call, int first, int second,
+                       int third, void __user *ptr, long fifth)
+{
+       int version, ret;
+
+       version = call >> 16; /* hack for backward compatibility */
+       call &= 0xffff;
+       ret = -ENOSYS;
+
+       switch (call) {
+       case SEMOP:
+               ret = sys_semtimedop (first, (struct sembuf __user *)ptr,
+                                    second, NULL);
+               break;
+
+       case SEMTIMEDOP:
+               ret = sys_semtimedop (first, (struct sembuf __user *)ptr,
+                                     second, (const struct timespec *) fifth);
+               break;
+
+       case SEMGET:
+               ret = sys_semget (first, second, third);
+               break;
+
+       case SEMCTL: {
+               union semun fourth;
+
+               if (ptr && !get_user(fourth.__pad, (void *__user *) ptr))
+                       ret = sys_semctl (first, second, third, fourth);
+               break;
+               }
+
+       case MSGSND:
+               ret = sys_msgsnd (first, (struct msgbuf __user*) ptr,
+                                 second, third);
+               break;
+
+       case MSGRCV:
+               switch (version) {
+               case 0: {
+                       struct ipc_kludge tmp;
+
+                       if (ptr && !copy_from_user(&tmp,
+                                          (struct ipc_kludge *) ptr,
+                                          sizeof (tmp)))
+                               ret = sys_msgrcv (first, tmp.msgp, second,
+                                                 tmp.msgtyp, third);
+                       break;
+                       }
+
+               default:
+                       ret = sys_msgrcv (first, (struct msgbuf __user *) ptr,
+                                         second, 0, third);
+                       break;
+               }
+               break;
+
+       case MSGGET:
+               ret = sys_msgget ((key_t) first, second);
+               break;
+
+       case MSGCTL:
+               ret = sys_msgctl (first, second, (struct msqid_ds __user*) ptr);
+               break;
+
+       case SHMAT: {
+               ulong raddr;
+               ret = do_shmat (first, (char __user *) ptr, second, &raddr);
+
+               if (!ret)
+                       ret = put_user (raddr, (ulong __user *) third);
+
+               break;
+               }
+
+       case SHMDT:
+               ret = sys_shmdt ((char __user *)ptr);
+               break;
+
+       case SHMGET:
+               ret = sys_shmget (first, second, third);
+               break;
+
+       case SHMCTL:
+               ret = sys_shmctl (first, second, (struct shmid_ds __user*) ptr);
+               break;
+       }
+       return ret;
+}
+
diff --git a/arch/xtensa/kernel/syscalls.h b/arch/xtensa/kernel/syscalls.h
new file mode 100644 (file)
index 0000000..5b3f75f
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * arch/xtensa/kernel/syscalls.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Changes by Joe Taylor <joe@tensilica.com>
+ */
+
+/*
+ * This file is being included twice - once to build a list of all
+ * syscalls and once to build a table of how many arguments each syscall
+ * accepts.  Syscalls that receive a pointer to the saved registers are
+ * marked as having zero arguments.
+ *
+ * The binary compatibility calls are in a separate list.
+ *
+ * Entry '0' used to be system_call.  It's removed to disable indirect
+ * system calls for now so user tasks can't recurse.  See mips'
+ * sys_syscall for a comparable example.
+ */
+
+SYSCALL(0, 0)                          /* 00 */
+
+SYSCALL(sys_exit, 1)
+SYSCALL(sys_fork, 0)
+SYSCALL(sys_read, 3)
+SYSCALL(sys_write, 3)
+SYSCALL(sys_open, 3)                   /* 05 */
+SYSCALL(sys_close, 1)
+SYSCALL(sys_waitpid, 3)
+SYSCALL(sys_creat, 2)
+SYSCALL(sys_link, 2)
+SYSCALL(sys_unlink, 1)                 /* 10 */
+SYSCALL(sys_execve, 0)
+SYSCALL(sys_chdir, 1)
+SYSCALL(sys_time, 1)
+SYSCALL(sys_mknod, 3)
+SYSCALL(sys_chmod, 2)                  /* 15 */
+SYSCALL(sys_lchown, 3)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_stat, 2)
+SYSCALL(sys_lseek, 3)
+SYSCALL(sys_getpid, 0)                 /* 20 */
+SYSCALL(sys_mount, 5)
+SYSCALL(sys_oldumount, 1)
+SYSCALL(sys_setuid, 1)
+SYSCALL(sys_getuid, 0)
+SYSCALL(sys_stime, 1)                  /* 25 */
+SYSCALL(sys_ptrace, 4)
+SYSCALL(sys_alarm, 1)
+SYSCALL(sys_fstat, 2)
+SYSCALL(sys_pause, 0)
+SYSCALL(sys_utime, 2)                  /* 30 */
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_access, 2)
+SYSCALL(sys_nice, 1)
+SYSCALL(sys_ni_syscall, 0)             /* 35 */
+SYSCALL(sys_sync, 0)
+SYSCALL(sys_kill, 2)
+SYSCALL(sys_rename, 2)
+SYSCALL(sys_mkdir, 2)
+SYSCALL(sys_rmdir, 1)                  /* 40 */
+SYSCALL(sys_dup, 1)
+SYSCALL(sys_pipe, 1)
+SYSCALL(sys_times, 1)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_brk, 1)                    /* 45 */
+SYSCALL(sys_setgid, 1)
+SYSCALL(sys_getgid, 0)
+SYSCALL(sys_ni_syscall, 0)             /* was signal(2) */
+SYSCALL(sys_geteuid, 0)
+SYSCALL(sys_getegid, 0)                        /* 50 */
+SYSCALL(sys_acct, 1)
+SYSCALL(sys_umount, 2)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_ioctl, 3)
+SYSCALL(sys_fcntl, 3)                  /* 55 */
+SYSCALL(sys_ni_syscall, 2)
+SYSCALL(sys_setpgid, 2)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_olduname, 1)
+SYSCALL(sys_umask, 1)                  /* 60 */
+SYSCALL(sys_chroot, 1)
+SYSCALL(sys_ustat, 2)
+SYSCALL(sys_dup2, 2)
+SYSCALL(sys_getppid, 0)
+SYSCALL(sys_getpgrp, 0)                        /* 65 */
+SYSCALL(sys_setsid, 0)
+SYSCALL(sys_sigaction, 3)
+SYSCALL(sys_sgetmask, 0)
+SYSCALL(sys_ssetmask, 1)
+SYSCALL(sys_setreuid, 2)               /* 70 */
+SYSCALL(sys_setregid, 2)
+SYSCALL(sys_sigsuspend, 0)
+SYSCALL(sys_sigpending, 1)
+SYSCALL(sys_sethostname, 2)
+SYSCALL(sys_setrlimit, 2)              /* 75 */
+SYSCALL(sys_getrlimit, 2)
+SYSCALL(sys_getrusage, 2)
+SYSCALL(sys_gettimeofday, 2)
+SYSCALL(sys_settimeofday, 2)
+SYSCALL(sys_getgroups, 2)              /* 80 */
+SYSCALL(sys_setgroups, 2)
+SYSCALL(sys_ni_syscall, 0)              /* old_select */
+SYSCALL(sys_symlink, 2)
+SYSCALL(sys_lstat, 2)
+SYSCALL(sys_readlink, 3)               /* 85 */
+SYSCALL(sys_uselib, 1)
+SYSCALL(sys_swapon, 2)
+SYSCALL(sys_reboot, 3)
+SYSCALL(old_readdir, 3)
+SYSCALL(old_mmap, 6)                   /* 90 */
+SYSCALL(sys_munmap, 2)
+SYSCALL(sys_truncate, 2)
+SYSCALL(sys_ftruncate, 2)
+SYSCALL(sys_fchmod, 2)
+SYSCALL(sys_fchown, 3)                 /* 95 */
+SYSCALL(sys_getpriority, 2)
+SYSCALL(sys_setpriority, 3)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_statfs, 2)
+SYSCALL(sys_fstatfs, 2)                        /* 100 */
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_socketcall, 2)
+SYSCALL(sys_syslog, 3)
+SYSCALL(sys_setitimer, 3)
+SYSCALL(sys_getitimer, 2)              /* 105 */
+SYSCALL(sys_newstat, 2)
+SYSCALL(sys_newlstat, 2)
+SYSCALL(sys_newfstat, 2)
+SYSCALL(sys_uname, 1)
+SYSCALL(sys_ni_syscall, 0)             /* 110 */
+SYSCALL(sys_vhangup, 0)
+SYSCALL(sys_ni_syscall, 0)             /* was sys_idle() */
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_wait4, 4)
+SYSCALL(sys_swapoff, 1)                        /* 115 */
+SYSCALL(sys_sysinfo, 1)
+SYSCALL(sys_ipc, 5)                    /* 6 really, but glibc uses only 5) */
+SYSCALL(sys_fsync, 1)
+SYSCALL(sys_sigreturn, 0)
+SYSCALL(sys_clone, 0)                  /* 120 */
+SYSCALL(sys_setdomainname, 2)
+SYSCALL(sys_newuname, 1)
+SYSCALL(sys_ni_syscall, 0)             /* sys_modify_ldt */
+SYSCALL(sys_adjtimex, 1)
+SYSCALL(sys_mprotect, 3)               /* 125 */
+SYSCALL(sys_sigprocmask, 3)
+SYSCALL(sys_ni_syscall, 2)             /* old sys_create_module */
+SYSCALL(sys_init_module, 2)
+SYSCALL(sys_delete_module, 1)
+SYSCALL(sys_ni_syscall, 1)             /* old sys_get_kernel_sysm */   /* 130 */
+SYSCALL(sys_quotactl, 0)
+SYSCALL(sys_getpgid, 1)
+SYSCALL(sys_fchdir, 1)
+SYSCALL(sys_bdflush, 2)
+SYSCALL(sys_sysfs, 3)                  /* 135 */
+SYSCALL(sys_personality, 1)
+SYSCALL(sys_ni_syscall, 0)             /* for afs_syscall */
+SYSCALL(sys_setfsuid, 1)
+SYSCALL(sys_setfsgid, 1)
+SYSCALL(sys_llseek, 5)                 /* 140 */
+SYSCALL(sys_getdents, 3)
+SYSCALL(sys_select, 5)
+SYSCALL(sys_flock, 2)
+SYSCALL(sys_msync, 3)
+SYSCALL(sys_readv, 3)                  /* 145 */
+SYSCALL(sys_writev, 3)
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_ni_syscall, 4)             /* handled in fast syscall handler. */
+SYSCALL(sys_ni_syscall, 0)             /* 150 */
+SYSCALL(sys_getsid, 1)
+SYSCALL(sys_fdatasync, 1)
+SYSCALL(sys_sysctl, 1)
+SYSCALL(sys_mlock, 2)
+SYSCALL(sys_munlock, 2)                        /* 155 */
+SYSCALL(sys_mlockall, 1)
+SYSCALL(sys_munlockall, 0)
+SYSCALL(sys_sched_setparam,2)
+SYSCALL(sys_sched_getparam,2)
+SYSCALL(sys_sched_setscheduler,3)      /* 160 */
+SYSCALL(sys_sched_getscheduler,1)
+SYSCALL(sys_sched_yield,0)
+SYSCALL(sys_sched_get_priority_max,1)
+SYSCALL(sys_sched_get_priority_min,1)
+SYSCALL(sys_sched_rr_get_interval,2)   /* 165 */
+SYSCALL(sys_nanosleep,2)
+SYSCALL(sys_mremap,4)
+SYSCALL(sys_accept, 3)
+SYSCALL(sys_bind, 3)
+SYSCALL(sys_connect, 3)                        /* 170 */
+SYSCALL(sys_getpeername, 3)
+SYSCALL(sys_getsockname, 3)
+SYSCALL(sys_getsockopt, 5)
+SYSCALL(sys_listen, 2)
+SYSCALL(sys_recv, 4)                   /* 175 */
+SYSCALL(sys_recvfrom, 6)
+SYSCALL(sys_recvmsg, 3)
+SYSCALL(sys_send, 4)
+SYSCALL(sys_sendmsg, 3)
+SYSCALL(sys_sendto, 6)                 /* 180 */
+SYSCALL(sys_setsockopt, 5)
+SYSCALL(sys_shutdown, 2)
+SYSCALL(sys_socket, 3)
+SYSCALL(sys_socketpair, 4)
+SYSCALL(sys_setresuid, 3)              /* 185 */
+SYSCALL(sys_getresuid, 3)
+SYSCALL(sys_ni_syscall, 5)             /* old sys_query_module */
+SYSCALL(sys_poll, 3)
+SYSCALL(sys_nfsservctl, 3)
+SYSCALL(sys_setresgid, 3)              /* 190 */
+SYSCALL(sys_getresgid, 3)
+SYSCALL(sys_prctl, 5)
+SYSCALL(sys_rt_sigreturn, 0)
+SYSCALL(sys_rt_sigaction, 4)
+SYSCALL(sys_rt_sigprocmask, 4)         /* 195 */
+SYSCALL(sys_rt_sigpending, 2)
+SYSCALL(sys_rt_sigtimedwait, 4)
+SYSCALL(sys_rt_sigqueueinfo, 3)
+SYSCALL(sys_rt_sigsuspend, 0)
+SYSCALL(sys_pread64, 5)                        /* 200 */
+SYSCALL(sys_pwrite64, 5)
+SYSCALL(sys_chown, 3)
+SYSCALL(sys_getcwd, 2)
+SYSCALL(sys_capget, 2)
+SYSCALL(sys_capset, 2)                 /* 205 */
+SYSCALL(sys_sigaltstack, 0)
+SYSCALL(sys_sendfile, 4)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_mmap2, 6)                  /* 210 */
+SYSCALL(sys_truncate64, 2)
+SYSCALL(sys_ftruncate64, 2)
+SYSCALL(sys_stat64, 2)
+SYSCALL(sys_lstat64, 2)
+SYSCALL(sys_fstat64, 2)                        /* 215 */
+SYSCALL(sys_pivot_root, 2)
+SYSCALL(sys_mincore, 3)
+SYSCALL(sys_madvise, 3)
+SYSCALL(sys_getdents64, 3)
+SYSCALL(sys_vfork, 0)                  /* 220 */
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
new file mode 100644 (file)
index 0000000..e07287d
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * arch/xtensa/kernel/time.c
+ *
+ * Timer and clock support.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/delay.h>
+
+#include <asm/timex.h>
+#include <asm/platform.h>
+
+
+extern volatile unsigned long wall_jiffies;
+
+u64 jiffies_64 = INITIAL_JIFFIES;
+EXPORT_SYMBOL(jiffies_64);
+
+spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+EXPORT_SYMBOL(rtc_lock);
+
+
+#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
+unsigned long ccount_per_jiffy;                /* per 1/HZ */
+unsigned long ccount_nsec;             /* nsec per ccount increment */
+#endif
+
+unsigned int last_ccount_stamp;
+static long last_rtc_update = 0;
+
+/*
+ * Scheduler clock - returns current tim in nanosec units.
+ */
+
+unsigned long long sched_clock(void)
+{
+       return (unsigned long long)jiffies * (1000000000 / HZ);
+}
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static struct irqaction timer_irqaction = {
+       .handler =      timer_interrupt,
+       .flags =        SA_INTERRUPT,
+       .name =         "timer",
+};
+
+void __init time_init(void)
+{
+       time_t sec_o, sec_n = 0;
+
+       /* The platform must provide a function to calibrate the processor
+        * speed for the CALIBRATE.
+        */
+
+#if CONFIG_XTENSA_CALIBRATE_CCOUNT
+       printk("Calibrating CPU frequency ");
+       platform_calibrate_ccount();
+       printk("%d.%02d MHz\n", (int)ccount_per_jiffy/(1000000/HZ),
+                       (int)(ccount_per_jiffy/(10000/HZ))%100);
+#endif
+
+       /* Set time from RTC (if provided) */
+
+       if (platform_get_rtc_time(&sec_o) == 0)
+               while (platform_get_rtc_time(&sec_n))
+                       if (sec_o != sec_n)
+                               break;
+
+       xtime.tv_nsec = 0;
+       last_rtc_update = xtime.tv_sec = sec_n;
+       last_ccount_stamp = get_ccount();
+
+       set_normalized_timespec(&wall_to_monotonic,
+               -xtime.tv_sec, -xtime.tv_nsec);
+
+       /* Initialize the linux timer interrupt. */
+
+       setup_irq(LINUX_TIMER_INT, &timer_irqaction);
+       set_linux_timer(get_ccount() + CCOUNT_PER_JIFFY);
+}
+
+
+int do_settimeofday(struct timespec *tv)
+{
+       time_t wtm_sec, sec = tv->tv_sec;
+       long wtm_nsec, nsec = tv->tv_nsec;
+       unsigned long ccount;
+
+       if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+               return -EINVAL;
+
+       write_seqlock_irq(&xtime_lock);
+
+       /* This is revolting. We need to set "xtime" correctly. However, the
+        * value in this location is the value at the most recent update of
+        * wall time.  Discover what correction gettimeofday() would have
+        * made, and then undo it!
+        */
+       ccount = get_ccount();
+       nsec -= (ccount - last_ccount_stamp) * CCOUNT_NSEC;
+       nsec -= (jiffies - wall_jiffies) * CCOUNT_PER_JIFFY * CCOUNT_NSEC;
+
+       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);
+
+       time_adjust = 0;                /* stop active adjtime() */
+       time_status |= STA_UNSYNC;
+       time_maxerror = NTP_PHASE_LIMIT;
+       time_esterror = NTP_PHASE_LIMIT;
+       write_sequnlock_irq(&xtime_lock);
+       return 0;
+}
+
+EXPORT_SYMBOL(do_settimeofday);
+
+
+void do_gettimeofday(struct timeval *tv)
+{
+       unsigned long flags;
+       unsigned long sec, usec, delta, lost, seq;
+
+       do {
+               seq = read_seqbegin_irqsave(&xtime_lock, flags);
+
+               delta = get_ccount() - last_ccount_stamp;
+               sec = xtime.tv_sec;
+               usec = (xtime.tv_nsec / NSEC_PER_USEC);
+
+               lost = jiffies - wall_jiffies;
+
+       } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+
+       usec += lost * (1000000UL/HZ) + (delta * CCOUNT_NSEC) / NSEC_PER_USEC;
+       for (; usec >= 1000000; sec++, usec -= 1000000)
+               ;
+
+       tv->tv_sec = sec;
+       tv->tv_usec = usec;
+}
+
+EXPORT_SYMBOL(do_gettimeofday);
+
+/*
+ * The timer interrupt is called HZ times per second.
+ */
+
+irqreturn_t timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+
+       unsigned long next;
+
+       next = get_linux_timer();
+
+again:
+       while ((signed long)(get_ccount() - next) > 0) {
+
+               profile_tick(CPU_PROFILING, regs);
+#ifndef CONFIG_SMP
+               update_process_times(user_mode(regs));
+#endif
+
+               write_seqlock(&xtime_lock);
+
+               last_ccount_stamp = next;
+               next += CCOUNT_PER_JIFFY;
+               do_timer (regs); /* Linux handler in kernel/timer.c */
+
+               if ((time_status & STA_UNSYNC) == 0 &&
+                   xtime.tv_sec - last_rtc_update >= 659 &&
+                   abs((xtime.tv_nsec/1000)-(1000000-1000000/HZ))<5000000/HZ &&
+                   jiffies - wall_jiffies == 1) {
+
+                       if (platform_set_rtc_time(xtime.tv_sec+1) == 0)
+                               last_rtc_update = xtime.tv_sec+1;
+                       else
+                               /* Do it again in 60 s */
+                               last_rtc_update += 60;
+               }
+               write_sequnlock(&xtime_lock);
+       }
+
+       /* NOTE: writing CCOMPAREn clears the interrupt.  */
+
+       set_linux_timer (next);
+
+       /* Make sure we didn't miss any tick... */
+
+       if ((signed long)(get_ccount() - next) > 0)
+               goto again;
+
+       /* Allow platform to do something usefull (Wdog). */
+
+       platform_heartbeat();
+
+       return IRQ_HANDLED;
+}
+
+#ifndef CONFIG_GENERIC_CALIBRATE_DELAY
+void __devinit calibrate_delay(void)
+{
+       loops_per_jiffy = CCOUNT_PER_JIFFY;
+       printk("Calibrating delay loop (skipped)... "
+              "%lu.%02lu BogoMIPS preset\n",
+              loops_per_jiffy/(1000000/HZ),
+              (loops_per_jiffy/(10000/HZ)) % 100);
+}
+#endif
+
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c
new file mode 100644 (file)
index 0000000..804246e
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * arch/xtensa/kernel/traps.c
+ *
+ * Exception handling.
+ *
+ * Derived from code with the following copyrights:
+ * Copyright (C) 1994 - 1999 by Ralf Baechle
+ * Modified for R3000 by Paul M. Antoine, 1995, 1996
+ * Complete output from die() by Ulf Carlsson, 1998
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ *
+ * Essentially rewritten for the Xtensa architecture port.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Joe Taylor  <joe@tensilica.com, joetylr@yahoo.com>
+ * Chris Zankel        <chris@zankel.net>
+ * Marc Gauthier<marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Kevin Chea
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include <linux/kallsyms.h>
+
+#include <asm/ptrace.h>
+#include <asm/timex.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+
+#ifdef CONFIG_KGDB
+extern int gdb_enter;
+extern int return_from_debug_flag;
+#endif
+
+/*
+ * Machine specific interrupt handlers
+ */
+
+extern void kernel_exception(void);
+extern void user_exception(void);
+
+extern void fast_syscall_kernel(void);
+extern void fast_syscall_user(void);
+extern void fast_alloca(void);
+extern void fast_unaligned(void);
+extern void fast_second_level_miss(void);
+extern void fast_store_prohibited(void);
+extern void fast_coprocessor(void);
+
+extern void do_illegal_instruction (struct pt_regs*);
+extern void do_interrupt (struct pt_regs*);
+extern void do_unaligned_user (struct pt_regs*);
+extern void do_multihit (struct pt_regs*, unsigned long);
+extern void do_page_fault (struct pt_regs*, unsigned long);
+extern void do_debug (struct pt_regs*);
+extern void system_call (struct pt_regs*);
+
+/*
+ * The vector table must be preceded by a save area (which
+ * implies it must be in RAM, unless one places RAM immediately
+ * before a ROM and puts the vector at the start of the ROM (!))
+ */
+
+#define KRNL           0x01
+#define USER           0x02
+
+#define COPROCESSOR(x)                                                 \
+{ XCHAL_EXCCAUSE_COPROCESSOR ## x ## _DISABLED, USER, fast_coprocessor }
+
+typedef struct {
+       int cause;
+       int fast;
+       void* handler;
+} dispatch_init_table_t;
+
+dispatch_init_table_t __init dispatch_init_table[] = {
+
+{ XCHAL_EXCCAUSE_ILLEGAL_INSTRUCTION,  0,         do_illegal_instruction},
+{ XCHAL_EXCCAUSE_SYSTEM_CALL,          KRNL,      fast_syscall_kernel },
+{ XCHAL_EXCCAUSE_SYSTEM_CALL,          USER,      fast_syscall_user },
+{ XCHAL_EXCCAUSE_SYSTEM_CALL,          0,         system_call },
+/* XCHAL_EXCCAUSE_INSTRUCTION_FETCH unhandled */
+/* XCHAL_EXCCAUSE_LOAD_STORE_ERROR unhandled*/
+{ XCHAL_EXCCAUSE_LEVEL1_INTERRUPT,     0,         do_interrupt },
+{ XCHAL_EXCCAUSE_ALLOCA,               USER|KRNL, fast_alloca },
+/* XCHAL_EXCCAUSE_INTEGER_DIVIDE_BY_ZERO unhandled */
+/* XCHAL_EXCCAUSE_PRIVILEGED unhandled */
+#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
+#ifdef CONFIG_UNALIGNED_USER
+{ XCHAL_EXCCAUSE_UNALIGNED,            USER,      fast_unaligned },
+#else
+{ XCHAL_EXCCAUSE_UNALIGNED,            0,         do_unaligned_user },
+#endif
+{ XCHAL_EXCCAUSE_UNALIGNED,            KRNL,      fast_unaligned },
+#endif
+{ XCHAL_EXCCAUSE_ITLB_MISS,            0,         do_page_fault },
+{ XCHAL_EXCCAUSE_ITLB_MISS,            USER|KRNL, fast_second_level_miss},
+{ XCHAL_EXCCAUSE_ITLB_MULTIHIT,                0,         do_multihit },
+{ XCHAL_EXCCAUSE_ITLB_PRIVILEGE,       0,         do_page_fault },
+/* XCHAL_EXCCAUSE_SIZE_RESTRICTION unhandled */
+{ XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE,        0,         do_page_fault },
+{ XCHAL_EXCCAUSE_DTLB_MISS,            USER|KRNL, fast_second_level_miss},
+{ XCHAL_EXCCAUSE_DTLB_MISS,            0,         do_page_fault },
+{ XCHAL_EXCCAUSE_DTLB_MULTIHIT,                0,         do_multihit },
+{ XCHAL_EXCCAUSE_DTLB_PRIVILEGE,       0,         do_page_fault },
+/* XCHAL_EXCCAUSE_DTLB_SIZE_RESTRICTION unhandled */
+{ XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE,        USER|KRNL, fast_store_prohibited },
+{ XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE,        0,         do_page_fault },
+{ XCHAL_EXCCAUSE_LOAD_CACHE_ATTRIBUTE, 0,         do_page_fault },
+/* XCCHAL_EXCCAUSE_FLOATING_POINT unhandled */
+#if (XCHAL_CP_MASK & 1)
+COPROCESSOR(0),
+#endif
+#if (XCHAL_CP_MASK & 2)
+COPROCESSOR(1),
+#endif
+#if (XCHAL_CP_MASK & 4)
+COPROCESSOR(2),
+#endif
+#if (XCHAL_CP_MASK & 8)
+COPROCESSOR(3),
+#endif
+#if (XCHAL_CP_MASK & 16)
+COPROCESSOR(4),
+#endif
+#if (XCHAL_CP_MASK & 32)
+COPROCESSOR(5),
+#endif
+#if (XCHAL_CP_MASK & 64)
+COPROCESSOR(6),
+#endif
+#if (XCHAL_CP_MASK & 128)
+COPROCESSOR(7),
+#endif
+{ EXCCAUSE_MAPPED_DEBUG,               0,              do_debug },
+{ -1, -1, 0 }
+
+};
+
+/* The exception table <exc_table> serves two functions:
+ * 1. it contains three dispatch tables (fast_user, fast_kernel, default-c)
+ * 2. it is a temporary memory buffer for the exception handlers.
+ */
+
+unsigned long exc_table[EXC_TABLE_SIZE/4];
+
+void die(const char*, struct pt_regs*, long);
+
+static inline void
+__die_if_kernel(const char *str, struct pt_regs *regs, long err)
+{
+       if (!user_mode(regs))
+               die(str, regs, err);
+}
+
+/*
+ * Unhandled Exceptions. Kill user task or panic if in kernel space.
+ */
+
+void do_unhandled(struct pt_regs *regs, unsigned long exccause)
+{
+       __die_if_kernel("Caught unhandled exception - should not happen",
+                       regs, SIGKILL);
+
+       /* If in user mode, send SIGILL signal to current process */
+       printk("Caught unhandled exception in '%s' "
+              "(pid = %d, pc = %#010lx) - should not happen\n"
+              "\tEXCCAUSE is %ld\n",
+              current->comm, current->pid, regs->pc, exccause);
+       force_sig(SIGILL, current);
+}
+
+/*
+ * Multi-hit exception. This if fatal!
+ */
+
+void do_multihit(struct pt_regs *regs, unsigned long exccause)
+{
+       die("Caught multihit exception", regs, SIGKILL);
+}
+
+/*
+ * Level-1 interrupt.
+ * We currently have no priority encoding.
+ */
+
+unsigned long ignored_level1_interrupts;
+extern void do_IRQ(int, struct pt_regs *);
+
+void do_interrupt (struct pt_regs *regs)
+{
+       unsigned long intread = get_sr (INTREAD);
+       unsigned long intenable = get_sr (INTENABLE);
+       int i, mask;
+
+       /* Handle all interrupts (no priorities).
+        * (Clear the interrupt before processing, in case it's
+        *  edge-triggered or software-generated)
+        */
+
+       for (i=0, mask = 1; i < XCHAL_NUM_INTERRUPTS; i++, mask <<= 1) {
+               if (mask & (intread & intenable)) {
+                       set_sr (mask, INTCLEAR);
+                       do_IRQ (i,regs);
+               }
+       }
+}
+
+/*
+ * Illegal instruction. Fatal if in kernel space.
+ */
+
+void
+do_illegal_instruction(struct pt_regs *regs)
+{
+       __die_if_kernel("Illegal instruction in kernel", regs, SIGKILL);
+
+       /* If in user mode, send SIGILL signal to current process. */
+
+       printk("Illegal Instruction in '%s' (pid = %d, pc = %#010lx)\n",
+           current->comm, current->pid, regs->pc);
+       force_sig(SIGILL, current);
+}
+
+
+/*
+ * Handle unaligned memory accesses from user space. Kill task.
+ *
+ * If CONFIG_UNALIGNED_USER is not set, we don't allow unaligned memory
+ * accesses causes from user space.
+ */
+
+#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
+#ifndef CONFIG_UNALIGNED_USER
+void
+do_unaligned_user (struct pt_regs *regs)
+{
+       siginfo_t info;
+
+       __die_if_kernel("Unhandled unaligned exception in kernel",
+                       regs, SIGKILL);
+
+       current->thread.bad_vaddr = regs->excvaddr;
+       current->thread.error_code = -3;
+       printk("Unaligned memory access to %08lx in '%s' "
+              "(pid = %d, pc = %#010lx)\n",
+              regs->excvaddr, current->comm, current->pid, regs->pc);
+       info.si_signo = SIGBUS;
+       info.si_errno = 0;
+       info.si_code = BUS_ADRALN;
+       info.si_addr = (void *) regs->excvaddr;
+       force_sig_info(SIGSEGV, &info, current);
+
+}
+#endif
+#endif
+
+void
+do_debug(struct pt_regs *regs)
+{
+#ifdef CONFIG_KGDB
+       /* If remote debugging is configured AND enabled, we give control to
+        * kgdb.  Otherwise, we fall through, perhaps giving control to the
+        * native debugger.
+        */
+
+       if (gdb_enter) {
+               extern void gdb_handle_exception(struct pt_regs *);
+               gdb_handle_exception(regs);
+               return_from_debug_flag = 1;
+               return;
+       }
+#endif
+
+       __die_if_kernel("Breakpoint in kernel", regs, SIGKILL);
+
+       /* If in user mode, send SIGTRAP signal to current process */
+
+       force_sig(SIGTRAP, current);
+}
+
+
+/*
+ * Initialize dispatch tables.
+ *
+ * The exception vectors are stored compressed the __init section in the
+ * dispatch_init_table. This function initializes the following three tables
+ * from that compressed table:
+ * - fast user         first dispatch table for user exceptions
+ * - fast kernel       first dispatch table for kernel exceptions
+ * - default C-handler C-handler called by the default fast handler.
+ *
+ * See vectors.S for more details.
+ */
+
+#define set_handler(idx,handler) (exc_table[idx] = (unsigned long) (handler))
+
+void trap_init(void)
+{
+       int i;
+
+       /* Setup default vectors. */
+
+       for(i = 0; i < 64; i++) {
+               set_handler(EXC_TABLE_FAST_USER/4   + i, user_exception);
+               set_handler(EXC_TABLE_FAST_KERNEL/4 + i, kernel_exception);
+               set_handler(EXC_TABLE_DEFAULT/4 + i, do_unhandled);
+       }
+
+       /* Setup specific handlers. */
+
+       for(i = 0; dispatch_init_table[i].cause >= 0; i++) {
+
+               int fast = dispatch_init_table[i].fast;
+               int cause = dispatch_init_table[i].cause;
+               void *handler = dispatch_init_table[i].handler;
+
+               if (fast == 0)
+                       set_handler (EXC_TABLE_DEFAULT/4 + cause, handler);
+               if (fast && fast & USER)
+                       set_handler (EXC_TABLE_FAST_USER/4 + cause, handler);
+               if (fast && fast & KRNL)
+                       set_handler (EXC_TABLE_FAST_KERNEL/4 + cause, handler);
+       }
+
+       /* Initialize EXCSAVE_1 to hold the address of the exception table. */
+
+       i = (unsigned long)exc_table;
+       __asm__ __volatile__("wsr  %0, "__stringify(EXCSAVE_1)"\n" : : "a" (i));
+}
+
+/*
+ * This function dumps the current valid window frame and other base registers.
+ */
+
+void show_regs(struct pt_regs * regs)
+{
+       int i, wmask;
+
+       wmask = regs->wmask & ~1;
+
+       for (i = 0; i < 32; i++) {
+               if (wmask & (1 << (i / 4)))
+                       break;
+               if ((i % 8) == 0)
+                       printk ("\n" KERN_INFO "a%02d: ", i);
+               printk("%08lx ", regs->areg[i]);
+       }
+       printk("\n");
+
+       printk("pc: %08lx, ps: %08lx, depc: %08lx, excvaddr: %08lx\n",
+              regs->pc, regs->ps, regs->depc, regs->excvaddr);
+       printk("lbeg: %08lx, lend: %08lx lcount: %08lx, sar: %08lx\n",
+              regs->lbeg, regs->lend, regs->lcount, regs->sar);
+       if (user_mode(regs))
+               printk("wb: %08lx, ws: %08lx, wmask: %08lx, syscall: %ld\n",
+                      regs->windowbase, regs->windowstart, regs->wmask,
+                      regs->syscall);
+}
+
+void show_trace(struct task_struct *task, unsigned long *sp)
+{
+       unsigned long a0, a1, pc;
+       unsigned long sp_start, sp_end;
+
+       a1 = (unsigned long)sp;
+
+       if (a1 == 0)
+               __asm__ __volatile__ ("mov %0, a1\n" : "=a"(a1));
+
+
+       sp_start = a1 & ~(THREAD_SIZE-1);
+       sp_end = sp_start + THREAD_SIZE;
+
+       printk("Call Trace:");
+#ifdef CONFIG_KALLSYMS
+       printk("\n");
+#endif
+       spill_registers();
+
+       while (a1 > sp_start && a1 < sp_end) {
+               sp = (unsigned long*)a1;
+
+               a0 = *(sp - 4);
+               a1 = *(sp - 3);
+
+               if (a1 <= (unsigned long) sp)
+                       break;
+
+               pc = MAKE_PC_FROM_RA(a0, a1);
+
+               if (kernel_text_address(pc)) {
+                       printk(" [<%08lx>] ", pc);
+                       print_symbol("%s\n", pc);
+               }
+       }
+       printk("\n");
+}
+
+/*
+ * This routine abuses get_user()/put_user() to reference pointers
+ * with at least a bit of error checking ...
+ */
+
+static int kstack_depth_to_print = 24;
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+       int i = 0;
+       unsigned long *stack;
+
+       if (sp == 0)
+               __asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp));
+
+       stack = sp;
+
+       printk("\nStack: ");
+
+       for (i = 0; i < kstack_depth_to_print; i++) {
+               if (kstack_end(sp))
+                       break;
+               if (i && ((i % 8) == 0))
+                       printk("\n       ");
+               printk("%08lx ", *sp++);
+       }
+       printk("\n");
+       show_trace(task, stack);
+}
+
+void dump_stack(void)
+{
+       show_stack(current, NULL);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+
+void show_code(unsigned int *pc)
+{
+       long i;
+
+       printk("\nCode:");
+
+       for(i = -3 ; i < 6 ; i++) {
+               unsigned long insn;
+               if (__get_user(insn, pc + i)) {
+                       printk(" (Bad address in pc)\n");
+                       break;
+               }
+               printk("%c%08lx%c",(i?' ':'<'),insn,(i?' ':'>'));
+       }
+}
+
+spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
+
+void die(const char * str, struct pt_regs * regs, long err)
+{
+       static int die_counter;
+       int nl = 0;
+
+       console_verbose();
+       spin_lock_irq(&die_lock);
+
+       printk("%s: sig: %ld [#%d]\n", str, err, ++die_counter);
+#ifdef CONFIG_PREEMPT
+       printk("PREEMPT ");
+       nl = 1;
+#endif
+       if (nl)
+               printk("\n");
+       show_regs(regs);
+       if (!user_mode(regs))
+               show_stack(NULL, (unsigned long*)regs->areg[1]);
+
+       spin_unlock_irq(&die_lock);
+
+       if (in_interrupt())
+               panic("Fatal exception in interrupt");
+
+       if (panic_on_oops) {
+               printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(5 * HZ);
+               panic("Fatal exception");
+       }
+       do_exit(err);
+}
+
+
diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S
new file mode 100644 (file)
index 0000000..81808f0
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * arch/xtensa/kernel/vectors.S
+ *
+ * This file contains all exception vectors (user, kernel, and double),
+ * as well as the window vectors (overflow and underflow), and the debug
+ * vector. These are the primary vectors executed by the processor if an
+ * exception occurs.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2005 Tensilica, Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ *
+ */
+
+/*
+ * We use a two-level table approach. The user and kernel exception vectors
+ * use a first-level dispatch table to dispatch the exception to a registered
+ * fast handler or the default handler, if no fast handler was registered.
+ * The default handler sets up a C-stack and dispatches the exception to a
+ * registerd C handler in the second-level dispatch table.
+ *
+ * Fast handler entry condition:
+ *
+ *   a0:       trashed, original value saved on stack (PT_AREG0)
+ *   a1:       a1
+ *   a2:       new stack pointer, original value in depc
+ *   a3:       dispatch table
+ *   depc:     a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:        a3
+ *
+ * The value for PT_DEPC saved to stack also functions as a boolean to
+ * indicate that the exception is either a double or a regular exception:
+ *
+ *   PT_DEPC   >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception
+ *             <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ *
+ * Note:  Neither the kernel nor the user exception handler generate literals.
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+#include <asm/ptrace.h>
+#include <asm/current.h>
+#include <asm/offsets.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/thread_info.h>
+#include <asm/processor.h>
+
+
+/*
+ * User exception vector. (Exceptions with PS.UM == 1, PS.EXCM == 0)
+ *
+ * We get here when an exception occurred while we were in userland.
+ * We switch to the kernel stack and jump to the first level handler
+ * associated to the exception cause.
+ *
+ * Note: the saved kernel stack pointer (EXC_TABLE_KSTK) is already
+ *       decremented by PT_USER_SIZE.
+ */
+
+       .section .UserExceptionVector.text, "ax"
+
+ENTRY(_UserExceptionVector)
+
+       xsr     a3, EXCSAVE_1           # save a3 and get dispatch table
+       wsr     a2, DEPC                # save a2
+       l32i    a2, a3, EXC_TABLE_KSTK  # load kernel stack to a2
+       s32i    a0, a2, PT_AREG0        # save a0 to ESF
+       rsr     a0, EXCCAUSE            # retrieve exception cause
+       s32i    a0, a2, PT_DEPC         # mark it as a regular exception
+       addx4   a0, a0, a3              # find entry in table
+       l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
+       jx      a0
+
+/*
+ * Kernel exception vector. (Exceptions with PS.UM == 0, PS.EXCM == 0)
+ *
+ * We get this exception when we were already in kernel space.
+ * We decrement the current stack pointer (kernel) by PT_SIZE and
+ * jump to the first-level handler associated with the exception cause.
+ *
+ * Note: we need to preserve space for the spill region.
+ */
+
+       .section .KernelExceptionVector.text, "ax"
+
+ENTRY(_KernelExceptionVector)
+
+       xsr     a3, EXCSAVE_1           # save a3, and get dispatch table
+       wsr     a2, DEPC                # save a2
+       addi    a2, a1, -16-PT_SIZE     # adjust stack pointer
+       s32i    a0, a2, PT_AREG0        # save a0 to ESF
+       rsr     a0, EXCCAUSE            # retrieve exception cause
+       s32i    a0, a2, PT_DEPC         # mark it as a regular exception
+       addx4   a0, a0, a3              # find entry in table
+       l32i    a0, a0, EXC_TABLE_FAST_KERNEL   # load handler address
+       jx      a0
+
+
+/*
+ * Double exception vector (Exceptions with PS.EXCM == 1)
+ * We get this exception when another exception occurs while were are
+ * already in an exception, such as window overflow/underflow exception,
+ * or 'expected' exceptions, for example memory exception when we were trying
+ * to read data from an invalid address in user space.
+ *
+ * Note that this vector is never invoked for level-1 interrupts, because such
+ * interrupts are disabled (masked) when PS.EXCM is set.
+ *
+ * We decode the exception and take the appropriate action.  However, the
+ * double exception vector is much more careful, because a lot more error
+ * cases go through the double exception vector than through the user and
+ * kernel exception vectors.
+ *
+ * Occasionally, the kernel expects a double exception to occur.  This usually
+ * happens when accessing user-space memory with the user's permissions
+ * (l32e/s32e instructions).  The kernel state, though, is not always suitable
+ * for immediate transfer of control to handle_double, where "normal" exception
+ * processing occurs. Also in kernel mode, TLB misses can occur if accessing
+ * vmalloc memory, possibly requiring repair in a double exception handler.
+ *
+ * The variable at TABLE_FIXUP offset from the pointer in EXCSAVE_1 doubles as
+ * a boolean variable and a pointer to a fixup routine. If the variable
+ * EXC_TABLE_FIXUP is non-zero, this handler jumps to that address. A value of
+ * zero indicates to use the default kernel/user exception handler.
+ * There is only one exception, when the value is identical to the exc_table
+ * label, the kernel is in trouble. This mechanism is used to protect critical
+ * sections, mainly when the handler writes to the stack to assert the stack
+ * pointer is valid. Once the fixup/default handler leaves that area, the
+ * EXC_TABLE_FIXUP variable is reset to the fixup handler or zero.
+ *
+ * Procedures wishing to use this mechanism should set EXC_TABLE_FIXUP to the
+ * nonzero address of a fixup routine before it could cause a double exception
+ * and reset it before it returns.
+ *
+ * Some other things to take care of when a fast exception handler doesn't
+ * specify a particular fixup handler but wants to use the default handlers:
+ *
+ *  - The original stack pointer (in a1) must not be modified. The fast
+ *    exception handler should only use a2 as the stack pointer.
+ *
+ *  - If the fast handler manipulates the stack pointer (in a2), it has to
+ *    register a valid fixup handler and cannot use the default handlers.
+ *
+ *  - The handler can use any other generic register from a3 to a15, but it
+ *    must save the content of these registers to stack (PT_AREG3...PT_AREGx)
+ *
+ *  - These registers must be saved before a double exception can occur.
+ *
+ *  - If we ever implement handling signals while in double exceptions, the
+ *    number of registers a fast handler has saved (excluding a0 and a1) must
+ *    be written to  PT_AREG1. (1 if only a3 is used, 2 for a3 and a4, etc. )
+ *
+ * The fixup handlers are special handlers:
+ *
+ *  - Fixup entry conditions differ from regular exceptions:
+ *
+ *     a0:        DEPC
+ *     a1:        a1
+ *     a2:        trashed, original value in EXC_TABLE_DOUBLE_A2
+ *     a3:        exctable
+ *     depc:      a0
+ *     excsave_1: a3
+ *
+ *  - When the kernel enters the fixup handler, it still assumes it is in a
+ *    critical section, so EXC_TABLE_FIXUP variable is set to exc_table.
+ *    The fixup handler, therefore, has to re-register itself as the fixup
+ *    handler before it returns from the double exception.
+ *
+ *  - Fixup handler can share the same exception frame with the fast handler.
+ *    The kernel stack pointer is not changed when entering the fixup handler.
+ *
+ *  - Fixup handlers can jump to the default kernel and user exception
+ *    handlers. Before it jumps, though, it has to setup a exception frame
+ *    on stack. Because the default handler resets the register fixup handler
+ *    the fixup handler must make sure that the default handler returns to
+ *    it instead of the exception address, so it can re-register itself as
+ *    the fixup handler.
+ *
+ * In case of a critical condition where the kernel cannot recover, we jump
+ * to unrecoverable_exception with the following entry conditions.
+ * All registers a0...a15 are unchanged from the last exception, except:
+ *
+ *     a0:        last address before we jumped to the unrecoverable_exception.
+ *     excsave_1: a0
+ *
+ *
+ * See the handle_alloca_user and spill_registers routines for example clients.
+ *
+ * FIXME: Note: we currently don't allow signal handling coming from a double
+ *        exception, so the item markt with (*) is not required.
+ */
+
+       .section .DoubleExceptionVector.text, "ax"
+       .begin literal_prefix .DoubleExceptionVector
+
+ENTRY(_DoubleExceptionVector)
+
+       /* Deliberately destroy excsave (don't assume it's value was valid). */
+
+       wsr     a3, EXCSAVE_1           # save a3
+
+       /* Check for kernel double exception (usually fatal). */
+
+       rsr     a3, PS
+       _bbci.l a3, PS_UM_SHIFT, .Lksp
+
+       /* Check if we are currently handling a window exception. */
+       /* Note: We don't need to indicate that we enter a critical section. */
+
+       xsr     a0, DEPC                # get DEPC, save a0
+
+       movi    a3, XCHAL_WINDOW_VECTORS_VADDR
+       _bltu   a0, a3, .Lfixup
+       addi    a3, a3, XSHAL_WINDOW_VECTORS_SIZE
+       _bgeu   a0, a3, .Lfixup
+
+       /* Window overflow/underflow exception. Get stack pointer. */
+
+       mov     a3, a2
+       movi    a2, exc_table
+       l32i    a2, a2, EXC_TABLE_KSTK
+
+       /* Check for overflow/underflow exception, jump if overflow. */
+
+       _bbci.l a0, 6, .Lovfl
+
+       /* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3  */
+
+       /* Restart window underflow exception.
+        * We return to the instruction in user space that caused the window
+        * underflow exception. Therefore, we change window base to the value
+        * before we entered the window underflow exception and prepare the
+        * registers to return as if we were coming from a regular exception
+        * by changing depc (in a0).
+        * Note: We can trash the current window frame (a0...a3) and depc!
+        */
+
+       wsr     a2, DEPC                # save stack pointer temporarily
+       rsr     a0, PS
+       extui   a0, a0, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS
+       wsr     a0, WINDOWBASE
+       rsync
+
+       /* We are now in the previous window frame. Save registers again. */
+
+       xsr     a2, DEPC                # save a2 and get stack pointer
+       s32i    a0, a2, PT_AREG0
+
+       wsr     a3, EXCSAVE_1           # save a3
+       movi    a3, exc_table
+
+       rsr     a0, EXCCAUSE
+       s32i    a0, a2, PT_DEPC         # mark it as a regular exception
+       addx4   a0, a0, a3
+       l32i    a0, a0, EXC_TABLE_FAST_USER
+       jx      a0
+
+.Lfixup:/* Check for a fixup handler or if we were in a critical section. */
+
+       /* a0: depc, a1: a1, a2: a2, a3: trashed, depc: a0, excsave1: a3 */
+
+       movi    a3, exc_table
+       s32i    a2, a3, EXC_TABLE_DOUBLE_SAVE   # temporary variable
+
+       /* Enter critical section. */
+
+       l32i    a2, a3, EXC_TABLE_FIXUP
+       s32i    a3, a3, EXC_TABLE_FIXUP
+       beq     a2, a3, .Lunrecoverable_fixup   # critical!
+       beqz    a2, .Ldflt                      # no handler was registered
+
+       /* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */
+
+       jx      a2
+
+.Ldflt:        /* Get stack pointer. */
+
+       l32i    a3, a3, EXC_TABLE_DOUBLE_SAVE
+       addi    a2, a3, -PT_USER_SIZE
+
+.Lovfl:        /* Jump to default handlers. */
+
+       /* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */
+
+       xsr     a3, DEPC
+       s32i    a0, a2, PT_DEPC
+       s32i    a3, a2, PT_AREG0
+
+       /* a0: avail, a1: a1, a2: kstk, a3: avail, depc: a2, excsave: a3 */
+
+       movi    a3, exc_table
+       rsr     a0, EXCCAUSE
+       addx4   a0, a0, a3
+       l32i    a0, a0, EXC_TABLE_FAST_USER
+       jx      a0
+
+       /*
+        * We only allow the ITLB miss exception if we are in kernel space.
+        * All other exceptions are unexpected and thus unrecoverable!
+        */
+
+       .extern fast_second_level_miss_double_kernel
+
+.Lksp: /* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */
+
+       rsr     a3, EXCCAUSE
+       beqi    a3, XCHAL_EXCCAUSE_ITLB_MISS, 1f
+       addi    a3, a3, -XCHAL_EXCCAUSE_DTLB_MISS
+       bnez    a3, .Lunrecoverable
+1:     movi    a3, fast_second_level_miss_double_kernel
+       jx      a3
+
+       /* Critical! We can't handle this situation. PANIC! */
+
+       .extern unrecoverable_exception
+
+.Lunrecoverable_fixup:
+       l32i    a2, a3, EXC_TABLE_DOUBLE_SAVE
+       xsr     a0, DEPC
+
+.Lunrecoverable:
+       rsr     a3, EXCSAVE_1
+       wsr     a0, EXCSAVE_1
+       movi    a0, unrecoverable_exception
+       callx0  a0
+
+       .end literal_prefix
+
+
+/*
+ * Debug interrupt vector
+ *
+ * There is not much space here, so simply jump to another handler.
+ * EXCSAVE[DEBUGLEVEL] has been set to that handler.
+ */
+
+       .section .DebugInterruptVector.text, "ax"
+
+ENTRY(_DebugInterruptVector)
+       xsr     a0, EXCSAVE + XCHAL_DEBUGLEVEL
+       jx      a0
+
+
+
+/* Window overflow and underflow handlers.
+ * The handlers must be 64 bytes apart, first starting with the underflow
+ * handlers underflow-4 to underflow-12, then the overflow handlers
+ * overflow-4 to overflow-12.
+ *
+ * Note: We rerun the underflow handlers if we hit an exception, so
+ *      we try to access any page that would cause a page fault early.
+ */
+
+       .section                .WindowVectors.text, "ax"
+
+
+/* 4-Register Window Overflow Vector (Handler) */
+
+       .align 64
+.global _WindowOverflow4
+_WindowOverflow4:
+       s32e    a0, a5, -16
+       s32e    a1, a5, -12
+       s32e    a2, a5,  -8
+       s32e    a3, a5,  -4
+       rfwo
+
+
+/* 4-Register Window Underflow Vector (Handler) */
+
+       .align 64
+.global _WindowUnderflow4
+_WindowUnderflow4:
+       l32e    a0, a5, -16
+       l32e    a1, a5, -12
+       l32e    a2, a5,  -8
+       l32e    a3, a5,  -4
+       rfwu
+
+
+/* 8-Register Window Overflow Vector (Handler) */
+
+       .align 64
+.global _WindowOverflow8
+_WindowOverflow8:
+       s32e    a0, a9, -16
+       l32e    a0, a1, -12
+       s32e    a2, a9,  -8
+       s32e    a1, a9, -12
+       s32e    a3, a9,  -4
+       s32e    a4, a0, -32
+       s32e    a5, a0, -28
+       s32e    a6, a0, -24
+       s32e    a7, a0, -20
+       rfwo
+
+/* 8-Register Window Underflow Vector (Handler) */
+
+       .align 64
+.global _WindowUnderflow8
+_WindowUnderflow8:
+       l32e    a1, a9, -12
+       l32e    a0, a9, -16
+       l32e    a7, a1, -12
+       l32e    a2, a9,  -8
+       l32e    a4, a7, -32
+       l32e    a3, a9,  -4
+       l32e    a5, a7, -28
+       l32e    a6, a7, -24
+       l32e    a7, a7, -20
+       rfwu
+
+
+/* 12-Register Window Overflow Vector (Handler) */
+
+       .align 64
+.global _WindowOverflow12
+_WindowOverflow12:
+       s32e    a0,  a13, -16
+       l32e    a0,  a1,  -12
+       s32e    a1,  a13, -12
+       s32e    a2,  a13,  -8
+       s32e    a3,  a13,  -4
+       s32e    a4,  a0,  -48
+       s32e    a5,  a0,  -44
+       s32e    a6,  a0,  -40
+       s32e    a7,  a0,  -36
+       s32e    a8,  a0,  -32
+       s32e    a9,  a0,  -28
+       s32e    a10, a0,  -24
+       s32e    a11, a0,  -20
+       rfwo
+
+/* 12-Register Window Underflow Vector (Handler) */
+
+       .align 64
+.global _WindowUnderflow12
+_WindowUnderflow12:
+       l32e    a1,  a13, -12
+       l32e    a0,  a13, -16
+       l32e    a11, a1,  -12
+       l32e    a2,  a13,  -8
+       l32e    a4,  a11, -48
+       l32e    a8,  a11, -32
+       l32e    a3,  a13,  -4
+       l32e    a5,  a11, -44
+       l32e    a6,  a11, -40
+       l32e    a7,  a11, -36
+       l32e    a9,  a11, -28
+       l32e    a10, a11, -24
+       l32e    a11, a11, -20
+       rfwu
+
+       .text
+
+
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
new file mode 100644 (file)
index 0000000..476b2b5
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * arch/xtensa/kernel/vmlinux.lds.S
+ *
+ * Xtensa linker script
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ */
+
+#include <asm-generic/vmlinux.lds.h>
+
+#include <linux/config.h>
+#define _NOCLANGUAGE
+#include <xtensa/config/core.h>
+#include <xtensa/config/system.h>
+OUTPUT_ARCH(xtensa)
+ENTRY(_start)
+
+#if XCHAL_MEMORY_ORDER == XTHAL_BIGENDIAN
+jiffies = jiffies_64 + 4;
+#else
+jiffies = jiffies_64;
+#endif
+
+#define KERNELOFFSET 0x1000
+
+/* Note: In the following macros, it would be nice to specify only the
+   vector name and section kind and construct "sym" and "section" using
+   CPP concatenation, but that does not work reliably.  Concatenating a
+   string with "." produces an invalid token.  CPP will not print a
+   warning because it thinks this is an assembly file, but it leaves
+   them as multiple tokens and there may or may not be whitespace
+   between them.  */
+
+/* Macro for a relocation entry */
+
+#define RELOCATE_ENTRY(sym, section)           \
+       LONG(sym ## _start);                    \
+       LONG(sym ## _end);                      \
+       LONG(LOADADDR(section))
+
+/* Macro to define a section for a vector.
+ *
+ * Use of the MIN function catches the types of errors illustrated in
+ * the following example:
+ *
+ * Assume the section .DoubleExceptionVector.literal is completely
+ * full.  Then a programmer adds code to .DoubleExceptionVector.text
+ * that produces another literal.  The final literal position will
+ * overlay onto the first word of the adjacent code section
+ * .DoubleExceptionVector.text.  (In practice, the literals will
+ * overwrite the code, and the first few instructions will be
+ * garbage.)
+ */
+
+#define SECTION_VECTOR(sym, section, addr, max_prevsec_size, prevsec)       \
+  section addr : AT((MIN(LOADADDR(prevsec) + max_prevsec_size,             \
+                        LOADADDR(prevsec) + SIZEOF(prevsec)) + 3) & ~ 3)   \
+  {                                                                        \
+    . = ALIGN(4);                                                          \
+    sym ## _start = ABSOLUTE(.);                                           \
+    *(section)                                                             \
+    sym ## _end = ABSOLUTE(.);                                             \
+  }
+
+/*
+ *  Mapping of input sections to output sections when linking.
+ */
+
+SECTIONS
+{
+  . = XCHAL_KSEG_CACHED_VADDR + KERNELOFFSET;
+  /* .text section */
+
+  _text = .;
+  _stext = .;
+  _ftext = .;
+
+  .text :
+  {
+    /* The .head.text section must be the first section! */
+    *(.head.text)
+    *(.literal .text)
+    *(.srom.text)
+    VMLINUX_SYMBOL(__sched_text_start) = .;
+    *(.sched.text.literal .sched.text)
+    VMLINUX_SYMBOL(__sched_text_end) = .;
+    VMLINUX_SYMBOL(__lock_text_start) = .;
+    *(.spinlock.text.literal .spinlock.text)
+    VMLINUX_SYMBOL(__lock_text_end) = .;
+
+  }
+  _etext = .;
+
+  . = ALIGN(16);
+
+  RODATA
+
+  /*  Relocation table */
+
+  . = ALIGN(16);
+  __boot_reloc_table_start = ABSOLUTE(.);
+
+  __relocate : {
+
+    RELOCATE_ENTRY(_WindowVectors_text,
+                  .WindowVectors.text);
+#if 0
+    RELOCATE_ENTRY(_KernelExceptionVector_literal,
+                  .KernelExceptionVector.literal);
+#endif
+    RELOCATE_ENTRY(_KernelExceptionVector_text,
+                  .KernelExceptionVector.text);
+#if 0
+    RELOCATE_ENTRY(_UserExceptionVector_literal,
+                  .UserExceptionVector.literal);
+#endif
+    RELOCATE_ENTRY(_UserExceptionVector_text,
+                  .UserExceptionVector.text);
+    RELOCATE_ENTRY(_DoubleExceptionVector_literal,
+                  .DoubleExceptionVector.literal);
+    RELOCATE_ENTRY(_DoubleExceptionVector_text,
+                  .DoubleExceptionVector.text);
+  }
+  __boot_reloc_table_end = ABSOLUTE(.) ;
+
+  .fixup   : { *(.fixup) }
+
+  . = ALIGN(16);
+
+  __ex_table : {
+    __start___ex_table = .;
+    *(__ex_table)
+    __stop___ex_table = .;
+  }
+
+  /* Data section */
+
+  . = ALIGN(XCHAL_ICACHE_LINESIZE);
+  _fdata = .;
+  .data :
+  {
+    *(.data) CONSTRUCTORS
+    . = ALIGN(XCHAL_ICACHE_LINESIZE);
+    *(.data.cacheline_aligned)
+  }
+
+  _edata = .;
+
+  /* The initial task */
+  . = ALIGN(8192);
+  .data.init_task : { *(.data.init_task) }
+
+  /* Initialization code and data: */
+
+  . = ALIGN(1<<XCHAL_MMU_MIN_PTE_PAGE_SIZE);
+  __init_begin = .;
+  .init.text : {
+       _sinittext = .;
+       *(.init.text.literal) *(.init.text)
+       _einittext = .;
+  }
+
+  .init.data :
+  {
+    *(.init.data)
+    . = ALIGN(0x4);
+    __tagtable_begin = .;
+    *(.taglist)
+    __tagtable_end = .;
+  }
+
+  . = ALIGN(XCHAL_ICACHE_LINESIZE);
+
+  __setup_start = .;
+  .init.setup : { *(.init.setup) }
+  __setup_end = .;
+
+  __initcall_start = .;
+  .initcall.init : {
+       *(.initcall1.init)
+       *(.initcall2.init)
+       *(.initcall3.init)
+       *(.initcall4.init)
+       *(.initcall5.init)
+       *(.initcall6.init)
+       *(.initcall7.init)
+  }
+  __initcall_end = .;
+
+  __con_initcall_start = .;
+  .con_initcall.init : { *(.con_initcall.init) }
+  __con_initcall_end = .;
+
+  SECURITY_INIT
+
+  . = ALIGN(4);
+
+  __start___ftr_fixup = .;
+  __ftr_fixup : { *(__ftr_fixup) }
+  __stop___ftr_fixup = .;
+
+  . = ALIGN(32);
+  __per_cpu_start = .;
+  .data.percpu  : { *(.data.percpu) }
+  __per_cpu_end = .;
+
+  . = ALIGN(4096);
+  __initramfs_start =.;
+  .init.ramfs : { *(.init.ramfs) }
+  __initramfs_end = .;
+
+  /* We need this dummy segment here */
+
+  . = ALIGN(4);
+  .dummy : { LONG(0) }
+
+  /* The vectors are relocated to the real position at startup time */
+
+  SECTION_VECTOR (_WindowVectors_text,
+                 .WindowVectors.text,
+                 XCHAL_WINDOW_VECTORS_VADDR, 4,
+                 .dummy)
+  SECTION_VECTOR (_DebugInterruptVector_literal,
+                 .DebugInterruptVector.literal,
+                 XCHAL_INTLEVEL_VECTOR_VADDR(XCHAL_DEBUGLEVEL) - 4,
+                 SIZEOF(.WindowVectors.text),
+                 .WindowVectors.text)
+  SECTION_VECTOR (_DebugInterruptVector_text,
+                 .DebugInterruptVector.text,
+                 XCHAL_INTLEVEL_VECTOR_VADDR(XCHAL_DEBUGLEVEL),
+                 4,
+                 .DebugInterruptVector.literal)
+  SECTION_VECTOR (_KernelExceptionVector_literal,
+                 .KernelExceptionVector.literal,
+                 XCHAL_KERNELEXC_VECTOR_VADDR - 4,
+                 SIZEOF(.DebugInterruptVector.text),
+                 .DebugInterruptVector.text)
+  SECTION_VECTOR (_KernelExceptionVector_text,
+                 .KernelExceptionVector.text,
+                 XCHAL_KERNELEXC_VECTOR_VADDR,
+                 4,
+                 .KernelExceptionVector.literal)
+  SECTION_VECTOR (_UserExceptionVector_literal,
+                 .UserExceptionVector.literal,
+                 XCHAL_USEREXC_VECTOR_VADDR - 4,
+                 SIZEOF(.KernelExceptionVector.text),
+                 .KernelExceptionVector.text)
+  SECTION_VECTOR (_UserExceptionVector_text,
+                 .UserExceptionVector.text,
+                 XCHAL_USEREXC_VECTOR_VADDR,
+                 4,
+                 .UserExceptionVector.literal)
+  SECTION_VECTOR (_DoubleExceptionVector_literal,
+                 .DoubleExceptionVector.literal,
+                 XCHAL_DOUBLEEXC_VECTOR_VADDR - 16,
+                 SIZEOF(.UserExceptionVector.text),
+                 .UserExceptionVector.text)
+  SECTION_VECTOR (_DoubleExceptionVector_text,
+                 .DoubleExceptionVector.text,
+                 XCHAL_DOUBLEEXC_VECTOR_VADDR,
+                 32,
+                 .DoubleExceptionVector.literal)
+
+  . = (LOADADDR( .DoubleExceptionVector.text ) + SIZEOF( .DoubleExceptionVector.text ) + 3) & ~ 3;
+  . = ALIGN(1<<XCHAL_MMU_MIN_PTE_PAGE_SIZE);
+
+  __init_end = .;
+
+  . = ALIGN(8192);
+
+  /* BSS section */
+  _bss_start = .;
+  .sbss : { *(.sbss) *(.scommon) }
+  .bss : { *(COMMON) *(.bss) }
+  _bss_end = .;
+  _end = .;
+
+  /* only used by the boot loader  */
+
+  . = ALIGN(0x10);
+  .bootstrap : { *(.bootstrap.literal .bootstrap.text .bootstrap.data) }
+
+  . = ALIGN(0x1000);
+  __initrd_start = .;
+  .initrd : { *(.initrd) }
+  __initrd_end = .;
+
+  .ResetVector.text XCHAL_RESET_VECTOR_VADDR :
+  {
+    *(.ResetVector.text)
+  }
+
+
+  /* Sections to be discarded */
+  /DISCARD/ :
+  {
+        *(.text.exit)
+       *(.text.exit.literal)
+        *(.data.exit)
+        *(.exitcall.exit)
+  }
+
+
+  .debug  0 :  { *(.debug) }
+  .line  0 :  { *(.line) }
+  .debug_srcinfo  0 :  { *(.debug_srcinfo) }
+  .debug_sfnames  0 :  { *(.debug_sfnames) }
+  .debug_aranges  0 :  { *(.debug_aranges) }
+  .debug_pubnames  0 :  { *(.debug_pubnames) }
+  .debug_info  0 :  { *(.debug_info) }
+  .debug_abbrev  0 :  { *(.debug_abbrev) }
+  .debug_line  0 :  { *(.debug_line) }
+  .debug_frame  0 :  { *(.debug_frame) }
+  .debug_str  0 :  { *(.debug_str) }
+  .debug_loc  0 :  { *(.debug_loc) }
+  .debug_macinfo  0 :  { *(.debug_macinfo) }
+  .debug_weaknames  0 :  { *(.debug_weaknames) }
+  .debug_funcnames  0 :  { *(.debug_funcnames) }
+  .debug_typenames  0 :  { *(.debug_typenames) }
+  .debug_varnames  0 :  { *(.debug_varnames) }
+
+  .xt.insn 0 :
+  {
+    *(.xt.insn)
+    *(.gnu.linkonce.x*)
+  }
+
+  .xt.lit 0 :
+  {
+    *(.xt.lit)
+    *(.gnu.linkonce.p*)
+  }
+}
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c
new file mode 100644 (file)
index 0000000..efae56a
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * arch/xtensa/kernel/xtensa_ksyms.c
+ *
+ * Export Xtensa-specific functions for loadable modules.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005  Tensilica Inc.
+ *
+ * Joe Taylor <joe@tensilica.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <linux/in6.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/semaphore.h>
+#ifdef CONFIG_BLK_DEV_FD
+#include <asm/floppy.h>
+#endif
+#ifdef CONFIG_NET
+#include <net/checksum.h>
+#endif /* CONFIG_NET */
+
+
+/*
+ * String functions
+ */
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memchr);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(strstr);
+
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(kernel_thread);
+
+/*
+ * gcc internal math functions
+ */
+extern long long __ashrdi3(long long, int);
+extern long long __ashldi3(long long, int);
+extern long long __lshrdi3(long long, int);
+extern int __divsi3(int, int);
+extern int __modsi3(int, int);
+extern long long __muldi3(long long, long long);
+extern int __mulsi3(int, int);
+extern unsigned int __udivsi3(unsigned int, unsigned int);
+extern unsigned int __umodsi3(unsigned int, unsigned int);
+extern unsigned long long __umoddi3(unsigned long long, unsigned long long);
+extern unsigned long long __udivdi3(unsigned long long, unsigned long long);
+
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__divsi3);
+EXPORT_SYMBOL(__modsi3);
+EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__mulsi3);
+EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(__umodsi3);
+EXPORT_SYMBOL(__udivdi3);
+EXPORT_SYMBOL(__umoddi3);
+
+/*
+ * Semaphore operations
+ */
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down_trylock);
+EXPORT_SYMBOL(__up);
+
+#ifdef CONFIG_NET
+/*
+ * Networking support
+ */
+EXPORT_SYMBOL(csum_partial_copy_generic);
+#endif /* CONFIG_NET */
+
+/*
+ * Architecture-specific symbols
+ */
+EXPORT_SYMBOL(__xtensa_copy_user);
+
+/*
+ * Kernel hacking ...
+ */
+
+#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
+// FIXME EXPORT_SYMBOL(screen_info);
+#endif
+
+EXPORT_SYMBOL(get_wchan);
+
+EXPORT_SYMBOL(outsb);
+EXPORT_SYMBOL(outsw);
+EXPORT_SYMBOL(outsl);
+EXPORT_SYMBOL(insb);
+EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(insl);
diff --git a/arch/xtensa/lib/Makefile b/arch/xtensa/lib/Makefile
new file mode 100644 (file)
index 0000000..ed935b5
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for Xtensa-specific library files.
+#
+
+lib-y  += memcopy.o memset.o checksum.o strcasecmp.o \
+          usercopy.o strncpy_user.o strnlen_user.o
+lib-$(CONFIG_PCI) += pci-auto.o
diff --git a/arch/xtensa/lib/checksum.S b/arch/xtensa/lib/checksum.S
new file mode 100644 (file)
index 0000000..e2d64df
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             IP/TCP/UDP checksumming routines
+ *
+ * Xtensa version:  Copyright (C) 2001 Tensilica, Inc. by Kevin Chea
+ *                  Optimized by Joe Taylor
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/errno.h>
+#include <linux/linkage.h>
+#define _ASMLANGUAGE
+#include <xtensa/config/core.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+/*
+ * unsigned int csum_partial(const unsigned char *buf, int len,
+ *                           unsigned int sum);
+ *    a2 = buf
+ *    a3 = len
+ *    a4 = sum
+ *
+ * This function assumes 2- or 4-byte alignment.  Other alignments will fail!
+ */
+
+/* ONES_ADD converts twos-complement math to ones-complement. */
+#define ONES_ADD(sum, val)       \
+       add     sum, sum, val   ; \
+       bgeu    sum, val, 99f   ; \
+       addi    sum, sum, 1     ; \
+99:                            ;
+
+.text
+ENTRY(csum_partial)
+         /*
+          * Experiments with Ethernet and SLIP connections show that buf
+          * is aligned on either a 2-byte or 4-byte boundary.
+          */
+       entry   sp, 32
+       extui   a5, a2, 0, 2
+       bnez    a5, 8f          /* branch if 2-byte aligned */
+       /* Fall-through on common case, 4-byte alignment */
+1:
+       srli    a5, a3, 5       /* 32-byte chunks */
+#if XCHAL_HAVE_LOOPS
+       loopgtz a5, 2f
+#else
+       beqz    a5, 2f
+       slli    a5, a5, 5
+       add     a5, a5, a2      /* a5 = end of last 32-byte chunk */
+.Loop1:
+#endif
+       l32i    a6, a2, 0
+       l32i    a7, a2, 4
+       ONES_ADD(a4, a6)
+       ONES_ADD(a4, a7)
+       l32i    a6, a2, 8
+       l32i    a7, a2, 12
+       ONES_ADD(a4, a6)
+       ONES_ADD(a4, a7)
+       l32i    a6, a2, 16
+       l32i    a7, a2, 20
+       ONES_ADD(a4, a6)
+       ONES_ADD(a4, a7)
+       l32i    a6, a2, 24
+       l32i    a7, a2, 28
+       ONES_ADD(a4, a6)
+       ONES_ADD(a4, a7)
+       addi    a2, a2, 4*8
+#if !XCHAL_HAVE_LOOPS
+       blt     a2, a5, .Loop1
+#endif
+2:
+       extui   a5, a3, 2, 3    /* remaining 4-byte chunks */
+#if XCHAL_HAVE_LOOPS
+       loopgtz a5, 3f
+#else
+       beqz    a5, 3f
+       slli    a5, a5, 2
+       add     a5, a5, a2      /* a5 = end of last 4-byte chunk */
+.Loop2:
+#endif
+       l32i    a6, a2, 0
+       ONES_ADD(a4, a6)
+       addi    a2, a2, 4
+#if !XCHAL_HAVE_LOOPS
+       blt     a2, a5, .Loop2
+#endif
+3:
+       _bbci.l a3, 1, 5f       /* remaining 2-byte chunk */
+       l16ui   a6, a2, 0
+       ONES_ADD(a4, a6)
+       addi    a2, a2, 2
+5:
+       _bbci.l a3, 0, 7f       /* remaining 1-byte chunk */
+6:     l8ui    a6, a2, 0
+#ifdef __XTENSA_EB__
+       slli    a6, a6, 8       /* load byte into bits 8..15 */
+#endif
+       ONES_ADD(a4, a6)
+7:
+       mov     a2, a4
+       retw
+
+       /* uncommon case, buf is 2-byte aligned */
+8:
+       beqz    a3, 7b          /* branch if len == 0 */
+       beqi    a3, 1, 6b       /* branch if len == 1 */
+
+       extui   a5, a2, 0, 1
+       bnez    a5, 8f          /* branch if 1-byte aligned */
+
+       l16ui   a6, a2, 0       /* common case, len >= 2 */
+       ONES_ADD(a4, a6)
+       addi    a2, a2, 2       /* adjust buf */
+       addi    a3, a3, -2      /* adjust len */
+       j       1b              /* now buf is 4-byte aligned */
+
+       /* case: odd-byte aligned, len > 1
+        * This case is dog slow, so don't give us an odd address.
+        * (I don't think this ever happens, but just in case.)
+        */
+8:
+       srli    a5, a3, 2       /* 4-byte chunks */
+#if XCHAL_HAVE_LOOPS
+       loopgtz a5, 2f
+#else
+       beqz    a5, 2f
+       slli    a5, a5, 2
+       add     a5, a5, a2      /* a5 = end of last 4-byte chunk */
+.Loop3:
+#endif
+       l8ui    a6, a2, 0       /* bits 24..31 */
+       l16ui   a7, a2, 1       /* bits  8..23 */
+       l8ui    a8, a2, 3       /* bits  0.. 8 */
+#ifdef __XTENSA_EB__
+       slli    a6, a6, 24
+#else
+       slli    a8, a8, 24
+#endif
+       slli    a7, a7, 8
+       or      a7, a7, a6
+       or      a7, a7, a8
+       ONES_ADD(a4, a7)
+       addi    a2, a2, 4
+#if !XCHAL_HAVE_LOOPS
+       blt     a2, a5, .Loop3
+#endif
+2:
+       _bbci.l a3, 1, 3f       /* remaining 2-byte chunk, still odd addr */
+       l8ui    a6, a2, 0
+       l8ui    a7, a2, 1
+#ifdef __XTENSA_EB__
+       slli    a6, a6, 8
+#else
+       slli    a7, a7, 8
+#endif
+       or      a7, a7, a6
+       ONES_ADD(a4, a7)
+       addi    a2, a2, 2
+3:
+       j       5b              /* branch to handle the remaining byte */
+
+
+
+/*
+ * Copy from ds while checksumming, otherwise like csum_partial
+ *
+ * The macros SRC and DST specify the type of access for the instruction.
+ * thus we can call a custom exception handler for each access type.
+ */
+
+#define SRC(y...)                      \
+       9999: y;                        \
+       .section __ex_table, "a";       \
+       .long 9999b, 6001f      ;       \
+       .previous
+
+#define DST(y...)                      \
+       9999: y;                        \
+       .section __ex_table, "a";       \
+       .long 9999b, 6002f      ;       \
+       .previous
+
+/*
+unsigned int csum_partial_copy_generic (const char *src, char *dst, int len,
+                                       int sum, int *src_err_ptr, int *dst_err_ptr)
+       a2  = src
+       a3  = dst
+       a4  = len
+       a5  = sum
+       a6  = src_err_ptr
+       a7  = dst_err_ptr
+       a8  = temp
+       a9  = temp
+       a10 = temp
+       a11 = original len for exception handling
+       a12 = original dst for exception handling
+
+    This function is optimized for 4-byte aligned addresses.  Other
+    alignments work, but not nearly as efficiently.
+ */
+
+ENTRY(csum_partial_copy_generic)
+       entry   sp, 32
+       mov     a12, a3
+       mov     a11, a4
+       or      a10, a2, a3
+
+       /* We optimize the following alignment tests for the 4-byte
+       aligned case.  Two bbsi.l instructions might seem more optimal
+       (commented out below).  However, both labels 5: and 3: are out
+       of the imm8 range, so the assembler relaxes them into
+       equivalent bbci.l, j combinations, which is actually
+       slower. */
+
+       extui   a9, a10, 0, 2
+       beqz    a9, 1f          /* branch if both are 4-byte aligned */
+       bbsi.l  a10, 0, 5f      /* branch if one address is odd */
+       j       3f              /* one address is 2-byte aligned */
+
+/*     _bbsi.l a10, 0, 5f */   /* branch if odd address */
+/*     _bbsi.l a10, 1, 3f */   /* branch if 2-byte-aligned address */
+
+1:
+       /* src and dst are both 4-byte aligned */
+       srli    a10, a4, 5      /* 32-byte chunks */
+#if XCHAL_HAVE_LOOPS
+       loopgtz a10, 2f
+#else
+       beqz    a10, 2f
+       slli    a10, a10, 5
+       add     a10, a10, a2    /* a10 = end of last 32-byte src chunk */
+.Loop5:
+#endif
+SRC(   l32i    a9, a2, 0       )
+SRC(   l32i    a8, a2, 4       )
+DST(   s32i    a9, a3, 0       )
+DST(   s32i    a8, a3, 4       )
+       ONES_ADD(a5, a9)
+       ONES_ADD(a5, a8)
+SRC(   l32i    a9, a2, 8       )
+SRC(   l32i    a8, a2, 12      )
+DST(   s32i    a9, a3, 8       )
+DST(   s32i    a8, a3, 12      )
+       ONES_ADD(a5, a9)
+       ONES_ADD(a5, a8)
+SRC(   l32i    a9, a2, 16      )
+SRC(   l32i    a8, a2, 20      )
+DST(   s32i    a9, a3, 16      )
+DST(   s32i    a8, a3, 20      )
+       ONES_ADD(a5, a9)
+       ONES_ADD(a5, a8)
+SRC(   l32i    a9, a2, 24      )
+SRC(   l32i    a8, a2, 28      )
+DST(   s32i    a9, a3, 24      )
+DST(   s32i    a8, a3, 28      )
+       ONES_ADD(a5, a9)
+       ONES_ADD(a5, a8)
+       addi    a2, a2, 32
+       addi    a3, a3, 32
+#if !XCHAL_HAVE_LOOPS
+       blt     a2, a10, .Loop5
+#endif
+2:
+       extui   a10, a4, 2, 3   /* remaining 4-byte chunks */
+       extui   a4, a4, 0, 2    /* reset len for general-case, 2-byte chunks */
+#if XCHAL_HAVE_LOOPS
+       loopgtz a10, 3f
+#else
+       beqz    a10, 3f
+       slli    a10, a10, 2
+       add     a10, a10, a2    /* a10 = end of last 4-byte src chunk */
+.Loop6:
+#endif
+SRC(   l32i    a9, a2, 0       )
+DST(   s32i    a9, a3, 0       )
+       ONES_ADD(a5, a9)
+       addi    a2, a2, 4
+       addi    a3, a3, 4
+#if !XCHAL_HAVE_LOOPS
+       blt     a2, a10, .Loop6
+#endif
+3:
+       /*
+       Control comes to here in two cases: (1) It may fall through
+       to here from the 4-byte alignment case to process, at most,
+       one 2-byte chunk.  (2) It branches to here from above if
+       either src or dst is 2-byte aligned, and we process all bytes
+       here, except for perhaps a trailing odd byte.  It's
+       inefficient, so align your addresses to 4-byte boundaries.
+
+       a2 = src
+       a3 = dst
+       a4 = len
+       a5 = sum
+       */
+       srli    a10, a4, 1      /* 2-byte chunks */
+#if XCHAL_HAVE_LOOPS
+       loopgtz a10, 4f
+#else
+       beqz    a10, 4f
+       slli    a10, a10, 1
+       add     a10, a10, a2    /* a10 = end of last 2-byte src chunk */
+.Loop7:
+#endif
+SRC(   l16ui   a9, a2, 0       )
+DST(   s16i    a9, a3, 0       )
+       ONES_ADD(a5, a9)
+       addi    a2, a2, 2
+       addi    a3, a3, 2
+#if !XCHAL_HAVE_LOOPS
+       blt     a2, a10, .Loop7
+#endif
+4:
+       /* This section processes a possible trailing odd byte. */
+       _bbci.l a4, 0, 8f       /* 1-byte chunk */
+SRC(   l8ui    a9, a2, 0       )
+DST(   s8i     a9, a3, 0       )
+#ifdef __XTENSA_EB__
+       slli    a9, a9, 8       /* shift byte to bits 8..15 */
+#endif
+       ONES_ADD(a5, a9)
+8:
+       mov     a2, a5
+       retw
+
+5:
+       /* Control branch to here when either src or dst is odd.  We
+       process all bytes using 8-bit accesses.  Grossly inefficient,
+       so don't feed us an odd address. */
+
+       srli    a10, a4, 1      /* handle in pairs for 16-bit csum */
+#if XCHAL_HAVE_LOOPS
+       loopgtz a10, 6f
+#else
+       beqz    a10, 6f
+       slli    a10, a10, 1
+       add     a10, a10, a2    /* a10 = end of last odd-aligned, 2-byte src chunk */
+.Loop8:
+#endif
+SRC(   l8ui    a9, a2, 0       )
+SRC(   l8ui    a8, a2, 1       )
+DST(   s8i     a9, a3, 0       )
+DST(   s8i     a8, a3, 1       )
+#ifdef __XTENSA_EB__
+       slli    a9, a9, 8       /* combine into a single 16-bit value */
+#else                          /* for checksum computation */
+       slli    a8, a8, 8
+#endif
+       or      a9, a9, a8
+       ONES_ADD(a5, a9)
+       addi    a2, a2, 2
+       addi    a3, a3, 2
+#if !XCHAL_HAVE_LOOPS
+       blt     a2, a10, .Loop8
+#endif
+6:
+       j       4b              /* process the possible trailing odd byte */
+
+
+# Exception handler:
+.section .fixup, "ax"
+/*
+       a6  = src_err_ptr
+       a7  = dst_err_ptr
+       a11 = original len for exception handling
+       a12 = original dst for exception handling
+*/
+
+6001:
+       _movi   a2, -EFAULT
+       s32i    a2, a6, 0       /* src_err_ptr */
+
+       # clear the complete destination - computing the rest
+       # is too much work
+       movi    a2, 0
+#if XCHAL_HAVE_LOOPS
+       loopgtz a11, 2f
+#else
+       beqz    a11, 2f
+       add     a11, a11, a12   /* a11 = ending address */
+.Leloop:
+#endif
+       s8i     a2, a12, 0
+       addi    a12, a12, 1
+#if !XCHAL_HAVE_LOOPS
+       blt     a12, a11, .Leloop
+#endif
+2:
+       retw
+
+6002:
+       movi    a2, -EFAULT
+       s32i    a2, a7, 0       /* dst_err_ptr */
+       movi    a2, 0
+       retw
+
+.previous
+
diff --git a/arch/xtensa/lib/memcopy.S b/arch/xtensa/lib/memcopy.S
new file mode 100644 (file)
index 0000000..e8f6d7e
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * arch/xtensa/lib/hal/memcopy.S -- Core HAL library functions
+ * xthal_memcpy and xthal_bcopy
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002 - 2005 Tensilica Inc.
+ */
+
+#include <xtensa/coreasm.h>
+
+       .macro  src_b   r, w0, w1
+#ifdef __XTENSA_EB__
+       src     \r, \w0, \w1
+#else
+       src     \r, \w1, \w0
+#endif
+       .endm
+
+       .macro  ssa8    r
+#ifdef __XTENSA_EB__
+       ssa8b   \r
+#else
+       ssa8l   \r
+#endif
+       .endm
+
+
+/*
+ * void *memcpy(void *dst, const void *src, size_t len);
+ * void *memmove(void *dst, const void *src, size_t len);
+ * void *bcopy(const void *src, void *dst, size_t len);
+ *
+ * This function is intended to do the same thing as the standard
+ * library function memcpy() (or bcopy()) for most cases.
+ * However, where the source and/or destination references
+ * an instruction RAM or ROM or a data RAM or ROM, that
+ * source and/or destination will always be accessed with
+ * 32-bit load and store instructions (as required for these
+ * types of devices).
+ *
+ * !!!!!!!  XTFIXME:
+ * !!!!!!!  Handling of IRAM/IROM has not yet
+ * !!!!!!!  been implemented.
+ *
+ * The bcopy version is provided here to avoid the overhead
+ * of an extra call, for callers that require this convention.
+ *
+ * The (general case) algorithm is as follows:
+ *   If destination is unaligned, align it by conditionally
+ *     copying 1 and 2 bytes.
+ *   If source is aligned,
+ *     do 16 bytes with a loop, and then finish up with
+ *     8, 4, 2, and 1 byte copies conditional on the length;
+ *   else (if source is unaligned),
+ *     do the same, but use SRC to align the source data.
+ *   This code tries to use fall-through branches for the common
+ *     case of aligned source and destination and multiple
+ *     of 4 (or 8) length.
+ *
+ * Register use:
+ *     a0/ return address
+ *     a1/ stack pointer
+ *     a2/ return value
+ *     a3/ src
+ *     a4/ length
+ *     a5/ dst
+ *     a6/ tmp
+ *     a7/ tmp
+ *     a8/ tmp
+ *     a9/ tmp
+ *     a10/ tmp
+ *     a11/ tmp
+ */
+
+       .text
+       .align  4
+       .global bcopy
+       .type   bcopy,@function
+bcopy:
+       entry   sp, 16          # minimal stack frame
+       # a2=src, a3=dst, a4=len
+       mov     a5, a3          # copy dst so that a2 is return value
+       mov     a3, a2
+       mov     a2, a5
+       j       .Lcommon        # go to common code for memcpy+bcopy
+
+
+/*
+ * Byte by byte copy
+ */
+       .align  4
+       .byte   0               # 1 mod 4 alignment for LOOPNEZ
+                               # (0 mod 4 alignment for LBEG)
+.Lbytecopy:
+#if XCHAL_HAVE_LOOPS
+       loopnez a4, .Lbytecopydone
+#else /* !XCHAL_HAVE_LOOPS */
+       beqz    a4, .Lbytecopydone
+       add     a7, a3, a4      # a7 = end address for source
+#endif /* !XCHAL_HAVE_LOOPS */
+.Lnextbyte:
+       l8ui    a6, a3, 0
+       addi    a3, a3, 1
+       s8i     a6, a5, 0
+       addi    a5, a5, 1
+#if !XCHAL_HAVE_LOOPS
+       blt     a3, a7, .Lnextbyte
+#endif /* !XCHAL_HAVE_LOOPS */
+.Lbytecopydone:
+       retw
+
+/*
+ * Destination is unaligned
+ */
+
+       .align  4
+.Ldst1mod2:    # dst is only byte aligned
+       _bltui  a4, 7, .Lbytecopy       # do short copies byte by byte
+
+       # copy 1 byte
+       l8ui    a6, a3,  0
+       addi    a3, a3,  1
+       addi    a4, a4, -1
+       s8i     a6, a5,  0
+       addi    a5, a5,  1
+       _bbci.l a5, 1, .Ldstaligned     # if dst is now aligned, then
+                                       # return to main algorithm
+.Ldst2mod4:    # dst 16-bit aligned
+       # copy 2 bytes
+       _bltui  a4, 6, .Lbytecopy       # do short copies byte by byte
+       l8ui    a6, a3,  0
+       l8ui    a7, a3,  1
+       addi    a3, a3,  2
+       addi    a4, a4, -2
+       s8i     a6, a5,  0
+       s8i     a7, a5,  1
+       addi    a5, a5,  2
+       j       .Ldstaligned    # dst is now aligned, return to main algorithm
+
+       .align  4
+       .global memcpy
+       .type   memcpy,@function
+memcpy:
+       .global memmove
+       .type   memmove,@function
+memmove:
+
+       entry   sp, 16          # minimal stack frame
+       # a2/ dst, a3/ src, a4/ len
+       mov     a5, a2          # copy dst so that a2 is return value
+.Lcommon:
+       _bbsi.l a2, 0, .Ldst1mod2       # if dst is 1 mod 2
+       _bbsi.l a2, 1, .Ldst2mod4       # if dst is 2 mod 4
+.Ldstaligned:  # return here from .Ldst?mod? once dst is aligned
+       srli    a7, a4, 4       # number of loop iterations with 16B
+                               # per iteration
+       movi    a8, 3           # if source is not aligned,
+       _bany   a3, a8, .Lsrcunaligned  # then use shifting copy
+       /*
+        * Destination and source are word-aligned, use word copy.
+        */
+       # copy 16 bytes per iteration for word-aligned dst and word-aligned src
+#if XCHAL_HAVE_LOOPS
+       loopnez a7, .Loop1done
+#else /* !XCHAL_HAVE_LOOPS */
+       beqz    a7, .Loop1done
+       slli    a8, a7, 4
+       add     a8, a8, a3      # a8 = end of last 16B source chunk
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop1:
+       l32i    a6, a3,  0
+       l32i    a7, a3,  4
+       s32i    a6, a5,  0
+       l32i    a6, a3,  8
+       s32i    a7, a5,  4
+       l32i    a7, a3, 12
+       s32i    a6, a5,  8
+       addi    a3, a3, 16
+       s32i    a7, a5, 12
+       addi    a5, a5, 16
+#if !XCHAL_HAVE_LOOPS
+       blt     a3, a8, .Loop1
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop1done:
+       bbci.l  a4, 3, .L2
+       # copy 8 bytes
+       l32i    a6, a3,  0
+       l32i    a7, a3,  4
+       addi    a3, a3,  8
+       s32i    a6, a5,  0
+       s32i    a7, a5,  4
+       addi    a5, a5,  8
+.L2:
+       bbsi.l  a4, 2, .L3
+       bbsi.l  a4, 1, .L4
+       bbsi.l  a4, 0, .L5
+       retw
+.L3:
+       # copy 4 bytes
+       l32i    a6, a3,  0
+       addi    a3, a3,  4
+       s32i    a6, a5,  0
+       addi    a5, a5,  4
+       bbsi.l  a4, 1, .L4
+       bbsi.l  a4, 0, .L5
+       retw
+.L4:
+       # copy 2 bytes
+       l16ui   a6, a3,  0
+       addi    a3, a3,  2
+       s16i    a6, a5,  0
+       addi    a5, a5,  2
+       bbsi.l  a4, 0, .L5
+       retw
+.L5:
+       # copy 1 byte
+       l8ui    a6, a3,  0
+       s8i     a6, a5,  0
+       retw
+
+/*
+ * Destination is aligned, Source is unaligned
+ */
+
+       .align  4
+.Lsrcunaligned:
+       _beqz   a4, .Ldone      # avoid loading anything for zero-length copies
+       # copy 16 bytes per iteration for word-aligned dst and unaligned src
+       ssa8    a3              # set shift amount from byte offset
+#define SIM_CHECKS_ALIGNMENT   1       /* set to 1 when running on ISS (simulator) with the
+                                          lint or ferret client, or 0 to save a few cycles */
+#if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT
+       and     a11, a3, a8     # save unalignment offset for below
+       sub     a3, a3, a11     # align a3
+#endif
+       l32i    a6, a3, 0       # load first word
+#if XCHAL_HAVE_LOOPS
+       loopnez a7, .Loop2done
+#else /* !XCHAL_HAVE_LOOPS */
+       beqz    a7, .Loop2done
+       slli    a10, a7, 4
+       add     a10, a10, a3    # a10 = end of last 16B source chunk
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop2:
+       l32i    a7, a3,  4
+       l32i    a8, a3,  8
+       src_b   a6, a6, a7
+       s32i    a6, a5,  0
+       l32i    a9, a3, 12
+       src_b   a7, a7, a8
+       s32i    a7, a5,  4
+       l32i    a6, a3, 16
+       src_b   a8, a8, a9
+       s32i    a8, a5,  8
+       addi    a3, a3, 16
+       src_b   a9, a9, a6
+       s32i    a9, a5, 12
+       addi    a5, a5, 16
+#if !XCHAL_HAVE_LOOPS
+       blt     a3, a10, .Loop2
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop2done:
+       bbci.l  a4, 3, .L12
+       # copy 8 bytes
+       l32i    a7, a3,  4
+       l32i    a8, a3,  8
+       src_b   a6, a6, a7
+       s32i    a6, a5,  0
+       addi    a3, a3,  8
+       src_b   a7, a7, a8
+       s32i    a7, a5,  4
+       addi    a5, a5,  8
+       mov     a6, a8
+.L12:
+       bbci.l  a4, 2, .L13
+       # copy 4 bytes
+       l32i    a7, a3,  4
+       addi    a3, a3,  4
+       src_b   a6, a6, a7
+       s32i    a6, a5,  0
+       addi    a5, a5,  4
+       mov     a6, a7
+.L13:
+#if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT
+       add     a3, a3, a11     # readjust a3 with correct misalignment
+#endif
+       bbsi.l  a4, 1, .L14
+       bbsi.l  a4, 0, .L15
+.Ldone:        retw
+.L14:
+       # copy 2 bytes
+       l8ui    a6, a3,  0
+       l8ui    a7, a3,  1
+       addi    a3, a3,  2
+       s8i     a6, a5,  0
+       s8i     a7, a5,  1
+       addi    a5, a5,  2
+       bbsi.l  a4, 0, .L15
+       retw
+.L15:
+       # copy 1 byte
+       l8ui    a6, a3,  0
+       s8i     a6, a5,  0
+       retw
+\f
+/*
+ * Local Variables:
+ * mode:fundamental
+ * comment-start: "# "
+ * comment-start-skip: "# *"
+ * End:
+ */
diff --git a/arch/xtensa/lib/memset.S b/arch/xtensa/lib/memset.S
new file mode 100644 (file)
index 0000000..4de2513
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ *  arch/xtensa/lib/memset.S
+ *
+ *  ANSI C standard library function memset
+ *  (Well, almost.  .fixup code might return zero.)
+ *
+ *  This file is subject to the terms and conditions of the GNU General
+ *  Public License.  See the file "COPYING" in the main directory of
+ *  this archive for more details.
+ *
+ *  Copyright (C) 2002 Tensilica Inc.
+ */
+
+#include <xtensa/coreasm.h>
+
+/*
+ * void *memset(void *dst, int c, size_t length)
+ *
+ * The algorithm is as follows:
+ *   Create a word with c in all byte positions
+ *   If the destination is aligned,
+ *     do 16B chucks with a loop, and then finish up with
+ *     8B, 4B, 2B, and 1B stores conditional on the length.
+ *   If destination is unaligned, align it by conditionally
+ *     setting 1B and 2B and then go to aligned case.
+ *   This code tries to use fall-through branches for the common
+ *     case of an aligned destination (except for the branches to
+ *     the alignment labels).
+ */
+
+/* Load or store instructions that may cause exceptions use the EX macro. */
+
+#define EX(insn,reg1,reg2,offset,handler)      \
+9:     insn    reg1, reg2, offset;             \
+       .section __ex_table, "a";               \
+       .word   9b, handler;                    \
+       .previous
+
+
+.text
+.align 4
+.global        memset
+.type  memset,@function
+memset:
+       entry   sp, 16          # minimal stack frame
+       # a2/ dst, a3/ c, a4/ length
+       extui   a3, a3, 0, 8    # mask to just 8 bits
+       slli    a7, a3, 8       # duplicate character in all bytes of word
+       or      a3, a3, a7      # ...
+       slli    a7, a3, 16      # ...
+       or      a3, a3, a7      # ...
+       mov     a5, a2          # copy dst so that a2 is return value
+       movi    a6, 3           # for alignment tests
+       bany    a2, a6, .Ldstunaligned # if dst is unaligned
+.L0:   # return here from .Ldstunaligned when dst is aligned
+       srli    a7, a4, 4       # number of loop iterations with 16B
+                               # per iteration
+       bnez    a4, .Laligned
+       retw
+
+/*
+ * Destination is word-aligned.
+ */
+       # set 16 bytes per iteration for word-aligned dst
+       .align  4               # 1 mod 4 alignment for LOOPNEZ
+       .byte   0               # (0 mod 4 alignment for LBEG)
+.Laligned:
+#if XCHAL_HAVE_LOOPS
+       loopnez a7, .Loop1done
+#else /* !XCHAL_HAVE_LOOPS */
+       beqz    a7, .Loop1done
+       slli    a6, a7, 4
+       add     a6, a6, a5      # a6 = end of last 16B chunk
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop1:
+       EX(s32i, a3, a5,  0, memset_fixup)
+       EX(s32i, a3, a5,  4, memset_fixup)
+       EX(s32i, a3, a5,  8, memset_fixup)
+       EX(s32i, a3, a5, 12, memset_fixup)
+       addi    a5, a5, 16
+#if !XCHAL_HAVE_LOOPS
+       blt     a5, a6, .Loop1
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop1done:
+       bbci.l  a4, 3, .L2
+       # set 8 bytes
+       EX(s32i, a3, a5,  0, memset_fixup)
+       EX(s32i, a3, a5,  4, memset_fixup)
+       addi    a5, a5,  8
+.L2:
+       bbci.l  a4, 2, .L3
+       # set 4 bytes
+       EX(s32i, a3, a5,  0, memset_fixup)
+       addi    a5, a5,  4
+.L3:
+       bbci.l  a4, 1, .L4
+       # set 2 bytes
+       EX(s16i, a3, a5,  0, memset_fixup)
+       addi    a5, a5,  2
+.L4:
+       bbci.l  a4, 0, .L5
+       # set 1 byte
+       EX(s8i, a3, a5,  0, memset_fixup)
+.L5:
+.Lret1:
+       retw
+
+/*
+ * Destination is unaligned
+ */
+
+.Ldstunaligned:
+       bltui   a4, 8, .Lbyteset        # do short copies byte by byte
+       bbci.l  a5, 0, .L20             # branch if dst alignment half-aligned
+       # dst is only byte aligned
+       # set 1 byte
+       EX(s8i, a3, a5,  0, memset_fixup)
+       addi    a5, a5,  1
+       addi    a4, a4, -1
+       # now retest if dst aligned
+       bbci.l  a5, 1, .L0      # if now aligned, return to main algorithm
+.L20:
+       # dst half-aligned
+       # set 2 bytes
+       EX(s16i, a3, a5,  0, memset_fixup)
+       addi    a5, a5,  2
+       addi    a4, a4, -2
+       j       .L0             # dst is now aligned, return to main algorithm
+
+/*
+ * Byte by byte set
+ */
+       .align  4
+       .byte   0               # 1 mod 4 alignment for LOOPNEZ
+                               # (0 mod 4 alignment for LBEG)
+.Lbyteset:
+#if XCHAL_HAVE_LOOPS
+       loopnez a4, .Lbytesetdone
+#else /* !XCHAL_HAVE_LOOPS */
+       beqz    a4, .Lbytesetdone
+       add     a6, a5, a4      # a6 = ending address
+#endif /* !XCHAL_HAVE_LOOPS */
+.Lbyteloop:
+       EX(s8i, a3, a5, 0, memset_fixup)
+       addi    a5, a5, 1
+#if !XCHAL_HAVE_LOOPS
+       blt     a5, a6, .Lbyteloop
+#endif /* !XCHAL_HAVE_LOOPS */
+.Lbytesetdone:
+       retw
+
+
+       .section .fixup, "ax"
+       .align  4
+
+/* We return zero if a failure occurred. */
+
+memset_fixup:
+       movi    a2, 0
+       retw
diff --git a/arch/xtensa/lib/pci-auto.c b/arch/xtensa/lib/pci-auto.c
new file mode 100644 (file)
index 0000000..90c790f
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * arch/xtensa/kernel/pci-auto.c
+ *
+ * PCI autoconfiguration library
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <zankel@tensilica.com, cez@zankel.net>
+ *
+ * Based on work from Matt Porter <mporter@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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/pci-bridge.h>
+
+
+/*
+ *
+ * Setting up a PCI
+ *
+ * pci_ctrl->first_busno = <first bus number (0)>
+ * pci_ctrl->last_busno = <last bus number (0xff)>
+ * pci_ctrl->ops = <PCI config operations>
+ * pci_ctrl->map_irq = <function to return the interrupt number for a device>
+ *
+ * pci_ctrl->io_space.start = <IO space start address (PCI view)>
+ * pci_ctrl->io_space.end = <IO space end address (PCI view)>
+ * pci_ctrl->io_space.base = <IO space offset: address 0 from CPU space>
+ * pci_ctrl->mem_space.start = <MEM space start address (PCI view)>
+ * pci_ctrl->mem_space.end = <MEM space end address (PCI view)>
+ * pci_ctrl->mem_space.base = <MEM space offset: address 0 from CPU space>
+ *
+ * pcibios_init_resource(&pci_ctrl->io_resource, <IO space start>,
+ *                      <IO space end>, IORESOURCE_IO, "PCI host bridge");
+ * pcibios_init_resource(&pci_ctrl->mem_resources[0], <MEM space start>,
+ *                      <MEM space end>, IORESOURCE_MEM, "PCI host bridge");
+ *
+ * pci_ctrl->last_busno = pciauto_bus_scan(pci_ctrl,pci_ctrl->first_busno);
+ *
+ * int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus)
+ *
+ */
+
+
+/* define DEBUG to print some debugging messages. */
+
+#undef DEBUG
+
+#ifdef DEBUG
+# define DBG(x...) printk(x)
+#else
+# define DBG(x...)
+#endif
+
+static int pciauto_upper_iospc;
+static int pciauto_upper_memspc;
+
+static struct pci_dev pciauto_dev;
+static struct pci_bus pciauto_bus;
+
+/*
+ * Helper functions
+ */
+
+/* Initialize the bars of a PCI device.  */
+
+static void __init
+pciauto_setup_bars(struct pci_dev *dev, int bar_limit)
+{
+       int bar_size;
+       int bar, bar_nr;
+       int *upper_limit;
+       int found_mem64 = 0;
+
+       for (bar = PCI_BASE_ADDRESS_0, bar_nr = 0;
+            bar <= bar_limit;
+            bar+=4, bar_nr++)
+       {
+               /* Tickle the BAR and get the size */
+               pci_write_config_dword(dev, bar, 0xffffffff);
+               pci_read_config_dword(dev, bar, &bar_size);
+
+               /* If BAR is not implemented go to the next BAR */
+               if (!bar_size)
+                       continue;
+
+               /* Check the BAR type and set our address mask */
+               if (bar_size & PCI_BASE_ADDRESS_SPACE_IO)
+               {
+                       bar_size &= PCI_BASE_ADDRESS_IO_MASK;
+                       upper_limit = &pciauto_upper_iospc;
+                       DBG("PCI Autoconfig: BAR %d, I/O, ", bar_nr);
+               }
+               else
+               {
+                       if ((bar_size & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+                           PCI_BASE_ADDRESS_MEM_TYPE_64)
+                               found_mem64 = 1;
+
+                       bar_size &= PCI_BASE_ADDRESS_MEM_MASK;
+                       upper_limit = &pciauto_upper_memspc;
+                       DBG("PCI Autoconfig: BAR %d, Mem, ", bar_nr);
+               }
+
+               /* Allocate a base address (bar_size is negative!) */
+               *upper_limit = (*upper_limit + bar_size) & bar_size;
+
+               /* Write it out and update our limit */
+               pci_write_config_dword(dev, bar, *upper_limit);
+
+               /*
+                * If we are a 64-bit decoder then increment to the
+                * upper 32 bits of the bar and force it to locate
+                * in the lower 4GB of memory.
+                */
+
+               if (found_mem64)
+                       pci_write_config_dword(dev, (bar+=4), 0x00000000);
+
+               DBG("size=0x%x, address=0x%x\n", ~bar_size + 1, *upper_limit);
+       }
+}
+
+/* Initialize the interrupt number. */
+
+static void __init
+pciauto_setup_irq(struct pci_controller* pci_ctrl,struct pci_dev *dev,int devfn)
+{
+       u8 pin;
+       int irq = 0;
+
+       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+
+       /* Fix illegal pin numbers. */
+
+       if (pin == 0 || pin > 4)
+               pin = 1;
+
+       if (pci_ctrl->map_irq)
+               irq = pci_ctrl->map_irq(dev, PCI_SLOT(devfn), pin);
+
+       if (irq == -1)
+               irq = 0;
+
+       DBG("PCI Autoconfig: Interrupt %d, pin %d\n", irq, pin);
+
+       pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+
+static void __init
+pciauto_prescan_setup_bridge(struct pci_dev *dev, int current_bus,
+                            int sub_bus, int *iosave, int *memsave)
+{
+       /* Configure bus number registers */
+       pci_write_config_byte(dev, PCI_PRIMARY_BUS, current_bus);
+       pci_write_config_byte(dev, PCI_SECONDARY_BUS, sub_bus + 1);
+       pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, 0xff);
+
+       /* Round memory allocator to 1MB boundary */
+       pciauto_upper_memspc &= ~(0x100000 - 1);
+       *memsave = pciauto_upper_memspc;
+
+       /* Round I/O allocator to 4KB boundary */
+       pciauto_upper_iospc &= ~(0x1000 - 1);
+       *iosave = pciauto_upper_iospc;
+
+       /* Set up memory and I/O filter limits, assume 32-bit I/O space */
+       pci_write_config_word(dev, PCI_MEMORY_LIMIT,
+                             ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
+       pci_write_config_byte(dev, PCI_IO_LIMIT,
+                             ((pciauto_upper_iospc - 1) & 0x0000f000) >> 8);
+       pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16,
+                             ((pciauto_upper_iospc - 1) & 0xffff0000) >> 16);
+}
+
+static void __init
+pciauto_postscan_setup_bridge(struct pci_dev *dev, int current_bus, int sub_bus,
+                             int *iosave, int *memsave)
+{
+       int cmdstat;
+
+       /* Configure bus number registers */
+       pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, sub_bus);
+
+       /*
+        * Round memory allocator to 1MB boundary.
+        * If no space used, allocate minimum.
+        */
+       pciauto_upper_memspc &= ~(0x100000 - 1);
+       if (*memsave == pciauto_upper_memspc)
+               pciauto_upper_memspc -= 0x00100000;
+
+       pci_write_config_word(dev, PCI_MEMORY_BASE, pciauto_upper_memspc >> 16);
+
+       /* Allocate 1MB for pre-fretch */
+       pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT,
+                             ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
+
+       pciauto_upper_memspc -= 0x100000;
+
+       pci_write_config_word(dev, PCI_PREF_MEMORY_BASE,
+                             pciauto_upper_memspc >> 16);
+
+       /* Round I/O allocator to 4KB boundary */
+       pciauto_upper_iospc &= ~(0x1000 - 1);
+       if (*iosave == pciauto_upper_iospc)
+               pciauto_upper_iospc -= 0x1000;
+
+       pci_write_config_byte(dev, PCI_IO_BASE,
+                             (pciauto_upper_iospc & 0x0000f000) >> 8);
+       pci_write_config_word(dev, PCI_IO_BASE_UPPER16,
+                             pciauto_upper_iospc >> 16);
+
+       /* Enable memory and I/O accesses, enable bus master */
+       pci_read_config_dword(dev, PCI_COMMAND, &cmdstat);
+       pci_write_config_dword(dev, PCI_COMMAND,
+                              cmdstat |
+                              PCI_COMMAND_IO |
+                              PCI_COMMAND_MEMORY |
+                              PCI_COMMAND_MASTER);
+}
+
+/*
+ * Scan the current PCI bus.
+ */
+
+
+int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus)
+{
+       int sub_bus, pci_devfn, pci_class, cmdstat, found_multi=0;
+       unsigned short vid;
+       unsigned char header_type;
+       struct pci_dev *dev = &pciauto_dev;
+
+        pciauto_dev.bus = &pciauto_bus;
+        pciauto_dev.sysdata = pci_ctrl;
+       pciauto_bus.ops = pci_ctrl->ops;
+
+       /*
+        * Fetch our I/O and memory space upper boundaries used
+        * to allocated base addresses on this pci_controller.
+        */
+
+       if (current_bus == pci_ctrl->first_busno)
+       {
+               pciauto_upper_iospc = pci_ctrl->io_resource.end + 1;
+               pciauto_upper_memspc = pci_ctrl->mem_resources[0].end + 1;
+       }
+
+       sub_bus = current_bus;
+
+       for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++)
+       {
+               /* Skip our host bridge */
+               if ((current_bus == pci_ctrl->first_busno) && (pci_devfn == 0))
+                       continue;
+
+               if (PCI_FUNC(pci_devfn) && !found_multi)
+                       continue;
+
+               pciauto_bus.number = current_bus;
+               pciauto_dev.devfn = pci_devfn;
+
+               /* If config space read fails from this device, move on */
+               if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type))
+                       continue;
+
+               if (!PCI_FUNC(pci_devfn))
+                       found_multi = header_type & 0x80;
+               pci_read_config_word(dev, PCI_VENDOR_ID, &vid);
+
+               if (vid == 0xffff || vid == 0x0000) {
+                       found_multi = 0;
+                       continue;
+               }
+
+               pci_read_config_dword(dev, PCI_CLASS_REVISION, &pci_class);
+
+               if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) {
+
+                       int iosave, memsave;
+
+                       DBG("PCI Autoconfig: Found P2P bridge, device %d\n",
+                           PCI_SLOT(pci_devfn));
+
+                       /* Allocate PCI I/O and/or memory space */
+                       pciauto_setup_bars(dev, PCI_BASE_ADDRESS_1);
+
+                       pciauto_prescan_setup_bridge(dev, current_bus, sub_bus,
+                                       &iosave, &memsave);
+                       sub_bus = pciauto_bus_scan(pci_ctrl, sub_bus+1);
+                       pciauto_postscan_setup_bridge(dev, current_bus, sub_bus,
+                                       &iosave, &memsave);
+                       pciauto_bus.number = current_bus;
+
+                       continue;
+
+               }
+
+
+#if 0
+               /* Skip legacy mode IDE controller */
+
+               if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) {
+
+                       unsigned char prg_iface;
+                       pci_read_config_byte(dev, PCI_CLASS_PROG, &prg_iface);
+
+                       if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
+                               DBG("PCI Autoconfig: Skipping legacy mode "
+                                   "IDE controller\n");
+                               continue;
+                       }
+               }
+#endif
+
+               /*
+                * Found a peripheral, enable some standard
+                * settings
+                */
+
+               pci_read_config_dword(dev, PCI_COMMAND, &cmdstat);
+               pci_write_config_dword(dev, PCI_COMMAND,
+                               cmdstat |
+                                       PCI_COMMAND_IO |
+                                       PCI_COMMAND_MEMORY |
+                                       PCI_COMMAND_MASTER);
+               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
+
+               /* Allocate PCI I/O and/or memory space */
+               DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n",
+                   current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) );
+
+               pciauto_setup_bars(dev, PCI_BASE_ADDRESS_5);
+               pciauto_setup_irq(pci_ctrl, dev, pci_devfn);
+       }
+       return sub_bus;
+}
+
+
+
+
+
diff --git a/arch/xtensa/lib/strcasecmp.c b/arch/xtensa/lib/strcasecmp.c
new file mode 100644 (file)
index 0000000..165b2d6
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *  linux/arch/xtensa/lib/strcasecmp.c
+ *
+ *  This file is subject to the terms and conditions of the GNU General
+ *  Public License.  See the file "COPYING" in the main directory of
+ *  this archive for more details.
+ *
+ *  Copyright (C) 2002 Tensilica Inc.
+ */
+
+#include <linux/string.h>
+
+
+/* We handle nothing here except the C locale.  Since this is used in
+   only one place, on strings known to contain only 7 bit ASCII, this
+   is ok.  */
+
+int strcasecmp(const char *a, const char *b)
+{
+       int ca, cb;
+
+       do {
+               ca = *a++ & 0xff;
+               cb = *b++ & 0xff;
+               if (ca >= 'A' && ca <= 'Z')
+                       ca += 'a' - 'A';
+               if (cb >= 'A' && cb <= 'Z')
+                       cb += 'a' - 'A';
+       } while (ca == cb && ca != '\0');
+
+       return ca - cb;
+}
diff --git a/arch/xtensa/lib/strncpy_user.S b/arch/xtensa/lib/strncpy_user.S
new file mode 100644 (file)
index 0000000..71d55df
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ *  arch/xtensa/lib/strncpy_user.S
+ *
+ *  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.
+ *
+ *  Returns: -EFAULT if exception before terminator, N if the entire
+ *  buffer filled, else strlen.
+ *
+ *  Copyright (C) 2002 Tensilica Inc.
+ */
+
+#include <xtensa/coreasm.h>
+#include <linux/errno.h>
+
+/* Load or store instructions that may cause exceptions use the EX macro. */
+
+#define EX(insn,reg1,reg2,offset,handler)      \
+9:     insn    reg1, reg2, offset;             \
+       .section __ex_table, "a";               \
+       .word   9b, handler;                    \
+       .previous
+
+/*
+ * char *__strncpy_user(char *dst, const char *src, size_t len)
+ */
+.text
+.begin literal
+.align 4
+.Lmask0:
+       .byte   0xff, 0x00, 0x00, 0x00
+.Lmask1:
+       .byte   0x00, 0xff, 0x00, 0x00
+.Lmask2:
+       .byte   0x00, 0x00, 0xff, 0x00
+.Lmask3:
+       .byte   0x00, 0x00, 0x00, 0xff
+.end literal
+
+# Register use
+#   a0/ return address
+#   a1/ stack pointer
+#   a2/ return value
+#   a3/ src
+#   a4/ len
+#   a5/ mask0
+#   a6/ mask1
+#   a7/ mask2
+#   a8/ mask3
+#   a9/ tmp
+#   a10/ tmp
+#   a11/ dst
+#   a12/ tmp
+
+.align 4
+.global        __strncpy_user
+.type  __strncpy_user,@function
+__strncpy_user:
+       entry   sp, 16          # minimal stack frame
+       # a2/ dst, a3/ src, a4/ len
+       mov     a11, a2         # leave dst in return value register
+       beqz    a4, .Lret       # if len is zero
+       l32r    a5, .Lmask0     # mask for byte 0
+       l32r    a6, .Lmask1     # mask for byte 1
+       l32r    a7, .Lmask2     # mask for byte 2
+       l32r    a8, .Lmask3     # mask for byte 3
+       bbsi.l  a3, 0, .Lsrc1mod2 # if only  8-bit aligned
+       bbsi.l  a3, 1, .Lsrc2mod4 # if only 16-bit aligned
+.Lsrcaligned:  # return here when src is word-aligned
+       srli    a12, a4, 2      # number of loop iterations with 4B per loop
+       movi    a9, 3
+       bnone   a11, a9, .Laligned
+       j       .Ldstunaligned
+
+.Lsrc1mod2:    # src address is odd
+       EX(l8ui, a9, a3, 0, fixup_l)    # get byte 0
+       addi    a3, a3, 1               # advance src pointer
+       EX(s8i, a9, a11, 0, fixup_s)    # store byte 0
+       beqz    a9, .Lret               # if byte 0 is zero
+       addi    a11, a11, 1             # advance dst pointer
+       addi    a4, a4, -1              # decrement len
+       beqz    a4, .Lret               # if len is zero
+       bbci.l  a3, 1, .Lsrcaligned     # if src is now word-aligned
+
+.Lsrc2mod4:    # src address is 2 mod 4
+       EX(l8ui, a9, a3, 0, fixup_l)    # get byte 0
+       /* 1-cycle interlock */
+       EX(s8i, a9, a11, 0, fixup_s)    # store byte 0
+       beqz    a9, .Lret               # if byte 0 is zero
+       addi    a11, a11, 1             # advance dst pointer
+       addi    a4, a4, -1              # decrement len
+       beqz    a4, .Lret               # if len is zero
+       EX(l8ui, a9, a3, 1, fixup_l)    # get byte 0
+       addi    a3, a3, 2               # advance src pointer
+       EX(s8i, a9, a11, 0, fixup_s)    # store byte 0
+       beqz    a9, .Lret               # if byte 0 is zero
+       addi    a11, a11, 1             # advance dst pointer
+       addi    a4, a4, -1              # decrement len
+       bnez    a4, .Lsrcaligned        # if len is nonzero
+.Lret:
+       sub     a2, a11, a2             # compute strlen
+       retw
+
+/*
+ * dst is word-aligned, src is word-aligned
+ */
+       .align  4               # 1 mod 4 alignment for LOOPNEZ
+       .byte   0               # (0 mod 4 alignment for LBEG)
+.Laligned:
+#if XCHAL_HAVE_LOOPS
+       loopnez a12, .Loop1done
+#else
+       beqz    a12, .Loop1done
+       slli    a12, a12, 2
+       add     a12, a12, a11   # a12 = end of last 4B chunck
+#endif
+.Loop1:
+       EX(l32i, a9, a3, 0, fixup_l)    # get word from src
+       addi    a3, a3, 4               # advance src pointer
+       bnone   a9, a5, .Lz0            # if byte 0 is zero
+       bnone   a9, a6, .Lz1            # if byte 1 is zero
+       bnone   a9, a7, .Lz2            # if byte 2 is zero
+       EX(s32i, a9, a11, 0, fixup_s)   # store word to dst
+       bnone   a9, a8, .Lz3            # if byte 3 is zero
+       addi    a11, a11, 4             # advance dst pointer
+#if !XCHAL_HAVE_LOOPS
+       blt     a11, a12, .Loop1
+#endif
+
+.Loop1done:
+       bbci.l  a4, 1, .L100
+       # copy 2 bytes
+       EX(l16ui, a9, a3, 0, fixup_l)
+       addi    a3, a3, 2               # advance src pointer
+#ifdef __XTENSA_EB__
+       bnone   a9, a7, .Lz0            # if byte 2 is zero
+       bnone   a9, a8, .Lz1            # if byte 3 is zero
+#else
+       bnone   a9, a5, .Lz0            # if byte 0 is zero
+       bnone   a9, a6, .Lz1            # if byte 1 is zero
+#endif
+       EX(s16i, a9, a11, 0, fixup_s)
+       addi    a11, a11, 2             # advance dst pointer
+.L100:
+       bbci.l  a4, 0, .Lret
+       EX(l8ui, a9, a3, 0, fixup_l)
+       /* slot */
+       EX(s8i, a9, a11, 0, fixup_s)
+       beqz    a9, .Lret               # if byte is zero
+       addi    a11, a11, 1-3           # advance dst ptr 1, but also cancel
+                                       # the effect of adding 3 in .Lz3 code
+       /* fall thru to .Lz3 and "retw" */
+
+.Lz3:  # byte 3 is zero
+       addi    a11, a11, 3             # advance dst pointer
+       sub     a2, a11, a2             # compute strlen
+       retw
+.Lz0:  # byte 0 is zero
+#ifdef __XTENSA_EB__
+       movi    a9, 0
+#endif /* __XTENSA_EB__ */
+       EX(s8i, a9, a11, 0, fixup_s)
+       sub     a2, a11, a2             # compute strlen
+       retw
+.Lz1:  # byte 1 is zero
+#ifdef __XTENSA_EB__
+        extui   a9, a9, 16, 16
+#endif /* __XTENSA_EB__ */
+       EX(s16i, a9, a11, 0, fixup_s)
+       addi    a11, a11, 1             # advance dst pointer
+       sub     a2, a11, a2             # compute strlen
+       retw
+.Lz2:  # byte 2 is zero
+#ifdef __XTENSA_EB__
+        extui   a9, a9, 16, 16
+#endif /* __XTENSA_EB__ */
+       EX(s16i, a9, a11, 0, fixup_s)
+       movi    a9, 0
+       EX(s8i, a9, a11, 2, fixup_s)
+       addi    a11, a11, 2             # advance dst pointer
+       sub     a2, a11, a2             # compute strlen
+       retw
+
+       .align  4               # 1 mod 4 alignment for LOOPNEZ
+       .byte   0               # (0 mod 4 alignment for LBEG)
+.Ldstunaligned:
+/*
+ * for now just use byte copy loop
+ */
+#if XCHAL_HAVE_LOOPS
+       loopnez a4, .Lunalignedend
+#else
+       beqz    a4, .Lunalignedend
+       add     a12, a11, a4            # a12 = ending address
+#endif /* XCHAL_HAVE_LOOPS */
+.Lnextbyte:
+       EX(l8ui, a9, a3, 0, fixup_l)
+       addi    a3, a3, 1
+       EX(s8i, a9, a11, 0, fixup_s)
+       beqz    a9, .Lunalignedend
+       addi    a11, a11, 1
+#if !XCHAL_HAVE_LOOPS
+       blt     a11, a12, .Lnextbyte
+#endif
+
+.Lunalignedend:
+       sub     a2, a11, a2             # compute strlen
+       retw
+
+
+       .section .fixup, "ax"
+       .align  4
+
+       /* For now, just return -EFAULT.  Future implementations might
+        * like to clear remaining kernel space, like the fixup
+        * implementation in memset().  Thus, we differentiate between
+        * load/store fixups. */
+
+fixup_s:
+fixup_l:
+       movi    a2, -EFAULT
+       retw
+
diff --git a/arch/xtensa/lib/strnlen_user.S b/arch/xtensa/lib/strnlen_user.S
new file mode 100644 (file)
index 0000000..cdff4d6
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ *  arch/xtensa/lib/strnlen_user.S
+ *
+ *  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.
+ *
+ *  Returns strnlen, including trailing zero terminator.
+ *  Zero indicates error.
+ *
+ *  Copyright (C) 2002 Tensilica Inc.
+ */
+
+#include <xtensa/coreasm.h>
+
+/* Load or store instructions that may cause exceptions use the EX macro. */
+
+#define EX(insn,reg1,reg2,offset,handler)      \
+9:     insn    reg1, reg2, offset;             \
+       .section __ex_table, "a";               \
+       .word   9b, handler;                    \
+       .previous
+
+/*
+ * size_t __strnlen_user(const char *s, size_t len)
+ */
+.text
+.begin literal
+.align 4
+.Lmask0:
+       .byte   0xff, 0x00, 0x00, 0x00
+.Lmask1:
+       .byte   0x00, 0xff, 0x00, 0x00
+.Lmask2:
+       .byte   0x00, 0x00, 0xff, 0x00
+.Lmask3:
+       .byte   0x00, 0x00, 0x00, 0xff
+.end literal
+
+# Register use:
+#   a2/ src
+#   a3/ len
+#   a4/ tmp
+#   a5/ mask0
+#   a6/ mask1
+#   a7/ mask2
+#   a8/ mask3
+#   a9/ tmp
+#   a10/ tmp
+
+.align 4
+.global        __strnlen_user
+.type  __strnlen_user,@function
+__strnlen_user:
+       entry   sp, 16          # minimal stack frame
+       # a2/ s, a3/ len
+       addi    a4, a2, -4      # because we overincrement at the end;
+                               # we compensate with load offsets of 4
+       l32r    a5, .Lmask0     # mask for byte 0
+       l32r    a6, .Lmask1     # mask for byte 1
+       l32r    a7, .Lmask2     # mask for byte 2
+       l32r    a8, .Lmask3     # mask for byte 3
+       bbsi.l  a2, 0, .L1mod2  # if only  8-bit aligned
+       bbsi.l  a2, 1, .L2mod4  # if only 16-bit aligned
+
+/*
+ * String is word-aligned.
+ */
+.Laligned:
+       srli    a10, a3, 2      # number of loop iterations with 4B per loop
+#if XCHAL_HAVE_LOOPS
+       loopnez a10, .Ldone
+#else
+       beqz    a10, .Ldone
+       slli    a10, a10, 2
+       add     a10, a10, a4    # a10 = end of last 4B chunk
+#endif /* XCHAL_HAVE_LOOPS */
+.Loop:
+       EX(l32i, a9, a4, 4, lenfixup)   # get next word of string
+       addi    a4, a4, 4               # advance string pointer
+       bnone   a9, a5, .Lz0            # if byte 0 is zero
+       bnone   a9, a6, .Lz1            # if byte 1 is zero
+       bnone   a9, a7, .Lz2            # if byte 2 is zero
+       bnone   a9, a8, .Lz3            # if byte 3 is zero
+#if !XCHAL_HAVE_LOOPS
+       blt     a4, a10, .Loop
+#endif
+
+.Ldone:
+       EX(l32i, a9, a4, 4, lenfixup)   # load 4 bytes for remaining checks
+
+       bbci.l  a3, 1, .L100
+       # check two more bytes (bytes 0, 1 of word)
+       addi    a4, a4, 2       # advance string pointer
+       bnone   a9, a5, .Lz0    # if byte 0 is zero
+       bnone   a9, a6, .Lz1    # if byte 1 is zero
+.L100:
+       bbci.l  a3, 0, .L101
+       # check one more byte (byte 2 of word)
+       # Actually, we don't need to check.  Zero or nonzero, we'll add one.
+       # Do not add an extra one for the NULL terminator since we have
+       #  exhausted the original len parameter.
+       addi    a4, a4, 1       # advance string pointer
+.L101:
+       sub     a2, a4, a2      # compute length
+       retw
+
+# NOTE that in several places below, we point to the byte just after
+# the zero byte in order to include the NULL terminator in the count.
+
+.Lz3:  # byte 3 is zero
+       addi    a4, a4, 3       # point to zero byte
+.Lz0:  # byte 0 is zero
+       addi    a4, a4, 1       # point just beyond zero byte
+       sub     a2, a4, a2      # subtract to get length
+       retw
+.Lz1:  # byte 1 is zero
+       addi    a4, a4, 1+1     # point just beyond zero byte
+       sub     a2, a4, a2      # subtract to get length
+       retw
+.Lz2:  # byte 2 is zero
+       addi    a4, a4, 2+1     # point just beyond zero byte
+       sub     a2, a4, a2      # subtract to get length
+       retw
+
+.L1mod2:       # address is odd
+       EX(l8ui, a9, a4, 4, lenfixup)   # get byte 0
+       addi    a4, a4, 1               # advance string pointer
+       beqz    a9, .Lz3                # if byte 0 is zero
+       bbci.l  a4, 1, .Laligned        # if string pointer is now word-aligned
+
+.L2mod4:       # address is 2 mod 4
+       addi    a4, a4, 2       # advance ptr for aligned access
+       EX(l32i, a9, a4, 0, lenfixup)   # get word with first two bytes of string
+       bnone   a9, a7, .Lz2    # if byte 2 (of word, not string) is zero
+       bany    a9, a8, .Laligned # if byte 3 (of word, not string) is nonzero
+       # byte 3 is zero
+       addi    a4, a4, 3+1     # point just beyond zero byte
+       sub     a2, a4, a2      # subtract to get length
+       retw
+
+       .section .fixup, "ax"
+       .align  4
+lenfixup:
+       movi    a2, 0
+       retw
+
diff --git a/arch/xtensa/lib/usercopy.S b/arch/xtensa/lib/usercopy.S
new file mode 100644 (file)
index 0000000..265db26
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ *  arch/xtensa/lib/usercopy.S
+ *
+ *  Copy to/from user space (derived from arch/xtensa/lib/hal/memcopy.S)
+ *
+ *  DO NOT COMBINE this function with <arch/xtensa/lib/hal/memcopy.S>.
+ *  It needs to remain separate and distinct.  The hal files are part
+ *  of the the Xtensa link-time HAL, and those files may differ per
+ *  processor configuration.  Patching the kernel for another
+ *  processor configuration includes replacing the hal files, and we
+ *  could loose the special functionality for accessing user-space
+ *  memory during such a patch.  We sacrifice a little code space here
+ *  in favor to simplify code maintenance.
+ *
+ *  This file is subject to the terms and conditions of the GNU General
+ *  Public License.  See the file "COPYING" in the main directory of
+ *  this archive for more details.
+ *
+ *  Copyright (C) 2002 Tensilica Inc.
+ */
+
+
+/*
+ * size_t __xtensa_copy_user (void *dst, const void *src, size_t len);
+ *
+ * The returned value is the number of bytes not copied.  Implies zero
+ * is success.
+ *
+ * The general case algorithm is as follows:
+ *   If the destination and source are both aligned,
+ *     do 16B chunks with a loop, and then finish up with
+ *     8B, 4B, 2B, and 1B copies conditional on the length.
+ *   If destination is aligned and source unaligned,
+ *     do the same, but use SRC to align the source data.
+ *   If destination is unaligned, align it by conditionally
+ *     copying 1B and 2B and then retest.
+ *   This code tries to use fall-through braches for the common
+ *     case of aligned destinations (except for the branches to
+ *     the alignment label).
+ *
+ * Register use:
+ *     a0/ return address
+ *     a1/ stack pointer
+ *     a2/ return value
+ *     a3/ src
+ *     a4/ length
+ *     a5/ dst
+ *     a6/ tmp
+ *     a7/ tmp
+ *     a8/ tmp
+ *     a9/ tmp
+ *     a10/ tmp
+ *     a11/ original length
+ */
+
+#include <xtensa/coreasm.h>
+
+#ifdef __XTENSA_EB__
+#define ALIGN(R, W0, W1) src   R, W0, W1
+#define SSA8(R)        ssa8b R
+#else
+#define ALIGN(R, W0, W1) src   R, W1, W0
+#define SSA8(R)        ssa8l R
+#endif
+
+/* Load or store instructions that may cause exceptions use the EX macro. */
+
+#define EX(insn,reg1,reg2,offset,handler)      \
+9:     insn    reg1, reg2, offset;             \
+       .section __ex_table, "a";               \
+       .word   9b, handler;                    \
+       .previous
+
+
+       .text
+       .align  4
+       .global __xtensa_copy_user
+       .type   __xtensa_copy_user,@function
+__xtensa_copy_user:
+       entry   sp, 16          # minimal stack frame
+       # a2/ dst, a3/ src, a4/ len
+       mov     a5, a2          # copy dst so that a2 is return value
+       mov     a11, a4         # preserve original len for error case
+.Lcommon:
+       bbsi.l  a2, 0, .Ldst1mod2 # if dst is 1 mod 2
+       bbsi.l  a2, 1, .Ldst2mod4 # if dst is 2 mod 4
+.Ldstaligned:  # return here from .Ldstunaligned when dst is aligned
+       srli    a7, a4, 4       # number of loop iterations with 16B
+                               # per iteration
+       movi    a8, 3             # if source is also aligned,
+       bnone   a3, a8, .Laligned # then use word copy
+       SSA8(   a3)             # set shift amount from byte offset
+       bnez    a4, .Lsrcunaligned
+       movi    a2, 0           # return success for len==0
+       retw
+
+/*
+ * Destination is unaligned
+ */
+
+.Ldst1mod2:    # dst is only byte aligned
+       bltui   a4, 7, .Lbytecopy       # do short copies byte by byte
+
+       # copy 1 byte
+       EX(l8ui, a6, a3, 0, l_fixup)
+       addi    a3, a3,  1
+       EX(s8i, a6, a5,  0, s_fixup)
+       addi    a5, a5,  1
+       addi    a4, a4, -1
+       bbci.l  a5, 1, .Ldstaligned     # if dst is now aligned, then
+                                       # return to main algorithm
+.Ldst2mod4:    # dst 16-bit aligned
+       # copy 2 bytes
+       bltui   a4, 6, .Lbytecopy       # do short copies byte by byte
+       EX(l8ui, a6, a3, 0, l_fixup)
+       EX(l8ui, a7, a3, 1, l_fixup)
+       addi    a3, a3,  2
+       EX(s8i, a6, a5,  0, s_fixup)
+       EX(s8i, a7, a5,  1, s_fixup)
+       addi    a5, a5,  2
+       addi    a4, a4, -2
+       j       .Ldstaligned    # dst is now aligned, return to main algorithm
+
+/*
+ * Byte by byte copy
+ */
+       .align  4
+       .byte   0               # 1 mod 4 alignment for LOOPNEZ
+                               # (0 mod 4 alignment for LBEG)
+.Lbytecopy:
+#if XCHAL_HAVE_LOOPS
+       loopnez a4, .Lbytecopydone
+#else /* !XCHAL_HAVE_LOOPS */
+       beqz    a4, .Lbytecopydone
+       add     a7, a3, a4      # a7 = end address for source
+#endif /* !XCHAL_HAVE_LOOPS */
+.Lnextbyte:
+       EX(l8ui, a6, a3, 0, l_fixup)
+       addi    a3, a3, 1
+       EX(s8i, a6, a5, 0, s_fixup)
+       addi    a5, a5, 1
+#if !XCHAL_HAVE_LOOPS
+       blt     a3, a7, .Lnextbyte
+#endif /* !XCHAL_HAVE_LOOPS */
+.Lbytecopydone:
+       movi    a2, 0           # return success for len bytes copied
+       retw
+
+/*
+ * Destination and source are word-aligned.
+ */
+       # copy 16 bytes per iteration for word-aligned dst and word-aligned src
+       .align  4               # 1 mod 4 alignment for LOOPNEZ
+       .byte   0               # (0 mod 4 alignment for LBEG)
+.Laligned:
+#if XCHAL_HAVE_LOOPS
+       loopnez a7, .Loop1done
+#else /* !XCHAL_HAVE_LOOPS */
+       beqz    a7, .Loop1done
+       slli    a8, a7, 4
+       add     a8, a8, a3      # a8 = end of last 16B source chunk
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop1:
+       EX(l32i, a6, a3,  0, l_fixup)
+       EX(l32i, a7, a3,  4, l_fixup)
+       EX(s32i, a6, a5,  0, s_fixup)
+       EX(l32i, a6, a3,  8, l_fixup)
+       EX(s32i, a7, a5,  4, s_fixup)
+       EX(l32i, a7, a3, 12, l_fixup)
+       EX(s32i, a6, a5,  8, s_fixup)
+       addi    a3, a3, 16
+       EX(s32i, a7, a5, 12, s_fixup)
+       addi    a5, a5, 16
+#if !XCHAL_HAVE_LOOPS
+       blt     a3, a8, .Loop1
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop1done:
+       bbci.l  a4, 3, .L2
+       # copy 8 bytes
+       EX(l32i, a6, a3,  0, l_fixup)
+       EX(l32i, a7, a3,  4, l_fixup)
+       addi    a3, a3,  8
+       EX(s32i, a6, a5,  0, s_fixup)
+       EX(s32i, a7, a5,  4, s_fixup)
+       addi    a5, a5,  8
+.L2:
+       bbci.l  a4, 2, .L3
+       # copy 4 bytes
+       EX(l32i, a6, a3,  0, l_fixup)
+       addi    a3, a3,  4
+       EX(s32i, a6, a5,  0, s_fixup)
+       addi    a5, a5,  4
+.L3:
+       bbci.l  a4, 1, .L4
+       # copy 2 bytes
+       EX(l16ui, a6, a3,  0, l_fixup)
+       addi    a3, a3,  2
+       EX(s16i,  a6, a5,  0, s_fixup)
+       addi    a5, a5,  2
+.L4:
+       bbci.l  a4, 0, .L5
+       # copy 1 byte
+       EX(l8ui, a6, a3,  0, l_fixup)
+       EX(s8i,  a6, a5,  0, s_fixup)
+.L5:
+       movi    a2, 0           # return success for len bytes copied
+       retw
+
+/*
+ * Destination is aligned, Source is unaligned
+ */
+
+       .align  4
+       .byte   0               # 1 mod 4 alignement for LOOPNEZ
+                               # (0 mod 4 alignment for LBEG)
+.Lsrcunaligned:
+       # copy 16 bytes per iteration for word-aligned dst and unaligned src
+       and     a10, a3, a8     # save unalignment offset for below
+       sub     a3, a3, a10     # align a3 (to avoid sim warnings only; not needed for hardware)
+       EX(l32i, a6, a3, 0, l_fixup)    # load first word
+#if XCHAL_HAVE_LOOPS
+       loopnez a7, .Loop2done
+#else /* !XCHAL_HAVE_LOOPS */
+       beqz    a7, .Loop2done
+       slli    a10, a7, 4
+       add     a10, a10, a3    # a10 = end of last 16B source chunk
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop2:
+       EX(l32i, a7, a3,  4, l_fixup)
+       EX(l32i, a8, a3,  8, l_fixup)
+       ALIGN(  a6, a6, a7)
+       EX(s32i, a6, a5,  0, s_fixup)
+       EX(l32i, a9, a3, 12, l_fixup)
+       ALIGN(  a7, a7, a8)
+       EX(s32i, a7, a5,  4, s_fixup)
+       EX(l32i, a6, a3, 16, l_fixup)
+       ALIGN(  a8, a8, a9)
+       EX(s32i, a8, a5,  8, s_fixup)
+       addi    a3, a3, 16
+       ALIGN(  a9, a9, a6)
+       EX(s32i, a9, a5, 12, s_fixup)
+       addi    a5, a5, 16
+#if !XCHAL_HAVE_LOOPS
+       blt     a3, a10, .Loop2
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop2done:
+       bbci.l  a4, 3, .L12
+       # copy 8 bytes
+       EX(l32i, a7, a3,  4, l_fixup)
+       EX(l32i, a8, a3,  8, l_fixup)
+       ALIGN(  a6, a6, a7)
+       EX(s32i, a6, a5,  0, s_fixup)
+       addi    a3, a3,  8
+       ALIGN(  a7, a7, a8)
+       EX(s32i, a7, a5,  4, s_fixup)
+       addi    a5, a5,  8
+       mov     a6, a8
+.L12:
+       bbci.l  a4, 2, .L13
+       # copy 4 bytes
+       EX(l32i, a7, a3,  4, l_fixup)
+       addi    a3, a3,  4
+       ALIGN(  a6, a6, a7)
+       EX(s32i, a6, a5,  0, s_fixup)
+       addi    a5, a5,  4
+       mov     a6, a7
+.L13:
+       add     a3, a3, a10     # readjust a3 with correct misalignment
+       bbci.l  a4, 1, .L14
+       # copy 2 bytes
+       EX(l8ui, a6, a3,  0, l_fixup)
+       EX(l8ui, a7, a3,  1, l_fixup)
+       addi    a3, a3,  2
+       EX(s8i, a6, a5,  0, s_fixup)
+       EX(s8i, a7, a5,  1, s_fixup)
+       addi    a5, a5,  2
+.L14:
+       bbci.l  a4, 0, .L15
+       # copy 1 byte
+       EX(l8ui, a6, a3,  0, l_fixup)
+       EX(s8i,  a6, a5,  0, s_fixup)
+.L15:
+       movi    a2, 0           # return success for len bytes copied
+       retw
+
+
+       .section .fixup, "ax"
+       .align  4
+
+/* a2 = original dst; a5 = current dst; a11= original len
+ * bytes_copied = a5 - a2
+ * retval = bytes_not_copied = original len - bytes_copied
+ * retval = a11 - (a5 - a2)
+ *
+ * Clearing the remaining pieces of kernel memory plugs security
+ * holes.  This functionality is the equivalent of the *_zeroing
+ * functions that some architectures provide.
+ */
+
+.Lmemset:
+       .word   memset
+
+s_fixup:
+       sub     a2, a5, a2      /* a2 <-- bytes copied */
+       sub     a2, a11, a2     /* a2 <-- bytes not copied */
+       retw
+
+l_fixup:
+       sub     a2, a5, a2      /* a2 <-- bytes copied */
+       sub     a2, a11, a2     /* a2 <-- bytes not copied == return value */
+
+       /* void *memset(void *s, int c, size_t n); */
+       mov     a6, a5          /* s */
+       movi    a7, 0           /* c */
+       mov     a8, a2          /* n */
+       l32r    a4, .Lmemset
+       callx4  a4
+       /* Ignore memset return value in a6. */
+       /* a2 still contains bytes not copied. */
+       retw
+
diff --git a/arch/xtensa/mm/Makefile b/arch/xtensa/mm/Makefile
new file mode 100644 (file)
index 0000000..a5aed59
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Makefile for the Linux/Xtensa-specific parts of the memory manager.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+obj-y   := init.o fault.o tlb.o misc.o
+obj-m   :=
+obj-n   :=
+obj-    :=
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
new file mode 100644 (file)
index 0000000..a945a33
--- /dev/null
@@ -0,0 +1,241 @@
+// TODO VM_EXEC flag work-around, cache aliasing
+/*
+ * arch/xtensa/mm/fault.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Joe Taylor  <joe@tensilica.com, joetylr@yahoo.com>
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <asm/mmu_context.h>
+#include <asm/cacheflush.h>
+#include <asm/hardirq.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/pgalloc.h>
+
+unsigned long asid_cache = ASID_FIRST_VERSION;
+void bad_page_fault(struct pt_regs*, unsigned long, int);
+
+/*
+ * This routine handles page faults.  It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ *
+ * Note: does not handle Miss and MultiHit.
+ */
+
+void do_page_fault(struct pt_regs *regs)
+{
+       struct vm_area_struct * vma;
+       struct mm_struct *mm = current->mm;
+       unsigned int exccause = regs->exccause;
+       unsigned int address = regs->excvaddr;
+       siginfo_t info;
+
+       int is_write, is_exec;
+
+       info.si_code = SEGV_MAPERR;
+
+       /* We fault-in kernel-space virtual memory on-demand. The
+        * 'reference' page table is init_mm.pgd.
+        */
+       if (address >= TASK_SIZE && !user_mode(regs))
+               goto vmalloc_fault;
+
+       /* If we're in an interrupt or have no user
+        * context, we must not take the fault..
+        */
+       if (in_atomic() || !mm) {
+               bad_page_fault(regs, address, SIGSEGV);
+               return;
+       }
+
+       is_write = (exccause == XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE) ? 1 : 0;
+       is_exec =  (exccause == XCHAL_EXCCAUSE_ITLB_PRIVILEGE ||
+                   exccause == XCHAL_EXCCAUSE_ITLB_MISS ||
+                   exccause == XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE) ? 1 : 0;
+
+#if 0
+       printk("[%s:%d:%08x:%d:%08x:%s%s]\n", current->comm, current->pid,
+              address, exccause, regs->pc, is_write? "w":"", is_exec? "x":"");
+#endif
+
+       down_read(&mm->mmap_sem);
+       vma = find_vma(mm, address);
+
+       if (!vma)
+               goto bad_area;
+       if (vma->vm_start <= address)
+               goto good_area;
+       if (!(vma->vm_flags & VM_GROWSDOWN))
+               goto bad_area;
+       if (expand_stack(vma, address))
+               goto bad_area;
+
+       /* Ok, we have a good vm_area for this memory access, so
+        * we can handle it..
+        */
+
+good_area:
+       info.si_code = SEGV_ACCERR;
+
+       if (is_write) {
+               if (!(vma->vm_flags & VM_WRITE))
+                       goto bad_area;
+       } else if (is_exec) {
+               if (!(vma->vm_flags & VM_EXEC))
+                       goto bad_area;
+       } else  /* Allow read even from write-only pages. */
+               if (!(vma->vm_flags & (VM_READ | VM_WRITE)))
+                       goto bad_area;
+
+       /* If for any reason at all we couldn't handle the fault,
+        * make sure we exit gracefully rather than endlessly redo
+        * the fault.
+        */
+survive:
+       switch (handle_mm_fault(mm, vma, address, is_write)) {
+       case VM_FAULT_MINOR:
+               current->min_flt++;
+               break;
+       case VM_FAULT_MAJOR:
+               current->maj_flt++;
+               break;
+       case VM_FAULT_SIGBUS:
+               goto do_sigbus;
+       case VM_FAULT_OOM:
+               goto out_of_memory;
+       default:
+               BUG();
+       }
+
+       up_read(&mm->mmap_sem);
+       return;
+
+       /* Something tried to access memory that isn't in our memory map..
+        * Fix it, but check if it's kernel or user first..
+        */
+bad_area:
+       up_read(&mm->mmap_sem);
+       if (user_mode(regs)) {
+               current->thread.bad_vaddr = address;
+               current->thread.error_code = is_write;
+               info.si_signo = SIGSEGV;
+               info.si_errno = 0;
+               /* info.si_code has been set above */
+               info.si_addr = (void *) address;
+               force_sig_info(SIGSEGV, &info, current);
+               return;
+       }
+       bad_page_fault(regs, address, SIGSEGV);
+       return;
+
+
+       /* We ran out of memory, or some other thing happened to us that made
+        * us unable to handle the page fault gracefully.
+        */
+out_of_memory:
+       up_read(&mm->mmap_sem);
+       if (current->pid == 1) {
+               yield();
+               down_read(&mm->mmap_sem);
+               goto survive;
+       }
+       printk("VM: killing process %s\n", current->comm);
+       if (user_mode(regs))
+               do_exit(SIGKILL);
+       bad_page_fault(regs, address, SIGKILL);
+       return;
+
+do_sigbus:
+       up_read(&mm->mmap_sem);
+
+       /* Send a sigbus, regardless of whether we were in kernel
+        * or user mode.
+        */
+       current->thread.bad_vaddr = address;
+       info.si_code = SIGBUS;
+       info.si_errno = 0;
+       info.si_code = BUS_ADRERR;
+       info.si_addr = (void *) address;
+       force_sig_info(SIGBUS, &info, current);
+
+       /* Kernel mode? Handle exceptions or die */
+       if (!user_mode(regs))
+               bad_page_fault(regs, address, SIGBUS);
+
+vmalloc_fault:
+       {
+               /* Synchronize this task's top level page-table
+                * with the 'reference' page table.
+                */
+               struct mm_struct *act_mm = current->active_mm;
+               int index = pgd_index(address);
+               pgd_t *pgd, *pgd_k;
+               pmd_t *pmd, *pmd_k;
+               pte_t *pte_k;
+
+               if (act_mm == NULL)
+                       goto bad_page_fault;
+
+               pgd = act_mm->pgd + index;
+               pgd_k = init_mm.pgd + index;
+
+               if (!pgd_present(*pgd_k))
+                       goto bad_page_fault;
+
+               pgd_val(*pgd) = pgd_val(*pgd_k);
+
+               pmd = pmd_offset(pgd, address);
+               pmd_k = pmd_offset(pgd_k, address);
+               if (!pmd_present(*pmd) || !pmd_present(*pmd_k))
+                       goto bad_page_fault;
+
+               pmd_val(*pmd) = pmd_val(*pmd_k);
+               pte_k = pte_offset_kernel(pmd_k, address);
+
+               if (!pte_present(*pte_k))
+                       goto bad_page_fault;
+               return;
+       }
+bad_page_fault:
+       bad_page_fault(regs, address, SIGKILL);
+       return;
+}
+
+
+void
+bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
+{
+       extern void die(const char*, struct pt_regs*, long);
+       const struct exception_table_entry *entry;
+
+       /* Are we prepared to handle this kernel fault?  */
+       if ((entry = search_exception_tables(regs->pc)) != NULL) {
+#if 1
+               printk(KERN_DEBUG "%s: Exception at pc=%#010lx (%lx)\n",
+                               current->comm, regs->pc, entry->fixup);
+#endif
+               current->thread.bad_uaddr = address;
+               regs->pc = entry->fixup;
+               return;
+       }
+
+       /* Oops. The kernel tried to access some bad page. We'll have to
+        * terminate things with extreme prejudice.
+        */
+       printk(KERN_ALERT "Unable to handle kernel paging request at virtual "
+              "address %08lx\n pc = %08lx, ra = %08lx\n",
+              address, regs->pc, regs->areg[0]);
+       die("Oops", regs, sig);
+       do_exit(sig);
+}
+
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c
new file mode 100644 (file)
index 0000000..56aace8
--- /dev/null
@@ -0,0 +1,551 @@
+/*
+ * arch/xtensa/mm/init.c
+ *
+ * Derived from MIPS, PPC.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel        <chris@zankel.net>
+ * Joe Taylor  <joe@tensilica.com, joetylr@yahoo.com>
+ * Marc Gauthier
+ * Kevin Chea
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/bootmem.h>
+#include <linux/swap.h>
+
+#include <asm/pgtable.h>
+#include <asm/bootparam.h>
+#include <asm/mmu_context.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+
+
+#define DEBUG 0
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+//static DEFINE_SPINLOCK(tlb_lock);
+
+/*
+ * This flag is used to indicate that the page was mapped and modified in
+ * kernel space, so the cache is probably dirty at that address.
+ * If cache aliasing is enabled and the page color mismatches, update_mmu_cache
+ * synchronizes the caches if this bit is set.
+ */
+
+#define PG_cache_clean PG_arch_1
+
+/* References to section boundaries */
+
+extern char _ftext, _etext, _fdata, _edata, _rodata_end;
+extern char __init_begin, __init_end;
+
+/*
+ * mem_reserve(start, end, must_exist)
+ *
+ * Reserve some memory from the memory pool.
+ *
+ * Parameters:
+ *  start      Start of region,
+ *  end                End of region,
+ *  must_exist Must exist in memory pool.
+ *
+ * Returns:
+ *  0 (memory area couldn't be mapped)
+ * -1 (success)
+ */
+
+int __init mem_reserve(unsigned long start, unsigned long end, int must_exist)
+{
+       int i;
+
+       if (start == end)
+               return 0;
+
+       start = start & PAGE_MASK;
+       end = PAGE_ALIGN(end);
+
+       for (i = 0; i < sysmem.nr_banks; i++)
+               if (start < sysmem.bank[i].end
+                   && end >= sysmem.bank[i].start)
+                       break;
+
+       if (i == sysmem.nr_banks) {
+               if (must_exist)
+                       printk (KERN_WARNING "mem_reserve: [0x%0lx, 0x%0lx) "
+                               "not in any region!\n", start, end);
+               return 0;
+       }
+
+       if (start > sysmem.bank[i].start) {
+               if (end < sysmem.bank[i].end) {
+                       /* split entry */
+                       if (sysmem.nr_banks >= SYSMEM_BANKS_MAX)
+                               panic("meminfo overflow\n");
+                       sysmem.bank[sysmem.nr_banks].start = end;
+                       sysmem.bank[sysmem.nr_banks].end = sysmem.bank[i].end;
+                       sysmem.nr_banks++;
+               }
+               sysmem.bank[i].end = start;
+       } else {
+               if (end < sysmem.bank[i].end)
+                       sysmem.bank[i].start = end;
+               else {
+                       /* remove entry */
+                       sysmem.nr_banks--;
+                       sysmem.bank[i].start = sysmem.bank[sysmem.nr_banks].start;
+                       sysmem.bank[i].end   = sysmem.bank[sysmem.nr_banks].end;
+               }
+       }
+       return -1;
+}
+
+
+/*
+ * Initialize the bootmem system and give it all the memory we have available.
+ */
+
+void __init bootmem_init(void)
+{
+       unsigned long pfn;
+       unsigned long bootmap_start, bootmap_size;
+       int i;
+
+       max_low_pfn = max_pfn = 0;
+       min_low_pfn = ~0;
+
+       for (i=0; i < sysmem.nr_banks; i++) {
+               pfn = PAGE_ALIGN(sysmem.bank[i].start) >> PAGE_SHIFT;
+               if (pfn < min_low_pfn)
+                       min_low_pfn = pfn;
+               pfn = PAGE_ALIGN(sysmem.bank[i].end - 1) >> PAGE_SHIFT;
+               if (pfn > max_pfn)
+                       max_pfn = pfn;
+       }
+
+       if (min_low_pfn > max_pfn)
+               panic("No memory found!\n");
+
+       max_low_pfn = max_pfn < MAX_LOW_MEMORY >> PAGE_SHIFT ?
+               max_pfn : MAX_LOW_MEMORY >> PAGE_SHIFT;
+
+       /* Find an area to use for the bootmem bitmap. */
+
+       bootmap_size = bootmem_bootmap_pages(max_low_pfn) << PAGE_SHIFT;
+       bootmap_start = ~0;
+
+       for (i=0; i<sysmem.nr_banks; i++)
+               if (sysmem.bank[i].end - sysmem.bank[i].start >= bootmap_size) {
+                       bootmap_start = sysmem.bank[i].start;
+                       break;
+               }
+
+       if (bootmap_start == ~0UL)
+               panic("Cannot find %ld bytes for bootmap\n", bootmap_size);
+
+       /* Reserve the bootmem bitmap area */
+
+       mem_reserve(bootmap_start, bootmap_start + bootmap_size, 1);
+       bootmap_size = init_bootmem_node(NODE_DATA(0), min_low_pfn,
+                                        bootmap_start >> PAGE_SHIFT,
+                                        max_low_pfn);
+
+       /* Add all remaining memory pieces into the bootmem map */
+
+       for (i=0; i<sysmem.nr_banks; i++)
+               free_bootmem(sysmem.bank[i].start,
+                            sysmem.bank[i].end - sysmem.bank[i].start);
+
+}
+
+
+void __init paging_init(void)
+{
+       unsigned long zones_size[MAX_NR_ZONES];
+       int i;
+
+       /* All pages are DMA-able, so we put them all in the DMA zone. */
+
+       zones_size[ZONE_DMA] = max_low_pfn;
+       for (i = 1; i < MAX_NR_ZONES; i++)
+               zones_size[i] = 0;
+
+#ifdef CONFIG_HIGHMEM
+       zones_size[ZONE_HIGHMEM] = max_pfn - max_low_pfn;
+#endif
+
+       /* Initialize the kernel's page tables. */
+
+       memset(swapper_pg_dir, 0, PAGE_SIZE);
+
+       free_area_init(zones_size);
+}
+
+/*
+ * Flush the mmu and reset associated register to default values.
+ */
+
+void __init init_mmu (void)
+{
+       /* Writing zeros to the <t>TLBCFG special registers ensure
+        * that valid values exist in the register.  For existing
+        * PGSZID<w> fields, zero selects the first element of the
+        * page-size array.  For nonexistant PGSZID<w> fields, zero is
+        * the best value to write.  Also, when changing PGSZID<w>
+        * fields, the corresponding TLB must be flushed.
+        */
+       set_itlbcfg_register (0);
+       set_dtlbcfg_register (0);
+       flush_tlb_all ();
+
+       /* Set rasid register to a known value. */
+
+       set_rasid_register (ASID_ALL_RESERVED);
+
+       /* Set PTEVADDR special register to the start of the page
+        * table, which is in kernel mappable space (ie. not
+        * statically mapped).  This register's value is undefined on
+        * reset.
+        */
+       set_ptevaddr_register (PGTABLE_START);
+}
+
+/*
+ * Initialize memory pages.
+ */
+
+void __init mem_init(void)
+{
+       unsigned long codesize, reservedpages, datasize, initsize;
+       unsigned long highmemsize, tmp, ram;
+
+       max_mapnr = num_physpages = max_low_pfn;
+       high_memory = (void *) __va(max_mapnr << PAGE_SHIFT);
+       highmemsize = 0;
+
+#if CONFIG_HIGHMEM
+#error HIGHGMEM not implemented in init.c
+#endif
+
+       totalram_pages += free_all_bootmem();
+
+       reservedpages = ram = 0;
+       for (tmp = 0; tmp < max_low_pfn; tmp++) {
+               ram++;
+               if (PageReserved(mem_map+tmp))
+                       reservedpages++;
+       }
+
+       codesize =  (unsigned long) &_etext - (unsigned long) &_ftext;
+       datasize =  (unsigned long) &_edata - (unsigned long) &_fdata;
+       initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
+
+       printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, "
+              "%ldk data, %ldk init %ldk highmem)\n",
+              (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+              ram << (PAGE_SHIFT-10),
+              codesize >> 10,
+              reservedpages << (PAGE_SHIFT-10),
+              datasize >> 10,
+              initsize >> 10,
+              highmemsize >> 10);
+}
+
+void
+free_reserved_mem(void *start, void *end)
+{
+       for (; start < end; start += PAGE_SIZE) {
+               ClearPageReserved(virt_to_page(start));
+               set_page_count(virt_to_page(start), 1);
+               free_page((unsigned long)start);
+               totalram_pages++;
+       }
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+extern int initrd_is_mapped;
+
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+       if (initrd_is_mapped) {
+               free_reserved_mem((void*)start, (void*)end);
+               printk ("Freeing initrd memory: %ldk freed\n",(end-start)>>10);
+       }
+}
+#endif
+
+void free_initmem(void)
+{
+       free_reserved_mem(&__init_begin, &__init_end);
+       printk("Freeing unused kernel memory: %dk freed\n",
+              (&__init_end - &__init_begin) >> 10);
+}
+
+void show_mem(void)
+{
+       int i, free = 0, total = 0, reserved = 0;
+       int shared = 0, cached = 0;
+
+       printk("Mem-info:\n");
+       show_free_areas();
+       printk("Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+       i = max_mapnr;
+       while (i-- > 0) {
+               total++;
+               if (PageReserved(mem_map+i))
+                       reserved++;
+               else if (PageSwapCache(mem_map+i))
+                       cached++;
+               else if (!page_count(mem_map + i))
+                       free++;
+               else
+                       shared += page_count(mem_map + i) - 1;
+       }
+       printk("%d pages of RAM\n", total);
+       printk("%d reserved pages\n", reserved);
+       printk("%d pages shared\n", shared);
+       printk("%d pages swap cached\n",cached);
+       printk("%d free pages\n", free);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+
+/*
+ * With cache aliasing, the page color of the page in kernel space and user
+ * space might mismatch. We temporarily map the page to a different virtual
+ * address with the same color and clear the page there.
+ */
+
+void clear_user_page(void *kaddr, unsigned long vaddr, struct page* page)
+{
+
+       /*  There shouldn't be any entries for this page. */
+
+       __flush_invalidate_dcache_page_phys(__pa(page_address(page)));
+
+       if (!PAGE_COLOR_EQ(vaddr, kaddr)) {
+               unsigned long v, p;
+
+               /* Temporarily map page to DTLB_WAY_DCACHE_ALIAS0. */
+
+               spin_lock(&tlb_lock);
+
+               p = (unsigned long)pte_val((mk_pte(page,PAGE_KERNEL)));
+               kaddr = (void*)PAGE_COLOR_MAP0(vaddr);
+               v = (unsigned long)kaddr | DTLB_WAY_DCACHE_ALIAS0;
+               __asm__ __volatile__("wdtlb %0,%1; dsync" : :"a" (p), "a" (v));
+
+               clear_page(kaddr);
+
+               spin_unlock(&tlb_lock);
+       } else {
+               clear_page(kaddr);
+       }
+
+       /* We need to make sure that i$ and d$ are coherent. */
+
+       clear_bit(PG_cache_clean, &page->flags);
+}
+
+/*
+ * With cache aliasing, we have to make sure that the page color of the page
+ * in kernel space matches that of the virtual user address before we read
+ * the page. If the page color differ, we create a temporary DTLB entry with
+ * the corrent page color and use this 'temporary' address as the source.
+ * We then use the same approach as in clear_user_page and copy the data
+ * to the kernel space and clear the PG_cache_clean bit to synchronize caches
+ * later.
+ *
+ * Note:
+ * Instead of using another 'way' for the temporary DTLB entry, we could
+ * probably use the same entry that points to the kernel address (after
+ * saving the original value and restoring it when we are done).
+ */
+
+void copy_user_page(void* to, void* from, unsigned long vaddr,
+                   struct page* to_page)
+{
+       /* There shouldn't be any entries for the new page. */
+
+       __flush_invalidate_dcache_page_phys(__pa(page_address(to_page)));
+
+       spin_lock(&tlb_lock);
+
+       if (!PAGE_COLOR_EQ(vaddr, from)) {
+               unsigned long v, p, t;
+
+               __asm__ __volatile__ ("pdtlb %1,%2; rdtlb1 %0,%1"
+                                     : "=a"(p), "=a"(t) : "a"(from));
+               from = (void*)PAGE_COLOR_MAP0(vaddr);
+               v = (unsigned long)from | DTLB_WAY_DCACHE_ALIAS0;
+               __asm__ __volatile__ ("wdtlb %0,%1; dsync" ::"a" (p), "a" (v));
+       }
+
+       if (!PAGE_COLOR_EQ(vaddr, to)) {
+               unsigned long v, p;
+
+               p = (unsigned long)pte_val((mk_pte(to_page,PAGE_KERNEL)));
+               to = (void*)PAGE_COLOR_MAP1(vaddr);
+               v = (unsigned long)to | DTLB_WAY_DCACHE_ALIAS1;
+               __asm__ __volatile__ ("wdtlb %0,%1; dsync" ::"a" (p), "a" (v));
+       }
+       copy_page(to, from);
+
+       spin_unlock(&tlb_lock);
+
+       /* We need to make sure that i$ and d$ are coherent. */
+
+       clear_bit(PG_cache_clean, &to_page->flags);
+}
+
+
+
+/*
+ * Any time the kernel writes to a user page cache page, or it is about to
+ * read from a page cache page this routine is called.
+ *
+ * Note:
+ * The kernel currently only provides one architecture bit in the page
+ * flags that we use for I$/D$ coherency. Maybe, in future, we can
+ * use a sepearte bit for deferred dcache aliasing:
+ * If the page is not mapped yet, we only need to set a flag,
+ * if mapped, we need to invalidate the page.
+ */
+// FIXME: we probably need this for WB caches not only for Page Coloring..
+
+void flush_dcache_page(struct page *page)
+{
+       unsigned long addr = __pa(page_address(page));
+       struct address_space *mapping = page_mapping(page);
+
+       __flush_invalidate_dcache_page_phys(addr);
+
+       if (!test_bit(PG_cache_clean, &page->flags))
+               return;
+
+       /* If this page hasn't been mapped, yet, handle I$/D$ coherency later.*/
+#if 0
+       if (mapping && !mapping_mapped(mapping))
+               clear_bit(PG_cache_clean, &page->flags);
+       else
+#endif
+               __invalidate_icache_page_phys(addr);
+}
+
+void flush_cache_range(struct vm_area_struct* vma, unsigned long s,
+                      unsigned long e)
+{
+       __flush_invalidate_cache_all();
+}
+
+void flush_cache_page(struct vm_area_struct* vma, unsigned long address,
+                     unsigned long pfn)
+{
+       struct page *page = pfn_to_page(pfn);
+
+       /* Remove any entry for the old mapping. */
+
+       if (current->active_mm == vma->vm_mm) {
+               unsigned long addr = __pa(page_address(page));
+               __flush_invalidate_dcache_page_phys(addr);
+               if ((vma->vm_flags & VM_EXEC) != 0)
+                       __invalidate_icache_page_phys(addr);
+       } else {
+               BUG();
+       }
+}
+
+#endif /* (DCACHE_WAY_SIZE > PAGE_SIZE) */
+
+
+pte_t* pte_alloc_one_kernel (struct mm_struct* mm, unsigned long addr)
+{
+       pte_t* pte = (pte_t*)__get_free_pages(GFP_KERNEL|__GFP_REPEAT, 0);
+       if (likely(pte)) {
+               pte_t* ptep = (pte_t*)(pte_val(*pte) + PAGE_OFFSET);
+               int i;
+               for (i = 0; i < 1024; i++, ptep++)
+                       pte_clear(mm, addr, ptep);
+       }
+       return pte;
+}
+
+struct page* pte_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+       struct page *page;
+
+       page = alloc_pages(GFP_KERNEL | __GFP_REPEAT, 0);
+
+       if (likely(page)) {
+               pte_t* ptep = kmap_atomic(page, KM_USER0);
+               int i;
+
+               for (i = 0; i < 1024; i++, ptep++)
+                       pte_clear(mm, addr, ptep);
+
+               kunmap_atomic(ptep, KM_USER0);
+       }
+       return page;
+}
+
+
+/*
+ * Handle D$/I$ coherency.
+ *
+ * Note:
+ * We only have one architecture bit for the page flags, so we cannot handle
+ * cache aliasing, yet.
+ */
+
+void
+update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t pte)
+{
+       unsigned long pfn = pte_pfn(pte);
+       struct page *page;
+       unsigned long vaddr = addr & PAGE_MASK;
+
+       if (!pfn_valid(pfn))
+               return;
+
+       page = pfn_to_page(pfn);
+
+       invalidate_itlb_mapping(addr);
+       invalidate_dtlb_mapping(addr);
+
+       /* We have a new mapping. Use it. */
+
+       write_dtlb_entry(pte, dtlb_probe(addr));
+
+       /* If the processor can execute from this page, synchronize D$/I$. */
+
+       if ((vma->vm_flags & VM_EXEC) != 0) {
+
+               write_itlb_entry(pte, itlb_probe(addr));
+
+               /* Synchronize caches, if not clean. */
+
+               if (!test_and_set_bit(PG_cache_clean, &page->flags)) {
+                       __flush_dcache_page(vaddr);
+                       __invalidate_icache_page(vaddr);
+               }
+       }
+}
+
diff --git a/arch/xtensa/mm/misc.S b/arch/xtensa/mm/misc.S
new file mode 100644 (file)
index 0000000..327c0f1
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * arch/xtensa/mm/misc.S
+ *
+ * Miscellaneous assembly functions.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel        <chris@zankel.net>
+ */
+
+/* Note: we might want to implement some of the loops as zero-overhead-loops,
+ *      where applicable and if supported by the processor.
+ */
+
+#include <linux/linkage.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include <xtensa/cacheasm.h>
+#include <xtensa/cacheattrasm.h>
+
+/* clear_page (page) */
+
+ENTRY(clear_page)
+       entry   a1, 16
+       addi    a4, a2, PAGE_SIZE
+       movi    a3, 0
+
+1:     s32i    a3, a2, 0
+       s32i    a3, a2, 4
+       s32i    a3, a2, 8
+       s32i    a3, a2, 12
+       s32i    a3, a2, 16
+       s32i    a3, a2, 20
+       s32i    a3, a2, 24
+       s32i    a3, a2, 28
+       addi    a2, a2, 32
+       blt     a2, a4, 1b
+
+       retw
+
+/*
+ * copy_page (void *to, void *from)
+ *                  a2        a3
+ */
+
+ENTRY(copy_page)
+       entry   a1, 16
+       addi    a4, a2, PAGE_SIZE
+
+1:     l32i    a5, a3, 0
+       l32i    a6, a3, 4
+       l32i    a7, a3, 8
+       s32i    a5, a2, 0
+       s32i    a6, a2, 4
+       s32i    a7, a2, 8
+       l32i    a5, a3, 12
+       l32i    a6, a3, 16
+       l32i    a7, a3, 20
+       s32i    a5, a2, 12
+       s32i    a6, a2, 16
+       s32i    a7, a2, 20
+       l32i    a5, a3, 24
+       l32i    a6, a3, 28
+       s32i    a5, a2, 24
+       s32i    a6, a2, 28
+       addi    a2, a2, 32
+       addi    a3, a3, 32
+       blt     a2, a4, 1b
+
+       retw
+
+
+/*
+ * void __flush_invalidate_cache_all(void)
+ */
+
+ENTRY(__flush_invalidate_cache_all)
+       entry   sp, 16
+       dcache_writeback_inv_all a2, a3
+       icache_invalidate_all a2, a3
+       retw
+
+/*
+ * void __invalidate_icache_all(void)
+ */
+
+ENTRY(__invalidate_icache_all)
+       entry   sp, 16
+       icache_invalidate_all a2, a3
+       retw
+
+/*
+ * void __flush_invalidate_dcache_all(void)
+ */
+
+ENTRY(__flush_invalidate_dcache_all)
+       entry   sp, 16
+       dcache_writeback_inv_all a2, a3
+       retw
+
+
+/*
+ * void __flush_invalidate_cache_range(ulong start, ulong size)
+ */
+
+ENTRY(__flush_invalidate_cache_range)
+       entry   sp, 16
+       mov     a4, a2
+       mov     a5, a3
+       dcache_writeback_inv_region a4, a5, a6
+       icache_invalidate_region a2, a3, a4
+       retw
+
+/*
+ * void __invalidate_icache_page(ulong start)
+ */
+
+ENTRY(__invalidate_icache_page)
+       entry   sp, 16
+       movi    a3, PAGE_SIZE
+       icache_invalidate_region a2, a3, a4
+       retw
+
+/*
+ * void __invalidate_dcache_page(ulong start)
+ */
+
+ENTRY(__invalidate_dcache_page)
+       entry   sp, 16
+       movi    a3, PAGE_SIZE
+       dcache_invalidate_region a2, a3, a4
+       retw
+
+/*
+ * void __invalidate_icache_range(ulong start, ulong size)
+ */
+
+ENTRY(__invalidate_icache_range)
+       entry   sp, 16
+       icache_invalidate_region a2, a3, a4
+       retw
+
+/*
+ * void __invalidate_dcache_range(ulong start, ulong size)
+ */
+
+ENTRY(__invalidate_dcache_range)
+       entry   sp, 16
+       dcache_invalidate_region a2, a3, a4
+       retw
+
+/*
+ * void __flush_dcache_page(ulong start)
+ */
+
+ENTRY(__flush_dcache_page)
+       entry   sp, 16
+       movi    a3, PAGE_SIZE
+       dcache_writeback_region a2, a3, a4
+       retw
+
+/*
+ * void __flush_invalidate_dcache_page(ulong start)
+ */
+
+ENTRY(__flush_invalidate_dcache_page)
+       entry   sp, 16
+       movi    a3, PAGE_SIZE
+       dcache_writeback_inv_region a2, a3, a4
+       retw
+
+/*
+ * void __flush_invalidate_dcache_range(ulong start, ulong size)
+ */
+
+ENTRY(__flush_invalidate_dcache_range)
+       entry   sp, 16
+       dcache_writeback_inv_region a2, a3, a4
+       retw
+
+/*
+ * void __invalidate_dcache_all(void)
+ */
+
+ENTRY(__invalidate_dcache_all)
+       entry   sp, 16
+       dcache_invalidate_all a2, a3
+       retw
+
+/*
+ * void __flush_invalidate_dcache_page_phys(ulong start)
+ */
+
+ENTRY(__flush_invalidate_dcache_page_phys)
+       entry   sp, 16
+
+       movi    a3, XCHAL_DCACHE_SIZE
+       movi    a4, PAGE_MASK | 1
+       addi    a2, a2, 1
+
+1:     addi    a3, a3, -XCHAL_DCACHE_LINESIZE
+
+       ldct    a6, a3
+       dsync
+       and     a6, a6, a4
+       beq     a6, a2, 2f
+       bgeui   a3, 2, 1b
+       retw
+
+2:     diwbi   a3, 0
+       bgeui   a3, 2, 1b
+       retw
+
+ENTRY(check_dcache_low0)
+       entry   sp, 16
+
+       movi    a3, XCHAL_DCACHE_SIZE / 4
+       movi    a4, PAGE_MASK | 1
+       addi    a2, a2, 1
+
+1:     addi    a3, a3, -XCHAL_DCACHE_LINESIZE
+
+       ldct    a6, a3
+       dsync
+       and     a6, a6, a4
+       beq     a6, a2, 2f
+       bgeui   a3, 2, 1b
+       retw
+
+2:     j 2b
+
+ENTRY(check_dcache_high0)
+       entry   sp, 16
+
+       movi    a5, XCHAL_DCACHE_SIZE / 4
+       movi    a3, XCHAL_DCACHE_SIZE / 2
+       movi    a4, PAGE_MASK | 1
+       addi    a2, a2, 1
+
+1:     addi    a3, a3, -XCHAL_DCACHE_LINESIZE
+       addi    a5, a5, -XCHAL_DCACHE_LINESIZE
+
+       ldct    a6, a3
+       dsync
+       and     a6, a6, a4
+       beq     a6, a2, 2f
+       bgeui   a5, 2, 1b
+       retw
+
+2:     j 2b
+
+ENTRY(check_dcache_low1)
+       entry   sp, 16
+
+       movi    a5, XCHAL_DCACHE_SIZE / 4
+       movi    a3, XCHAL_DCACHE_SIZE * 3 / 4
+       movi    a4, PAGE_MASK | 1
+       addi    a2, a2, 1
+
+1:     addi    a3, a3, -XCHAL_DCACHE_LINESIZE
+       addi    a5, a5, -XCHAL_DCACHE_LINESIZE
+
+       ldct    a6, a3
+       dsync
+       and     a6, a6, a4
+       beq     a6, a2, 2f
+       bgeui   a5, 2, 1b
+       retw
+
+2:     j 2b
+
+ENTRY(check_dcache_high1)
+       entry   sp, 16
+
+       movi    a5, XCHAL_DCACHE_SIZE / 4
+       movi    a3, XCHAL_DCACHE_SIZE
+       movi    a4, PAGE_MASK | 1
+       addi    a2, a2, 1
+
+1:     addi    a3, a3, -XCHAL_DCACHE_LINESIZE
+       addi    a5, a5, -XCHAL_DCACHE_LINESIZE
+
+       ldct    a6, a3
+       dsync
+       and     a6, a6, a4
+       beq     a6, a2, 2f
+       bgeui   a5, 2, 1b
+       retw
+
+2:     j 2b
+
+
+/*
+ * void __invalidate_icache_page_phys(ulong start)
+ */
+
+ENTRY(__invalidate_icache_page_phys)
+       entry   sp, 16
+
+       movi    a3, XCHAL_ICACHE_SIZE
+       movi    a4, PAGE_MASK | 1
+       addi    a2, a2, 1
+
+1:     addi    a3, a3, -XCHAL_ICACHE_LINESIZE
+
+       lict    a6, a3
+       isync
+       and     a6, a6, a4
+       beq     a6, a2, 2f
+       bgeui   a3, 2, 1b
+       retw
+
+2:     iii     a3, 0
+       bgeui   a3, 2, 1b
+       retw
+
+
+#if 0
+
+       movi    a3, XCHAL_DCACHE_WAYS - 1
+       movi    a4, PAGE_SIZE
+
+1:     mov     a5, a2
+       add     a6, a2, a4
+
+2:     diwbi   a5, 0
+       diwbi   a5, XCHAL_DCACHE_LINESIZE
+       diwbi   a5, XCHAL_DCACHE_LINESIZE * 2
+       diwbi   a5, XCHAL_DCACHE_LINESIZE * 3
+
+       addi    a5, a5, XCHAL_DCACHE_LINESIZE * 4
+       blt     a5, a6, 2b
+
+       addi    a3, a3, -1
+       addi    a2, a2, XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS
+       bgez    a3, 1b
+
+       retw
+
+ENTRY(__invalidate_icache_page_index)
+       entry   sp, 16
+
+       movi    a3, XCHAL_ICACHE_WAYS - 1
+       movi    a4, PAGE_SIZE
+
+1:     mov     a5, a2
+       add     a6, a2, a4
+
+2:     iii     a5, 0
+       iii     a5, XCHAL_ICACHE_LINESIZE
+       iii     a5, XCHAL_ICACHE_LINESIZE * 2
+       iii     a5, XCHAL_ICACHE_LINESIZE * 3
+
+       addi    a5, a5, XCHAL_ICACHE_LINESIZE * 4
+       blt     a5, a6, 2b
+
+       addi    a3, a3, -1
+       addi    a2, a2, XCHAL_ICACHE_SIZE / XCHAL_ICACHE_WAYS
+       bgez    a3, 2b
+
+       retw
+
+#endif
+
+
+
+
+
+
diff --git a/arch/xtensa/mm/pgtable.c b/arch/xtensa/mm/pgtable.c
new file mode 100644 (file)
index 0000000..e5e119c
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * arch/xtensa/mm/fault.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ */
+
+#if (DCACHE_SIZE > PAGE_SIZE)
+
+pte_t* pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+{
+       pte_t *pte, p;
+       int color = ADDR_COLOR(address);
+       int i;
+
+       p = (pte_t*) __get_free_pages(GFP_KERNEL|__GFP_REPEAT, COLOR_ORDER);
+
+       if (likely(p)) {
+               struct page *page;
+
+               for (i = 0; i < COLOR_SIZE; i++, p++) {
+                       page = virt_to_page(pte);
+
+                       set_page_count(page, 1);
+                       ClearPageCompound(page);
+
+                       if (ADDR_COLOR(p) == color)
+                               pte = p;
+                       else
+                               free_page(p);
+               }
+               clear_page(pte);
+       }
+       return pte;
+}
+
+#ifdef PROFILING
+
+int mask;
+int hit;
+int flush;
+
+#endif
+
+struct page* pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+       struct page *page, p;
+       int color = ADDR_COLOR(address);
+
+       p = alloc_pages(GFP_KERNEL | __GFP_REPEAT, PTE_ORDER);
+
+       if (likely(p)) {
+               for (i = 0; i < PAGE_ORDER; i++) {
+                       set_page_count(p, 1);
+                       ClearPageCompound(p);
+
+                       if (PADDR_COLOR(page_address(pg)) == color)
+                               page = p;
+                       else
+                               free_page(p);
+               }
+               clear_highpage(page);
+       }
+
+       return page;
+}
+
+#endif
+
+
+
diff --git a/arch/xtensa/mm/tlb.c b/arch/xtensa/mm/tlb.c
new file mode 100644 (file)
index 0000000..d3bd3bf
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ * arch/xtensa/mm/mmu.c
+ *
+ * Logic that manipulates the Xtensa MMU.  Derived from MIPS.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2003 Tensilica Inc.
+ *
+ * Joe Taylor
+ * Chris Zankel        <chris@zankel.net>
+ * Marc Gauthier
+ */
+
+#include <linux/mm.h>
+#include <asm/processor.h>
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
+#include <asm/system.h>
+#include <asm/cacheflush.h>
+
+
+static inline void __flush_itlb_all (void)
+{
+       int way, index;
+
+       for (way = 0; way < XCHAL_ITLB_ARF_WAYS; way++) {
+               for (index = 0; index < ITLB_ENTRIES_PER_ARF_WAY; index++) {
+                       int entry = way + (index << PAGE_SHIFT);
+                       invalidate_itlb_entry_no_isync (entry);
+               }
+       }
+       asm volatile ("isync\n");
+}
+
+static inline void __flush_dtlb_all (void)
+{
+       int way, index;
+
+       for (way = 0; way < XCHAL_DTLB_ARF_WAYS; way++) {
+               for (index = 0; index < DTLB_ENTRIES_PER_ARF_WAY; index++) {
+                       int entry = way + (index << PAGE_SHIFT);
+                       invalidate_dtlb_entry_no_isync (entry);
+               }
+       }
+       asm volatile ("isync\n");
+}
+
+
+void flush_tlb_all (void)
+{
+       __flush_itlb_all();
+       __flush_dtlb_all();
+}
+
+/* If mm is current, we simply assign the current task a new ASID, thus,
+ * invalidating all previous tlb entries. If mm is someone else's user mapping,
+ * wie invalidate the context, thus, when that user mapping is swapped in,
+ * a new context will be assigned to it.
+ */
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+#if 0
+       printk("[tlbmm<%lx>]\n", (unsigned long)mm->context);
+#endif
+
+       if (mm == current->active_mm) {
+               int flags;
+               local_save_flags(flags);
+               get_new_mmu_context(mm, asid_cache);
+               set_rasid_register(ASID_INSERT(mm->context));
+               local_irq_restore(flags);
+       }
+       else
+               mm->context = 0;
+}
+
+void flush_tlb_range (struct vm_area_struct *vma,
+                     unsigned long start, unsigned long end)
+{
+       struct mm_struct *mm = vma->vm_mm;
+       unsigned long flags;
+
+       if (mm->context == NO_CONTEXT)
+               return;
+
+#if 0
+       printk("[tlbrange<%02lx,%08lx,%08lx>]\n",
+                       (unsigned long)mm->context, start, end);
+#endif
+       local_save_flags(flags);
+
+       if (end-start + (PAGE_SIZE-1) <= SMALLEST_NTLB_ENTRIES << PAGE_SHIFT) {
+               int oldpid = get_rasid_register();
+               set_rasid_register (ASID_INSERT(mm->context));
+               start &= PAGE_MASK;
+               if (vma->vm_flags & VM_EXEC)
+                       while(start < end) {
+                               invalidate_itlb_mapping(start);
+                               invalidate_dtlb_mapping(start);
+                               start += PAGE_SIZE;
+                       }
+               else
+                       while(start < end) {
+                               invalidate_dtlb_mapping(start);
+                               start += PAGE_SIZE;
+                       }
+
+               set_rasid_register(oldpid);
+       } else {
+               get_new_mmu_context(mm, asid_cache);
+               if (mm == current->active_mm)
+                       set_rasid_register(ASID_INSERT(mm->context));
+       }
+       local_irq_restore(flags);
+}
+
+void flush_tlb_page (struct vm_area_struct *vma, unsigned long page)
+{
+       struct mm_struct* mm = vma->vm_mm;
+       unsigned long flags;
+       int oldpid;
+#if 0
+       printk("[tlbpage<%02lx,%08lx>]\n",
+                       (unsigned long)mm->context, page);
+#endif
+
+       if(mm->context == NO_CONTEXT)
+               return;
+
+       local_save_flags(flags);
+
+               oldpid = get_rasid_register();
+
+       if (vma->vm_flags & VM_EXEC)
+               invalidate_itlb_mapping(page);
+       invalidate_dtlb_mapping(page);
+
+       set_rasid_register(oldpid);
+
+       local_irq_restore(flags);
+
+#if 0
+       flush_tlb_all();
+       return;
+#endif
+}
+
+
+#ifdef DEBUG_TLB
+
+#define USE_ITLB  0
+#define USE_DTLB  1
+
+struct way_config_t {
+       int indicies;
+       int indicies_log2;
+       int pgsz_log2;
+       int arf;
+};
+
+static struct way_config_t itlb[XCHAL_ITLB_WAYS] =
+{
+       { XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ENTRIES),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ENTRIES_LOG2),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, PAGESZ_LOG2_MIN),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ARF)
+       },
+       { XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ENTRIES),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ENTRIES_LOG2),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, PAGESZ_LOG2_MIN),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ARF)
+       },
+       { XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ENTRIES),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ENTRIES_LOG2),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, PAGESZ_LOG2_MIN),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ARF)
+       },
+       { XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ENTRIES),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ENTRIES_LOG2),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, PAGESZ_LOG2_MIN),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ARF)
+       },
+       { XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ENTRIES),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ENTRIES_LOG2),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, PAGESZ_LOG2_MIN),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ARF)
+       },
+       { XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ENTRIES),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ENTRIES_LOG2),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, PAGESZ_LOG2_MIN),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ARF)
+       },
+       { XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ENTRIES),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ENTRIES_LOG2),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, PAGESZ_LOG2_MIN),
+         XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ARF)
+       }
+};
+
+static struct way_config_t dtlb[XCHAL_DTLB_WAYS] =
+{
+       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ENTRIES),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ENTRIES_LOG2),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, PAGESZ_LOG2_MIN),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ARF)
+       },
+       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ENTRIES),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ENTRIES_LOG2),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, PAGESZ_LOG2_MIN),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ARF)
+       },
+       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ENTRIES),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ENTRIES_LOG2),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, PAGESZ_LOG2_MIN),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ARF)
+       },
+       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ENTRIES),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ENTRIES_LOG2),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, PAGESZ_LOG2_MIN),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ARF)
+       },
+       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ENTRIES),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ENTRIES_LOG2),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, PAGESZ_LOG2_MIN),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ARF)
+       },
+       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ENTRIES),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ENTRIES_LOG2),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, PAGESZ_LOG2_MIN),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ARF)
+       },
+       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ENTRIES),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ENTRIES_LOG2),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, PAGESZ_LOG2_MIN),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ARF)
+       },
+       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ENTRIES),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ENTRIES_LOG2),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, PAGESZ_LOG2_MIN),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ARF)
+       },
+       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ENTRIES),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ENTRIES_LOG2),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, PAGESZ_LOG2_MIN),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ARF)
+       },
+       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ENTRIES),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ENTRIES_LOG2),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, PAGESZ_LOG2_MIN),
+         XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ARF)
+       }
+};
+
+/*  Total number of entries:  */
+#define ITLB_TOTAL_ENTRIES     \
+               XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ENTRIES) + \
+               XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ENTRIES) + \
+               XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ENTRIES) + \
+               XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ENTRIES) + \
+               XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ENTRIES) + \
+               XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ENTRIES) + \
+               XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ENTRIES)
+#define DTLB_TOTAL_ENTRIES     \
+               XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ENTRIES) + \
+               XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ENTRIES) + \
+               XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ENTRIES) + \
+               XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ENTRIES) + \
+               XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ENTRIES) + \
+               XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ENTRIES) + \
+               XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ENTRIES) + \
+               XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ENTRIES) + \
+               XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ENTRIES) + \
+               XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ENTRIES)
+
+
+typedef struct {
+    unsigned           va;
+    unsigned           pa;
+    unsigned char      asid;
+    unsigned char      ca;
+    unsigned char      way;
+    unsigned char      index;
+    unsigned char      pgsz_log2;      /* 0 .. 32 */
+    unsigned char      type;           /* 0=ITLB 1=DTLB */
+} tlb_dump_entry_t;
+
+/*  Return -1 if a precedes b, +1 if a follows b, 0 if same:  */
+int cmp_tlb_dump_info( tlb_dump_entry_t *a, tlb_dump_entry_t *b )
+{
+    if (a->asid < b->asid) return -1;
+    if (a->asid > b->asid) return  1;
+    if (a->va < b->va) return -1;
+    if (a->va > b->va) return  1;
+    if (a->pa < b->pa) return -1;
+    if (a->pa > b->pa) return  1;
+    if (a->ca < b->ca) return -1;
+    if (a->ca > b->ca) return  1;
+    if (a->way < b->way) return -1;
+    if (a->way > b->way) return  1;
+    if (a->index < b->index) return -1;
+    if (a->index > b->index) return  1;
+    return 0;
+}
+
+void sort_tlb_dump_info( tlb_dump_entry_t *t, int n )
+{
+    int i, j;
+    /*  Simple O(n*n) sort:  */
+    for (i = 0; i < n-1; i++)
+       for (j = i+1; j < n; j++)
+           if (cmp_tlb_dump_info(t+i, t+j) > 0) {
+               tlb_dump_entry_t tmp = t[i];
+               t[i] = t[j];
+               t[j] = tmp;
+           }
+}
+
+
+static tlb_dump_entry_t itlb_dump_info[ITLB_TOTAL_ENTRIES];
+static tlb_dump_entry_t dtlb_dump_info[DTLB_TOTAL_ENTRIES];
+
+
+static inline char *way_type (int type)
+{
+       return type ? "autorefill" : "non-autorefill";
+}
+
+void print_entry (struct way_config_t *way_info,
+                 unsigned int way,
+                 unsigned int index,
+                 unsigned int virtual,
+                 unsigned int translation)
+{
+       char valid_chr;
+       unsigned int va, pa, asid, ca;
+
+       va = virtual &
+               ~((1 << (way_info->pgsz_log2 + way_info->indicies_log2)) - 1);
+       asid = virtual & ((1 << XCHAL_MMU_ASID_BITS) - 1);
+       pa = translation & ~((1 << way_info->pgsz_log2) - 1);
+       ca = translation & ((1 << XCHAL_MMU_CA_BITS) - 1);
+       valid_chr = asid ? 'V' : 'I';
+
+       /* Compute and incorporate the effect of the index bits on the
+        * va.  It's more useful for kernel debugging, since we always
+        * want to know the effective va anyway. */
+
+       va += index << way_info->pgsz_log2;
+
+       printk ("\t[%d,%d] (%c) vpn 0x%.8x  ppn 0x%.8x  asid 0x%.2x  am 0x%x\n",
+               way, index, valid_chr, va, pa, asid, ca);
+}
+
+void print_itlb_entry (struct way_config_t *way_info, int way, int index)
+{
+       print_entry (way_info, way, index,
+                    read_itlb_virtual (way + (index << way_info->pgsz_log2)),
+                    read_itlb_translation (way + (index << way_info->pgsz_log2)));
+}
+
+void print_dtlb_entry (struct way_config_t *way_info, int way, int index)
+{
+       print_entry (way_info, way, index,
+                    read_dtlb_virtual (way + (index << way_info->pgsz_log2)),
+                    read_dtlb_translation (way + (index << way_info->pgsz_log2)));
+}
+
+void dump_itlb (void)
+{
+       int way, index;
+
+       printk ("\nITLB: ways = %d\n", XCHAL_ITLB_WAYS);
+
+       for (way = 0; way < XCHAL_ITLB_WAYS; way++) {
+               printk ("\nWay: %d, Entries: %d, MinPageSize: %d, Type: %s\n",
+                       way, itlb[way].indicies,
+                       itlb[way].pgsz_log2, way_type(itlb[way].arf));
+               for (index = 0; index < itlb[way].indicies; index++) {
+                       print_itlb_entry(&itlb[way], way, index);
+               }
+       }
+}
+
+void dump_dtlb (void)
+{
+       int way, index;
+
+       printk ("\nDTLB: ways = %d\n", XCHAL_DTLB_WAYS);
+
+       for (way = 0; way < XCHAL_DTLB_WAYS; way++) {
+               printk ("\nWay: %d, Entries: %d, MinPageSize: %d, Type: %s\n",
+                       way, dtlb[way].indicies,
+                       dtlb[way].pgsz_log2, way_type(dtlb[way].arf));
+               for (index = 0; index < dtlb[way].indicies; index++) {
+                       print_dtlb_entry(&dtlb[way], way, index);
+               }
+       }
+}
+
+void dump_tlb (tlb_dump_entry_t *tinfo, struct way_config_t *config,
+               int entries, int ways, int type, int show_invalid)
+{
+    tlb_dump_entry_t *e = tinfo;
+    int way, i;
+
+    /*  Gather all info:  */
+    for (way = 0; way < ways; way++) {
+       struct way_config_t *cfg = config + way;
+       for (i = 0; i < cfg->indicies; i++) {
+           unsigned wayindex = way + (i << cfg->pgsz_log2);
+           unsigned vv = (type ? read_dtlb_virtual (wayindex)
+                               : read_itlb_virtual (wayindex));
+           unsigned pp = (type ? read_dtlb_translation (wayindex)
+                               : read_itlb_translation (wayindex));
+
+           /* Compute and incorporate the effect of the index bits on the
+            * va.  It's more useful for kernel debugging, since we always
+            * want to know the effective va anyway. */
+
+           e->va = (vv & ~((1 << (cfg->pgsz_log2 + cfg->indicies_log2)) - 1));
+           e->va += (i << cfg->pgsz_log2);
+           e->pa = (pp & ~((1 << cfg->pgsz_log2) - 1));
+           e->asid = (vv & ((1 << XCHAL_MMU_ASID_BITS) - 1));
+           e->ca = (pp & ((1 << XCHAL_MMU_CA_BITS) - 1));
+           e->way = way;
+           e->index = i;
+           e->pgsz_log2 = cfg->pgsz_log2;
+           e->type = type;
+           e++;
+       }
+    }
+#if 1
+    /*  Sort by ASID and VADDR:  */
+    sort_tlb_dump_info (tinfo, entries);
+#endif
+
+    /*  Display all sorted info:  */
+    printk ("\n%cTLB dump:\n", (type ? 'D' : 'I'));
+    for (e = tinfo, i = 0; i < entries; i++, e++) {
+#if 0
+       if (e->asid == 0 && !show_invalid)
+           continue;
+#endif
+       printk ("%c way=%d i=%d  ASID=%02X V=%08X -> P=%08X CA=%X (%d %cB)\n",
+               (e->type ? 'D' : 'I'), e->way, e->index,
+               e->asid, e->va, e->pa, e->ca,
+               (1 << (e->pgsz_log2 % 10)),
+               " kMG"[e->pgsz_log2 / 10]
+               );
+    }
+}
+
+void dump_tlbs2 (int showinv)
+{
+    dump_tlb (itlb_dump_info, itlb, ITLB_TOTAL_ENTRIES, XCHAL_ITLB_WAYS, 0, showinv);
+    dump_tlb (dtlb_dump_info, dtlb, DTLB_TOTAL_ENTRIES, XCHAL_DTLB_WAYS, 1, showinv);
+}
+
+void dump_all_tlbs (void)
+{
+    dump_tlbs2 (1);
+}
+
+void dump_valid_tlbs (void)
+{
+    dump_tlbs2 (0);
+}
+
+
+void dump_tlbs (void)
+{
+       dump_itlb();
+       dump_dtlb();
+}
+
+void dump_cache_tag(int dcache, int idx)
+{
+       int w, i, s, e;
+       unsigned long tag, index;
+       unsigned long num_lines, num_ways, cache_size, line_size;
+
+       num_ways = dcache ? XCHAL_DCACHE_WAYS : XCHAL_ICACHE_WAYS;
+       cache_size = dcache ? XCHAL_DCACHE_SIZE : XCHAL_ICACHE_SIZE;
+       line_size = dcache ? XCHAL_DCACHE_LINESIZE : XCHAL_ICACHE_LINESIZE;
+
+       num_lines = cache_size / num_ways;
+
+       s = 0; e = num_lines;
+
+       if (idx >= 0)
+               e = (s = idx * line_size) + 1;
+
+       for (i = s; i < e; i+= line_size) {
+               printk("\nline %#08x:", i);
+               for (w = 0; w < num_ways; w++) {
+                       index = w * num_lines + i;
+                       if (dcache)
+                               __asm__ __volatile__("ldct %0, %1\n\t"
+                                               : "=a"(tag) : "a"(index));
+                       else
+                               __asm__ __volatile__("lict %0, %1\n\t"
+                                               : "=a"(tag) : "a"(index));
+
+                       printk(" %#010lx", tag);
+               }
+       }
+       printk ("\n");
+}
+
+void dump_icache(int index)
+{
+       unsigned long data, addr;
+       int w, i;
+
+       const unsigned long num_ways = XCHAL_ICACHE_WAYS;
+       const unsigned long cache_size = XCHAL_ICACHE_SIZE;
+       const unsigned long line_size = XCHAL_ICACHE_LINESIZE;
+       const unsigned long num_lines = cache_size / num_ways / line_size;
+
+       for (w = 0; w < num_ways; w++) {
+               printk ("\nWay %d", w);
+
+               for (i = 0; i < line_size; i+= 4) {
+                       addr = w * num_lines + index * line_size + i;
+                       __asm__ __volatile__("licw %0, %1\n\t"
+                                       : "=a"(data) : "a"(addr));
+                       printk(" %#010lx", data);
+               }
+       }
+       printk ("\n");
+}
+
+void dump_cache_tags(void)
+{
+       printk("Instruction cache\n");
+       dump_cache_tag(0, -1);
+       printk("Data cache\n");
+       dump_cache_tag(1, -1);
+}
+
+#endif
diff --git a/arch/xtensa/platform-iss/Makefile b/arch/xtensa/platform-iss/Makefile
new file mode 100644 (file)
index 0000000..5b394e9
--- /dev/null
@@ -0,0 +1,13 @@
+# $Id: Makefile,v 1.1.1.1 2002/08/28 16:10:14 aroll Exp $
+#
+# Makefile for the Xtensa Instruction Set Simulator (ISS)
+# "prom monitor" library routines under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are in the main makefile...
+
+obj-y                  = io.o console.o setup.o network.o
+
diff --git a/arch/xtensa/platform-iss/console.c b/arch/xtensa/platform-iss/console.c
new file mode 100644 (file)
index 0000000..4fbddf9
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * arch/xtensa/platform-iss/console.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001-2005 Tensilica Inc.
+ *   Authors   Christian Zankel, Joe Taylor
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/major.h>
+#include <linux/param.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/console.h>
+
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+
+#include <xtensa/simcall.h>
+
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#endif
+
+#define SERIAL_MAX_NUM_LINES 1
+#define SERIAL_TIMER_VALUE (20 * HZ)
+
+static struct tty_driver *serial_driver;
+static struct timer_list serial_timer;
+
+static DEFINE_SPINLOCK(timer_lock);
+
+int errno;
+
+static int __simc (int a, int b, int c, int d, int e, int f)
+{
+       int ret;
+       __asm__ __volatile__ ("simcall\n"
+                       "mov %0, a2\n"
+                       "mov %1, a3\n" : "=a" (ret), "=a" (errno)
+                       : : "a2", "a3");
+       return ret;
+}
+
+static char *serial_version = "0.1";
+static char *serial_name = "ISS serial driver";
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+
+static void rs_poll(unsigned long);
+
+static int rs_open(struct tty_struct *tty, struct file * filp)
+{
+       int line = tty->index;
+
+       if ((line < 0) || (line >= SERIAL_MAX_NUM_LINES))
+               return -ENODEV;
+
+       spin_lock(&timer_lock);
+
+       if (tty->count == 1) {
+               init_timer(&serial_timer);
+               serial_timer.data = (unsigned long) tty;
+               serial_timer.function = rs_poll;
+               mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
+       }
+       spin_unlock(&timer_lock);
+
+       return 0;
+}
+
+
+/*
+ * ------------------------------------------------------------
+ * iss_serial_close()
+ *
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+       spin_lock(&timer_lock);
+       if (tty->count == 1)
+               del_timer_sync(&serial_timer);
+       spin_unlock(&timer_lock);
+}
+
+
+static int rs_write(struct tty_struct * tty,
+                   const unsigned char *buf, int count)
+{
+       /* see drivers/char/serialX.c to reference original version */
+
+       __simc (SYS_write, 1, (unsigned long)buf, count, 0, 0);
+       return count;
+}
+
+static void rs_poll(unsigned long priv)
+{
+       struct tty_struct* tty = (struct tty_struct*) priv;
+
+       struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
+       int i = 0;
+       unsigned char c;
+
+       spin_lock(&timer_lock);
+
+       while (__simc(SYS_select_one, 0, XTISS_SELECT_ONE_READ, (int)&tv,0,0)){
+               __simc (SYS_read, 0, (unsigned long)&c, 1, 0, 0);
+               tty->flip.count++;
+               *tty->flip.char_buf_ptr++ = c;
+               *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+               i++;
+       }
+
+       if (i)
+               tty_flip_buffer_push(tty);
+
+
+       mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
+       spin_unlock(&timer_lock);
+}
+
+
+static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       char buf[2];
+
+       if (!tty)
+               return;
+
+       buf[0] = ch;
+       buf[1] = '\0';          /* Is this NULL necessary? */
+       __simc (SYS_write, 1, (unsigned long) buf, 1, 0, 0);
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+       /* Let's say iss can always accept 2K characters.. */
+       return 2 * 1024;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+       /* the iss doesn't buffer characters */
+       return 0;
+}
+
+static void rs_hangup(struct tty_struct *tty)
+{
+       /* Stub, once again.. */
+}
+
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       /* Stub, once again.. */
+}
+
+static int rs_read_proc(char *page, char **start, off_t off, int count,
+                       int *eof, void *data)
+{
+       int len = 0;
+       off_t begin = 0;
+
+       len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+       *eof = 1;
+
+       if (off >= len + begin)
+               return 0;
+
+       *start = page + (off - begin);
+       return ((count < begin + len - off) ? count : begin + len - off);
+}
+
+
+static struct tty_operations serial_ops = {
+       .open = rs_open,
+       .close = rs_close,
+       .write = rs_write,
+       .put_char = rs_put_char,
+       .flush_chars = rs_flush_chars,
+       .write_room = rs_write_room,
+       .chars_in_buffer = rs_chars_in_buffer,
+       .hangup = rs_hangup,
+       .wait_until_sent = rs_wait_until_sent,
+       .read_proc = rs_read_proc
+};
+
+int __init rs_init(void)
+{
+       serial_driver = alloc_tty_driver(1);
+
+       printk ("%s %s\n", serial_name, serial_version);
+
+       /* Initialize the tty_driver structure */
+
+       serial_driver->owner = THIS_MODULE;
+       serial_driver->driver_name = "iss_serial";
+       serial_driver->name = "ttyS";
+       serial_driver->major = TTY_MAJOR;
+       serial_driver->minor_start = 64;
+       serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+       serial_driver->subtype = SERIAL_TYPE_NORMAL;
+       serial_driver->init_termios = tty_std_termios;
+       serial_driver->init_termios.c_cflag =
+               B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       serial_driver->flags = TTY_DRIVER_REAL_RAW;
+
+       tty_set_operations(serial_driver, &serial_ops);
+
+       if (tty_register_driver(serial_driver))
+               panic("Couldn't register serial driver\n");
+       return 0;
+}
+
+
+static __exit void rs_exit(void)
+{
+       int error;
+
+       if ((error = tty_unregister_driver(serial_driver)))
+               printk("ISS_SERIAL: failed to unregister serial driver (%d)\n",
+                      error);
+       put_tty_driver(serial_driver);
+}
+
+
+/* We use `late_initcall' instead of just `__initcall' as a workaround for
+ * the fact that (1) simcons_tty_init can't be called before tty_init,
+ * (2) tty_init is called via `module_init', (3) if statically linked,
+ * module_init == device_init, and (4) there's no ordering of init lists.
+ * We can do this easily because simcons is always statically linked, but
+ * other tty drivers that depend on tty_init and which must use
+ * `module_init' to declare their init routines are likely to be broken.
+ */
+
+late_initcall(rs_init);
+
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+static void iss_console_write(struct console *co, const char *s, unsigned count)
+{
+       int len = strlen(s);
+
+       if (s != 0 && *s != 0)
+               __simc (SYS_write, 1, (unsigned long)s,
+                       count < len ? count : len,0,0);
+}
+
+static struct tty_driver* iss_console_device(struct console *c, int *index)
+{
+       *index = c->index;
+       return serial_driver;
+}
+
+
+static struct console sercons = {
+       .name = "ttyS",
+       .write = iss_console_write,
+       .device = iss_console_device,
+       .flags = CON_PRINTBUFFER,
+       .index = -1
+};
+
+static int __init iss_console_init(void)
+{
+       register_console(&sercons);
+       return 0;
+}
+
+console_initcall(iss_console_init);
+
+#endif /* CONFIG_SERIAL_CONSOLE */
+
diff --git a/arch/xtensa/platform-iss/io.c b/arch/xtensa/platform-iss/io.c
new file mode 100644 (file)
index 0000000..5b161a5
--- /dev/null
@@ -0,0 +1,32 @@
+/* This file isn't really needed right now. */
+
+#if 0
+
+#include <asm/io.h>
+#include <xtensa/simcall.h>
+
+extern int __simc ();
+
+
+char iss_serial_getc()
+{
+  char c;
+  __simc( SYS_read, 0, &c, 1 );
+  return c;
+}
+
+void iss_serial_putc( char c )
+{
+  __simc( SYS_write, 1, &c, 1 );
+}
+
+void iss_serial_puts( char *s )
+{
+  if( s != 0 && *s != 0 )
+    __simc( SYS_write, 1, s, strlen(s) );
+}
+
+/*#error Need I/O ports to specific hardware!*/
+
+#endif
+
diff --git a/arch/xtensa/platform-iss/network.c b/arch/xtensa/platform-iss/network.c
new file mode 100644 (file)
index 0000000..498d7dc
--- /dev/null
@@ -0,0 +1,855 @@
+/*
+ *
+ * arch/xtensa/platform-iss/network.c
+ *
+ * Platform specific initialization.
+ *
+ * Authors: Chris Zankel <chris@zankel.net>
+ * Based on work form the UML team.
+ *
+ * Copyright 2005 Tensilica 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/config.h>
+#include <linux/list.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/if_ether.h>
+#include <linux/inetdevice.h>
+#include <linux/init.h>
+#include <linux/if_tun.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/bootmem.h>
+#include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
+#include <linux/timer.h>
+
+#include <xtensa/simcall.h>
+
+#define DRIVER_NAME "iss-netdev"
+#define ETH_MAX_PACKET 1500
+#define ETH_HEADER_OTHER 14
+#define ISS_NET_TIMER_VALUE (2 * HZ)
+
+
+static DEFINE_SPINLOCK(opened_lock);
+static LIST_HEAD(opened);
+
+static DEFINE_SPINLOCK(devices_lock);
+static LIST_HEAD(devices);
+
+/* ------------------------------------------------------------------------- */
+
+/* We currently only support the TUNTAP transport protocol. */
+
+#define TRANSPORT_TUNTAP_NAME "tuntap"
+#define TRANSPORT_TUNTAP_MTU ETH_MAX_PACKET
+
+struct tuntap_info {
+       char dev_name[IFNAMSIZ];
+       int fixed_config;
+       unsigned char gw[ETH_ALEN];
+       int fd;
+};
+
+/* ------------------------------------------------------------------------- */
+
+
+/* This structure contains out private information for the driver. */
+
+struct iss_net_private {
+
+       struct list_head device_list;
+       struct list_head opened_list;
+
+       spinlock_t lock;
+       struct net_device *dev;
+       struct platform_device pdev;
+       struct timer_list tl;
+       struct net_device_stats stats;
+
+       struct timer_list timer;
+       unsigned int timer_val;
+
+       int index;
+       int mtu;
+
+       unsigned char mac[ETH_ALEN];
+       int have_mac;
+
+       struct {
+               union {
+                       struct tuntap_info tuntap;
+               } info;
+
+               int (*open)(struct iss_net_private *lp);
+               void (*close)(struct iss_net_private *lp);
+               int (*read)(struct iss_net_private *lp, struct sk_buff **skb);
+               int (*write)(struct iss_net_private *lp, struct sk_buff **skb);
+               unsigned short (*protocol)(struct sk_buff *skb);
+               int (*poll)(struct iss_net_private *lp);
+       } tp;
+
+};
+
+/* ======================= ISS SIMCALL INTERFACE =========================== */
+
+/* Note: __simc must _not_ be declared inline! */
+
+static int errno;
+
+static int __simc (int a, int b, int c, int d, int e, int f)
+{
+       int ret;
+       __asm__ __volatile__ ("simcall\n"
+                             "mov %0, a2\n"
+                             "mov %1, a3\n" : "=a" (ret), "=a" (errno)
+                             : : "a2", "a3");
+       return ret;
+}
+
+static int inline simc_open(char *file, int flags, int mode)
+{
+       return __simc(SYS_open, (int) file, flags, mode, 0, 0);
+}
+
+static int inline simc_close(int fd)
+{
+       return __simc(SYS_close, fd, 0, 0, 0, 0);
+}
+
+static int inline simc_ioctl(int fd, int request, void *arg)
+{
+       return __simc(SYS_ioctl, fd, request, (int) arg, 0, 0);
+}
+
+static int inline simc_read(int fd, void *buf, size_t count)
+{
+       return __simc(SYS_read, fd, (int) buf, count, 0, 0);
+}
+
+static int inline simc_write(int fd, void *buf, size_t count)
+{
+       return __simc(SYS_write, fd, (int) buf, count, 0, 0);
+}
+
+static int inline simc_poll(int fd)
+{
+       struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
+
+       return __simc(SYS_select_one, fd, XTISS_SELECT_ONE_READ, (int)&tv,0,0);
+}
+
+/* ================================ HELPERS ================================ */
+
+
+static char *split_if_spec(char *str, ...)
+{
+       char **arg, *end;
+       va_list ap;
+
+       va_start(ap, str);
+       while ((arg = va_arg(ap, char**)) != NULL) {
+               if (*str == '\0')
+                       return NULL;
+               end = strchr(str, ',');
+               if (end != str)
+                       *arg = str;
+               if (end == NULL)
+                       return NULL;
+               *end ++ = '\0';
+               str = end;
+       }
+       va_end(ap);
+       return str;
+}
+
+
+#if 0
+/* Adjust SKB. */
+
+struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra)
+{
+       if ((skb != NULL) && (skb_tailroom(skb) < extra)) {
+               struct sk_buff *skb2;
+
+               skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC);
+               dev_kfree_skb(skb);
+               skb = skb2;
+       }
+       if (skb != NULL)
+               skb_put(skb, extra);
+
+       return skb;
+}
+#endif
+
+/* Return the IP address as a string for a given device. */
+
+static void dev_ip_addr(void *d, char *buf, char *bin_buf)
+{
+       struct net_device *dev = d;
+       struct in_device *ip = dev->ip_ptr;
+       struct in_ifaddr *in;
+       u32 addr;
+
+       if ((ip == NULL) || ((in = ip->ifa_list) == NULL)) {
+               printk(KERN_WARNING "Device not assigned an IP address!\n");
+               return;
+       }
+
+       addr = in->ifa_address;
+       sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff,
+               (addr >> 16) & 0xff, addr >> 24);
+
+       if (bin_buf) {
+               bin_buf[0] = addr & 0xff;
+               bin_buf[1] = (addr >> 8) & 0xff;
+               bin_buf[2] = (addr >> 16) & 0xff;
+               bin_buf[3] = addr >> 24;
+       }
+}
+
+/* Set Ethernet address of the specified device. */
+
+static void inline set_ether_mac(void *d, unsigned char *addr)
+{
+       struct net_device *dev = d;
+       memcpy(dev->dev_addr, addr, ETH_ALEN);
+}
+
+
+/* ======================= TUNTAP TRANSPORT INTERFACE ====================== */
+
+static int tuntap_open(struct iss_net_private *lp)
+{
+       struct ifreq ifr;
+       char *dev_name = lp->tp.info.tuntap.dev_name;
+       int err = -EINVAL;
+       int fd;
+
+       /* We currently only support a fixed configuration. */
+
+       if (!lp->tp.info.tuntap.fixed_config)
+               return -EINVAL;
+
+       if ((fd = simc_open("/dev/net/tun", 02, 0)) < 0) {      /* O_RDWR */
+               printk("Failed to open /dev/net/tun, returned %d "
+                      "(errno = %d)\n", fd, errno);
+               return fd;
+       }
+
+       memset(&ifr, 0, sizeof ifr);
+       ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+       strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name - 1);
+
+       if ((err = simc_ioctl(fd, TUNSETIFF, (void*) &ifr)) < 0) {
+               printk("Failed to set interface, returned %d "
+                      "(errno = %d)\n", err, errno);
+               simc_close(fd);
+               return err;
+       }
+
+       lp->tp.info.tuntap.fd = fd;
+       return err;
+}
+
+static void tuntap_close(struct iss_net_private *lp)
+{
+#if 0
+       if (lp->tp.info.tuntap.fixed_config)
+               iter_addresses(lp->tp.info.tuntap.dev, close_addr, lp->host.dev_name);
+#endif
+       simc_close(lp->tp.info.tuntap.fd);
+       lp->tp.info.tuntap.fd = -1;
+}
+
+static int tuntap_read (struct iss_net_private *lp, struct sk_buff **skb)
+{
+#if 0
+       *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
+       if (*skb == NULL)
+               return -ENOMEM;
+#endif
+
+       return simc_read(lp->tp.info.tuntap.fd,
+                       (*skb)->data, (*skb)->dev->mtu + ETH_HEADER_OTHER);
+}
+
+static int tuntap_write (struct iss_net_private *lp, struct sk_buff **skb)
+{
+       return simc_write(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->len);
+}
+
+unsigned short tuntap_protocol(struct sk_buff *skb)
+{
+       return eth_type_trans(skb, skb->dev);
+}
+
+static int tuntap_poll(struct iss_net_private *lp)
+{
+       return simc_poll(lp->tp.info.tuntap.fd);
+}
+
+/*
+ * Currently only a device name is supported.
+ * ethX=tuntap[,[mac address][,[device name]]]
+ */
+
+static int tuntap_probe(struct iss_net_private *lp, int index, char *init)
+{
+       const int len = strlen(TRANSPORT_TUNTAP_NAME);
+       char *dev_name = NULL, *mac_str = NULL, *rem = NULL;
+
+       /* Transport should be 'tuntap': ethX=tuntap,mac,dev_name */
+
+       if (strncmp(init, TRANSPORT_TUNTAP_NAME, len))
+               return 0;
+
+       if (*(init += strlen(TRANSPORT_TUNTAP_NAME)) == ',') {
+               if ((rem=split_if_spec(init+1, &mac_str, &dev_name)) != NULL) {
+                       printk("Extra garbage on specification : '%s'\n", rem);
+                       return 0;
+               }
+       } else if (*init != '\0') {
+               printk("Invalid argument: %s. Skipping device!\n", init);
+               return 0;
+       }
+
+       if (dev_name) {
+               strncpy(lp->tp.info.tuntap.dev_name, dev_name,
+                        sizeof lp->tp.info.tuntap.dev_name);
+               lp->tp.info.tuntap.fixed_config = 1;
+       } else
+               strcpy(lp->tp.info.tuntap.dev_name, TRANSPORT_TUNTAP_NAME);
+
+
+#if 0
+       if (setup_etheraddr(mac_str, lp->mac))
+               lp->have_mac = 1;
+#endif
+       lp->mtu = TRANSPORT_TUNTAP_MTU;
+
+       //lp->info.tuntap.gate_addr = gate_addr;
+
+       lp->tp.info.tuntap.fd = -1;
+
+       lp->tp.open = tuntap_open;
+       lp->tp.close = tuntap_close;
+       lp->tp.read = tuntap_read;
+       lp->tp.write = tuntap_write;
+       lp->tp.protocol = tuntap_protocol;
+       lp->tp.poll = tuntap_poll;
+
+       printk("TUN/TAP backend - ");
+#if 0
+       if (lp->host.gate_addr != NULL)
+               printk("IP = %s", lp->host.gate_addr);
+#endif
+       printk("\n");
+
+       return 1;
+}
+
+/* ================================ ISS NET ================================ */
+
+static int iss_net_rx(struct net_device *dev)
+{
+       struct iss_net_private *lp = dev->priv;
+       int pkt_len;
+       struct sk_buff *skb;
+
+       /* Check if there is any new data. */
+
+       if (lp->tp.poll(lp) == 0)
+               return 0;
+
+       /* Try to allocate memory, if it fails, try again next round. */
+
+       if ((skb = dev_alloc_skb(dev->mtu + 2 + ETH_HEADER_OTHER)) == NULL) {
+               lp->stats.rx_dropped++;
+               return 0;
+       }
+
+       skb_reserve(skb, 2);
+
+       /* Setup skb */
+
+       skb->dev = dev;
+       skb->mac.raw = skb->data;
+       pkt_len = lp->tp.read(lp, &skb);
+       skb_put(skb, pkt_len);
+
+       if (pkt_len > 0) {
+               skb_trim(skb, pkt_len);
+               skb->protocol = lp->tp.protocol(skb);
+       //      netif_rx(skb);
+               netif_rx_ni(skb);
+
+               lp->stats.rx_bytes += skb->len;
+               lp->stats.rx_packets++;
+               return pkt_len;
+       }
+       kfree_skb(skb);
+       return pkt_len;
+}
+
+static int iss_net_poll(void)
+{
+       struct list_head *ele;
+       int err, ret = 0;
+
+       spin_lock(&opened_lock);
+
+       list_for_each(ele, &opened) {
+               struct iss_net_private *lp;
+
+               lp = list_entry(ele, struct iss_net_private, opened_list);
+
+               if (!netif_running(lp->dev))
+                       break;
+
+               spin_lock(&lp->lock);
+
+               while ((err = iss_net_rx(lp->dev)) > 0)
+                       ret++;
+
+               spin_unlock(&lp->lock);
+
+               if (err < 0) {
+                       printk(KERN_ERR "Device '%s' read returned %d, "
+                              "shutting it down\n", lp->dev->name, err);
+                       dev_close(lp->dev);
+               } else {
+                       // FIXME reactivate_fd(lp->fd, ISS_ETH_IRQ);
+               }
+       }
+
+       spin_unlock(&opened_lock);
+       return ret;
+}
+
+
+static void iss_net_timer(unsigned long priv)
+{
+       struct iss_net_private* lp = (struct iss_net_private*) priv;
+
+       spin_lock(&lp->lock);
+
+       iss_net_poll();
+
+       mod_timer(&lp->timer, jiffies + lp->timer_val);
+
+       spin_unlock(&lp->lock);
+}
+
+
+static int iss_net_open(struct net_device *dev)
+{
+       struct iss_net_private *lp = dev->priv;
+       char addr[sizeof "255.255.255.255\0"];
+       int err;
+
+       spin_lock(&lp->lock);
+
+       if ((err = lp->tp.open(lp)) < 0)
+               goto out;
+
+       if (!lp->have_mac) {
+               dev_ip_addr(dev, addr, &lp->mac[2]);
+               set_ether_mac(dev, lp->mac);
+       }
+
+       netif_start_queue(dev);
+
+       /* clear buffer - it can happen that the host side of the interface
+        * is full when we gethere. In this case, new data is never queued,
+        * SIGIOs never arrive, and the net never works.
+        */
+       while ((err = iss_net_rx(dev)) > 0)
+               ;
+
+       spin_lock(&opened_lock);
+       list_add(&lp->opened_list, &opened);
+       spin_unlock(&opened_lock);
+
+       init_timer(&lp->timer);
+       lp->timer_val = ISS_NET_TIMER_VALUE;
+       lp->timer.data = (unsigned long) lp;
+       lp->timer.function = iss_net_timer;
+       mod_timer(&lp->timer, jiffies + lp->timer_val);
+
+out:
+       spin_unlock(&lp->lock);
+       return err;
+}
+
+static int iss_net_close(struct net_device *dev)
+{
+       struct iss_net_private *lp = dev->priv;
+printk("iss_net_close!\n");
+       netif_stop_queue(dev);
+       spin_lock(&lp->lock);
+
+       spin_lock(&opened_lock);
+       list_del(&opened);
+       spin_unlock(&opened_lock);
+
+       del_timer_sync(&lp->timer);
+
+       lp->tp.close(lp);
+
+       spin_unlock(&lp->lock);
+       return 0;
+}
+
+static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct iss_net_private *lp = dev->priv;
+       unsigned long flags;
+       int len;
+
+       netif_stop_queue(dev);
+       spin_lock_irqsave(&lp->lock, flags);
+
+       len = lp->tp.write(lp, &skb);
+
+       if (len == skb->len) {
+               lp->stats.tx_packets++;
+               lp->stats.tx_bytes += skb->len;
+               dev->trans_start = jiffies;
+               netif_start_queue(dev);
+
+               /* this is normally done in the interrupt when tx finishes */
+               netif_wake_queue(dev);
+
+       } else if (len == 0) {
+               netif_start_queue(dev);
+               lp->stats.tx_dropped++;
+
+       } else {
+               netif_start_queue(dev);
+               printk(KERN_ERR "iss_net_start_xmit: failed(%d)\n", len);
+       }
+
+       spin_unlock_irqrestore(&lp->lock, flags);
+
+       dev_kfree_skb(skb);
+       return 0;
+}
+
+
+static struct net_device_stats *iss_net_get_stats(struct net_device *dev)
+{
+       struct iss_net_private *lp = dev->priv;
+       return &lp->stats;
+}
+
+static void iss_net_set_multicast_list(struct net_device *dev)
+{
+#if 0
+       if (dev->flags & IFF_PROMISC)
+               return;
+       else if (dev->mc_count)
+               dev->flags |= IFF_ALLMULTI;
+       else
+               dev->flags &= ~IFF_ALLMULTI;
+#endif
+}
+
+static void iss_net_tx_timeout(struct net_device *dev)
+{
+#if 0
+       dev->trans_start = jiffies;
+       netif_wake_queue(dev);
+#endif
+}
+
+static int iss_net_set_mac(struct net_device *dev, void *addr)
+{
+#if 0
+       struct iss_net_private *lp = dev->priv;
+       struct sockaddr *hwaddr = addr;
+
+       spin_lock(&lp->lock);
+       memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN);
+       spin_unlock(&lp->lock);
+#endif
+
+       return 0;
+}
+
+static int iss_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+#if 0
+       struct iss_net_private *lp = dev->priv;
+       int err = 0;
+
+       spin_lock(&lp->lock);
+
+       // FIXME not needed new_mtu = transport_set_mtu(new_mtu, &lp->user);
+
+       if (new_mtu < 0)
+               err = new_mtu;
+       else
+               dev->mtu = new_mtu;
+
+       spin_unlock(&lp->lock);
+       return err;
+#endif
+       return -EINVAL;
+}
+
+static int iss_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+#if 0
+       static const struct ethtool_drvinfo info = {
+               .cmd     = ETHTOOL_GDRVINFO,
+               .driver  = DRIVER_NAME,
+               .version = "42",
+       };
+       void *useraddr;
+       u32 ethcmd;
+
+       switch (cmd) {
+       case SIOCETHTOOL:
+               useraddr = ifr->ifr_data;
+               if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+                       return -EFAULT;
+
+               switch (ethcmd) {
+                       case ETHTOOL_GDRVINFO:
+                               if (copy_to_user(useraddr, &info, sizeof(info)))
+                                       return -EFAULT;
+                               return 0;
+                       default:
+                               return -EOPNOTSUPP;
+               }
+       default:
+               return -EINVAL;
+       }
+#endif
+       return -EINVAL;
+}
+
+void iss_net_user_timer_expire(unsigned long _conn)
+{
+}
+
+
+static struct device_driver iss_net_driver = {
+       .name  = DRIVER_NAME,
+       .bus   = &platform_bus_type,
+};
+
+static int driver_registered;
+
+static int iss_net_configure(int index, char *init)
+{
+       struct net_device *dev;
+       struct iss_net_private *lp;
+       int err;
+
+       if ((dev = alloc_etherdev(sizeof *lp)) == NULL) {
+               printk(KERN_ERR "eth_configure: failed to allocate device\n");
+               return 1;
+       }
+
+       /* Initialize private element. */
+
+       lp = dev->priv;
+       *lp = ((struct iss_net_private) {
+               .device_list            = LIST_HEAD_INIT(lp->device_list),
+               .opened_list            = LIST_HEAD_INIT(lp->opened_list),
+               .lock                   = SPIN_LOCK_UNLOCKED,
+               .dev                    = dev,
+               .index                  = index,
+               //.fd                   = -1,
+               .mac                    = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 },
+               .have_mac               = 0,
+               });
+
+       /*
+        * Try all transport protocols.
+        * Note: more protocols can be added by adding '&& !X_init(lp, eth)'.
+        */
+
+       if (!tuntap_probe(lp, index, init)) {
+               printk("Invalid arguments. Skipping device!\n");
+               goto errout;
+       }
+
+       printk(KERN_INFO "Netdevice %d ", index);
+       if (lp->have_mac)
+               printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
+                               lp->mac[0], lp->mac[1],
+                               lp->mac[2], lp->mac[3],
+                               lp->mac[4], lp->mac[5]);
+       printk(": ");
+
+       /* sysfs register */
+
+       if (!driver_registered) {
+               driver_register(&iss_net_driver);
+               driver_registered = 1;
+       }
+
+       spin_lock(&devices_lock);
+       list_add(&lp->device_list, &devices);
+       spin_unlock(&devices_lock);
+
+       lp->pdev.id = index;
+       lp->pdev.name = DRIVER_NAME;
+       platform_device_register(&lp->pdev);
+       SET_NETDEV_DEV(dev,&lp->pdev.dev);
+
+       /*
+        * If this name ends up conflicting with an existing registered
+        * netdevice, that is OK, register_netdev{,ice}() will notice this
+        * and fail.
+        */
+       snprintf(dev->name, sizeof dev->name, "eth%d", index);
+
+       dev->mtu = lp->mtu;
+       dev->open = iss_net_open;
+       dev->hard_start_xmit = iss_net_start_xmit;
+       dev->stop = iss_net_close;
+       dev->get_stats = iss_net_get_stats;
+       dev->set_multicast_list = iss_net_set_multicast_list;
+       dev->tx_timeout = iss_net_tx_timeout;
+       dev->set_mac_address = iss_net_set_mac;
+       dev->change_mtu = iss_net_change_mtu;
+       dev->do_ioctl = iss_net_ioctl;
+       dev->watchdog_timeo = (HZ >> 1);
+       dev->irq = -1;
+
+       rtnl_lock();
+       err = register_netdevice(dev);
+       rtnl_unlock();
+
+       if (err) {
+               printk("Error registering net device!\n");
+               /* XXX: should we call ->remove() here? */
+               free_netdev(dev);
+               return 1;
+       }
+
+       init_timer(&lp->tl);
+       lp->tl.function = iss_net_user_timer_expire;
+
+#if 0
+       if (lp->have_mac)
+               set_ether_mac(dev, lp->mac);
+#endif
+       return 0;
+
+errout:
+       // FIXME: unregister; free, etc..
+       return -EIO;
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Filled in during early boot */
+
+struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
+
+struct iss_net_init {
+       struct list_head list;
+       char *init;             /* init string */
+       int index;
+};
+
+/*
+ * Parse the command line and look for 'ethX=...' fields, and register all
+ * those fields. They will be later initialized in iss_net_init.
+ */
+
+#define ERR KERN_ERR "iss_net_setup: "
+
+static int iss_net_setup(char *str)
+{
+       struct iss_net_private *device = NULL;
+       struct iss_net_init *new;
+       struct list_head *ele;
+       char *end;
+       int n;
+
+       n = simple_strtoul(str, &end, 0);
+       if (end == str) {
+               printk(ERR "Failed to parse '%s'\n", str);
+               return 1;
+       }
+       if (n < 0) {
+               printk(ERR "Device %d is negative\n", n);
+               return 1;
+       }
+       if (*(str = end) != '=') {
+               printk(ERR "Expected '=' after device number\n");
+               return 1;
+       }
+
+       spin_lock(&devices_lock);
+
+       list_for_each(ele, &devices) {
+               device = list_entry(ele, struct iss_net_private, device_list);
+               if (device->index == n)
+                       break;
+       }
+
+       spin_unlock(&devices_lock);
+
+       if (device && device->index == n) {
+               printk(ERR "Device %d already configured\n", n);
+               return 1;
+       }
+
+       if ((new = alloc_bootmem(sizeof new)) == NULL) {
+               printk("Alloc_bootmem failed\n");
+               return 1;
+       }
+
+       INIT_LIST_HEAD(&new->list);
+       new->index = n;
+       new->init = str + 1;
+
+       list_add_tail(&new->list, &eth_cmd_line);
+       return 1;
+}
+
+#undef ERR
+
+__setup("eth", iss_net_setup);
+
+/*
+ * Initialize all ISS Ethernet devices previously registered in iss_net_setup.
+ */
+
+static int iss_net_init(void)
+{
+       struct list_head *ele, *next;
+
+       /* Walk through all Ethernet devices specified in the command line. */
+
+       list_for_each_safe(ele, next, &eth_cmd_line) {
+               struct iss_net_init *eth;
+               eth = list_entry(ele, struct iss_net_init, list);
+               iss_net_configure(eth->index, eth->init);
+       }
+
+       return 1;
+}
+
+module_init(iss_net_init);
+
diff --git a/arch/xtensa/platform-iss/setup.c b/arch/xtensa/platform-iss/setup.c
new file mode 100644 (file)
index 0000000..2e6dcbf
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *
+ * arch/xtensa/platform-iss/setup.c
+ *
+ * Platform specific initialization.
+ *
+ * Authors: Chris Zankel <chris@zankel.net>
+ *          Joe Taylor <joe@tensilica.com>
+ *
+ * Copyright 2001 - 2005 Tensilica 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/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/stringify.h>
+#include <linux/notifier.h>
+
+#include <asm/platform.h>
+#include <asm/bootparam.h>
+
+
+void __init platform_init(bp_tag_t* bootparam)
+{
+
+}
+
+void platform_halt(void)
+{
+       printk (" ** Called platform_halt(), looping forever! **\n");
+       while (1);
+}
+
+void platform_power_off(void)
+{
+       printk (" ** Called platform_power_off(), looping forever! **\n");
+       while (1);
+}
+void platform_restart(void)
+{
+       /* Flush and reset the mmu, simulate a processor reset, and
+        * jump to the reset vector. */
+
+       __asm__ __volatile__("movi      a2, 15\n\t"
+                            "wsr       a2, " __stringify(ICOUNTLEVEL) "\n\t"
+                            "movi      a2, 0\n\t"
+                            "wsr       a2, " __stringify(ICOUNT) "\n\t"
+                            "wsr       a2, " __stringify(IBREAKENABLE) "\n\t"
+                            "wsr       a2, " __stringify(LCOUNT) "\n\t"
+                            "movi      a2, 0x1f\n\t"
+                            "wsr       a2, " __stringify(PS) "\n\t"
+                            "isync\n\t"
+                            "jx        %0\n\t"
+                            :
+                            : "a" (XCHAL_RESET_VECTOR_VADDR)
+                            : "a2");
+
+       /* control never gets here */
+}
+
+extern void iss_net_poll(void);
+
+const char twirl[]="|/-\\|/-\\";
+
+void platform_heartbeat(void)
+{
+#if 0
+       static int i = 0, j = 0;
+
+       if (--i < 0) {
+               i = 99;
+               printk("\r%c\r", twirl[j++]);
+               if (j == 8)
+                       j = 0;
+       }
+#endif
+}
+
+
+
+static int
+iss_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+       __asm__ __volatile__("movi a2, -1; simcall\n");
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block iss_panic_block = {
+       iss_panic_event,
+       NULL,
+       0
+};
+
+void __init platform_setup(char **p_cmdline)
+{
+       notifier_chain_register(&panic_notifier_list, &iss_panic_block);
+}
index 670fdb5142d17d3da59717b844560c861bbad8a5..86c52520ed348aa5049823dd2c5a55cfcb40513f 100644 (file)
@@ -55,7 +55,7 @@ if ACPI_INTERPRETER
 
 config ACPI_SLEEP
        bool "Sleep States (EXPERIMENTAL)"
-       depends on X86
+       depends on X86 && (!SMP || SUSPEND_SMP)
        depends on EXPERIMENTAL && PM
        default y
        ---help---
index 5a0adbf8bc04545c51139156ae5eb5caad772691..97013ddfa202b5d01678778d8443b0eba6cbfe64 100644 (file)
@@ -153,7 +153,7 @@ container_device_add(struct acpi_device **device, acpi_handle handle)
                return_VALUE(-ENODEV);
        }
 
-       result = acpi_bus_scan(*device);
+       result = acpi_bus_start(*device);
 
        return_VALUE(result);
 }
index 5d19b39e9e2b1b94226aa58b50c4550cccc1ac35..5148f3c10b5cf268d56fd0562f59ab7c538937f0 100644 (file)
@@ -61,15 +61,14 @@ acpi_pci_data_handler (
 
 
 /**
- * acpi_os_get_pci_id
+ * acpi_get_pci_id
  * ------------------
  * This function is used by the ACPI Interpreter (a.k.a. Core Subsystem)
  * to resolve PCI information for ACPI-PCI devices defined in the namespace.
  * This typically occurs when resolving PCI operation region information.
  */
-#ifdef ACPI_FUTURE_USAGE
 acpi_status
-acpi_os_get_pci_id (
+acpi_get_pci_id (
        acpi_handle             handle,
        struct acpi_pci_id      *id)
 {
@@ -78,7 +77,7 @@ acpi_os_get_pci_id (
        struct acpi_device      *device = NULL;
        struct acpi_pci_data    *data = NULL;
 
-       ACPI_FUNCTION_TRACE("acpi_os_get_pci_id");
+       ACPI_FUNCTION_TRACE("acpi_get_pci_id");
 
        if (!id)
                return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -92,7 +91,7 @@ acpi_os_get_pci_id (
        }
 
        status = acpi_get_data(handle, acpi_pci_data_handler, (void**) &data);
-       if (ACPI_FAILURE(status) || !data || !data->dev) {
+       if (ACPI_FAILURE(status) || !data) {
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
                        "Invalid ACPI-PCI context for device %s\n",
                        acpi_device_bid(device)));
@@ -115,7 +114,7 @@ acpi_os_get_pci_id (
 
        return_ACPI_STATUS(AE_OK);
 }
-#endif  /*  ACPI_FUTURE_USAGE  */
+EXPORT_SYMBOL(acpi_get_pci_id);
 
        
 int
@@ -129,6 +128,8 @@ acpi_pci_bind (
        char                    *pathname = NULL;
        struct acpi_buffer      buffer = {0, NULL};
        acpi_handle             handle = NULL;
+       struct pci_dev          *dev;
+       struct pci_bus          *bus;
 
        ACPI_FUNCTION_TRACE("acpi_pci_bind");
 
@@ -193,8 +194,20 @@ acpi_pci_bind (
         * Locate matching device in PCI namespace.  If it doesn't exist
         * this typically means that the device isn't currently inserted
         * (e.g. docking station, port replicator, etc.).
+        * We cannot simply search the global pci device list, since
+        * PCI devices are added to the global pci list when the root
+        * bridge start ops are run, which may not have happened yet.
         */
-       data->dev = pci_find_slot(data->id.bus, PCI_DEVFN(data->id.device, data->id.function));
+       bus = pci_find_bus(data->id.segment, data->id.bus);
+       if (bus) {
+               list_for_each_entry(dev, &bus->devices, bus_list) {
+                       if (dev->devfn == PCI_DEVFN(data->id.device,
+                                               data->id.function)) {
+                               data->dev = dev;
+                               break;
+                       }
+               }
+       }
        if (!data->dev) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
                        "Device %02x:%02x:%02x.%02x not present in PCI namespace\n",
index 8093f2e003215156d376c9a8c086e8d9dfaf9d30..8dbf802ee7f819d9c885247a35d0d736ca4a5979 100644 (file)
@@ -435,6 +435,7 @@ acpi_pci_irq_enable (
                /* Interrupt Line values above 0xF are forbidden */
                if (dev->irq >= 0 && (dev->irq <= 0xF)) {
                        printk(" - using IRQ %d\n", dev->irq);
+                       acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
                        return_VALUE(0);
                }
                else {
index 7e6b8e3b2ed418e15af1c0cad4eabb6b01e02031..5d2f77fcd50c7a2992a3f7957a1862ac33da1f8d 100644 (file)
@@ -46,6 +46,7 @@ ACPI_MODULE_NAME              ("pci_root")
 
 static int acpi_pci_root_add (struct acpi_device *device);
 static int acpi_pci_root_remove (struct acpi_device *device, int type);
+static int acpi_pci_root_start (struct acpi_device *device);
 
 static struct acpi_driver acpi_pci_root_driver = {
        .name =         ACPI_PCI_ROOT_DRIVER_NAME,
@@ -54,6 +55,7 @@ static struct acpi_driver acpi_pci_root_driver = {
        .ops =          {
                                .add =    acpi_pci_root_add,
                                .remove = acpi_pci_root_remove,
+                               .start =  acpi_pci_root_start,
                        },
 };
 
@@ -169,6 +171,7 @@ acpi_pci_root_add (
        if (!root)
                return_VALUE(-ENOMEM);
        memset(root, 0, sizeof(struct acpi_pci_root));
+       INIT_LIST_HEAD(&root->node);
 
        root->handle = device->handle;
        strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
@@ -298,12 +301,31 @@ acpi_pci_root_add (
                        root->id.bus);
 
 end:
-       if (result)
+       if (result) {
+               if (!list_empty(&root->node))
+                       list_del(&root->node);
                kfree(root);
+       }
 
        return_VALUE(result);
 }
 
+static int
+acpi_pci_root_start (
+       struct acpi_device      *device)
+{
+       struct acpi_pci_root    *root;
+
+       ACPI_FUNCTION_TRACE("acpi_pci_root_start");
+
+       list_for_each_entry(root, &acpi_pci_roots, node) {
+               if (root->handle == device->handle) {
+                       pci_bus_add_devices(root->bus);
+                       return_VALUE(0);
+               }
+       }
+       return_VALUE(-ENODEV);
+}
 
 static int
 acpi_pci_root_remove (
index f4778747e889bd6dae32f77287b3580a042081b1..76156ac91bd36b49b62a7232b48432254e71be50 100644 (file)
@@ -723,7 +723,7 @@ int acpi_processor_device_add(
                return_VALUE(-ENODEV);
        }
 
-       acpi_bus_scan(*device);
+       acpi_bus_start(*device);
 
        pr = acpi_driver_data(*device);
        if (!pr)
index e85885593280dde6313df7ac701785c23511ecb0..337d49b5564bb6130a712d84eb854d5d586aba06 100644 (file)
@@ -553,20 +553,29 @@ acpi_bus_driver_init (
         * upon possible configuration and currently allocated resources.
         */
 
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n"));
+       return_VALUE(0);
+}
+
+int
+acpi_start_single_object (
+               struct acpi_device *device)
+{
+       int result = 0;
+       struct acpi_driver *driver;
+
+       ACPI_FUNCTION_TRACE("acpi_start_single_object");
+
+       if (!(driver = device->driver))
+               return_VALUE(0);
+
        if (driver->ops.start) {
                result = driver->ops.start(device);
                if (result && driver->ops.remove)
                        driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
-               return_VALUE(result);
        }
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n"));
-
-       if (driver->ops.scan) {
-               driver->ops.scan(device);
-       }
-
-       return_VALUE(0);
+       return_VALUE(result);
 }
 
 static int acpi_driver_attach(struct acpi_driver * drv)
@@ -586,6 +595,7 @@ static int acpi_driver_attach(struct acpi_driver * drv)
 
                if (!acpi_bus_match(dev, drv)) {
                        if (!acpi_bus_driver_init(dev, drv)) {
+                               acpi_start_single_object(dev);
                                atomic_inc(&drv->references);
                                count++;
                                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n",
@@ -1009,8 +1019,8 @@ acpi_bus_remove (
 }
 
 
-int
-acpi_bus_add (
+static int
+acpi_add_single_object (
        struct acpi_device      **child,
        struct acpi_device      *parent,
        acpi_handle             handle,
@@ -1019,7 +1029,7 @@ acpi_bus_add (
        int                     result = 0;
        struct acpi_device      *device = NULL;
 
-       ACPI_FUNCTION_TRACE("acpi_bus_add");
+       ACPI_FUNCTION_TRACE("acpi_add_single_object");
 
        if (!child)
                return_VALUE(-EINVAL);
@@ -1140,7 +1150,7 @@ acpi_bus_add (
         *
         * TBD: Assumes LDM provides driver hot-plug capability.
         */
-       acpi_bus_find_driver(device);
+       result = acpi_bus_find_driver(device);
 
 end:
        if (!result)
@@ -1153,10 +1163,10 @@ end:
 
        return_VALUE(result);
 }
-EXPORT_SYMBOL(acpi_bus_add);
 
 
-int acpi_bus_scan (struct acpi_device  *start)
+static int acpi_bus_scan (struct acpi_device   *start,
+               struct acpi_bus_ops *ops)
 {
        acpi_status             status = AE_OK;
        struct acpi_device      *parent = NULL;
@@ -1229,9 +1239,20 @@ int acpi_bus_scan (struct acpi_device    *start)
                        continue;
                }
 
-               status = acpi_bus_add(&child, parent, chandle, type);
-               if (ACPI_FAILURE(status))
-                       continue;
+               if (ops->acpi_op_add)
+                       status = acpi_add_single_object(&child, parent,
+                                       chandle, type);
+                else
+                       status = acpi_bus_get_device(chandle, &child);
+
+                if (ACPI_FAILURE(status))
+                        continue;
+
+               if (ops->acpi_op_start) {
+                       status = acpi_start_single_object(child);
+                       if (ACPI_FAILURE(status))
+                               continue;
+               }
 
                /*
                 * If the device is present, enabled, and functioning then
@@ -1257,8 +1278,50 @@ int acpi_bus_scan (struct acpi_device    *start)
 
        return_VALUE(0);
 }
-EXPORT_SYMBOL(acpi_bus_scan);
 
+int
+acpi_bus_add (
+       struct acpi_device      **child,
+       struct acpi_device      *parent,
+       acpi_handle             handle,
+       int                     type)
+{
+       int result;
+       struct acpi_bus_ops ops;
+
+       ACPI_FUNCTION_TRACE("acpi_bus_add");
+
+       result = acpi_add_single_object(child, parent, handle, type);
+       if (!result) {
+               memset(&ops, 0, sizeof(ops));
+               ops.acpi_op_add = 1;
+               result = acpi_bus_scan(*child, &ops);
+       }
+       return_VALUE(result);
+}
+EXPORT_SYMBOL(acpi_bus_add);
+
+int
+acpi_bus_start (
+       struct acpi_device *device)
+{
+       int result;
+       struct acpi_bus_ops ops;
+
+       ACPI_FUNCTION_TRACE("acpi_bus_start");
+
+       if (!device)
+               return_VALUE(-EINVAL);
+
+       result = acpi_start_single_object(device);
+       if (!result) {
+               memset(&ops, 0, sizeof(ops));
+               ops.acpi_op_start = 1;
+               result = acpi_bus_scan(device, &ops);
+       }
+       return_VALUE(result);
+}
+EXPORT_SYMBOL(acpi_bus_start);
 
 static int
 acpi_bus_trim(struct acpi_device       *start,
@@ -1331,13 +1394,19 @@ acpi_bus_scan_fixed (
        /*
         * Enumerate all fixed-feature devices.
         */
-       if (acpi_fadt.pwr_button == 0)
-               result = acpi_bus_add(&device, acpi_root, 
+       if (acpi_fadt.pwr_button == 0) {
+               result = acpi_add_single_object(&device, acpi_root,
                        NULL, ACPI_BUS_TYPE_POWER_BUTTON);
+               if (!result)
+                       result = acpi_start_single_object(device);
+       }
 
-       if (acpi_fadt.sleep_button == 0)
-               result = acpi_bus_add(&device, acpi_root, 
+       if (acpi_fadt.sleep_button == 0) {
+               result = acpi_add_single_object(&device, acpi_root,
                        NULL, ACPI_BUS_TYPE_SLEEP_BUTTON);
+               if (!result)
+                       result = acpi_start_single_object(device);
+       }
 
        return_VALUE(result);
 }
@@ -1346,6 +1415,7 @@ acpi_bus_scan_fixed (
 static int __init acpi_scan_init(void)
 {
        int result;
+       struct acpi_bus_ops ops;
 
        ACPI_FUNCTION_TRACE("acpi_scan_init");
 
@@ -1357,17 +1427,23 @@ static int __init acpi_scan_init(void)
        /*
         * Create the root device in the bus's device tree
         */
-       result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT, 
+       result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT,
                ACPI_BUS_TYPE_SYSTEM);
        if (result)
                goto Done;
 
+       result = acpi_start_single_object(acpi_root);
+
        /*
         * Enumerate devices in the ACPI namespace.
         */
        result = acpi_bus_scan_fixed(acpi_root);
-       if (!result) 
-               result = acpi_bus_scan(acpi_root);
+       if (!result) {
+               memset(&ops, 0, sizeof(ops));
+               ops.acpi_op_add = 1;
+               ops.acpi_op_start = 1;
+               result = acpi_bus_scan(acpi_root, &ops);
+       }
 
        if (result)
                acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
index 645f626929209dd9e59cef9cd3070de9f0181a71..783752b68a9a3209de221e940dfea43c78f79b6b 100644 (file)
@@ -5,6 +5,7 @@ extern int bus_add_driver(struct device_driver *);
 extern void bus_remove_driver(struct device_driver *);
 
 extern void driver_detach(struct device_driver * drv);
+extern int driver_probe_device(struct device_driver *, struct device *);
 
 static inline struct class_device *to_class_dev(struct kobject *obj)
 {
index c3fac7fd555e6e45debce0501c8643b36d58640e..96fe2f956754a38a2bfcde9299fe9b5223109466 100644 (file)
@@ -133,6 +133,58 @@ static struct kobj_type ktype_bus = {
 decl_subsys(bus, &ktype_bus, NULL);
 
 
+/* Manually detach a device from it's associated driver. */
+static int driver_helper(struct device *dev, void *data)
+{
+       const char *name = data;
+
+       if (strcmp(name, dev->bus_id) == 0)
+               return 1;
+       return 0;
+}
+
+static ssize_t driver_unbind(struct device_driver *drv,
+                            const char *buf, size_t count)
+{
+       struct bus_type *bus = get_bus(drv->bus);
+       struct device *dev;
+       int err = -ENODEV;
+
+       dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
+       if ((dev) &&
+           (dev->driver == drv)) {
+               device_release_driver(dev);
+               err = count;
+       }
+       return err;
+}
+static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
+
+/*
+ * Manually attach a device to a driver.
+ * Note: the driver must want to bind to the device,
+ * it is not possible to override the driver's id table.
+ */
+static ssize_t driver_bind(struct device_driver *drv,
+                          const char *buf, size_t count)
+{
+       struct bus_type *bus = get_bus(drv->bus);
+       struct device *dev;
+       int err = -ENODEV;
+
+       dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
+       if ((dev) &&
+           (dev->driver == NULL)) {
+               down(&dev->sem);
+               err = driver_probe_device(drv, dev);
+               up(&dev->sem);
+               put_device(dev);
+       }
+       return err;
+}
+static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
+
+
 static struct device * next_device(struct klist_iter * i)
 {
        struct klist_node * n = klist_next(i);
@@ -177,6 +229,39 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start,
        return error;
 }
 
+/**
+ * bus_find_device - device iterator for locating a particular device.
+ * @bus: bus type
+ * @start: Device to begin with
+ * @data: Data to pass to match function
+ * @match: Callback function to check device
+ *
+ * This is similar to the bus_for_each_dev() function above, but it
+ * returns a reference to a device that is 'found' for later use, as
+ * determined by the @match callback.
+ *
+ * The callback should return 0 if the device doesn't match and non-zero
+ * if it does.  If the callback returns non-zero, this function will
+ * return to the caller and not iterate over any more devices.
+ */
+struct device * bus_find_device(struct bus_type *bus,
+                               struct device *start, void *data,
+                               int (*match)(struct device *, void *))
+{
+       struct klist_iter i;
+       struct device *dev;
+
+       if (!bus)
+               return NULL;
+
+       klist_iter_init_node(&bus->klist_devices, &i,
+                            (start ? &start->knode_bus : NULL));
+       while ((dev = next_device(&i)))
+               if (match(dev, data) && get_device(dev))
+                       break;
+       klist_iter_exit(&i);
+       return dev;
+}
 
 
 static struct device_driver * next_driver(struct klist_iter * i)
@@ -363,6 +448,8 @@ int bus_add_driver(struct device_driver * drv)
                module_add_driver(drv->owner, drv);
 
                driver_add_attrs(bus, drv);
+               driver_create_file(drv, &driver_attr_unbind);
+               driver_create_file(drv, &driver_attr_bind);
        }
        return error;
 }
@@ -380,6 +467,8 @@ int bus_add_driver(struct device_driver * drv)
 void bus_remove_driver(struct device_driver * drv)
 {
        if (drv->bus) {
+               driver_remove_file(drv, &driver_attr_bind);
+               driver_remove_file(drv, &driver_attr_unbind);
                driver_remove_attrs(drv->bus, drv);
                klist_remove(&drv->knode_bus);
                pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
@@ -394,31 +483,22 @@ void bus_remove_driver(struct device_driver * drv)
 /* Helper for bus_rescan_devices's iter */
 static int bus_rescan_devices_helper(struct device *dev, void *data)
 {
-       int *count = data;
-
-       if (!dev->driver && (device_attach(dev) > 0))
-               (*count)++;
-
+       if (!dev->driver)
+               device_attach(dev);
        return 0;
 }
 
-
 /**
- *     bus_rescan_devices - rescan devices on the bus for possible drivers
- *     @bus:   the bus to scan.
+ * bus_rescan_devices - rescan devices on the bus for possible drivers
+ * @bus: the bus to scan.
  *
- *     This function will look for devices on the bus with no driver
- *     attached and rescan it against existing drivers to see if it
- *     matches any. Calls device_attach(). Returns the number of devices
- *     that were sucessfully bound to a driver.
+ * This function will look for devices on the bus with no driver
+ * attached and rescan it against existing drivers to see if it matches
+ * any by calling device_attach() for the unbound devices.
  */
-int bus_rescan_devices(struct bus_type * bus)
+void bus_rescan_devices(struct bus_type * bus)
 {
-       int count = 0;
-
-       bus_for_each_dev(bus, NULL, &count, bus_rescan_devices_helper);
-
-       return count;
+       bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);
 }
 
 
@@ -557,6 +637,7 @@ int __init buses_init(void)
 
 
 EXPORT_SYMBOL_GPL(bus_for_each_dev);
+EXPORT_SYMBOL_GPL(bus_find_device);
 EXPORT_SYMBOL_GPL(bus_for_each_drv);
 
 EXPORT_SYMBOL_GPL(bus_add_device);
index 86d79755fbfb9d4c62c572df8d0585200d1064bf..efe03a024a5bc39bf958881143d740312c3b09bc 100644 (file)
@@ -333,7 +333,7 @@ void device_del(struct device * dev)
        struct device * parent = dev->parent;
 
        if (parent)
-               klist_remove(&dev->knode_parent);
+               klist_del(&dev->knode_parent);
 
        /* Notify the platform of the removal, in case they
         * need to do anything...
index 6ef3069b57107f2e12c5d2c7f238b77f5dacd97c..b79badd0f1588dea649df9033652f0f5d2afbacf 100644 (file)
@@ -16,6 +16,11 @@ struct sysdev_class cpu_sysdev_class = {
 EXPORT_SYMBOL(cpu_sysdev_class);
 
 #ifdef CONFIG_HOTPLUG_CPU
+int __attribute__((weak)) smp_prepare_cpu (int cpu)
+{
+       return 0;
+}
+
 static ssize_t show_online(struct sys_device *dev, char *buf)
 {
        struct cpu *cpu = container_of(dev, struct cpu, sysdev);
@@ -36,7 +41,11 @@ static ssize_t store_online(struct sys_device *dev, const char *buf,
                        kobject_hotplug(&dev->kobj, KOBJ_OFFLINE);
                break;
        case '1':
-               ret = cpu_up(cpu->sysdev.id);
+               ret = smp_prepare_cpu(cpu->sysdev.id);
+               if (!ret)
+                       ret = cpu_up(cpu->sysdev.id);
+               if (!ret)
+                       kobject_hotplug(&dev->kobj, KOBJ_ONLINE);
                break;
        default:
                ret = -EINVAL;
index 6db3a789c54f2f92eb292f09cac74d3fa3382ab9..16323f9cbff08fb066f8d10cda4bb76cfe711564 100644 (file)
@@ -65,7 +65,7 @@ void device_bind_driver(struct device * dev)
  *
  *     This function must be called with @dev->sem held.
  */
-static int driver_probe_device(struct device_driver * drv, struct device * dev)
+int driver_probe_device(struct device_driver * drv, struct device * dev)
 {
        int ret = 0;
 
index 1b645886e9eba14046fbb0d62fd7051477ff43a5..291c5954a3af58afd353a8a6369850a5bf19e483 100644 (file)
@@ -55,6 +55,41 @@ int driver_for_each_device(struct device_driver * drv, struct device * start,
 EXPORT_SYMBOL_GPL(driver_for_each_device);
 
 
+/**
+ * driver_find_device - device iterator for locating a particular device.
+ * @driver: The device's driver
+ * @start: Device to begin with
+ * @data: Data to pass to match function
+ * @match: Callback function to check device
+ *
+ * This is similar to the driver_for_each_device() function above, but
+ * it returns a reference to a device that is 'found' for later use, as
+ * determined by the @match callback.
+ *
+ * The callback should return 0 if the device doesn't match and non-zero
+ * if it does.  If the callback returns non-zero, this function will
+ * return to the caller and not iterate over any more devices.
+ */
+struct device * driver_find_device(struct device_driver *drv,
+                                  struct device * start, void * data,
+                                  int (*match)(struct device *, void *))
+{
+       struct klist_iter i;
+       struct device *dev;
+
+       if (!drv)
+               return NULL;
+
+       klist_iter_init_node(&drv->klist_devices, &i,
+                            (start ? &start->knode_driver : NULL));
+       while ((dev = next_device(&i)))
+               if (match(dev, data) && get_device(dev))
+                       break;
+       klist_iter_exit(&i);
+       return dev;
+}
+EXPORT_SYMBOL_GPL(driver_find_device);
+
 /**
  *     driver_create_file - create sysfs file for driver.
  *     @drv:   driver.
index 97fe13f7f07c85d6fa2d07efd3f04afab932ec46..652281402c923860d449ec7a652ff81fa6903447 100644 (file)
@@ -74,6 +74,8 @@ static ssize_t
 firmware_timeout_store(struct class *class, const char *buf, size_t count)
 {
        loading_timeout = simple_strtol(buf, NULL, 10);
+       if (loading_timeout < 0)
+               loading_timeout = 0;
        return count;
 }
 
@@ -138,6 +140,10 @@ firmware_loading_store(struct class_device *class_dev,
        switch (loading) {
        case 1:
                down(&fw_lock);
+               if (!fw_priv->fw) {
+                       up(&fw_lock);
+                       break;
+               }
                vfree(fw_priv->fw->data);
                fw_priv->fw->data = NULL;
                fw_priv->fw->size = 0;
@@ -178,7 +184,7 @@ firmware_data_read(struct kobject *kobj,
 
        down(&fw_lock);
        fw = fw_priv->fw;
-       if (test_bit(FW_STATUS_DONE, &fw_priv->status)) {
+       if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
                ret_count = -ENODEV;
                goto out;
        }
@@ -238,9 +244,10 @@ firmware_data_write(struct kobject *kobj,
 
        if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
+
        down(&fw_lock);
        fw = fw_priv->fw;
-       if (test_bit(FW_STATUS_DONE, &fw_priv->status)) {
+       if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
                retval = -ENODEV;
                goto out;
        }
@@ -418,7 +425,7 @@ request_firmware(const struct firmware **firmware_p, const char *name,
 
        fw_priv = class_get_devdata(class_dev);
 
-       if (loading_timeout) {
+       if (loading_timeout > 0) {
                fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
                add_timer(&fw_priv->timeout);
        }
index 3410b4d294b990323c92a927a9f532480809db57..91aeb678135dbe84798ca1b2f5fcfe2f6b0ebf2b 100644 (file)
@@ -1806,7 +1806,8 @@ static void as_put_request(request_queue_t *q, struct request *rq)
        rq->elevator_private = NULL;
 }
 
-static int as_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+static int as_set_request(request_queue_t *q, struct request *rq,
+                         struct bio *bio, int gfp_mask)
 {
        struct as_data *ad = q->elevator->elevator_data;
        struct as_rq *arq = mempool_alloc(ad->arq_pool, gfp_mask);
@@ -1827,7 +1828,7 @@ static int as_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
        return 1;
 }
 
-static int as_may_queue(request_queue_t *q, int rw)
+static int as_may_queue(request_queue_t *q, int rw, struct bio *bio)
 {
        int ret = ELV_MQUEUE_MAY;
        struct as_data *ad = q->elevator->elevator_data;
index abde27027c06b5cddd2dd873267e80b7a27dda51..3e9fb6e4a52a39f433e04c1a2f8a672823224215 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *    Disk Array driver for HP SA 5xxx and 6xxx Controllers
- *    Copyright 2000, 2002 Hewlett-Packard Development Company, L.P.
+ *    Copyright 2000, 2005 Hewlett-Packard Development Company, L.P.
  *
  *    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
@@ -54,7 +54,7 @@
 MODULE_AUTHOR("Hewlett-Packard Company");
 MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.6");
 MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
-                       " SA6i P600 P800 E400");
+                       " SA6i P600 P800 E400 E300");
 MODULE_LICENSE("GPL");
 
 #include "cciss_cmd.h"
@@ -85,8 +85,10 @@ static const struct pci_device_id cciss_pci_device_id[] = {
                0x103C, 0x3225, 0, 0, 0},
        { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
                0x103c, 0x3223, 0, 0, 0},
-       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
                0x103c, 0x3231, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
+               0x103c, 0x3233, 0, 0, 0},
        {0,}
 };
 MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -110,6 +112,7 @@ static struct board_type products[] = {
        { 0x3225103C, "Smart Array P600", &SA5_access},
        { 0x3223103C, "Smart Array P800", &SA5_access},
        { 0x3231103C, "Smart Array E400", &SA5_access},
+       { 0x3233103C, "Smart Array E300", &SA5_access},
 };
 
 /* How long to wait (in millesconds) for board to go into simple mode */
@@ -635,6 +638,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
                cciss_pci_info_struct pciinfo;
 
                if (!arg) return -EINVAL;
+               pciinfo.domain = pci_domain_nr(host->pdev->bus);
                pciinfo.bus = host->pdev->bus->number;
                pciinfo.dev_fn = host->pdev->devfn;
                pciinfo.board_id = host->board_id;
@@ -782,18 +786,10 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
 
        case CCISS_GETLUNINFO: {
                LogvolInfo_struct luninfo;
-               int i;
                
                luninfo.LunID = drv->LunID;
                luninfo.num_opens = drv->usage_count;
                luninfo.num_parts = 0;
-               /* count partitions 1 to 15 with sizes > 0 */
-               for (i = 0; i < MAX_PART - 1; i++) {
-                       if (!disk->part[i])
-                               continue;
-                       if (disk->part[i]->nr_sects != 0)
-                               luninfo.num_parts++;
-               }
                if (copy_to_user(argp, &luninfo,
                                sizeof(LogvolInfo_struct)))
                        return -EFAULT;
index 3ac47dde64da3be93b5e4bed65cee827f16db952..de5746e38af935a01c45a866ae7598d24108a6ac 100644 (file)
 #include <linux/hash.h>
 #include <linux/rbtree.h>
 #include <linux/mempool.h>
-
-static unsigned long max_elapsed_crq;
-static unsigned long max_elapsed_dispatch;
+#include <linux/ioprio.h>
+#include <linux/writeback.h>
 
 /*
  * tunables
  */
 static int cfq_quantum = 4;            /* max queue in one round of service */
 static int cfq_queued = 8;             /* minimum rq allocate limit per-queue*/
-static int cfq_service = HZ;           /* period over which service is avg */
-static int cfq_fifo_expire_r = HZ / 2; /* fifo timeout for sync requests */
-static int cfq_fifo_expire_w = 5 * HZ; /* fifo timeout for async requests */
-static int cfq_fifo_rate = HZ / 8;     /* fifo expiry rate */
+static int cfq_fifo_expire[2] = { HZ / 4, HZ / 8 };
 static int cfq_back_max = 16 * 1024;   /* maximum backwards seek, in KiB */
 static int cfq_back_penalty = 2;       /* penalty of a backwards seek */
 
+static int cfq_slice_sync = HZ / 10;
+static int cfq_slice_async = HZ / 25;
+static int cfq_slice_async_rq = 2;
+static int cfq_slice_idle = HZ / 100;
+
+#define CFQ_IDLE_GRACE         (HZ / 10)
+#define CFQ_SLICE_SCALE                (5)
+
+#define CFQ_KEY_ASYNC          (0)
+#define CFQ_KEY_ANY            (0xffff)
+
+/*
+ * disable queueing at the driver/hardware level
+ */
+static int cfq_max_depth = 1;
+
 /*
  * for the hash of cfqq inside the cfqd
  */
@@ -55,6 +67,7 @@ static int cfq_back_penalty = 2;      /* penalty of a backwards seek */
 #define list_entry_hash(ptr)   hlist_entry((ptr), struct cfq_rq, hash)
 
 #define list_entry_cfqq(ptr)   list_entry((ptr), struct cfq_queue, cfq_list)
+#define list_entry_fifo(ptr)   list_entry((ptr), struct request, queuelist)
 
 #define RQ_DATA(rq)            (rq)->elevator_private
 
@@ -75,78 +88,110 @@ static int cfq_back_penalty = 2;   /* penalty of a backwards seek */
 #define rb_entry_crq(node)     rb_entry((node), struct cfq_rq, rb_node)
 #define rq_rb_key(rq)          (rq)->sector
 
-/*
- * threshold for switching off non-tag accounting
- */
-#define CFQ_MAX_TAG            (4)
-
-/*
- * sort key types and names
- */
-enum {
-       CFQ_KEY_PGID,
-       CFQ_KEY_TGID,
-       CFQ_KEY_UID,
-       CFQ_KEY_GID,
-       CFQ_KEY_LAST,
-};
-
-static char *cfq_key_types[] = { "pgid", "tgid", "uid", "gid", NULL };
-
 static kmem_cache_t *crq_pool;
 static kmem_cache_t *cfq_pool;
 static kmem_cache_t *cfq_ioc_pool;
 
+#define CFQ_PRIO_LISTS         IOPRIO_BE_NR
+#define cfq_class_idle(cfqq)   ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE)
+#define cfq_class_be(cfqq)     ((cfqq)->ioprio_class == IOPRIO_CLASS_BE)
+#define cfq_class_rt(cfqq)     ((cfqq)->ioprio_class == IOPRIO_CLASS_RT)
+
+#define ASYNC                  (0)
+#define SYNC                   (1)
+
+#define cfq_cfqq_dispatched(cfqq)      \
+       ((cfqq)->on_dispatch[ASYNC] + (cfqq)->on_dispatch[SYNC])
+
+#define cfq_cfqq_class_sync(cfqq)      ((cfqq)->key != CFQ_KEY_ASYNC)
+
+#define cfq_cfqq_sync(cfqq)            \
+       (cfq_cfqq_class_sync(cfqq) || (cfqq)->on_dispatch[SYNC])
+
+/*
+ * Per block device queue structure
+ */
 struct cfq_data {
-       struct list_head rr_list;
+       atomic_t ref;
+       request_queue_t *queue;
+
+       /*
+        * rr list of queues with requests and the count of them
+        */
+       struct list_head rr_list[CFQ_PRIO_LISTS];
+       struct list_head busy_rr;
+       struct list_head cur_rr;
+       struct list_head idle_rr;
+       unsigned int busy_queues;
+
+       /*
+        * non-ordered list of empty cfqq's
+        */
        struct list_head empty_list;
 
+       /*
+        * cfqq lookup hash
+        */
        struct hlist_head *cfq_hash;
-       struct hlist_head *crq_hash;
 
-       /* queues on rr_list (ie they have pending requests */
-       unsigned int busy_queues;
+       /*
+        * global crq hash for all queues
+        */
+       struct hlist_head *crq_hash;
 
        unsigned int max_queued;
 
-       atomic_t ref;
+       mempool_t *crq_pool;
 
-       int key_type;
+       int rq_in_driver;
 
-       mempool_t *crq_pool;
+       /*
+        * schedule slice state info
+        */
+       /*
+        * idle window management
+        */
+       struct timer_list idle_slice_timer;
+       struct work_struct unplug_work;
 
-       request_queue_t *queue;
+       struct cfq_queue *active_queue;
+       struct cfq_io_context *active_cic;
+       int cur_prio, cur_end_prio;
+       unsigned int dispatch_slice;
+
+       struct timer_list idle_class_timer;
 
        sector_t last_sector;
+       unsigned long last_end_request;
 
-       int rq_in_driver;
+       unsigned int rq_starved;
 
        /*
         * tunables, see top of file
         */
        unsigned int cfq_quantum;
        unsigned int cfq_queued;
-       unsigned int cfq_fifo_expire_r;
-       unsigned int cfq_fifo_expire_w;
-       unsigned int cfq_fifo_batch_expire;
+       unsigned int cfq_fifo_expire[2];
        unsigned int cfq_back_penalty;
        unsigned int cfq_back_max;
-       unsigned int find_best_crq;
-
-       unsigned int cfq_tagged;
+       unsigned int cfq_slice[2];
+       unsigned int cfq_slice_async_rq;
+       unsigned int cfq_slice_idle;
+       unsigned int cfq_max_depth;
 };
 
+/*
+ * Per process-grouping structure
+ */
 struct cfq_queue {
        /* reference count */
        atomic_t ref;
        /* parent cfq_data */
        struct cfq_data *cfqd;
-       /* hash of mergeable requests */
+       /* cfqq lookup hash */
        struct hlist_node cfq_hash;
        /* hash key */
-       unsigned long key;
-       /* whether queue is on rr (or empty) list */
-       int on_rr;
+       unsigned int key;
        /* on either rr or empty list of cfqd */
        struct list_head cfq_list;
        /* sorted list of pending requests */
@@ -158,21 +203,22 @@ struct cfq_queue {
        /* currently allocated requests */
        int allocated[2];
        /* fifo list of requests in sort_list */
-       struct list_head fifo[2];
-       /* last time fifo expired */
-       unsigned long last_fifo_expire;
+       struct list_head fifo;
 
-       int key_type;
+       unsigned long slice_start;
+       unsigned long slice_end;
+       unsigned long slice_left;
+       unsigned long service_last;
 
-       unsigned long service_start;
-       unsigned long service_used;
+       /* number of requests that are on the dispatch list */
+       int on_dispatch[2];
 
-       unsigned int max_rate;
+       /* io prio of this group */
+       unsigned short ioprio, org_ioprio;
+       unsigned short ioprio_class, org_ioprio_class;
 
-       /* number of requests that have been handed to the driver */
-       int in_flight;
-       /* number of currently allocated requests */
-       int alloc_limit[2];
+       /* various state flags, see below */
+       unsigned int flags;
 };
 
 struct cfq_rq {
@@ -184,42 +230,78 @@ struct cfq_rq {
        struct cfq_queue *cfq_queue;
        struct cfq_io_context *io_context;
 
-       unsigned long service_start;
-       unsigned long queue_start;
+       unsigned int crq_flags;
+};
+
+enum cfqq_state_flags {
+       CFQ_CFQQ_FLAG_on_rr = 0,
+       CFQ_CFQQ_FLAG_wait_request,
+       CFQ_CFQQ_FLAG_must_alloc,
+       CFQ_CFQQ_FLAG_must_alloc_slice,
+       CFQ_CFQQ_FLAG_must_dispatch,
+       CFQ_CFQQ_FLAG_fifo_expire,
+       CFQ_CFQQ_FLAG_idle_window,
+       CFQ_CFQQ_FLAG_prio_changed,
+       CFQ_CFQQ_FLAG_expired,
+};
 
-       unsigned int in_flight : 1;
-       unsigned int accounted : 1;
-       unsigned int is_sync   : 1;
-       unsigned int is_write  : 1;
+#define CFQ_CFQQ_FNS(name)                                             \
+static inline void cfq_mark_cfqq_##name(struct cfq_queue *cfqq)                \
+{                                                                      \
+       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);                    \
+}                                                                      \
+static inline int cfq_cfqq_##name(const struct cfq_queue *cfqq)                \
+{                                                                      \
+       return (cfqq->flags & (1 << CFQ_CFQQ_FLAG_##name)) != 0;        \
+}
+
+CFQ_CFQQ_FNS(on_rr);
+CFQ_CFQQ_FNS(wait_request);
+CFQ_CFQQ_FNS(must_alloc);
+CFQ_CFQQ_FNS(must_alloc_slice);
+CFQ_CFQQ_FNS(must_dispatch);
+CFQ_CFQQ_FNS(fifo_expire);
+CFQ_CFQQ_FNS(idle_window);
+CFQ_CFQQ_FNS(prio_changed);
+CFQ_CFQQ_FNS(expired);
+#undef CFQ_CFQQ_FNS
+
+enum cfq_rq_state_flags {
+       CFQ_CRQ_FLAG_in_flight = 0,
+       CFQ_CRQ_FLAG_in_driver,
+       CFQ_CRQ_FLAG_is_sync,
+       CFQ_CRQ_FLAG_requeued,
 };
 
-static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned long);
+#define CFQ_CRQ_FNS(name)                                              \
+static inline void cfq_mark_crq_##name(struct cfq_rq *crq)             \
+{                                                                      \
+       crq->crq_flags |= (1 << CFQ_CRQ_FLAG_##name);                   \
+}                                                                      \
+static inline void cfq_clear_crq_##name(struct cfq_rq *crq)            \
+{                                                                      \
+       crq->crq_flags &= ~(1 << CFQ_CRQ_FLAG_##name);                  \
+}                                                                      \
+static inline int cfq_crq_##name(const struct cfq_rq *crq)             \
+{                                                                      \
+       return (crq->crq_flags & (1 << CFQ_CRQ_FLAG_##name)) != 0;      \
+}
+
+CFQ_CRQ_FNS(in_flight);
+CFQ_CRQ_FNS(in_driver);
+CFQ_CRQ_FNS(is_sync);
+CFQ_CRQ_FNS(requeued);
+#undef CFQ_CRQ_FNS
+
+static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short);
 static void cfq_dispatch_sort(request_queue_t *, struct cfq_rq *);
-static void cfq_update_next_crq(struct cfq_rq *);
 static void cfq_put_cfqd(struct cfq_data *cfqd);
 
-/*
- * what the fairness is based on (ie how processes are grouped and
- * differentiated)
- */
-static inline unsigned long
-cfq_hash_key(struct cfq_data *cfqd, struct task_struct *tsk)
-{
-       /*
-        * optimize this so that ->key_type is the offset into the struct
-        */
-       switch (cfqd->key_type) {
-               case CFQ_KEY_PGID:
-                       return process_group(tsk);
-               default:
-               case CFQ_KEY_TGID:
-                       return tsk->tgid;
-               case CFQ_KEY_UID:
-                       return tsk->uid;
-               case CFQ_KEY_GID:
-                       return tsk->gid;
-       }
-}
+#define process_sync(tsk)      ((tsk)->flags & PF_SYNCWRITE)
 
 /*
  * lots of deadline iosched dupes, can be abstracted later...
@@ -235,16 +317,12 @@ static void cfq_remove_merge_hints(request_queue_t *q, struct cfq_rq *crq)
 
        if (q->last_merge == crq->request)
                q->last_merge = NULL;
-
-       cfq_update_next_crq(crq);
 }
 
 static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq)
 {
        const int hash_idx = CFQ_MHASH_FN(rq_hash_key(crq->request));
 
-       BUG_ON(!hlist_unhashed(&crq->hash));
-
        hlist_add_head(&crq->hash, &cfqd->crq_hash[hash_idx]);
 }
 
@@ -257,8 +335,6 @@ static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset)
                struct cfq_rq *crq = list_entry_hash(entry);
                struct request *__rq = crq->request;
 
-               BUG_ON(hlist_unhashed(&crq->hash));
-
                if (!rq_mergeable(__rq)) {
                        cfq_del_crq_hash(crq);
                        continue;
@@ -271,6 +347,28 @@ static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset)
        return NULL;
 }
 
+static inline int cfq_pending_requests(struct cfq_data *cfqd)
+{
+       return !list_empty(&cfqd->queue->queue_head) || cfqd->busy_queues;
+}
+
+/*
+ * scheduler run of queue, if there are requests pending and no one in the
+ * driver that will restart queueing
+ */
+static inline void cfq_schedule_dispatch(struct cfq_data *cfqd)
+{
+       if (!cfqd->rq_in_driver && cfq_pending_requests(cfqd))
+               kblockd_schedule_work(&cfqd->unplug_work);
+}
+
+static int cfq_queue_empty(request_queue_t *q)
+{
+       struct cfq_data *cfqd = q->elevator->elevator_data;
+
+       return !cfq_pending_requests(cfqd);
+}
+
 /*
  * Lifted from AS - choose which of crq1 and crq2 that is best served now.
  * We choose the request that is closest to the head right now. Distance
@@ -287,36 +385,16 @@ cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2)
                return crq2;
        if (crq2 == NULL)
                return crq1;
+       if (cfq_crq_requeued(crq1))
+               return crq1;
+       if (cfq_crq_requeued(crq2))
+               return crq2;
 
        s1 = crq1->request->sector;
        s2 = crq2->request->sector;
 
        last = cfqd->last_sector;
 
-#if 0
-       if (!list_empty(&cfqd->queue->queue_head)) {
-               struct list_head *entry = &cfqd->queue->queue_head;
-               unsigned long distance = ~0UL;
-               struct request *rq;
-
-               while ((entry = entry->prev) != &cfqd->queue->queue_head) {
-                       rq = list_entry_rq(entry);
-
-                       if (blk_barrier_rq(rq))
-                               break;
-
-                       if (distance < abs(s1 - rq->sector + rq->nr_sectors)) {
-                               distance = abs(s1 - rq->sector +rq->nr_sectors);
-                               last = rq->sector + rq->nr_sectors;
-                       }
-                       if (distance < abs(s2 - rq->sector + rq->nr_sectors)) {
-                               distance = abs(s2 - rq->sector +rq->nr_sectors);
-                               last = rq->sector + rq->nr_sectors;
-                       }
-               }
-       }
-#endif
-
        /*
         * by definition, 1KiB is 2 sectors
         */
@@ -377,11 +455,14 @@ cfq_find_next_crq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        struct cfq_rq *crq_next = NULL, *crq_prev = NULL;
        struct rb_node *rbnext, *rbprev;
 
-       if (!ON_RB(&last->rb_node))
-               return NULL;
-
-       if ((rbnext = rb_next(&last->rb_node)) == NULL)
+       rbnext = NULL;
+       if (ON_RB(&last->rb_node))
+               rbnext = rb_next(&last->rb_node);
+       if (!rbnext) {
                rbnext = rb_first(&cfqq->sort_list);
+               if (rbnext == &last->rb_node)
+                       rbnext = NULL;
+       }
 
        rbprev = rb_prev(&last->rb_node);
 
@@ -401,67 +482,53 @@ static void cfq_update_next_crq(struct cfq_rq *crq)
                cfqq->next_crq = cfq_find_next_crq(cfqq->cfqd, cfqq, crq);
 }
 
-static int cfq_check_sort_rr_list(struct cfq_queue *cfqq)
+static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
 {
-       struct list_head *head = &cfqq->cfqd->rr_list;
-       struct list_head *next, *prev;
-
-       /*
-        * list might still be ordered
-        */
-       next = cfqq->cfq_list.next;
-       if (next != head) {
-               struct cfq_queue *cnext = list_entry_cfqq(next);
+       struct cfq_data *cfqd = cfqq->cfqd;
+       struct list_head *list, *entry;
 
-               if (cfqq->service_used > cnext->service_used)
-                       return 1;
-       }
+       BUG_ON(!cfq_cfqq_on_rr(cfqq));
 
-       prev = cfqq->cfq_list.prev;
-       if (prev != head) {
-               struct cfq_queue *cprev = list_entry_cfqq(prev);
+       list_del(&cfqq->cfq_list);
 
-               if (cfqq->service_used < cprev->service_used)
-                       return 1;
+       if (cfq_class_rt(cfqq))
+               list = &cfqd->cur_rr;
+       else if (cfq_class_idle(cfqq))
+               list = &cfqd->idle_rr;
+       else {
+               /*
+                * if cfqq has requests in flight, don't allow it to be
+                * found in cfq_set_active_queue before it has finished them.
+                * this is done to increase fairness between a process that
+                * has lots of io pending vs one that only generates one
+                * sporadically or synchronously
+                */
+               if (cfq_cfqq_dispatched(cfqq))
+                       list = &cfqd->busy_rr;
+               else
+                       list = &cfqd->rr_list[cfqq->ioprio];
        }
 
-       return 0;
-}
-
-static void cfq_sort_rr_list(struct cfq_queue *cfqq, int new_queue)
-{
-       struct list_head *entry = &cfqq->cfqd->rr_list;
-
-       if (!cfqq->on_rr)
-               return;
-       if (!new_queue && !cfq_check_sort_rr_list(cfqq))
+       /*
+        * if queue was preempted, just add to front to be fair. busy_rr
+        * isn't sorted.
+        */
+       if (preempted || list == &cfqd->busy_rr) {
+               list_add(&cfqq->cfq_list, list);
                return;
-
-       list_del(&cfqq->cfq_list);
+       }
 
        /*
-        * sort by our mean service_used, sub-sort by in-flight requests
+        * sort by when queue was last serviced
         */
-       while ((entry = entry->prev) != &cfqq->cfqd->rr_list) {
+       entry = list;
+       while ((entry = entry->prev) != list) {
                struct cfq_queue *__cfqq = list_entry_cfqq(entry);
 
-               if (cfqq->service_used > __cfqq->service_used)
+               if (!__cfqq->service_last)
+                       break;
+               if (time_before(__cfqq->service_last, cfqq->service_last))
                        break;
-               else if (cfqq->service_used == __cfqq->service_used) {
-                       struct list_head *prv;
-
-                       while ((prv = entry->prev) != &cfqq->cfqd->rr_list) {
-                               __cfqq = list_entry_cfqq(prv);
-
-                               WARN_ON(__cfqq->service_used > cfqq->service_used);
-                               if (cfqq->service_used != __cfqq->service_used)
-                                       break;
-                               if (cfqq->in_flight > __cfqq->in_flight)
-                                       break;
-
-                               entry = prv;
-                       }
-               }
        }
 
        list_add(&cfqq->cfq_list, entry);
@@ -469,28 +536,24 @@ static void cfq_sort_rr_list(struct cfq_queue *cfqq, int new_queue)
 
 /*
  * add to busy list of queues for service, trying to be fair in ordering
- * the pending list according to requests serviced
+ * the pending list according to last request service
  */
 static inline void
-cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq, int requeue)
 {
-       /*
-        * it's currently on the empty list
-        */
-       cfqq->on_rr = 1;
+       BUG_ON(cfq_cfqq_on_rr(cfqq));
+       cfq_mark_cfqq_on_rr(cfqq);
        cfqd->busy_queues++;
 
-       if (time_after(jiffies, cfqq->service_start + cfq_service))
-               cfqq->service_used >>= 3;
-
-       cfq_sort_rr_list(cfqq, 1);
+       cfq_resort_rr_list(cfqq, requeue);
 }
 
 static inline void
 cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
+       BUG_ON(!cfq_cfqq_on_rr(cfqq));
+       cfq_clear_cfqq_on_rr(cfqq);
        list_move(&cfqq->cfq_list, &cfqd->empty_list);
-       cfqq->on_rr = 0;
 
        BUG_ON(!cfqd->busy_queues);
        cfqd->busy_queues--;
@@ -505,16 +568,17 @@ static inline void cfq_del_crq_rb(struct cfq_rq *crq)
 
        if (ON_RB(&crq->rb_node)) {
                struct cfq_data *cfqd = cfqq->cfqd;
+               const int sync = cfq_crq_is_sync(crq);
 
-               BUG_ON(!cfqq->queued[crq->is_sync]);
+               BUG_ON(!cfqq->queued[sync]);
+               cfqq->queued[sync]--;
 
                cfq_update_next_crq(crq);
 
-               cfqq->queued[crq->is_sync]--;
                rb_erase(&crq->rb_node, &cfqq->sort_list);
                RB_CLEAR_COLOR(&crq->rb_node);
 
-               if (RB_EMPTY(&cfqq->sort_list) && cfqq->on_rr)
+               if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list))
                        cfq_del_cfqq_rr(cfqd, cfqq);
        }
 }
@@ -550,7 +614,7 @@ static void cfq_add_crq_rb(struct cfq_rq *crq)
        struct cfq_rq *__alias;
 
        crq->rb_key = rq_rb_key(rq);
-       cfqq->queued[crq->is_sync]++;
+       cfqq->queued[cfq_crq_is_sync(crq)]++;
 
        /*
         * looks a little odd, but the first insert might return an alias.
@@ -561,8 +625,8 @@ static void cfq_add_crq_rb(struct cfq_rq *crq)
 
        rb_insert_color(&crq->rb_node, &cfqq->sort_list);
 
-       if (!cfqq->on_rr)
-               cfq_add_cfqq_rr(cfqd, cfqq);
+       if (!cfq_cfqq_on_rr(cfqq))
+               cfq_add_cfqq_rr(cfqd, cfqq, cfq_crq_requeued(crq));
 
        /*
         * check if this request is a better next-serve candidate
@@ -575,17 +639,16 @@ cfq_reposition_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq)
 {
        if (ON_RB(&crq->rb_node)) {
                rb_erase(&crq->rb_node, &cfqq->sort_list);
-               cfqq->queued[crq->is_sync]--;
+               cfqq->queued[cfq_crq_is_sync(crq)]--;
        }
 
        cfq_add_crq_rb(crq);
 }
 
-static struct request *
-cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector)
+static struct request *cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector)
+
 {
-       const unsigned long key = cfq_hash_key(cfqd, current);
-       struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, key);
+       struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, current->pid, CFQ_KEY_ANY);
        struct rb_node *n;
 
        if (!cfqq)
@@ -609,20 +672,25 @@ out:
 
 static void cfq_deactivate_request(request_queue_t *q, struct request *rq)
 {
+       struct cfq_data *cfqd = q->elevator->elevator_data;
        struct cfq_rq *crq = RQ_DATA(rq);
 
        if (crq) {
                struct cfq_queue *cfqq = crq->cfq_queue;
 
-               if (cfqq->cfqd->cfq_tagged) {
-                       cfqq->service_used--;
-                       cfq_sort_rr_list(cfqq, 0);
+               if (cfq_crq_in_driver(crq)) {
+                       cfq_clear_crq_in_driver(crq);
+                       WARN_ON(!cfqd->rq_in_driver);
+                       cfqd->rq_in_driver--;
                }
+               if (cfq_crq_in_flight(crq)) {
+                       const int sync = cfq_crq_is_sync(crq);
 
-               if (crq->accounted) {
-                       crq->accounted = 0;
-                       cfqq->cfqd->rq_in_driver--;
+                       cfq_clear_crq_in_flight(crq);
+                       WARN_ON(!cfqq->on_dispatch[sync]);
+                       cfqq->on_dispatch[sync]--;
                }
+               cfq_mark_crq_requeued(crq);
        }
 }
 
@@ -640,11 +708,10 @@ static void cfq_remove_request(request_queue_t *q, struct request *rq)
        struct cfq_rq *crq = RQ_DATA(rq);
 
        if (crq) {
-               cfq_remove_merge_hints(q, crq);
                list_del_init(&rq->queuelist);
+               cfq_del_crq_rb(crq);
+               cfq_remove_merge_hints(q, crq);
 
-               if (crq->cfq_queue)
-                       cfq_del_crq_rb(crq);
        }
 }
 
@@ -662,21 +729,15 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
        }
 
        __rq = cfq_find_rq_hash(cfqd, bio->bi_sector);
-       if (__rq) {
-               BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector);
-
-               if (elv_rq_merge_ok(__rq, bio)) {
-                       ret = ELEVATOR_BACK_MERGE;
-                       goto out;
-               }
+       if (__rq && elv_rq_merge_ok(__rq, bio)) {
+               ret = ELEVATOR_BACK_MERGE;
+               goto out;
        }
 
        __rq = cfq_find_rq_rb(cfqd, bio->bi_sector + bio_sectors(bio));
-       if (__rq) {
-               if (elv_rq_merge_ok(__rq, bio)) {
-                       ret = ELEVATOR_FRONT_MERGE;
-                       goto out;
-               }
+       if (__rq && elv_rq_merge_ok(__rq, bio)) {
+               ret = ELEVATOR_FRONT_MERGE;
+               goto out;
        }
 
        return ELEVATOR_NO_MERGE;
@@ -709,235 +770,496 @@ static void
 cfq_merged_requests(request_queue_t *q, struct request *rq,
                    struct request *next)
 {
-       struct cfq_rq *crq = RQ_DATA(rq);
-       struct cfq_rq *cnext = RQ_DATA(next);
-
        cfq_merged_request(q, rq);
 
-       if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist)) {
-               if (time_before(cnext->queue_start, crq->queue_start)) {
-                       list_move(&rq->queuelist, &next->queuelist);
-                       crq->queue_start = cnext->queue_start;
-               }
-       }
+       /*
+        * reposition in fifo if next is older than rq
+        */
+       if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist) &&
+           time_before(next->start_time, rq->start_time))
+               list_move(&rq->queuelist, &next->queuelist);
 
-       cfq_update_next_crq(cnext);
        cfq_remove_request(q, next);
 }
 
+static inline void
+__cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+       if (cfqq) {
+               /*
+                * stop potential idle class queues waiting service
+                */
+               del_timer(&cfqd->idle_class_timer);
+
+               cfqq->slice_start = jiffies;
+               cfqq->slice_end = 0;
+               cfqq->slice_left = 0;
+               cfq_clear_cfqq_must_alloc_slice(cfqq);
+               cfq_clear_cfqq_fifo_expire(cfqq);
+               cfq_clear_cfqq_expired(cfqq);
+       }
+
+       cfqd->active_queue = cfqq;
+}
+
 /*
- * we dispatch cfqd->cfq_quantum requests in total from the rr_list queues,
- * this function sector sorts the selected request to minimize seeks. we start
- * at cfqd->last_sector, not 0.
+ * 0
+ * 0,1
+ * 0,1,2
+ * 0,1,2,3
+ * 0,1,2,3,4
+ * 0,1,2,3,4,5
+ * 0,1,2,3,4,5,6
+ * 0,1,2,3,4,5,6,7
  */
-static void cfq_dispatch_sort(request_queue_t *q, struct cfq_rq *crq)
+static int cfq_get_next_prio_level(struct cfq_data *cfqd)
 {
-       struct cfq_data *cfqd = q->elevator->elevator_data;
-       struct cfq_queue *cfqq = crq->cfq_queue;
-       struct list_head *head = &q->queue_head, *entry = head;
-       struct request *__rq;
-       sector_t last;
-
-       cfq_del_crq_rb(crq);
-       cfq_remove_merge_hints(q, crq);
-       list_del(&crq->request->queuelist);
+       int prio, wrap;
 
-       last = cfqd->last_sector;
-       while ((entry = entry->prev) != head) {
-               __rq = list_entry_rq(entry);
+       prio = -1;
+       wrap = 0;
+       do {
+               int p;
 
-               if (blk_barrier_rq(crq->request))
-                       break;
-               if (!blk_fs_request(crq->request))
-                       break;
+               for (p = cfqd->cur_prio; p <= cfqd->cur_end_prio; p++) {
+                       if (!list_empty(&cfqd->rr_list[p])) {
+                               prio = p;
+                               break;
+                       }
+               }
 
-               if (crq->request->sector > __rq->sector)
-                       break;
-               if (__rq->sector > last && crq->request->sector < last) {
-                       last = crq->request->sector;
+               if (prio != -1)
                        break;
+               cfqd->cur_prio = 0;
+               if (++cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
+                       cfqd->cur_end_prio = 0;
+                       if (wrap)
+                               break;
+                       wrap = 1;
                }
-       }
+       } while (1);
 
-       cfqd->last_sector = last;
-       crq->in_flight = 1;
-       cfqq->in_flight++;
-       list_add(&crq->request->queuelist, entry);
-}
+       if (unlikely(prio == -1))
+               return -1;
 
-/*
- * return expired entry, or NULL to just start from scratch in rbtree
- */
-static inline struct cfq_rq *cfq_check_fifo(struct cfq_queue *cfqq)
-{
-       struct cfq_data *cfqd = cfqq->cfqd;
-       const int reads = !list_empty(&cfqq->fifo[0]);
-       const int writes = !list_empty(&cfqq->fifo[1]);
-       unsigned long now = jiffies;
-       struct cfq_rq *crq;
+       BUG_ON(prio >= CFQ_PRIO_LISTS);
 
-       if (time_before(now, cfqq->last_fifo_expire + cfqd->cfq_fifo_batch_expire))
-               return NULL;
+       list_splice_init(&cfqd->rr_list[prio], &cfqd->cur_rr);
 
-       crq = RQ_DATA(list_entry(cfqq->fifo[0].next, struct request, queuelist));
-       if (reads && time_after(now, crq->queue_start + cfqd->cfq_fifo_expire_r)) {
-               cfqq->last_fifo_expire = now;
-               return crq;
+       cfqd->cur_prio = prio + 1;
+       if (cfqd->cur_prio > cfqd->cur_end_prio) {
+               cfqd->cur_end_prio = cfqd->cur_prio;
+               cfqd->cur_prio = 0;
        }
-
-       crq = RQ_DATA(list_entry(cfqq->fifo[1].next, struct request, queuelist));
-       if (writes && time_after(now, crq->queue_start + cfqd->cfq_fifo_expire_w)) {
-               cfqq->last_fifo_expire = now;
-               return crq;
+       if (cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
+               cfqd->cur_prio = 0;
+               cfqd->cur_end_prio = 0;
        }
 
-       return NULL;
+       return prio;
 }
 
-/*
- * dispatch a single request from given queue
- */
-static inline void
-cfq_dispatch_request(request_queue_t *q, struct cfq_data *cfqd,
-                    struct cfq_queue *cfqq)
+static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
 {
-       struct cfq_rq *crq;
+       struct cfq_queue *cfqq;
 
        /*
-        * follow expired path, else get first next available
+        * if current queue is expired but not done with its requests yet,
+        * wait for that to happen
         */
-       if ((crq = cfq_check_fifo(cfqq)) == NULL) {
-               if (cfqd->find_best_crq)
-                       crq = cfqq->next_crq;
-               else
-                       crq = rb_entry_crq(rb_first(&cfqq->sort_list));
+       if ((cfqq = cfqd->active_queue) != NULL) {
+               if (cfq_cfqq_expired(cfqq) && cfq_cfqq_dispatched(cfqq))
+                       return NULL;
        }
 
-       cfqd->last_sector = crq->request->sector + crq->request->nr_sectors;
+       /*
+        * if current list is non-empty, grab first entry. if it is empty,
+        * get next prio level and grab first entry then if any are spliced
+        */
+       if (!list_empty(&cfqd->cur_rr) || cfq_get_next_prio_level(cfqd) != -1)
+               cfqq = list_entry_cfqq(cfqd->cur_rr.next);
 
        /*
-        * finally, insert request into driver list
+        * if we have idle queues and no rt or be queues had pending
+        * requests, either allow immediate service if the grace period
+        * has passed or arm the idle grace timer
         */
-       cfq_dispatch_sort(q, crq);
+       if (!cfqq && !list_empty(&cfqd->idle_rr)) {
+               unsigned long end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+
+               if (time_after_eq(jiffies, end))
+                       cfqq = list_entry_cfqq(cfqd->idle_rr.next);
+               else
+                       mod_timer(&cfqd->idle_class_timer, end);
+       }
+
+       __cfq_set_active_queue(cfqd, cfqq);
+       return cfqq;
 }
 
-static int cfq_dispatch_requests(request_queue_t *q, int max_dispatch)
+/*
+ * current cfqq expired its slice (or was too idle), select new one
+ */
+static void
+__cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+                   int preempted)
 {
-       struct cfq_data *cfqd = q->elevator->elevator_data;
-       struct cfq_queue *cfqq;
-       struct list_head *entry, *tmp;
-       int queued, busy_queues, first_round;
-
-       if (list_empty(&cfqd->rr_list))
-               return 0;
+       unsigned long now = jiffies;
 
-       queued = 0;
-       first_round = 1;
-restart:
-       busy_queues = 0;
-       list_for_each_safe(entry, tmp, &cfqd->rr_list) {
-               cfqq = list_entry_cfqq(entry);
+       if (cfq_cfqq_wait_request(cfqq))
+               del_timer(&cfqd->idle_slice_timer);
 
-               BUG_ON(RB_EMPTY(&cfqq->sort_list));
+       if (!preempted && !cfq_cfqq_dispatched(cfqq))
+               cfqq->service_last = now;
 
-               /*
-                * first round of queueing, only select from queues that
-                * don't already have io in-flight
-                */
-               if (first_round && cfqq->in_flight)
-                       continue;
+       cfq_clear_cfqq_must_dispatch(cfqq);
+       cfq_clear_cfqq_wait_request(cfqq);
 
-               cfq_dispatch_request(q, cfqd, cfqq);
+       /*
+        * store what was left of this slice, if the queue idled out
+        * or was preempted
+        */
+       if (time_after(now, cfqq->slice_end))
+               cfqq->slice_left = now - cfqq->slice_end;
+       else
+               cfqq->slice_left = 0;
 
-               if (!RB_EMPTY(&cfqq->sort_list))
-                       busy_queues++;
+       if (cfq_cfqq_on_rr(cfqq))
+               cfq_resort_rr_list(cfqq, preempted);
 
-               queued++;
-       }
+       if (cfqq == cfqd->active_queue)
+               cfqd->active_queue = NULL;
 
-       if ((queued < max_dispatch) && (busy_queues || first_round)) {
-               first_round = 0;
-               goto restart;
+       if (cfqd->active_cic) {
+               put_io_context(cfqd->active_cic->ioc);
+               cfqd->active_cic = NULL;
        }
 
-       return queued;
+       cfqd->dispatch_slice = 0;
 }
 
-static inline void cfq_account_dispatch(struct cfq_rq *crq)
+static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted)
 {
-       struct cfq_queue *cfqq = crq->cfq_queue;
-       struct cfq_data *cfqd = cfqq->cfqd;
-       unsigned long now, elapsed;
+       struct cfq_queue *cfqq = cfqd->active_queue;
 
-       if (!blk_fs_request(crq->request))
-               return;
+       if (cfqq) {
+               /*
+                * use deferred expiry, if there are requests in progress as
+                * not to disturb the slice of the next queue
+                */
+               if (cfq_cfqq_dispatched(cfqq))
+                       cfq_mark_cfqq_expired(cfqq);
+               else
+                       __cfq_slice_expired(cfqd, cfqq, preempted);
+       }
+}
 
-       /*
-        * accounted bit is necessary since some drivers will call
-        * elv_next_request() many times for the same request (eg ide)
-        */
-       if (crq->accounted)
-               return;
+static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 
-       now = jiffies;
-       if (cfqq->service_start == ~0UL)
-               cfqq->service_start = now;
+{
+       WARN_ON(!RB_EMPTY(&cfqq->sort_list));
+       WARN_ON(cfqq != cfqd->active_queue);
 
        /*
-        * on drives with tagged command queueing, command turn-around time
-        * doesn't necessarily reflect the time spent processing this very
-        * command inside the drive. so do the accounting differently there,
-        * by just sorting on the number of requests
+        * idle is disabled, either manually or by past process history
         */
-       if (cfqd->cfq_tagged) {
-               if (time_after(now, cfqq->service_start + cfq_service)) {
-                       cfqq->service_start = now;
-                       cfqq->service_used /= 10;
-               }
-
-               cfqq->service_used++;
-               cfq_sort_rr_list(cfqq, 0);
-       }
+       if (!cfqd->cfq_slice_idle)
+               return 0;
+       if (!cfq_cfqq_idle_window(cfqq))
+               return 0;
+       /*
+        * task has exited, don't wait
+        */
+       if (cfqd->active_cic && !cfqd->active_cic->ioc->task)
+               return 0;
 
-       elapsed = now - crq->queue_start;
-       if (elapsed > max_elapsed_dispatch)
-               max_elapsed_dispatch = elapsed;
+       cfq_mark_cfqq_must_dispatch(cfqq);
+       cfq_mark_cfqq_wait_request(cfqq);
 
-       crq->accounted = 1;
-       crq->service_start = now;
+       if (!timer_pending(&cfqd->idle_slice_timer)) {
+               unsigned long slice_left = min(cfqq->slice_end - 1, (unsigned long) cfqd->cfq_slice_idle);
 
-       if (++cfqd->rq_in_driver >= CFQ_MAX_TAG && !cfqd->cfq_tagged) {
-               cfqq->cfqd->cfq_tagged = 1;
-               printk("cfq: depth %d reached, tagging now on\n", CFQ_MAX_TAG);
+               cfqd->idle_slice_timer.expires = jiffies + slice_left;
+               add_timer(&cfqd->idle_slice_timer);
        }
+
+       return 1;
 }
 
-static inline void
-cfq_account_completion(struct cfq_queue *cfqq, struct cfq_rq *crq)
+/*
+ * we dispatch cfqd->cfq_quantum requests in total from the rr_list queues,
+ * this function sector sorts the selected request to minimize seeks. we start
+ * at cfqd->last_sector, not 0.
+ */
+static void cfq_dispatch_sort(request_queue_t *q, struct cfq_rq *crq)
+{
+       struct cfq_data *cfqd = q->elevator->elevator_data;
+       struct cfq_queue *cfqq = crq->cfq_queue;
+       struct list_head *head = &q->queue_head, *entry = head;
+       struct request *__rq;
+       sector_t last;
+
+       list_del(&crq->request->queuelist);
+
+       last = cfqd->last_sector;
+       list_for_each_entry_reverse(__rq, head, queuelist) {
+               struct cfq_rq *__crq = RQ_DATA(__rq);
+
+               if (blk_barrier_rq(__rq))
+                       break;
+               if (!blk_fs_request(__rq))
+                       break;
+               if (cfq_crq_requeued(__crq))
+                       break;
+
+               if (__rq->sector <= crq->request->sector)
+                       break;
+               if (__rq->sector > last && crq->request->sector < last) {
+                       last = crq->request->sector + crq->request->nr_sectors;
+                       break;
+               }
+               entry = &__rq->queuelist;
+       }
+
+       cfqd->last_sector = last;
+
+       cfqq->next_crq = cfq_find_next_crq(cfqd, cfqq, crq);
+
+       cfq_del_crq_rb(crq);
+       cfq_remove_merge_hints(q, crq);
+
+       cfq_mark_crq_in_flight(crq);
+       cfq_clear_crq_requeued(crq);
+
+       cfqq->on_dispatch[cfq_crq_is_sync(crq)]++;
+       list_add_tail(&crq->request->queuelist, entry);
+}
+
+/*
+ * return expired entry, or NULL to just start from scratch in rbtree
+ */
+static inline struct cfq_rq *cfq_check_fifo(struct cfq_queue *cfqq)
 {
        struct cfq_data *cfqd = cfqq->cfqd;
+       struct request *rq;
+       struct cfq_rq *crq;
 
-       if (!crq->accounted)
+       if (cfq_cfqq_fifo_expire(cfqq))
+               return NULL;
+
+       if (!list_empty(&cfqq->fifo)) {
+               int fifo = cfq_cfqq_class_sync(cfqq);
+
+               crq = RQ_DATA(list_entry_fifo(cfqq->fifo.next));
+               rq = crq->request;
+               if (time_after(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) {
+                       cfq_mark_cfqq_fifo_expire(cfqq);
+                       return crq;
+               }
+       }
+
+       return NULL;
+}
+
+/*
+ * Scale schedule slice based on io priority. Use the sync time slice only
+ * if a queue is marked sync and has sync io queued. A sync queue with async
+ * io only, should not get full sync slice length.
+ */
+static inline int
+cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+       const int base_slice = cfqd->cfq_slice[cfq_cfqq_sync(cfqq)];
+
+       WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
+
+       return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - cfqq->ioprio));
+}
+
+static inline void
+cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+       cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies;
+}
+
+static inline int
+cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+       const int base_rq = cfqd->cfq_slice_async_rq;
+
+       WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
+
+       return 2 * (base_rq + base_rq * (CFQ_PRIO_LISTS - 1 - cfqq->ioprio));
+}
+
+/*
+ * get next queue for service
+ */
+static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd, int force)
+{
+       unsigned long now = jiffies;
+       struct cfq_queue *cfqq;
+
+       cfqq = cfqd->active_queue;
+       if (!cfqq)
+               goto new_queue;
+
+       if (cfq_cfqq_expired(cfqq))
+               goto new_queue;
+
+       /*
+        * slice has expired
+        */
+       if (!cfq_cfqq_must_dispatch(cfqq) && time_after(now, cfqq->slice_end))
+               goto expire;
+
+       /*
+        * if queue has requests, dispatch one. if not, check if
+        * enough slice is left to wait for one
+        */
+       if (!RB_EMPTY(&cfqq->sort_list))
+               goto keep_queue;
+       else if (!force && cfq_cfqq_class_sync(cfqq) &&
+                time_before(now, cfqq->slice_end)) {
+               if (cfq_arm_slice_timer(cfqd, cfqq))
+                       return NULL;
+       }
+
+expire:
+       cfq_slice_expired(cfqd, 0);
+new_queue:
+       cfqq = cfq_set_active_queue(cfqd);
+keep_queue:
+       return cfqq;
+}
+
+static int
+__cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+                       int max_dispatch)
+{
+       int dispatched = 0;
+
+       BUG_ON(RB_EMPTY(&cfqq->sort_list));
+
+       do {
+               struct cfq_rq *crq;
+
+               /*
+                * follow expired path, else get first next available
+                */
+               if ((crq = cfq_check_fifo(cfqq)) == NULL)
+                       crq = cfqq->next_crq;
+
+               /*
+                * finally, insert request into driver dispatch list
+                */
+               cfq_dispatch_sort(cfqd->queue, crq);
+
+               cfqd->dispatch_slice++;
+               dispatched++;
+
+               if (!cfqd->active_cic) {
+                       atomic_inc(&crq->io_context->ioc->refcount);
+                       cfqd->active_cic = crq->io_context;
+               }
+
+               if (RB_EMPTY(&cfqq->sort_list))
+                       break;
+
+       } while (dispatched < max_dispatch);
+
+       /*
+        * if slice end isn't set yet, set it. if at least one request was
+        * sync, use the sync time slice value
+        */
+       if (!cfqq->slice_end)
+               cfq_set_prio_slice(cfqd, cfqq);
+
+       /*
+        * expire an async queue immediately if it has used up its slice. idle
+        * queue always expire after 1 dispatch round.
+        */
+       if ((!cfq_cfqq_sync(cfqq) &&
+           cfqd->dispatch_slice >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
+           cfq_class_idle(cfqq))
+               cfq_slice_expired(cfqd, 0);
+
+       return dispatched;
+}
+
+static int
+cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force)
+{
+       struct cfq_data *cfqd = q->elevator->elevator_data;
+       struct cfq_queue *cfqq;
+
+       if (!cfqd->busy_queues)
+               return 0;
+
+       cfqq = cfq_select_queue(cfqd, force);
+       if (cfqq) {
+               cfq_clear_cfqq_must_dispatch(cfqq);
+               cfq_clear_cfqq_wait_request(cfqq);
+               del_timer(&cfqd->idle_slice_timer);
+
+               if (cfq_class_idle(cfqq))
+                       max_dispatch = 1;
+
+               return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);
+       }
+
+       return 0;
+}
+
+static inline void cfq_account_dispatch(struct cfq_rq *crq)
+{
+       struct cfq_queue *cfqq = crq->cfq_queue;
+       struct cfq_data *cfqd = cfqq->cfqd;
+
+       if (unlikely(!blk_fs_request(crq->request)))
+               return;
+
+       /*
+        * accounted bit is necessary since some drivers will call
+        * elv_next_request() many times for the same request (eg ide)
+        */
+       if (cfq_crq_in_driver(crq))
+               return;
+
+       cfq_mark_crq_in_driver(crq);
+       cfqd->rq_in_driver++;
+}
+
+static inline void
+cfq_account_completion(struct cfq_queue *cfqq, struct cfq_rq *crq)
+{
+       struct cfq_data *cfqd = cfqq->cfqd;
+       unsigned long now;
+
+       if (!cfq_crq_in_driver(crq))
                return;
 
+       now = jiffies;
+
        WARN_ON(!cfqd->rq_in_driver);
        cfqd->rq_in_driver--;
 
-       if (!cfqd->cfq_tagged) {
-               unsigned long now = jiffies;
-               unsigned long duration = now - crq->service_start;
+       if (!cfq_class_idle(cfqq))
+               cfqd->last_end_request = now;
 
-               if (time_after(now, cfqq->service_start + cfq_service)) {
-                       cfqq->service_start = now;
-                       cfqq->service_used >>= 3;
+       if (!cfq_cfqq_dispatched(cfqq)) {
+               if (cfq_cfqq_on_rr(cfqq)) {
+                       cfqq->service_last = now;
+                       cfq_resort_rr_list(cfqq, 0);
+               }
+               if (cfq_cfqq_expired(cfqq)) {
+                       __cfq_slice_expired(cfqd, cfqq, 0);
+                       cfq_schedule_dispatch(cfqd);
                }
-
-               cfqq->service_used += duration;
-               cfq_sort_rr_list(cfqq, 0);
-
-               if (duration > max_elapsed_crq)
-                       max_elapsed_crq = duration;
        }
+
+       if (cfq_crq_is_sync(crq))
+               crq->io_context->last_end_request = now;
 }
 
 static struct request *cfq_next_request(request_queue_t *q)
@@ -950,7 +1272,18 @@ static struct request *cfq_next_request(request_queue_t *q)
 dispatch:
                rq = list_entry_rq(q->queue_head.next);
 
-               if ((crq = RQ_DATA(rq)) != NULL) {
+               crq = RQ_DATA(rq);
+               if (crq) {
+                       struct cfq_queue *cfqq = crq->cfq_queue;
+
+                       /*
+                        * if idle window is disabled, allow queue buildup
+                        */
+                       if (!cfq_crq_in_driver(crq) &&
+                           !cfq_cfqq_idle_window(cfqq) &&
+                           cfqd->rq_in_driver >= cfqd->cfq_max_depth)
+                               return NULL;
+
                        cfq_remove_merge_hints(q, crq);
                        cfq_account_dispatch(crq);
                }
@@ -958,7 +1291,7 @@ dispatch:
                return rq;
        }
 
-       if (cfq_dispatch_requests(q, cfqd->cfq_quantum))
+       if (cfq_dispatch_requests(q, cfqd->cfq_quantum, 0))
                goto dispatch;
 
        return NULL;
@@ -972,13 +1305,21 @@ dispatch:
  */
 static void cfq_put_queue(struct cfq_queue *cfqq)
 {
-       BUG_ON(!atomic_read(&cfqq->ref));
+       struct cfq_data *cfqd = cfqq->cfqd;
+
+       BUG_ON(atomic_read(&cfqq->ref) <= 0);
 
        if (!atomic_dec_and_test(&cfqq->ref))
                return;
 
        BUG_ON(rb_first(&cfqq->sort_list));
-       BUG_ON(cfqq->on_rr);
+       BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]);
+       BUG_ON(cfq_cfqq_on_rr(cfqq));
+
+       if (unlikely(cfqd->active_queue == cfqq)) {
+               __cfq_slice_expired(cfqd, cfqq, 0);
+               cfq_schedule_dispatch(cfqd);
+       }
 
        cfq_put_cfqd(cfqq->cfqd);
 
@@ -991,15 +1332,17 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
 }
 
 static inline struct cfq_queue *
-__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned long key, const int hashval)
+__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio,
+                   const int hashval)
 {
        struct hlist_head *hash_list = &cfqd->cfq_hash[hashval];
        struct hlist_node *entry, *next;
 
        hlist_for_each_safe(entry, next, hash_list) {
                struct cfq_queue *__cfqq = list_entry_qhash(entry);
+               const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->ioprio_class, __cfqq->ioprio);
 
-               if (__cfqq->key == key)
+               if (__cfqq->key == key && (__p == prio || prio == CFQ_KEY_ANY))
                        return __cfqq;
        }
 
@@ -1007,94 +1350,220 @@ __cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned long key, const int hashval)
 }
 
 static struct cfq_queue *
-cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned long key)
+cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned short prio)
 {
-       return __cfq_find_cfq_hash(cfqd, key, hash_long(key, CFQ_QHASH_SHIFT));
+       return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT));
 }
 
-static inline void
-cfq_rehash_cfqq(struct cfq_data *cfqd, struct cfq_queue **cfqq,
-               struct cfq_io_context *cic)
+static void cfq_free_io_context(struct cfq_io_context *cic)
 {
-       unsigned long hashkey = cfq_hash_key(cfqd, current);
-       unsigned long hashval = hash_long(hashkey, CFQ_QHASH_SHIFT);
-       struct cfq_queue *__cfqq;
-       unsigned long flags;
-
-       spin_lock_irqsave(cfqd->queue->queue_lock, flags);
-
-       hlist_del(&(*cfqq)->cfq_hash);
+       struct cfq_io_context *__cic;
+       struct list_head *entry, *next;
 
-       __cfqq = __cfq_find_cfq_hash(cfqd, hashkey, hashval);
-       if (!__cfqq || __cfqq == *cfqq) {
-               __cfqq = *cfqq;
-               hlist_add_head(&__cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
-               __cfqq->key_type = cfqd->key_type;
-       } else {
-               atomic_inc(&__cfqq->ref);
-               cic->cfqq = __cfqq;
-               cfq_put_queue(*cfqq);
-               *cfqq = __cfqq;
+       list_for_each_safe(entry, next, &cic->list) {
+               __cic = list_entry(entry, struct cfq_io_context, list);
+               kmem_cache_free(cfq_ioc_pool, __cic);
        }
 
-       cic->cfqq = __cfqq;
-       spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+       kmem_cache_free(cfq_ioc_pool, cic);
 }
 
-static void cfq_free_io_context(struct cfq_io_context *cic)
+/*
+ * Called with interrupts disabled
+ */
+static void cfq_exit_single_io_context(struct cfq_io_context *cic)
 {
-       kmem_cache_free(cfq_ioc_pool, cic);
+       struct cfq_data *cfqd = cic->cfqq->cfqd;
+       request_queue_t *q = cfqd->queue;
+
+       WARN_ON(!irqs_disabled());
+
+       spin_lock(q->queue_lock);
+
+       if (unlikely(cic->cfqq == cfqd->active_queue)) {
+               __cfq_slice_expired(cfqd, cic->cfqq, 0);
+               cfq_schedule_dispatch(cfqd);
+       }
+
+       cfq_put_queue(cic->cfqq);
+       cic->cfqq = NULL;
+       spin_unlock(q->queue_lock);
 }
 
 /*
- * locking hierarchy is: io_context lock -> queue locks
+ * Another task may update the task cic list, if it is doing a queue lookup
+ * on its behalf. cfq_cic_lock excludes such concurrent updates
  */
 static void cfq_exit_io_context(struct cfq_io_context *cic)
 {
-       struct cfq_queue *cfqq = cic->cfqq;
-       struct list_head *entry = &cic->list;
-       request_queue_t *q;
+       struct cfq_io_context *__cic;
+       struct list_head *entry;
        unsigned long flags;
 
+       local_irq_save(flags);
+
        /*
         * put the reference this task is holding to the various queues
         */
-       spin_lock_irqsave(&cic->ioc->lock, flags);
-       while ((entry = cic->list.next) != &cic->list) {
-               struct cfq_io_context *__cic;
-
+       list_for_each(entry, &cic->list) {
                __cic = list_entry(entry, struct cfq_io_context, list);
-               list_del(entry);
-
-               q = __cic->cfqq->cfqd->queue;
-               spin_lock(q->queue_lock);
-               cfq_put_queue(__cic->cfqq);
-               spin_unlock(q->queue_lock);
+               cfq_exit_single_io_context(__cic);
        }
 
-       q = cfqq->cfqd->queue;
-       spin_lock(q->queue_lock);
-       cfq_put_queue(cfqq);
-       spin_unlock(q->queue_lock);
-
-       cic->cfqq = NULL;
-       spin_unlock_irqrestore(&cic->ioc->lock, flags);
+       cfq_exit_single_io_context(cic);
+       local_irq_restore(flags);
 }
 
-static struct cfq_io_context *cfq_alloc_io_context(int gfp_flags)
+static struct cfq_io_context *
+cfq_alloc_io_context(struct cfq_data *cfqd, int gfp_mask)
 {
-       struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_flags);
+       struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask);
 
        if (cic) {
-               cic->dtor = cfq_free_io_context;
-               cic->exit = cfq_exit_io_context;
                INIT_LIST_HEAD(&cic->list);
                cic->cfqq = NULL;
+               cic->key = NULL;
+               cic->last_end_request = jiffies;
+               cic->ttime_total = 0;
+               cic->ttime_samples = 0;
+               cic->ttime_mean = 0;
+               cic->dtor = cfq_free_io_context;
+               cic->exit = cfq_exit_io_context;
        }
 
        return cic;
 }
 
+static void cfq_init_prio_data(struct cfq_queue *cfqq)
+{
+       struct task_struct *tsk = current;
+       int ioprio_class;
+
+       if (!cfq_cfqq_prio_changed(cfqq))
+               return;
+
+       ioprio_class = IOPRIO_PRIO_CLASS(tsk->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(tsk);
+                       cfqq->ioprio_class = IOPRIO_CLASS_RT;
+                       break;
+               case IOPRIO_CLASS_BE:
+                       cfqq->ioprio = task_ioprio(tsk);
+                       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;
+       }
+
+       /*
+        * keep track of original prio settings in case we have to temporarily
+        * elevate the priority of this queue
+        */
+       cfqq->org_ioprio = cfqq->ioprio;
+       cfqq->org_ioprio_class = cfqq->ioprio_class;
+
+       if (cfq_cfqq_on_rr(cfqq))
+               cfq_resort_rr_list(cfqq, 0);
+
+       cfq_clear_cfqq_prio_changed(cfqq);
+}
+
+static inline void changed_ioprio(struct cfq_queue *cfqq)
+{
+       if (cfqq) {
+               struct cfq_data *cfqd = cfqq->cfqd;
+
+               spin_lock(cfqd->queue->queue_lock);
+               cfq_mark_cfqq_prio_changed(cfqq);
+               cfq_init_prio_data(cfqq);
+               spin_unlock(cfqd->queue->queue_lock);
+       }
+}
+
+/*
+ * callback from sys_ioprio_set, irqs are disabled
+ */
+static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio)
+{
+       struct cfq_io_context *cic = ioc->cic;
+
+       changed_ioprio(cic->cfqq);
+
+       list_for_each_entry(cic, &cic->list, list)
+               changed_ioprio(cic->cfqq);
+
+       return 0;
+}
+
+static struct cfq_queue *
+cfq_get_queue(struct cfq_data *cfqd, unsigned int key, unsigned short ioprio,
+             int gfp_mask)
+{
+       const int hashval = hash_long(key, CFQ_QHASH_SHIFT);
+       struct cfq_queue *cfqq, *new_cfqq = NULL;
+
+retry:
+       cfqq = __cfq_find_cfq_hash(cfqd, key, ioprio, hashval);
+
+       if (!cfqq) {
+               if (new_cfqq) {
+                       cfqq = new_cfqq;
+                       new_cfqq = NULL;
+               } else if (gfp_mask & __GFP_WAIT) {
+                       spin_unlock_irq(cfqd->queue->queue_lock);
+                       new_cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
+                       spin_lock_irq(cfqd->queue->queue_lock);
+                       goto retry;
+               } else {
+                       cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
+                       if (!cfqq)
+                               goto out;
+               }
+
+               memset(cfqq, 0, sizeof(*cfqq));
+
+               INIT_HLIST_NODE(&cfqq->cfq_hash);
+               INIT_LIST_HEAD(&cfqq->cfq_list);
+               RB_CLEAR_ROOT(&cfqq->sort_list);
+               INIT_LIST_HEAD(&cfqq->fifo);
+
+               cfqq->key = key;
+               hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
+               atomic_set(&cfqq->ref, 0);
+               cfqq->cfqd = cfqd;
+               atomic_inc(&cfqd->ref);
+               cfqq->service_last = 0;
+               /*
+                * set ->slice_left to allow preemption for a new process
+                */
+               cfqq->slice_left = 2 * cfqd->cfq_slice_idle;
+               cfq_mark_cfqq_idle_window(cfqq);
+               cfq_mark_cfqq_prio_changed(cfqq);
+               cfq_init_prio_data(cfqq);
+       }
+
+       if (new_cfqq)
+               kmem_cache_free(cfq_pool, new_cfqq);
+
+       atomic_inc(&cfqq->ref);
+out:
+       WARN_ON((gfp_mask & __GFP_WAIT) && !cfqq);
+       return cfqq;
+}
+
 /*
  * Setup general io context and cfq io context. There can be several cfq
  * io contexts per general io context, if this process is doing io to more
@@ -1102,39 +1571,39 @@ static struct cfq_io_context *cfq_alloc_io_context(int gfp_flags)
  * cfqq, so we don't need to worry about it disappearing
  */
 static struct cfq_io_context *
-cfq_get_io_context(struct cfq_queue **cfqq, int gfp_flags)
+cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, int gfp_mask)
 {
-       struct cfq_data *cfqd = (*cfqq)->cfqd;
-       struct cfq_queue *__cfqq = *cfqq;
+       struct io_context *ioc = NULL;
        struct cfq_io_context *cic;
-       struct io_context *ioc;
 
-       might_sleep_if(gfp_flags & __GFP_WAIT);
+       might_sleep_if(gfp_mask & __GFP_WAIT);
 
-       ioc = get_io_context(gfp_flags);
+       ioc = get_io_context(gfp_mask);
        if (!ioc)
                return NULL;
 
        if ((cic = ioc->cic) == NULL) {
-               cic = cfq_alloc_io_context(gfp_flags);
+               cic = cfq_alloc_io_context(cfqd, gfp_mask);
 
                if (cic == NULL)
                        goto err;
 
+               /*
+                * manually increment generic io_context usage count, it
+                * cannot go away since we are already holding one ref to it
+                */
                ioc->cic = cic;
+               ioc->set_ioprio = cfq_ioc_set_ioprio;
                cic->ioc = ioc;
-               cic->cfqq = __cfqq;
-               atomic_inc(&__cfqq->ref);
+               cic->key = cfqd;
+               atomic_inc(&cfqd->ref);
        } else {
                struct cfq_io_context *__cic;
-               unsigned long flags;
 
                /*
-                * since the first cic on the list is actually the head
-                * itself, need to check this here or we'll duplicate an
-                * cic per ioc for no reason
+                * the first cic on the list is actually the head itself
                 */
-               if (cic->cfqq == __cfqq)
+               if (cic->key == cfqd)
                        goto out;
 
                /*
@@ -1142,152 +1611,250 @@ cfq_get_io_context(struct cfq_queue **cfqq, int gfp_flags)
                 * should be ok here, the list will usually not be more than
                 * 1 or a few entries long
                 */
-               spin_lock_irqsave(&ioc->lock, flags);
                list_for_each_entry(__cic, &cic->list, list) {
                        /*
                         * this process is already holding a reference to
                         * this queue, so no need to get one more
                         */
-                       if (__cic->cfqq == __cfqq) {
+                       if (__cic->key == cfqd) {
                                cic = __cic;
-                               spin_unlock_irqrestore(&ioc->lock, flags);
                                goto out;
                        }
                }
-               spin_unlock_irqrestore(&ioc->lock, flags);
 
                /*
                 * nope, process doesn't have a cic assoicated with this
                 * cfqq yet. get a new one and add to list
                 */
-               __cic = cfq_alloc_io_context(gfp_flags);
+               __cic = cfq_alloc_io_context(cfqd, gfp_mask);
                if (__cic == NULL)
                        goto err;
 
                __cic->ioc = ioc;
-               __cic->cfqq = __cfqq;
-               atomic_inc(&__cfqq->ref);
-               spin_lock_irqsave(&ioc->lock, flags);
+               __cic->key = cfqd;
+               atomic_inc(&cfqd->ref);
                list_add(&__cic->list, &cic->list);
-               spin_unlock_irqrestore(&ioc->lock, flags);
+               cic = __cic;
+       }
+
+out:
+       return cic;
+err:
+       put_io_context(ioc);
+       return NULL;
+}
+
+static void
+cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic)
+{
+       unsigned long elapsed, ttime;
+
+       /*
+        * if this context already has stuff queued, thinktime is from
+        * last queue not last end
+        */
+#if 0
+       if (time_after(cic->last_end_request, cic->last_queue))
+               elapsed = jiffies - cic->last_end_request;
+       else
+               elapsed = jiffies - cic->last_queue;
+#else
+               elapsed = jiffies - cic->last_end_request;
+#endif
+
+       ttime = min(elapsed, 2UL * cfqd->cfq_slice_idle);
+
+       cic->ttime_samples = (7*cic->ttime_samples + 256) / 8;
+       cic->ttime_total = (7*cic->ttime_total + 256*ttime) / 8;
+       cic->ttime_mean = (cic->ttime_total + 128) / cic->ttime_samples;
+}
+
+#define sample_valid(samples)  ((samples) > 80)
+
+/*
+ * Disable idle window if the process thinks too long or seeks so much that
+ * it doesn't matter
+ */
+static void
+cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+                      struct cfq_io_context *cic)
+{
+       int enable_idle = cfq_cfqq_idle_window(cfqq);
+
+       if (!cic->ioc->task || !cfqd->cfq_slice_idle)
+               enable_idle = 0;
+       else if (sample_valid(cic->ttime_samples)) {
+               if (cic->ttime_mean > cfqd->cfq_slice_idle)
+                       enable_idle = 0;
+               else
+                       enable_idle = 1;
+       }
+
+       if (enable_idle)
+               cfq_mark_cfqq_idle_window(cfqq);
+       else
+               cfq_clear_cfqq_idle_window(cfqq);
+}
+
+
+/*
+ * Check if new_cfqq should preempt the currently active queue. Return 0 for
+ * no or if we aren't sure, a 1 will cause a preempt.
+ */
+static int
+cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
+                  struct cfq_rq *crq)
+{
+       struct cfq_queue *cfqq = cfqd->active_queue;
+
+       if (cfq_class_idle(new_cfqq))
+               return 0;
+
+       if (!cfqq)
+               return 1;
+
+       if (cfq_class_idle(cfqq))
+               return 1;
+       if (!cfq_cfqq_wait_request(new_cfqq))
+               return 0;
+       /*
+        * if it doesn't have slice left, forget it
+        */
+       if (new_cfqq->slice_left < cfqd->cfq_slice_idle)
+               return 0;
+       if (cfq_crq_is_sync(crq) && !cfq_cfqq_sync(cfqq))
+               return 1;
+
+       return 0;
+}
+
+/*
+ * cfqq preempts the active queue. if we allowed preempt with no slice left,
+ * let it have half of its nominal slice.
+ */
+static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+       struct cfq_queue *__cfqq, *next;
 
-               cic = __cic;
-               *cfqq = __cfqq;
-       }
+       list_for_each_entry_safe(__cfqq, next, &cfqd->cur_rr, cfq_list)
+               cfq_resort_rr_list(__cfqq, 1);
 
-out:
-       /*
-        * if key_type has been changed on the fly, we lazily rehash
-        * each queue at lookup time
-        */
-       if ((*cfqq)->key_type != cfqd->key_type)
-               cfq_rehash_cfqq(cfqd, cfqq, cic);
+       if (!cfqq->slice_left)
+               cfqq->slice_left = cfq_prio_to_slice(cfqd, cfqq) / 2;
 
-       return cic;
-err:
-       put_io_context(ioc);
-       return NULL;
+       cfqq->slice_end = cfqq->slice_left + jiffies;
+       __cfq_slice_expired(cfqd, cfqq, 1);
+       __cfq_set_active_queue(cfqd, cfqq);
 }
 
-static struct cfq_queue *
-__cfq_get_queue(struct cfq_data *cfqd, unsigned long key, int gfp_mask)
+/*
+ * should really be a ll_rw_blk.c helper
+ */
+static void cfq_start_queueing(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
-       const int hashval = hash_long(key, CFQ_QHASH_SHIFT);
-       struct cfq_queue *cfqq, *new_cfqq = NULL;
-
-retry:
-       cfqq = __cfq_find_cfq_hash(cfqd, key, hashval);
+       request_queue_t *q = cfqd->queue;
 
-       if (!cfqq) {
-               if (new_cfqq) {
-                       cfqq = new_cfqq;
-                       new_cfqq = NULL;
-               } else {
-                       spin_unlock_irq(cfqd->queue->queue_lock);
-                       new_cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
-                       spin_lock_irq(cfqd->queue->queue_lock);
+       if (!blk_queue_plugged(q))
+               q->request_fn(q);
+       else
+               __generic_unplug_device(q);
+}
 
-                       if (!new_cfqq && !(gfp_mask & __GFP_WAIT))
-                               goto out;
+/*
+ * Called when a new fs request (crq) is added (to cfqq). Check if there's
+ * something we should do about it
+ */
+static void
+cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+                struct cfq_rq *crq)
+{
+       const int sync = cfq_crq_is_sync(crq);
 
-                       goto retry;
-               }
+       cfqq->next_crq = cfq_choose_req(cfqd, cfqq->next_crq, crq);
 
-               memset(cfqq, 0, sizeof(*cfqq));
+       if (sync) {
+               struct cfq_io_context *cic = crq->io_context;
 
-               INIT_HLIST_NODE(&cfqq->cfq_hash);
-               INIT_LIST_HEAD(&cfqq->cfq_list);
-               RB_CLEAR_ROOT(&cfqq->sort_list);
-               INIT_LIST_HEAD(&cfqq->fifo[0]);
-               INIT_LIST_HEAD(&cfqq->fifo[1]);
+               cfq_update_io_thinktime(cfqd, cic);
+               cfq_update_idle_window(cfqd, cfqq, cic);
 
-               cfqq->key = key;
-               hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
-               atomic_set(&cfqq->ref, 0);
-               cfqq->cfqd = cfqd;
-               atomic_inc(&cfqd->ref);
-               cfqq->key_type = cfqd->key_type;
-               cfqq->service_start = ~0UL;
+               cic->last_queue = jiffies;
        }
 
-       if (new_cfqq)
-               kmem_cache_free(cfq_pool, new_cfqq);
-
-       atomic_inc(&cfqq->ref);
-out:
-       WARN_ON((gfp_mask & __GFP_WAIT) && !cfqq);
-       return cfqq;
+       if (cfqq == cfqd->active_queue) {
+               /*
+                * if we are waiting for a request for this queue, let it rip
+                * immediately and flag that we must not expire this queue
+                * just now
+                */
+               if (cfq_cfqq_wait_request(cfqq)) {
+                       cfq_mark_cfqq_must_dispatch(cfqq);
+                       del_timer(&cfqd->idle_slice_timer);
+                       cfq_start_queueing(cfqd, cfqq);
+               }
+       } else if (cfq_should_preempt(cfqd, cfqq, crq)) {
+               /*
+                * not the active queue - expire current slice if it is
+                * idle and has expired it's mean thinktime or this new queue
+                * has some old slice time left and is of higher priority
+                */
+               cfq_preempt_queue(cfqd, cfqq);
+               cfq_mark_cfqq_must_dispatch(cfqq);
+               cfq_start_queueing(cfqd, cfqq);
+       }
 }
 
-static void cfq_enqueue(struct cfq_data *cfqd, struct cfq_rq *crq)
+static void cfq_enqueue(struct cfq_data *cfqd, struct request *rq)
 {
-       crq->is_sync = 0;
-       if (rq_data_dir(crq->request) == READ || current->flags & PF_SYNCWRITE)
-               crq->is_sync = 1;
+       struct cfq_rq *crq = RQ_DATA(rq);
+       struct cfq_queue *cfqq = crq->cfq_queue;
+
+       cfq_init_prio_data(cfqq);
 
        cfq_add_crq_rb(crq);
-       crq->queue_start = jiffies;
 
-       list_add_tail(&crq->request->queuelist, &crq->cfq_queue->fifo[crq->is_sync]);
+       list_add_tail(&rq->queuelist, &cfqq->fifo);
+
+       if (rq_mergeable(rq)) {
+               cfq_add_crq_hash(cfqd, crq);
+
+               if (!cfqd->queue->last_merge)
+                       cfqd->queue->last_merge = rq;
+       }
+
+       cfq_crq_enqueued(cfqd, cfqq, crq);
 }
 
 static void
 cfq_insert_request(request_queue_t *q, struct request *rq, int where)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
-       struct cfq_rq *crq = RQ_DATA(rq);
 
        switch (where) {
                case ELEVATOR_INSERT_BACK:
-                       while (cfq_dispatch_requests(q, cfqd->cfq_quantum))
+                       while (cfq_dispatch_requests(q, INT_MAX, 1))
                                ;
                        list_add_tail(&rq->queuelist, &q->queue_head);
+                       /*
+                        * If we were idling with pending requests on
+                        * inactive cfqqs, force dispatching will
+                        * remove the idle timer and the queue won't
+                        * be kicked by __make_request() afterward.
+                        * Kick it here.
+                        */
+                       cfq_schedule_dispatch(cfqd);
                        break;
                case ELEVATOR_INSERT_FRONT:
                        list_add(&rq->queuelist, &q->queue_head);
                        break;
                case ELEVATOR_INSERT_SORT:
                        BUG_ON(!blk_fs_request(rq));
-                       cfq_enqueue(cfqd, crq);
+                       cfq_enqueue(cfqd, rq);
                        break;
                default:
                        printk("%s: bad insert point %d\n", __FUNCTION__,where);
                        return;
        }
-
-       if (rq_mergeable(rq)) {
-               cfq_add_crq_hash(cfqd, crq);
-
-               if (!q->last_merge)
-                       q->last_merge = rq;
-       }
-}
-
-static int cfq_queue_empty(request_queue_t *q)
-{
-       struct cfq_data *cfqd = q->elevator->elevator_data;
-
-       return list_empty(&q->queue_head) && list_empty(&cfqd->rr_list);
 }
 
 static void cfq_completed_request(request_queue_t *q, struct request *rq)
@@ -1300,9 +1867,11 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
 
        cfqq = crq->cfq_queue;
 
-       if (crq->in_flight) {
-               WARN_ON(!cfqq->in_flight);
-               cfqq->in_flight--;
+       if (cfq_crq_in_flight(crq)) {
+               const int sync = cfq_crq_is_sync(crq);
+
+               WARN_ON(!cfqq->on_dispatch[sync]);
+               cfqq->on_dispatch[sync]--;
        }
 
        cfq_account_completion(cfqq, crq);
@@ -1332,51 +1901,136 @@ cfq_latter_request(request_queue_t *q, struct request *rq)
        return NULL;
 }
 
-static int cfq_may_queue(request_queue_t *q, int rw)
+/*
+ * we temporarily boost lower priority queues if they are holding fs exclusive
+ * resources. they are boosted to normal prio (CLASS_BE/4)
+ */
+static void cfq_prio_boost(struct cfq_queue *cfqq)
 {
-       struct cfq_data *cfqd = q->elevator->elevator_data;
-       struct cfq_queue *cfqq;
-       int ret = ELV_MQUEUE_MAY;
+       const int ioprio_class = cfqq->ioprio_class;
+       const int ioprio = cfqq->ioprio;
 
-       if (current->flags & PF_MEMALLOC)
-               return ELV_MQUEUE_MAY;
+       if (has_fs_excl()) {
+               /*
+                * boost idle prio on transactions that would lock out other
+                * users of the filesystem
+                */
+               if (cfq_class_idle(cfqq))
+                       cfqq->ioprio_class = IOPRIO_CLASS_BE;
+               if (cfqq->ioprio > IOPRIO_NORM)
+                       cfqq->ioprio = IOPRIO_NORM;
+       } else {
+               /*
+                * check if we need to unboost the queue
+                */
+               if (cfqq->ioprio_class != cfqq->org_ioprio_class)
+                       cfqq->ioprio_class = cfqq->org_ioprio_class;
+               if (cfqq->ioprio != cfqq->org_ioprio)
+                       cfqq->ioprio = cfqq->org_ioprio;
+       }
 
-       cfqq = cfq_find_cfq_hash(cfqd, cfq_hash_key(cfqd, current));
-       if (cfqq) {
-               int limit = cfqd->max_queued;
+       /*
+        * refile between round-robin lists if we moved the priority class
+        */
+       if ((ioprio_class != cfqq->ioprio_class || ioprio != cfqq->ioprio) &&
+           cfq_cfqq_on_rr(cfqq))
+               cfq_resort_rr_list(cfqq, 0);
+}
 
-               if (cfqq->allocated[rw] < cfqd->cfq_queued)
-                       return ELV_MQUEUE_MUST;
+static inline pid_t cfq_queue_pid(struct task_struct *task, int rw)
+{
+       if (rw == READ || process_sync(task))
+               return task->pid;
 
-               if (cfqd->busy_queues)
-                       limit = q->nr_requests / cfqd->busy_queues;
+       return CFQ_KEY_ASYNC;
+}
 
-               if (limit < cfqd->cfq_queued)
-                       limit = cfqd->cfq_queued;
-               else if (limit > cfqd->max_queued)
-                       limit = cfqd->max_queued;
+static inline int
+__cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+               struct task_struct *task, int rw)
+{
+#if 1
+       if ((cfq_cfqq_wait_request(cfqq) || cfq_cfqq_must_alloc(cfqq)) &&
+           !cfq_cfqq_must_alloc_slice(cfqq)) {
+               cfq_mark_cfqq_must_alloc_slice(cfqq);
+               return ELV_MQUEUE_MUST;
+       }
 
-               if (cfqq->allocated[rw] >= limit) {
-                       if (limit > cfqq->alloc_limit[rw])
-                               cfqq->alloc_limit[rw] = limit;
+       return ELV_MQUEUE_MAY;
+#else
+       if (!cfqq || task->flags & PF_MEMALLOC)
+               return ELV_MQUEUE_MAY;
+       if (!cfqq->allocated[rw] || cfq_cfqq_must_alloc(cfqq)) {
+               if (cfq_cfqq_wait_request(cfqq))
+                       return ELV_MQUEUE_MUST;
 
-                       ret = ELV_MQUEUE_NO;
+               /*
+                * only allow 1 ELV_MQUEUE_MUST per slice, otherwise we
+                * can quickly flood the queue with writes from a single task
+                */
+               if (rw == READ || !cfq_cfqq_must_alloc_slice(cfqq)) {
+                       cfq_mark_cfqq_must_alloc_slice(cfqq);
+                       return ELV_MQUEUE_MUST;
                }
+
+               return ELV_MQUEUE_MAY;
        }
+       if (cfq_class_idle(cfqq))
+               return ELV_MQUEUE_NO;
+       if (cfqq->allocated[rw] >= cfqd->max_queued) {
+               struct io_context *ioc = get_io_context(GFP_ATOMIC);
+               int ret = ELV_MQUEUE_NO;
 
-       return ret;
+               if (ioc && ioc->nr_batch_requests)
+                       ret = ELV_MQUEUE_MAY;
+
+               put_io_context(ioc);
+               return ret;
+       }
+
+       return ELV_MQUEUE_MAY;
+#endif
+}
+
+static int cfq_may_queue(request_queue_t *q, int rw, struct bio *bio)
+{
+       struct cfq_data *cfqd = q->elevator->elevator_data;
+       struct task_struct *tsk = current;
+       struct cfq_queue *cfqq;
+
+       /*
+        * don't force setup of a queue from here, as a call to may_queue
+        * does not necessarily imply that a request actually will be queued.
+        * so just lookup a possibly existing queue, or return 'may queue'
+        * if that fails
+        */
+       cfqq = cfq_find_cfq_hash(cfqd, cfq_queue_pid(tsk, rw), tsk->ioprio);
+       if (cfqq) {
+               cfq_init_prio_data(cfqq);
+               cfq_prio_boost(cfqq);
+
+               return __cfq_may_queue(cfqd, cfqq, tsk, rw);
+       }
+
+       return ELV_MQUEUE_MAY;
 }
 
 static void cfq_check_waiters(request_queue_t *q, struct cfq_queue *cfqq)
 {
+       struct cfq_data *cfqd = q->elevator->elevator_data;
        struct request_list *rl = &q->rq;
-       const int write = waitqueue_active(&rl->wait[WRITE]);
-       const int read = waitqueue_active(&rl->wait[READ]);
 
-       if (read && cfqq->allocated[READ] < cfqq->alloc_limit[READ])
-               wake_up(&rl->wait[READ]);
-       if (write && cfqq->allocated[WRITE] < cfqq->alloc_limit[WRITE])
-               wake_up(&rl->wait[WRITE]);
+       if (cfqq->allocated[READ] <= cfqd->max_queued || cfqd->rq_starved) {
+               smp_mb();
+               if (waitqueue_active(&rl->wait[READ]))
+                       wake_up(&rl->wait[READ]);
+       }
+
+       if (cfqq->allocated[WRITE] <= cfqd->max_queued || cfqd->rq_starved) {
+               smp_mb();
+               if (waitqueue_active(&rl->wait[WRITE]))
+                       wake_up(&rl->wait[WRITE]);
+       }
 }
 
 /*
@@ -1389,69 +2043,61 @@ static void cfq_put_request(request_queue_t *q, struct request *rq)
 
        if (crq) {
                struct cfq_queue *cfqq = crq->cfq_queue;
+               const int rw = rq_data_dir(rq);
 
-               BUG_ON(q->last_merge == rq);
-               BUG_ON(!hlist_unhashed(&crq->hash));
-
-               if (crq->io_context)
-                       put_io_context(crq->io_context->ioc);
+               BUG_ON(!cfqq->allocated[rw]);
+               cfqq->allocated[rw]--;
 
-               BUG_ON(!cfqq->allocated[crq->is_write]);
-               cfqq->allocated[crq->is_write]--;
+               put_io_context(crq->io_context->ioc);
 
                mempool_free(crq, cfqd->crq_pool);
                rq->elevator_private = NULL;
 
-               smp_mb();
                cfq_check_waiters(q, cfqq);
                cfq_put_queue(cfqq);
        }
 }
 
 /*
- * Allocate cfq data structures associated with this request. A queue and
+ * Allocate cfq data structures associated with this request.
  */
-static int cfq_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+static int
+cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+               int gfp_mask)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
+       struct task_struct *tsk = current;
        struct cfq_io_context *cic;
        const int rw = rq_data_dir(rq);
-       struct cfq_queue *cfqq, *saved_cfqq;
+       pid_t key = cfq_queue_pid(tsk, rw);
+       struct cfq_queue *cfqq;
        struct cfq_rq *crq;
        unsigned long flags;
 
        might_sleep_if(gfp_mask & __GFP_WAIT);
 
+       cic = cfq_get_io_context(cfqd, key, gfp_mask);
+
        spin_lock_irqsave(q->queue_lock, flags);
 
-       cfqq = __cfq_get_queue(cfqd, cfq_hash_key(cfqd, current), gfp_mask);
-       if (!cfqq)
-               goto out_lock;
+       if (!cic)
+               goto queue_fail;
 
-repeat:
-       if (cfqq->allocated[rw] >= cfqd->max_queued)
-               goto out_lock;
+       if (!cic->cfqq) {
+               cfqq = cfq_get_queue(cfqd, key, tsk->ioprio, gfp_mask);
+               if (!cfqq)
+                       goto queue_fail;
+
+               cic->cfqq = cfqq;
+       } else
+               cfqq = cic->cfqq;
 
        cfqq->allocated[rw]++;
+       cfq_clear_cfqq_must_alloc(cfqq);
+       cfqd->rq_starved = 0;
+       atomic_inc(&cfqq->ref);
        spin_unlock_irqrestore(q->queue_lock, flags);
 
-       /*
-        * if hashing type has changed, the cfq_queue might change here.
-        */
-       saved_cfqq = cfqq;
-       cic = cfq_get_io_context(&cfqq, gfp_mask);
-       if (!cic)
-               goto err;
-
-       /*
-        * repeat allocation checks on queue change
-        */
-       if (unlikely(saved_cfqq != cfqq)) {
-               spin_lock_irqsave(q->queue_lock, flags);
-               saved_cfqq->allocated[rw]--;
-               goto repeat;
-       }
-
        crq = mempool_alloc(cfqd->crq_pool, gfp_mask);
        if (crq) {
                RB_CLEAR(&crq->rb_node);
@@ -1460,24 +2106,141 @@ repeat:
                INIT_HLIST_NODE(&crq->hash);
                crq->cfq_queue = cfqq;
                crq->io_context = cic;
-               crq->service_start = crq->queue_start = 0;
-               crq->in_flight = crq->accounted = crq->is_sync = 0;
-               crq->is_write = rw;
+               cfq_clear_crq_in_flight(crq);
+               cfq_clear_crq_in_driver(crq);
+               cfq_clear_crq_requeued(crq);
+
+               if (rw == READ || process_sync(tsk))
+                       cfq_mark_crq_is_sync(crq);
+               else
+                       cfq_clear_crq_is_sync(crq);
+
                rq->elevator_private = crq;
-               cfqq->alloc_limit[rw] = 0;
                return 0;
        }
 
-       put_io_context(cic->ioc);
-err:
        spin_lock_irqsave(q->queue_lock, flags);
        cfqq->allocated[rw]--;
+       if (!(cfqq->allocated[0] + cfqq->allocated[1]))
+               cfq_mark_cfqq_must_alloc(cfqq);
        cfq_put_queue(cfqq);
-out_lock:
+queue_fail:
+       if (cic)
+               put_io_context(cic->ioc);
+       /*
+        * mark us rq allocation starved. we need to kickstart the process
+        * ourselves if there are no pending requests that can do it for us.
+        * that would be an extremely rare OOM situation
+        */
+       cfqd->rq_starved = 1;
+       cfq_schedule_dispatch(cfqd);
        spin_unlock_irqrestore(q->queue_lock, flags);
        return 1;
 }
 
+static void cfq_kick_queue(void *data)
+{
+       request_queue_t *q = data;
+       struct cfq_data *cfqd = q->elevator->elevator_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(q->queue_lock, flags);
+
+       if (cfqd->rq_starved) {
+               struct request_list *rl = &q->rq;
+
+               /*
+                * we aren't guaranteed to get a request after this, but we
+                * have to be opportunistic
+                */
+               smp_mb();
+               if (waitqueue_active(&rl->wait[READ]))
+                       wake_up(&rl->wait[READ]);
+               if (waitqueue_active(&rl->wait[WRITE]))
+                       wake_up(&rl->wait[WRITE]);
+       }
+
+       blk_remove_plug(q);
+       q->request_fn(q);
+       spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+/*
+ * Timer running if the active_queue is currently idling inside its time slice
+ */
+static void cfq_idle_slice_timer(unsigned long data)
+{
+       struct cfq_data *cfqd = (struct cfq_data *) data;
+       struct cfq_queue *cfqq;
+       unsigned long flags;
+
+       spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+
+       if ((cfqq = cfqd->active_queue) != NULL) {
+               unsigned long now = jiffies;
+
+               /*
+                * expired
+                */
+               if (time_after(now, cfqq->slice_end))
+                       goto expire;
+
+               /*
+                * only expire and reinvoke request handler, if there are
+                * other queues with pending requests
+                */
+               if (!cfq_pending_requests(cfqd)) {
+                       cfqd->idle_slice_timer.expires = min(now + cfqd->cfq_slice_idle, cfqq->slice_end);
+                       add_timer(&cfqd->idle_slice_timer);
+                       goto out_cont;
+               }
+
+               /*
+                * not expired and it has a request pending, let it dispatch
+                */
+               if (!RB_EMPTY(&cfqq->sort_list)) {
+                       cfq_mark_cfqq_must_dispatch(cfqq);
+                       goto out_kick;
+               }
+       }
+expire:
+       cfq_slice_expired(cfqd, 0);
+out_kick:
+       cfq_schedule_dispatch(cfqd);
+out_cont:
+       spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+}
+
+/*
+ * Timer running if an idle class queue is waiting for service
+ */
+static void cfq_idle_class_timer(unsigned long data)
+{
+       struct cfq_data *cfqd = (struct cfq_data *) data;
+       unsigned long flags, end;
+
+       spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+
+       /*
+        * race with a non-idle queue, reset timer
+        */
+       end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+       if (!time_after_eq(jiffies, end)) {
+               cfqd->idle_class_timer.expires = end;
+               add_timer(&cfqd->idle_class_timer);
+       } else
+               cfq_schedule_dispatch(cfqd);
+
+       spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+}
+
+static void cfq_shutdown_timer_wq(struct cfq_data *cfqd)
+{
+       del_timer_sync(&cfqd->idle_slice_timer);
+       del_timer_sync(&cfqd->idle_class_timer);
+       blk_sync_queue(cfqd->queue);
+}
+
 static void cfq_put_cfqd(struct cfq_data *cfqd)
 {
        request_queue_t *q = cfqd->queue;
@@ -1487,6 +2250,9 @@ static void cfq_put_cfqd(struct cfq_data *cfqd)
 
        blk_put_queue(q);
 
+       cfq_shutdown_timer_wq(cfqd);
+       q->elevator->elevator_data = NULL;
+
        mempool_destroy(cfqd->crq_pool);
        kfree(cfqd->crq_hash);
        kfree(cfqd->cfq_hash);
@@ -1495,7 +2261,10 @@ static void cfq_put_cfqd(struct cfq_data *cfqd)
 
 static void cfq_exit_queue(elevator_t *e)
 {
-       cfq_put_cfqd(e->elevator_data);
+       struct cfq_data *cfqd = e->elevator_data;
+
+       cfq_shutdown_timer_wq(cfqd);
+       cfq_put_cfqd(cfqd);
 }
 
 static int cfq_init_queue(request_queue_t *q, elevator_t *e)
@@ -1508,7 +2277,13 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e)
                return -ENOMEM;
 
        memset(cfqd, 0, sizeof(*cfqd));
-       INIT_LIST_HEAD(&cfqd->rr_list);
+
+       for (i = 0; i < CFQ_PRIO_LISTS; i++)
+               INIT_LIST_HEAD(&cfqd->rr_list[i]);
+
+       INIT_LIST_HEAD(&cfqd->busy_rr);
+       INIT_LIST_HEAD(&cfqd->cur_rr);
+       INIT_LIST_HEAD(&cfqd->idle_rr);
        INIT_LIST_HEAD(&cfqd->empty_list);
 
        cfqd->crq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL);
@@ -1533,24 +2308,32 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e)
        cfqd->queue = q;
        atomic_inc(&q->refcnt);
 
-       /*
-        * just set it to some high value, we want anyone to be able to queue
-        * some requests. fairness is handled differently
-        */
-       q->nr_requests = 1024;
-       cfqd->max_queued = q->nr_requests / 16;
+       cfqd->max_queued = q->nr_requests / 4;
        q->nr_batching = cfq_queued;
-       cfqd->key_type = CFQ_KEY_TGID;
-       cfqd->find_best_crq = 1;
+
+       init_timer(&cfqd->idle_slice_timer);
+       cfqd->idle_slice_timer.function = cfq_idle_slice_timer;
+       cfqd->idle_slice_timer.data = (unsigned long) cfqd;
+
+       init_timer(&cfqd->idle_class_timer);
+       cfqd->idle_class_timer.function = cfq_idle_class_timer;
+       cfqd->idle_class_timer.data = (unsigned long) cfqd;
+
+       INIT_WORK(&cfqd->unplug_work, cfq_kick_queue, q);
+
        atomic_set(&cfqd->ref, 1);
 
        cfqd->cfq_queued = cfq_queued;
        cfqd->cfq_quantum = cfq_quantum;
-       cfqd->cfq_fifo_expire_r = cfq_fifo_expire_r;
-       cfqd->cfq_fifo_expire_w = cfq_fifo_expire_w;
-       cfqd->cfq_fifo_batch_expire = cfq_fifo_rate;
+       cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0];
+       cfqd->cfq_fifo_expire[1] = cfq_fifo_expire[1];
        cfqd->cfq_back_max = cfq_back_max;
        cfqd->cfq_back_penalty = cfq_back_penalty;
+       cfqd->cfq_slice[0] = cfq_slice_async;
+       cfqd->cfq_slice[1] = cfq_slice_sync;
+       cfqd->cfq_slice_async_rq = cfq_slice_async_rq;
+       cfqd->cfq_slice_idle = cfq_slice_idle;
+       cfqd->cfq_max_depth = cfq_max_depth;
 
        return 0;
 out_crqpool:
@@ -1595,7 +2378,6 @@ fail:
        return -ENOMEM;
 }
 
-
 /*
  * sysfs parts below -->
  */
@@ -1620,45 +2402,6 @@ cfq_var_store(unsigned int *var, const char *page, size_t count)
        return count;
 }
 
-static ssize_t
-cfq_clear_elapsed(struct cfq_data *cfqd, const char *page, size_t count)
-{
-       max_elapsed_dispatch = max_elapsed_crq = 0;
-       return count;
-}
-
-static ssize_t
-cfq_set_key_type(struct cfq_data *cfqd, const char *page, size_t count)
-{
-       spin_lock_irq(cfqd->queue->queue_lock);
-       if (!strncmp(page, "pgid", 4))
-               cfqd->key_type = CFQ_KEY_PGID;
-       else if (!strncmp(page, "tgid", 4))
-               cfqd->key_type = CFQ_KEY_TGID;
-       else if (!strncmp(page, "uid", 3))
-               cfqd->key_type = CFQ_KEY_UID;
-       else if (!strncmp(page, "gid", 3))
-               cfqd->key_type = CFQ_KEY_GID;
-       spin_unlock_irq(cfqd->queue->queue_lock);
-       return count;
-}
-
-static ssize_t
-cfq_read_key_type(struct cfq_data *cfqd, char *page)
-{
-       ssize_t len = 0;
-       int i;
-
-       for (i = CFQ_KEY_PGID; i < CFQ_KEY_LAST; i++) {
-               if (cfqd->key_type == i)
-                       len += sprintf(page+len, "[%s] ", cfq_key_types[i]);
-               else
-                       len += sprintf(page+len, "%s ", cfq_key_types[i]);
-       }
-       len += sprintf(page+len, "\n");
-       return len;
-}
-
 #define SHOW_FUNCTION(__FUNC, __VAR, __CONV)                           \
 static ssize_t __FUNC(struct cfq_data *cfqd, char *page)               \
 {                                                                      \
@@ -1669,12 +2412,15 @@ static ssize_t __FUNC(struct cfq_data *cfqd, char *page)                \
 }
 SHOW_FUNCTION(cfq_quantum_show, cfqd->cfq_quantum, 0);
 SHOW_FUNCTION(cfq_queued_show, cfqd->cfq_queued, 0);
-SHOW_FUNCTION(cfq_fifo_expire_r_show, cfqd->cfq_fifo_expire_r, 1);
-SHOW_FUNCTION(cfq_fifo_expire_w_show, cfqd->cfq_fifo_expire_w, 1);
-SHOW_FUNCTION(cfq_fifo_batch_expire_show, cfqd->cfq_fifo_batch_expire, 1);
-SHOW_FUNCTION(cfq_find_best_show, cfqd->find_best_crq, 0);
+SHOW_FUNCTION(cfq_fifo_expire_sync_show, cfqd->cfq_fifo_expire[1], 1);
+SHOW_FUNCTION(cfq_fifo_expire_async_show, cfqd->cfq_fifo_expire[0], 1);
 SHOW_FUNCTION(cfq_back_max_show, cfqd->cfq_back_max, 0);
 SHOW_FUNCTION(cfq_back_penalty_show, cfqd->cfq_back_penalty, 0);
+SHOW_FUNCTION(cfq_slice_idle_show, cfqd->cfq_slice_idle, 1);
+SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1);
+SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1);
+SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0);
+SHOW_FUNCTION(cfq_max_depth_show, cfqd->cfq_max_depth, 0);
 #undef SHOW_FUNCTION
 
 #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV)                        \
@@ -1694,12 +2440,15 @@ static ssize_t __FUNC(struct cfq_data *cfqd, const char *page, size_t count)    \
 }
 STORE_FUNCTION(cfq_quantum_store, &cfqd->cfq_quantum, 1, UINT_MAX, 0);
 STORE_FUNCTION(cfq_queued_store, &cfqd->cfq_queued, 1, UINT_MAX, 0);
-STORE_FUNCTION(cfq_fifo_expire_r_store, &cfqd->cfq_fifo_expire_r, 1, UINT_MAX, 1);
-STORE_FUNCTION(cfq_fifo_expire_w_store, &cfqd->cfq_fifo_expire_w, 1, UINT_MAX, 1);
-STORE_FUNCTION(cfq_fifo_batch_expire_store, &cfqd->cfq_fifo_batch_expire, 0, UINT_MAX, 1);
-STORE_FUNCTION(cfq_find_best_store, &cfqd->find_best_crq, 0, 1, 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_back_max_store, &cfqd->cfq_back_max, 0, UINT_MAX, 0);
 STORE_FUNCTION(cfq_back_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_max_depth_store, &cfqd->cfq_max_depth, 1, UINT_MAX, 0);
 #undef STORE_FUNCTION
 
 static struct cfq_fs_entry cfq_quantum_entry = {
@@ -1712,25 +2461,15 @@ static struct cfq_fs_entry cfq_queued_entry = {
        .show = cfq_queued_show,
        .store = cfq_queued_store,
 };
-static struct cfq_fs_entry cfq_fifo_expire_r_entry = {
+static struct cfq_fs_entry cfq_fifo_expire_sync_entry = {
        .attr = {.name = "fifo_expire_sync", .mode = S_IRUGO | S_IWUSR },
-       .show = cfq_fifo_expire_r_show,
-       .store = cfq_fifo_expire_r_store,
+       .show = cfq_fifo_expire_sync_show,
+       .store = cfq_fifo_expire_sync_store,
 };
-static struct cfq_fs_entry cfq_fifo_expire_w_entry = {
+static struct cfq_fs_entry cfq_fifo_expire_async_entry = {
        .attr = {.name = "fifo_expire_async", .mode = S_IRUGO | S_IWUSR },
-       .show = cfq_fifo_expire_w_show,
-       .store = cfq_fifo_expire_w_store,
-};
-static struct cfq_fs_entry cfq_fifo_batch_expire_entry = {
-       .attr = {.name = "fifo_batch_expire", .mode = S_IRUGO | S_IWUSR },
-       .show = cfq_fifo_batch_expire_show,
-       .store = cfq_fifo_batch_expire_store,
-};
-static struct cfq_fs_entry cfq_find_best_entry = {
-       .attr = {.name = "find_best_crq", .mode = S_IRUGO | S_IWUSR },
-       .show = cfq_find_best_show,
-       .store = cfq_find_best_store,
+       .show = cfq_fifo_expire_async_show,
+       .store = cfq_fifo_expire_async_store,
 };
 static struct cfq_fs_entry cfq_back_max_entry = {
        .attr = {.name = "back_seek_max", .mode = S_IRUGO | S_IWUSR },
@@ -1742,27 +2481,44 @@ static struct cfq_fs_entry cfq_back_penalty_entry = {
        .show = cfq_back_penalty_show,
        .store = cfq_back_penalty_store,
 };
-static struct cfq_fs_entry cfq_clear_elapsed_entry = {
-       .attr = {.name = "clear_elapsed", .mode = S_IWUSR },
-       .store = cfq_clear_elapsed,
+static struct cfq_fs_entry cfq_slice_sync_entry = {
+       .attr = {.name = "slice_sync", .mode = S_IRUGO | S_IWUSR },
+       .show = cfq_slice_sync_show,
+       .store = cfq_slice_sync_store,
+};
+static struct cfq_fs_entry cfq_slice_async_entry = {
+       .attr = {.name = "slice_async", .mode = S_IRUGO | S_IWUSR },
+       .show = cfq_slice_async_show,
+       .store = cfq_slice_async_store,
+};
+static struct cfq_fs_entry cfq_slice_async_rq_entry = {
+       .attr = {.name = "slice_async_rq", .mode = S_IRUGO | S_IWUSR },
+       .show = cfq_slice_async_rq_show,
+       .store = cfq_slice_async_rq_store,
 };
-static struct cfq_fs_entry cfq_key_type_entry = {
-       .attr = {.name = "key_type", .mode = S_IRUGO | S_IWUSR },
-       .show = cfq_read_key_type,
-       .store = cfq_set_key_type,
+static struct cfq_fs_entry cfq_slice_idle_entry = {
+       .attr = {.name = "slice_idle", .mode = S_IRUGO | S_IWUSR },
+       .show = cfq_slice_idle_show,
+       .store = cfq_slice_idle_store,
+};
+static struct cfq_fs_entry cfq_max_depth_entry = {
+       .attr = {.name = "max_depth", .mode = S_IRUGO | S_IWUSR },
+       .show = cfq_max_depth_show,
+       .store = cfq_max_depth_store,
 };
 
 static struct attribute *default_attrs[] = {
        &cfq_quantum_entry.attr,
        &cfq_queued_entry.attr,
-       &cfq_fifo_expire_r_entry.attr,
-       &cfq_fifo_expire_w_entry.attr,
-       &cfq_fifo_batch_expire_entry.attr,
-       &cfq_key_type_entry.attr,
-       &cfq_find_best_entry.attr,
+       &cfq_fifo_expire_sync_entry.attr,
+       &cfq_fifo_expire_async_entry.attr,
        &cfq_back_max_entry.attr,
        &cfq_back_penalty_entry.attr,
-       &cfq_clear_elapsed_entry.attr,
+       &cfq_slice_sync_entry.attr,
+       &cfq_slice_async_entry.attr,
+       &cfq_slice_async_rq_entry.attr,
+       &cfq_slice_idle_entry.attr,
+       &cfq_max_depth_entry.attr,
        NULL,
 };
 
@@ -1832,21 +2588,46 @@ static int __init cfq_init(void)
 {
        int ret;
 
+       /*
+        * could be 0 on HZ < 1000 setups
+        */
+       if (!cfq_slice_async)
+               cfq_slice_async = 1;
+       if (!cfq_slice_idle)
+               cfq_slice_idle = 1;
+
        if (cfq_slab_setup())
                return -ENOMEM;
 
        ret = elv_register(&iosched_cfq);
-       if (!ret) {
-               __module_get(THIS_MODULE);
-               return 0;
-       }
+       if (ret)
+               cfq_slab_kill();
 
-       cfq_slab_kill();
        return ret;
 }
 
 static void __exit cfq_exit(void)
 {
+       struct task_struct *g, *p;
+       unsigned long flags;
+
+       read_lock_irqsave(&tasklist_lock, flags);
+
+       /*
+        * iterate each process in the system, removing our io_context
+        */
+       do_each_thread(g, p) {
+               struct io_context *ioc = p->io_context;
+
+               if (ioc && ioc->cic) {
+                       ioc->cic->exit(ioc->cic);
+                       cfq_free_io_context(ioc->cic);
+                       ioc->cic = NULL;
+               }
+       } while_each_thread(g, p);
+
+       read_unlock_irqrestore(&tasklist_lock, flags);
+
        cfq_slab_kill();
        elv_unregister(&iosched_cfq);
 }
index 4bc2fea73273dcee94482bd094f0c02a2833bc59..ff5201e021534693987f30597817ef7cdb2de317 100644 (file)
@@ -760,7 +760,8 @@ static void deadline_put_request(request_queue_t *q, struct request *rq)
 }
 
 static int
-deadline_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+                    int gfp_mask)
 {
        struct deadline_data *dd = q->elevator->elevator_data;
        struct deadline_rq *drq;
index f831f08f839c14d145cb19d322b361c47a08a2e6..98f0126a2deb3228e0866abcb44bf8b2c1af5859 100644 (file)
@@ -486,12 +486,13 @@ struct request *elv_former_request(request_queue_t *q, struct request *rq)
        return NULL;
 }
 
-int elv_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+int elv_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+                   int gfp_mask)
 {
        elevator_t *e = q->elevator;
 
        if (e->ops->elevator_set_req_fn)
-               return e->ops->elevator_set_req_fn(q, rq, gfp_mask);
+               return e->ops->elevator_set_req_fn(q, rq, bio, gfp_mask);
 
        rq->elevator_private = NULL;
        return 0;
@@ -505,12 +506,12 @@ void elv_put_request(request_queue_t *q, struct request *rq)
                e->ops->elevator_put_req_fn(q, rq);
 }
 
-int elv_may_queue(request_queue_t *q, int rw)
+int elv_may_queue(request_queue_t *q, int rw, struct bio *bio)
 {
        elevator_t *e = q->elevator;
 
        if (e->ops->elevator_may_queue_fn)
-               return e->ops->elevator_may_queue_fn(q, rw);
+               return e->ops->elevator_may_queue_fn(q, rw, bio);
 
        return ELV_MQUEUE_MAY;
 }
index fd94ea27d594f39473546477f81486c22cdf17c3..692a5fced76e448819f4e649cd5576a066deae4f 100644 (file)
@@ -37,6 +37,7 @@
 
 static void blk_unplug_work(void *data);
 static void blk_unplug_timeout(unsigned long data);
+static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io);
 
 /*
  * For the allocated request tables
@@ -275,6 +276,7 @@ static inline void rq_init(request_queue_t *q, struct request *rq)
        rq->errors = 0;
        rq->rq_status = RQ_ACTIVE;
        rq->bio = rq->biotail = NULL;
+       rq->ioprio = 0;
        rq->buffer = NULL;
        rq->ref_count = 1;
        rq->q = q;
@@ -1137,7 +1139,7 @@ new_hw_segment:
 }
 
 
-int blk_phys_contig_segment(request_queue_t *q, struct bio *bio,
+static int blk_phys_contig_segment(request_queue_t *q, struct bio *bio,
                                   struct bio *nxt)
 {
        if (!(q->queue_flags & (1 << QUEUE_FLAG_CLUSTER)))
@@ -1158,9 +1160,7 @@ int blk_phys_contig_segment(request_queue_t *q, struct bio *bio,
        return 0;
 }
 
-EXPORT_SYMBOL(blk_phys_contig_segment);
-
-int blk_hw_contig_segment(request_queue_t *q, struct bio *bio,
+static int blk_hw_contig_segment(request_queue_t *q, struct bio *bio,
                                 struct bio *nxt)
 {
        if (unlikely(!bio_flagged(bio, BIO_SEG_VALID)))
@@ -1176,8 +1176,6 @@ int blk_hw_contig_segment(request_queue_t *q, struct bio *bio,
        return 1;
 }
 
-EXPORT_SYMBOL(blk_hw_contig_segment);
-
 /*
  * map a request to scatterlist, return number of sg entries setup. Caller
  * must make sure sg can hold rq->nr_phys_segments entries
@@ -1347,8 +1345,8 @@ static int ll_front_merge_fn(request_queue_t *q, struct request *req,
 static int ll_merge_requests_fn(request_queue_t *q, struct request *req,
                                struct request *next)
 {
-       int total_phys_segments = req->nr_phys_segments +next->nr_phys_segments;
-       int total_hw_segments = req->nr_hw_segments + next->nr_hw_segments;
+       int total_phys_segments;
+       int total_hw_segments;
 
        /*
         * First check if the either of the requests are re-queued
@@ -1358,7 +1356,7 @@ static int ll_merge_requests_fn(request_queue_t *q, struct request *req,
                return 0;
 
        /*
-        * Will it become to large?
+        * Will it become too large?
         */
        if ((req->nr_sectors + next->nr_sectors) > q->max_sectors)
                return 0;
@@ -1445,11 +1443,7 @@ void __generic_unplug_device(request_queue_t *q)
        if (!blk_remove_plug(q))
                return;
 
-       /*
-        * was plugged, fire request_fn if queue has stuff to do
-        */
-       if (elv_next_request(q))
-               q->request_fn(q);
+       q->request_fn(q);
 }
 EXPORT_SYMBOL(__generic_unplug_device);
 
@@ -1779,8 +1773,8 @@ static inline void blk_free_request(request_queue_t *q, struct request *rq)
        mempool_free(rq, q->rq.rq_pool);
 }
 
-static inline struct request *blk_alloc_request(request_queue_t *q, int rw,
-                                               int gfp_mask)
+static inline struct request *
+blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask)
 {
        struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask);
 
@@ -1793,7 +1787,7 @@ static inline struct request *blk_alloc_request(request_queue_t *q, int rw,
         */
        rq->flags = rw;
 
-       if (!elv_set_request(q, rq, gfp_mask))
+       if (!elv_set_request(q, rq, bio, gfp_mask))
                return rq;
 
        mempool_free(rq, q->rq.rq_pool);
@@ -1825,7 +1819,7 @@ static inline int ioc_batching(request_queue_t *q, struct io_context *ioc)
  * is the behaviour we want though - once it gets a wakeup it should be given
  * a nice run.
  */
-void ioc_set_batching(request_queue_t *q, struct io_context *ioc)
+static void ioc_set_batching(request_queue_t *q, struct io_context *ioc)
 {
        if (!ioc || ioc_batching(q, ioc))
                return;
@@ -1873,18 +1867,20 @@ static void freed_request(request_queue_t *q, int rw)
 
 #define blkdev_free_rq(list) list_entry((list)->next, struct request, queuelist)
 /*
- * Get a free request, queue_lock must not be held
+ * Get a free request, queue_lock must be held.
+ * Returns NULL on failure, with queue_lock held.
+ * Returns !NULL on success, with queue_lock *not held*.
  */
-static struct request *get_request(request_queue_t *q, int rw, int gfp_mask)
+static struct request *get_request(request_queue_t *q, int rw, struct bio *bio,
+                                  int gfp_mask)
 {
        struct request *rq = NULL;
        struct request_list *rl = &q->rq;
-       struct io_context *ioc = get_io_context(gfp_mask);
+       struct io_context *ioc = current_io_context(GFP_ATOMIC);
 
        if (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags)))
                goto out;
 
-       spin_lock_irq(q->queue_lock);
        if (rl->count[rw]+1 >= q->nr_requests) {
                /*
                 * The queue will fill after this allocation, so set it as
@@ -1898,7 +1894,7 @@ static struct request *get_request(request_queue_t *q, int rw, int gfp_mask)
                }
        }
 
-       switch (elv_may_queue(q, rw)) {
+       switch (elv_may_queue(q, rw, bio)) {
                case ELV_MQUEUE_NO:
                        goto rq_starved;
                case ELV_MQUEUE_MAY:
@@ -1912,18 +1908,25 @@ static struct request *get_request(request_queue_t *q, int rw, int gfp_mask)
                 * The queue is full and the allocating process is not a
                 * "batcher", and not exempted by the IO scheduler
                 */
-               spin_unlock_irq(q->queue_lock);
                goto out;
        }
 
 get_rq:
+       /*
+        * Only allow batching queuers to allocate up to 50% over the defined
+        * limit of requests, otherwise we could have thousands of requests
+        * allocated with any setting of ->nr_requests
+        */
+       if (rl->count[rw] >= (3 * q->nr_requests / 2))
+               goto out;
+
        rl->count[rw]++;
        rl->starved[rw] = 0;
        if (rl->count[rw] >= queue_congestion_on_threshold(q))
                set_queue_congested(q, rw);
        spin_unlock_irq(q->queue_lock);
 
-       rq = blk_alloc_request(q, rw, gfp_mask);
+       rq = blk_alloc_request(q, rw, bio, gfp_mask);
        if (!rq) {
                /*
                 * Allocation failed presumably due to memory. Undo anything
@@ -1946,7 +1949,6 @@ rq_starved:
                if (unlikely(rl->count[rw] == 0))
                        rl->starved[rw] = 1;
 
-               spin_unlock_irq(q->queue_lock);
                goto out;
        }
 
@@ -1956,31 +1958,35 @@ rq_starved:
        rq_init(q, rq);
        rq->rl = rl;
 out:
-       put_io_context(ioc);
        return rq;
 }
 
 /*
  * No available requests for this queue, unplug the device and wait for some
  * requests to become available.
+ *
+ * Called with q->queue_lock held, and returns with it unlocked.
  */
-static struct request *get_request_wait(request_queue_t *q, int rw)
+static struct request *get_request_wait(request_queue_t *q, int rw,
+                                       struct bio *bio)
 {
-       DEFINE_WAIT(wait);
        struct request *rq;
 
-       do {
+       rq = get_request(q, rw, bio, GFP_NOIO);
+       while (!rq) {
+               DEFINE_WAIT(wait);
                struct request_list *rl = &q->rq;
 
                prepare_to_wait_exclusive(&rl->wait[rw], &wait,
                                TASK_UNINTERRUPTIBLE);
 
-               rq = get_request(q, rw, GFP_NOIO);
+               rq = get_request(q, rw, bio, GFP_NOIO);
 
                if (!rq) {
                        struct io_context *ioc;
 
-                       generic_unplug_device(q);
+                       __generic_unplug_device(q);
+                       spin_unlock_irq(q->queue_lock);
                        io_schedule();
 
                        /*
@@ -1989,12 +1995,13 @@ static struct request *get_request_wait(request_queue_t *q, int rw)
                         * up to a big batch of them for a small period time.
                         * See ioc_batching, ioc_set_batching
                         */
-                       ioc = get_io_context(GFP_NOIO);
+                       ioc = current_io_context(GFP_NOIO);
                        ioc_set_batching(q, ioc);
-                       put_io_context(ioc);
+
+                       spin_lock_irq(q->queue_lock);
                }
                finish_wait(&rl->wait[rw], &wait);
-       } while (!rq);
+       }
 
        return rq;
 }
@@ -2005,14 +2012,18 @@ struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask)
 
        BUG_ON(rw != READ && rw != WRITE);
 
-       if (gfp_mask & __GFP_WAIT)
-               rq = get_request_wait(q, rw);
-       else
-               rq = get_request(q, rw, gfp_mask);
+       spin_lock_irq(q->queue_lock);
+       if (gfp_mask & __GFP_WAIT) {
+               rq = get_request_wait(q, rw, NULL);
+       } else {
+               rq = get_request(q, rw, NULL, gfp_mask);
+               if (!rq)
+                       spin_unlock_irq(q->queue_lock);
+       }
+       /* q->queue_lock is unlocked at this point */
 
        return rq;
 }
-
 EXPORT_SYMBOL(blk_get_request);
 
 /**
@@ -2254,45 +2265,7 @@ int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector)
 
 EXPORT_SYMBOL(blkdev_issue_flush);
 
-/**
- * blkdev_scsi_issue_flush_fn - issue flush for SCSI devices
- * @q:         device queue
- * @disk:      gendisk
- * @error_sector:      error offset
- *
- * Description:
- *    Devices understanding the SCSI command set, can use this function as
- *    a helper for issuing a cache flush. Note: driver is required to store
- *    the error offset (in case of error flushing) in ->sector of struct
- *    request.
- */
-int blkdev_scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
-                              sector_t *error_sector)
-{
-       struct request *rq = blk_get_request(q, WRITE, __GFP_WAIT);
-       int ret;
-
-       rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
-       rq->sector = 0;
-       memset(rq->cmd, 0, sizeof(rq->cmd));
-       rq->cmd[0] = 0x35;
-       rq->cmd_len = 12;
-       rq->data = NULL;
-       rq->data_len = 0;
-       rq->timeout = 60 * HZ;
-
-       ret = blk_execute_rq(q, disk, rq);
-
-       if (ret && error_sector)
-               *error_sector = rq->sector;
-
-       blk_put_request(rq);
-       return ret;
-}
-
-EXPORT_SYMBOL(blkdev_scsi_issue_flush_fn);
-
-void drive_stat_acct(struct request *rq, int nr_sectors, int new_io)
+static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io)
 {
        int rw = rq_data_dir(rq);
 
@@ -2374,7 +2347,6 @@ static void __blk_put_request(request_queue_t *q, struct request *req)
                return;
 
        req->rq_status = RQ_INACTIVE;
-       req->q = NULL;
        req->rl = NULL;
 
        /*
@@ -2503,6 +2475,8 @@ static int attempt_merge(request_queue_t *q, struct request *req,
                req->rq_disk->in_flight--;
        }
 
+       req->ioprio = ioprio_best(req->ioprio, next->ioprio);
+
        __blk_put_request(q, next);
        return 1;
 }
@@ -2551,25 +2525,17 @@ void blk_attempt_remerge(request_queue_t *q, struct request *rq)
 
 EXPORT_SYMBOL(blk_attempt_remerge);
 
-/*
- * Non-locking blk_attempt_remerge variant.
- */
-void __blk_attempt_remerge(request_queue_t *q, struct request *rq)
-{
-       attempt_back_merge(q, rq);
-}
-
-EXPORT_SYMBOL(__blk_attempt_remerge);
-
 static int __make_request(request_queue_t *q, struct bio *bio)
 {
-       struct request *req, *freereq = NULL;
+       struct request *req;
        int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync;
+       unsigned short prio;
        sector_t sector;
 
        sector = bio->bi_sector;
        nr_sectors = bio_sectors(bio);
        cur_nr_sectors = bio_cur_sectors(bio);
+       prio = bio_prio(bio);
 
        rw = bio_data_dir(bio);
        sync = bio_sync(bio);
@@ -2589,14 +2555,9 @@ static int __make_request(request_queue_t *q, struct bio *bio)
                goto end_io;
        }
 
-again:
        spin_lock_irq(q->queue_lock);
 
-       if (elv_queue_empty(q)) {
-               blk_plug_device(q);
-               goto get_rq;
-       }
-       if (barrier)
+       if (unlikely(barrier) || elv_queue_empty(q))
                goto get_rq;
 
        el_ret = elv_merge(q, &req, bio);
@@ -2610,6 +2571,7 @@ again:
                        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, nr_sectors, 0);
                        if (!attempt_back_merge(q, req))
                                elv_merged_request(q, req);
@@ -2634,45 +2596,30 @@ again:
                        req->hard_cur_sectors = cur_nr_sectors;
                        req->sector = req->hard_sector = sector;
                        req->nr_sectors = req->hard_nr_sectors += nr_sectors;
+                       req->ioprio = ioprio_best(req->ioprio, prio);
                        drive_stat_acct(req, nr_sectors, 0);
                        if (!attempt_front_merge(q, req))
                                elv_merged_request(q, req);
                        goto out;
 
-               /*
-                * elevator says don't/can't merge. get new request
-                */
-               case ELEVATOR_NO_MERGE:
-                       break;
-
+               /* ELV_NO_MERGE: elevator says don't/can't merge. */
                default:
-                       printk("elevator returned crap (%d)\n", el_ret);
-                       BUG();
+                       ;
        }
 
+get_rq:
        /*
-        * Grab a free request from the freelist - if that is empty, check
-        * if we are doing read ahead and abort instead of blocking for
-        * a free slot.
+        * Grab a free request. This is might sleep but can not fail.
+        * Returns with the queue unlocked.
+        */
+       req = get_request_wait(q, rw, bio);
+
+       /*
+        * After dropping the lock and possibly sleeping here, our request
+        * may now be mergeable after it had proven unmergeable (above).
+        * We don't worry about that case for efficiency. It won't happen
+        * often, and the elevators are able to handle it.
         */
-get_rq:
-       if (freereq) {
-               req = freereq;
-               freereq = NULL;
-       } else {
-               spin_unlock_irq(q->queue_lock);
-               if ((freereq = get_request(q, rw, GFP_ATOMIC)) == NULL) {
-                       /*
-                        * READA bit set
-                        */
-                       err = -EWOULDBLOCK;
-                       if (bio_rw_ahead(bio))
-                               goto end_io;
-       
-                       freereq = get_request_wait(q, rw);
-               }
-               goto again;
-       }
 
        req->flags |= REQ_CMD;
 
@@ -2697,13 +2644,15 @@ get_rq:
        req->buffer = bio_data(bio);    /* see ->buffer comment above */
        req->waiting = NULL;
        req->bio = req->biotail = bio;
+       req->ioprio = prio;
        req->rq_disk = bio->bi_bdev->bd_disk;
        req->start_time = jiffies;
 
+       spin_lock_irq(q->queue_lock);
+       if (elv_queue_empty(q))
+               blk_plug_device(q);
        add_request(q, req);
 out:
-       if (freereq)
-               __blk_put_request(q, freereq);
        if (sync)
                __generic_unplug_device(q);
 
@@ -2725,7 +2674,7 @@ static inline void blk_partition_remap(struct bio *bio)
        if (bdev != bdev->bd_contains) {
                struct hd_struct *p = bdev->bd_part;
 
-               switch (bio->bi_rw) {
+               switch (bio_data_dir(bio)) {
                case READ:
                        p->read_sectors += bio_sectors(bio);
                        p->reads++;
@@ -2744,6 +2693,7 @@ void blk_finish_queue_drain(request_queue_t *q)
 {
        struct request_list *rl = &q->rq;
        struct request *rq;
+       int requeued = 0;
 
        spin_lock_irq(q->queue_lock);
        clear_bit(QUEUE_FLAG_DRAIN, &q->queue_flags);
@@ -2752,9 +2702,13 @@ void blk_finish_queue_drain(request_queue_t *q)
                rq = list_entry_rq(q->drain_list.next);
 
                list_del_init(&rq->queuelist);
-               __elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
+               elv_requeue_request(q, rq);
+               requeued++;
        }
 
+       if (requeued)
+               q->request_fn(q);
+
        spin_unlock_irq(q->queue_lock);
 
        wake_up(&rl->wait[0]);
@@ -2951,7 +2905,7 @@ void submit_bio(int rw, struct bio *bio)
 
        BIO_BUG_ON(!bio->bi_size);
        BIO_BUG_ON(!bio->bi_io_vec);
-       bio->bi_rw = rw;
+       bio->bi_rw |= rw;
        if (rw & WRITE)
                mod_page_state(pgpgout, count);
        else
@@ -2971,7 +2925,7 @@ void submit_bio(int rw, struct bio *bio)
 
 EXPORT_SYMBOL(submit_bio);
 
-void blk_recalc_rq_segments(struct request *rq)
+static void blk_recalc_rq_segments(struct request *rq)
 {
        struct bio *bio, *prevbio = NULL;
        int nr_phys_segs, nr_hw_segs;
@@ -3013,7 +2967,7 @@ void blk_recalc_rq_segments(struct request *rq)
        rq->nr_hw_segments = nr_hw_segs;
 }
 
-void blk_recalc_rq_sectors(struct request *rq, int nsect)
+static void blk_recalc_rq_sectors(struct request *rq, int nsect)
 {
        if (blk_fs_request(rq)) {
                rq->hard_sector += nsect;
@@ -3308,8 +3262,11 @@ void exit_io_context(void)
        struct io_context *ioc;
 
        local_irq_save(flags);
+       task_lock(current);
        ioc = current->io_context;
        current->io_context = NULL;
+       ioc->task = NULL;
+       task_unlock(current);
        local_irq_restore(flags);
 
        if (ioc->aic && ioc->aic->exit)
@@ -3322,53 +3279,49 @@ void exit_io_context(void)
 
 /*
  * If the current task has no IO context then create one and initialise it.
- * If it does have a context, take a ref on it.
+ * Otherwise, return its existing IO context.
  *
- * This is always called in the context of the task which submitted the I/O.
- * But weird things happen, so we disable local interrupts to ensure exclusive
- * access to *current.
+ * This returned IO context doesn't have a specifically elevated refcount,
+ * but since the current task itself holds a reference, the context can be
+ * used in general code, so long as it stays within `current` context.
  */
-struct io_context *get_io_context(int gfp_flags)
+struct io_context *current_io_context(int gfp_flags)
 {
        struct task_struct *tsk = current;
-       unsigned long flags;
        struct io_context *ret;
 
-       local_irq_save(flags);
        ret = tsk->io_context;
-       if (ret)
-               goto out;
-
-       local_irq_restore(flags);
+       if (likely(ret))
+               return ret;
 
        ret = kmem_cache_alloc(iocontext_cachep, gfp_flags);
        if (ret) {
                atomic_set(&ret->refcount, 1);
-               ret->pid = tsk->pid;
+               ret->task = current;
+               ret->set_ioprio = NULL;
                ret->last_waited = jiffies; /* doesn't matter... */
                ret->nr_batch_requests = 0; /* because this is 0 */
                ret->aic = NULL;
                ret->cic = NULL;
-               spin_lock_init(&ret->lock);
-
-               local_irq_save(flags);
+               tsk->io_context = ret;
+       }
 
-               /*
-                * very unlikely, someone raced with us in setting up the task
-                * io context. free new context and just grab a reference.
-                */
-               if (!tsk->io_context)
-                       tsk->io_context = ret;
-               else {
-                       kmem_cache_free(iocontext_cachep, ret);
-                       ret = tsk->io_context;
-               }
+       return ret;
+}
+EXPORT_SYMBOL(current_io_context);
 
-out:
+/*
+ * If the current task has no IO context then create one and initialise it.
+ * If it does have a context, take a ref on it.
+ *
+ * This is always called in the context of the task which submitted the I/O.
+ */
+struct io_context *get_io_context(int gfp_flags)
+{
+       struct io_context *ret;
+       ret = current_io_context(gfp_flags);
+       if (likely(ret))
                atomic_inc(&ret->refcount);
-               local_irq_restore(flags);
-       }
-
        return ret;
 }
 EXPORT_SYMBOL(get_io_context);
@@ -3601,7 +3554,7 @@ static struct sysfs_ops queue_sysfs_ops = {
        .store  = queue_attr_store,
 };
 
-struct kobj_type queue_ktype = {
+static struct kobj_type queue_ktype = {
        .sysfs_ops      = &queue_sysfs_ops,
        .default_attrs  = default_attrs,
 };
index 7f3d78de265c389af02d763ba0ddb0ea339404b3..7b838342f0a353939324c228212074b15ea48c76 100644 (file)
@@ -1251,8 +1251,7 @@ static int kcdrwd(void *foobar)
                        VPRINTK("kcdrwd: wake up\n");
 
                        /* make swsusp happy with our thread */
-                       if (current->flags & PF_FREEZE)
-                               refrigerator(PF_FREEZE);
+                       try_to_freeze();
 
                        list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
                                if (!pkt->sleep_time)
index 5b09cf154ac7f3d9f29e1569952f53bebdd2cb71..e5f7494c00eed322d946269a568acf9240632c55 100644 (file)
@@ -253,7 +253,7 @@ static int floppy_revalidate(struct gendisk *disk);
 static int swim3_add_device(struct device_node *swims);
 int swim3_init(void);
 
-#ifndef CONFIG_PMAC_PBOOK
+#ifndef CONFIG_PMAC_MEDIABAY
 #define check_media_bay(which, what)   1
 #endif
 
@@ -297,9 +297,11 @@ static void do_fd_request(request_queue_t * q)
        int i;
        for(i=0;i<floppy_count;i++)
        {
+#ifdef CONFIG_PMAC_MEDIABAY
                if (floppy_states[i].media_bay &&
                        check_media_bay(floppy_states[i].media_bay, MB_FD))
                        continue;
+#endif /* CONFIG_PMAC_MEDIABAY */
                start_request(&floppy_states[i]);
        }
        sti();
@@ -856,8 +858,10 @@ static int floppy_ioctl(struct inode *inode, struct file *filp,
        if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
                return -EPERM;
 
+#ifdef CONFIG_PMAC_MEDIABAY
        if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
                return -ENXIO;
+#endif
 
        switch (cmd) {
        case FDEJECT:
@@ -881,8 +885,10 @@ static int floppy_open(struct inode *inode, struct file *filp)
        int n, err = 0;
 
        if (fs->ref_count == 0) {
+#ifdef CONFIG_PMAC_MEDIABAY
                if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
                        return -ENXIO;
+#endif
                out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2);
                out_8(&sw->control_bic, 0xff);
                out_8(&sw->mode, 0x95);
@@ -967,8 +973,10 @@ static int floppy_revalidate(struct gendisk *disk)
        struct swim3 __iomem *sw;
        int ret, n;
 
+#ifdef CONFIG_PMAC_MEDIABAY
        if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
                return -ENXIO;
+#endif
 
        sw = fs->swim3;
        grab_drive(fs, revalidating, 0);
index 5ed3a63794522ae0fbca00d787daf6a780aaf717..9db0a9e3e59c3981109b65f58d1de8e6369fdc91 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/time.h>
 #include <linux/hdreg.h>
+#include <linux/dma-mapping.h>
 #include <asm/io.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -1582,9 +1583,9 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out;
 
 #if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
-       rc = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+       rc = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
        if (!rc) {
-               rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+               rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
                if (rc) {
                        printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n",
                                pci_name(pdev));
@@ -1593,7 +1594,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                pci_dac = 1;
        } else {
 #endif
-               rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+               rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
                if (rc) {
                        printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n",
                                pci_name(pdev));
index e481cc411b5dba5d3bd957b43a86f0762655f7d5..5ef9adb9fe7363919cce8c530a282df0f6b562f9 100644 (file)
@@ -1089,6 +1089,14 @@ static int bluecard_event(event_t event, int priority, event_callback_args_t *ar
        return 0;
 }
 
+static struct pcmcia_device_id bluecard_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("BlueCard", "LSE041", 0xbaf16fbf, 0x657cc15e),
+       PCMCIA_DEVICE_PROD_ID12("BTCFCARD", "LSE139", 0xe3987764, 0x2524b59c),
+       PCMCIA_DEVICE_PROD_ID12("WSS", "LSE039", 0x0a0736ec, 0x24e6dfab),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, bluecard_ids);
+
 static struct pcmcia_driver bluecard_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -1096,6 +1104,7 @@ static struct pcmcia_driver bluecard_driver = {
        },
        .attach         = bluecard_attach,
        .detach         = bluecard_detach,
+       .id_table       = bluecard_ids,
 };
 
 static int __init init_bluecard_cs(void)
index f71e5c76963d27abf5a4d14a0b0767225e513df7..9013cd759afb755cc9c406f86195ed3f9f1cb616 100644 (file)
@@ -935,6 +935,12 @@ static int bt3c_event(event_t event, int priority, event_callback_args_t *args)
        return 0;
 }
 
+static struct pcmcia_device_id bt3c_ids[] = {
+       PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, bt3c_ids);
+
 static struct pcmcia_driver bt3c_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -942,6 +948,7 @@ static struct pcmcia_driver bt3c_driver = {
        },
        .attach         = bt3c_attach,
        .detach         = bt3c_detach,
+       .id_table       = bt3c_ids,
 };
 
 static int __init init_bt3c_cs(void)
index ad8d972444a522e682776e97ffbb1fe758df5a06..c479484a1f7f0d004aa888be03b6103d2bc85ebb 100644 (file)
@@ -855,6 +855,12 @@ static int btuart_event(event_t event, int priority, event_callback_args_t *args
        return 0;
 }
 
+static struct pcmcia_device_id btuart_ids[] = {
+       /* don't use this driver. Use serial_cs + hci_uart instead */
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, btuart_ids);
+
 static struct pcmcia_driver btuart_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -862,6 +868,7 @@ static struct pcmcia_driver btuart_driver = {
        },
        .attach         = btuart_attach,
        .detach         = btuart_detach,
+       .id_table       = btuart_ids,
 };
 
 static int __init init_btuart_cs(void)
index fe954e5d9a1d8961395c9acf7f8e03cb43621d00..bb12f7daeb9195ce8a3981bab468beea50a2c041 100644 (file)
@@ -807,6 +807,13 @@ static int dtl1_event(event_t event, int priority, event_callback_args_t *args)
        return 0;
 }
 
+static struct pcmcia_device_id dtl1_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
+       PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, dtl1_ids);
+
 static struct pcmcia_driver dtl1_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -814,6 +821,7 @@ static struct pcmcia_driver dtl1_driver = {
        },
        .attach         = dtl1_attach,
        .detach         = dtl1_detach,
+       .id_table       = dtl1_ids,
 };
 
 static int __init init_dtl1_cs(void)
index da80b14335a524d532ef9086d19a7e4ac26e81c3..01f0351733285520f1394d6a86a67b69d8dcab85 100644 (file)
@@ -307,7 +307,7 @@ static DEFINE_SPINLOCK(cm206_lock);
 /* First, we define some polling functions. These are actually
    only being used in the initialization. */
 
-void send_command_polled(int command)
+static void send_command_polled(int command)
 {
        int loop = POLLOOP;
        while (!(inw(r_line_status) & ls_transmitter_buffer_empty)
@@ -318,7 +318,7 @@ void send_command_polled(int command)
        outw(command, r_uart_transmit);
 }
 
-uch receive_echo_polled(void)
+static uch receive_echo_polled(void)
 {
        int loop = POLLOOP;
        while (!(inw(r_line_status) & ls_receive_buffer_full) && loop > 0) {
@@ -328,13 +328,13 @@ uch receive_echo_polled(void)
        return ((uch) inw(r_uart_receive));
 }
 
-uch send_receive_polled(int command)
+static uch send_receive_polled(int command)
 {
        send_command_polled(command);
        return receive_echo_polled();
 }
 
-inline void clear_ur(void)
+static inline void clear_ur(void)
 {
        if (cd->ur_r != cd->ur_w) {
                debug(("Deleting bytes from fifo:"));
@@ -439,7 +439,7 @@ static irqreturn_t cm206_interrupt(int sig, void *dev_id, struct pt_regs *regs)
 }
 
 /* we have put the address of the wait queue in who */
-void cm206_timeout(unsigned long who)
+static void cm206_timeout(unsigned long who)
 {
        cd->timed_out = 1;
        debug(("Timing out\n"));
@@ -448,7 +448,7 @@ void cm206_timeout(unsigned long who)
 
 /* This function returns 1 if a timeout occurred, 0 if an interrupt
    happened */
-int sleep_or_timeout(wait_queue_head_t * wait, int timeout)
+static int sleep_or_timeout(wait_queue_head_t * wait, int timeout)
 {
        cd->timed_out = 0;
        init_timer(&cd->timer);
@@ -465,13 +465,7 @@ int sleep_or_timeout(wait_queue_head_t * wait, int timeout)
                return 0;
 }
 
-void cm206_delay(int nr_jiffies)
-{
-       DECLARE_WAIT_QUEUE_HEAD(wait);
-       sleep_or_timeout(&wait, nr_jiffies);
-}
-
-void send_command(int command)
+static void send_command(int command)
 {
        debug(("Sending 0x%x\n", command));
        if (!(inw(r_line_status) & ls_transmitter_buffer_empty)) {
@@ -490,7 +484,7 @@ void send_command(int command)
                outw(command, r_uart_transmit);
 }
 
-uch receive_byte(int timeout)
+static uch receive_byte(int timeout)
 {
        uch ret;
        cli();
@@ -521,23 +515,23 @@ uch receive_byte(int timeout)
        return ret;
 }
 
-inline uch receive_echo(void)
+static inline uch receive_echo(void)
 {
        return receive_byte(UART_TIMEOUT);
 }
 
-inline uch send_receive(int command)
+static inline uch send_receive(int command)
 {
        send_command(command);
        return receive_echo();
 }
 
-inline uch wait_dsb(void)
+static inline uch wait_dsb(void)
 {
        return receive_byte(DSB_TIMEOUT);
 }
 
-int type_0_command(int command, int expect_dsb)
+static int type_0_command(int command, int expect_dsb)
 {
        int e;
        clear_ur();
@@ -552,7 +546,7 @@ int type_0_command(int command, int expect_dsb)
        return 0;
 }
 
-int type_1_command(int command, int bytes, uch * status)
+static int type_1_command(int command, int bytes, uch * status)
 {                              /* returns info */
        int i;
        if (type_0_command(command, 0))
@@ -564,7 +558,7 @@ int type_1_command(int command, int bytes, uch * status)
 
 /* This function resets the adapter card. We'd better not do this too
  * often, because it tends to generate `lost interrupts.' */
-void reset_cm260(void)
+static void reset_cm260(void)
 {
        outw(dc_normal | dc_initialize | READ_AHEAD, r_data_control);
        udelay(10);             /* 3.3 mu sec minimum */
@@ -572,7 +566,7 @@ void reset_cm260(void)
 }
 
 /* fsm: frame-sec-min from linear address; one of many */
-void fsm(int lba, uch * fsm)
+static void fsm(int lba, uch * fsm)
 {
        fsm[0] = lba % 75;
        lba /= 75;
@@ -581,17 +575,17 @@ void fsm(int lba, uch * fsm)
        fsm[2] = lba / 60;
 }
 
-inline int fsm2lba(uch * fsm)
+static inline int fsm2lba(uch * fsm)
 {
        return fsm[0] + 75 * (fsm[1] - 2 + 60 * fsm[2]);
 }
 
-inline int f_s_m2lba(uch f, uch s, uch m)
+static inline int f_s_m2lba(uch f, uch s, uch m)
 {
        return f + 75 * (s - 2 + 60 * m);
 }
 
-int start_read(int start)
+static int start_read(int start)
 {
        uch read_sector[4] = { c_read_data, };
        int i, e;
@@ -613,7 +607,7 @@ int start_read(int start)
        return 0;
 }
 
-int stop_read(void)
+static int stop_read(void)
 {
        int e;
        type_0_command(c_stop, 0);
@@ -630,7 +624,7 @@ int stop_read(void)
    routine takes care of this. Set a flag `background' in the cd
    struct to indicate the process. */
 
-int read_background(int start, int reading)
+static int read_background(int start, int reading)
 {
        if (cd->background)
                return -1;      /* can't do twice */
@@ -658,7 +652,7 @@ void transport_data(int port, ush * dest, int count)
 
 
 #define MAX_TRIES 100
-int read_sector(int start)
+static int read_sector(int start)
 {
        int tries = 0;
        if (cd->background) {
@@ -753,7 +747,7 @@ static DECLARE_TASKLET(cm206_tasklet, cm206_tasklet_func, 0);
 /* This command clears the dsb_possible_media_change flag, so we must 
  * retain it.
  */
-void get_drive_status(void)
+static void get_drive_status(void)
 {
        uch status[2];
        type_1_command(c_drive_status, 2, status);      /* this might be done faster */
@@ -764,7 +758,7 @@ void get_drive_status(void)
                          dsb_drive_not_ready | dsb_tray_not_closed));
 }
 
-void get_disc_status(void)
+static void get_disc_status(void)
 {
        if (type_1_command(c_disc_status, 7, cd->disc_status)) {
                debug(("get_disc_status: error\n"));
@@ -801,7 +795,7 @@ static void cm206_release(struct cdrom_device_info *cdi)
 
 /* Empty buffer empties $sectors$ sectors of the adapter card buffer,
  * and then reads a sector in kernel memory.  */
-void empty_buffer(int sectors)
+static void empty_buffer(int sectors)
 {
        while (sectors >= 0) {
                transport_data(r_fifo_output_buffer,
@@ -819,7 +813,7 @@ void empty_buffer(int sectors)
 /* try_adapter. This function determines if the requested sector is
    in adapter memory, or will appear there soon. Returns 0 upon
    success */
-int try_adapter(int sector)
+static int try_adapter(int sector)
 {
        if (cd->adapter_first <= sector && sector < cd->adapter_last) {
                /* sector is in adapter memory */
@@ -910,7 +904,7 @@ static void do_cm206_request(request_queue_t * q)
 */
 
 /* seek seeks to address lba. It does wait to arrive there. */
-void seek(int lba)
+static void seek(int lba)
 {
        int i;
        uch seek_command[4] = { c_seek, };
@@ -926,7 +920,7 @@ uch bcdbin(unsigned char bcd)
        return (bcd >> 4) * 10 + (bcd & 0xf);
 }
 
-inline uch normalize_track(uch track)
+static inline uch normalize_track(uch track)
 {
        if (track < 1)
                return 1;
@@ -939,7 +933,7 @@ inline uch normalize_track(uch track)
  * tracks seen in the process. Input $track$ must be between 1 and
  * #-of-tracks+1.  Note that the start of the disc must be in toc[1].fsm. 
  */
-int get_toc_lba(uch track)
+static int get_toc_lba(uch track)
 {
        int max = 74 * 60 * 75 - 150, min = fsm2lba(cd->toc[1].fsm);
        int i, lba, l, old_lba = 0;
@@ -991,7 +985,7 @@ int get_toc_lba(uch track)
        return lba;
 }
 
-void update_toc_entry(uch track)
+static void update_toc_entry(uch track)
 {
        track = normalize_track(track);
        if (!cd->toc[track].track)
@@ -999,7 +993,7 @@ void update_toc_entry(uch track)
 }
 
 /* return 0 upon success */
-int read_toc_header(struct cdrom_tochdr *hp)
+static int read_toc_header(struct cdrom_tochdr *hp)
 {
        if (!FIRST_TRACK)
                get_disc_status();
@@ -1016,7 +1010,7 @@ int read_toc_header(struct cdrom_tochdr *hp)
        return -1;
 }
 
-void play_from_to_msf(struct cdrom_msf *msfp)
+static void play_from_to_msf(struct cdrom_msf *msfp)
 {
        uch play_command[] = { c_play,
                msfp->cdmsf_frame0, msfp->cdmsf_sec0, msfp->cdmsf_min0,
@@ -1032,7 +1026,7 @@ void play_from_to_msf(struct cdrom_msf *msfp)
        cd->dsb = wait_dsb();
 }
 
-void play_from_to_track(int from, int to)
+static void play_from_to_track(int from, int to)
 {
        uch play_command[8] = { c_play, };
        int i;
@@ -1059,7 +1053,7 @@ void play_from_to_track(int from, int to)
        cd->dsb = wait_dsb();
 }
 
-int get_current_q(struct cdrom_subchnl *qp)
+static int get_current_q(struct cdrom_subchnl *qp)
 {
        int i;
        uch *q = cd->q;
@@ -1093,14 +1087,14 @@ int get_current_q(struct cdrom_subchnl *qp)
        return 0;
 }
 
-void invalidate_toc(void)
+static void invalidate_toc(void)
 {
        memset(cd->toc, 0, sizeof(cd->toc));
        memset(cd->disc_status, 0, sizeof(cd->disc_status));
 }
 
 /* cdrom.c guarantees that cdte_format == CDROM_MSF */
-void get_toc_entry(struct cdrom_tocentry *ep)
+static void get_toc_entry(struct cdrom_tocentry *ep)
 {
        uch track = normalize_track(ep->cdte_track);
        update_toc_entry(track);
@@ -1117,8 +1111,8 @@ void get_toc_entry(struct cdrom_tocentry *ep)
  * upon success. Memory checking has been done by cdrom_ioctl(), the
  * calling function, as well as LBA/MSF sanitization.
 */
-int cm206_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
-                     void *arg)
+static int cm206_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
+                            void *arg)
 {
        switch (cmd) {
        case CDROMREADTOCHDR:
@@ -1189,7 +1183,7 @@ static int cm206_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
        }
 }
 
-int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr)
+static int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr)
 {
        if (cd != NULL) {
                int r;
@@ -1204,16 +1198,9 @@ int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr)
 /* The new generic cdrom support. Routines should be concise, most of
    the logic should be in cdrom.c */
 
-/* returns number of times device is in use */
-int cm206_open_files(struct cdrom_device_info *cdi)
-{
-       if (cd)
-               return cd->openfiles;
-       return -1;
-}
 
 /* controls tray movement */
-int cm206_tray_move(struct cdrom_device_info *cdi, int position)
+static int cm206_tray_move(struct cdrom_device_info *cdi, int position)
 {
        if (position) {         /* 1: eject */
                type_0_command(c_open_tray, 1);
@@ -1224,7 +1211,7 @@ int cm206_tray_move(struct cdrom_device_info *cdi, int position)
 }
 
 /* gives current state of the drive */
-int cm206_drive_status(struct cdrom_device_info *cdi, int slot_nr)
+static int cm206_drive_status(struct cdrom_device_info *cdi, int slot_nr)
 {
        get_drive_status();
        if (cd->dsb & dsb_tray_not_closed)
@@ -1237,7 +1224,7 @@ int cm206_drive_status(struct cdrom_device_info *cdi, int slot_nr)
 }
 
 /* locks or unlocks door lock==1: lock; return 0 upon success */
-int cm206_lock_door(struct cdrom_device_info *cdi, int lock)
+static int cm206_lock_door(struct cdrom_device_info *cdi, int lock)
 {
        uch command = (lock) ? c_lock_tray : c_unlock_tray;
        type_0_command(command, 1);     /* wait and get dsb */
@@ -1248,8 +1235,8 @@ int cm206_lock_door(struct cdrom_device_info *cdi, int lock)
 /* Although a session start should be in LBA format, we return it in 
    MSF format because it is slightly easier, and the new generic ioctl
    will take care of the necessary conversion. */
-int cm206_get_last_session(struct cdrom_device_info *cdi,
-                          struct cdrom_multisession *mssp)
+static int cm206_get_last_session(struct cdrom_device_info *cdi,
+                                 struct cdrom_multisession *mssp)
 {
        if (!FIRST_TRACK)
                get_disc_status();
@@ -1268,7 +1255,7 @@ int cm206_get_last_session(struct cdrom_device_info *cdi,
        return 0;
 }
 
-int cm206_get_upc(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
+static int cm206_get_upc(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
 {
        uch upc[10];
        char *ret = mcn->medium_catalog_number;
@@ -1287,7 +1274,7 @@ int cm206_get_upc(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
        return 0;
 }
 
-int cm206_reset(struct cdrom_device_info *cdi)
+static int cm206_reset(struct cdrom_device_info *cdi)
 {
        stop_read();
        reset_cm260();
@@ -1300,7 +1287,7 @@ int cm206_reset(struct cdrom_device_info *cdi)
        return 0;
 }
 
-int cm206_select_speed(struct cdrom_device_info *cdi, int speed)
+static int cm206_select_speed(struct cdrom_device_info *cdi, int speed)
 {
        int r;
        switch (speed) {
@@ -1392,7 +1379,7 @@ static struct gendisk *cm206_gendisk;
    request_region, 15 bits of one port and 6 of another make things
    likely enough to accept the region on the first hit...
  */
-int __init probe_base_port(int base)
+static int __init probe_base_port(int base)
 {
        int b = 0x300, e = 0x370;       /* this is the range of start addresses */
        volatile int fool, i;
@@ -1416,7 +1403,7 @@ int __init probe_base_port(int base)
 
 #if !defined(MODULE) || defined(AUTO_PROBE_MODULE)
 /* Probe for irq# nr. If nr==0, probe for all possible irq's. */
-int __init probe_irq(int nr)
+static int __init probe_irq(int nr)
 {
        int irqs, irq;
        outw(dc_normal | READ_AHEAD, r_data_control);   /* disable irq-generation */
@@ -1558,7 +1545,7 @@ static void __init parse_options(void)
        }
 }
 
-int __cm206_init(void)
+static int __cm206_init(void)
 {
        parse_options();
 #if !defined(AUTO_PROBE_MODULE)
@@ -1567,7 +1554,7 @@ int __cm206_init(void)
        return cm206_init();
 }
 
-void __exit cm206_exit(void)
+static void __exit cm206_exit(void)
 {
        del_gendisk(cm206_gendisk);
        put_disk(cm206_gendisk);
index f4be7bfd6675ee4ef7f2c024404c0ab64abfe5c3..9f22e8f1f6c0182dbbbb9ecd5689d01235f53404 100644 (file)
@@ -1605,8 +1605,7 @@ out7:
        put_disk(cdu_disk);
 out6:
        for (i = 0; i < sony_buffer_sectors; i++)
-               if (sony_buffer[i]) 
-                       kfree(sony_buffer[i]);
+               kfree(sony_buffer[i]);
 out5:
        kfree(sony_buffer);
 out4:
index 7ccf871d3c9dd77178fa9ca46fb3e5def6c33a0e..43d0cb19ef6ad839c391e2ad8aa65a0c425de60d 100644 (file)
@@ -940,8 +940,8 @@ config RAW_DRIVER
          Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. 
          See the raw(8) manpage for more details.
 
-          The raw driver is deprecated and may be removed from 2.7
-          kernels.  Applications should simply open the device (eg /dev/hda1)
+          The raw driver is deprecated and will be removed soon.
+          Applications should simply open the device (eg /dev/hda1)
           with the O_DIRECT flag.
 
 config HPET
index 1407945a5892887565219b6594dde1444a6e30ea..59f589d733f929d12639eab6852622a618a1796f 100644 (file)
@@ -686,6 +686,15 @@ static struct pci_device_id agp_amd64_pci_table[] = {
        .subvendor      = PCI_ANY_ID,
        .subdevice      = PCI_ANY_ID,
        },
+       /* SIS 760 */
+       {
+       .class          = (PCI_CLASS_BRIDGE_HOST << 8),
+       .class_mask     = ~0,
+       .vendor         = PCI_VENDOR_ID_SI,
+       .device         = PCI_DEVICE_ID_SI_760,
+       .subvendor      = PCI_ANY_ID,
+       .subdevice      = PCI_ANY_ID,
+       },
        { }
 };
 
index 777bc499bbbd103fcb9246b9b65c72a1514a0eb6..2a36561eec68dab6efc8e690167df7a78668f1eb 100644 (file)
@@ -1973,10 +1973,6 @@ static _INLINE_ void show_serial_version(void)
 }
 
 
-int register_serial(struct serial_struct *req);
-void unregister_serial(int line);
-
-
 static struct tty_operations serial_ops = {
        .open = rs_open,
        .close = rs_close,
index 6bf2e27dc23ad9371aaeacaee12a2eb72d81cebe..11f9ee5811242973f15bc0232d1e15fbee33373e 100644 (file)
@@ -599,7 +599,7 @@ static ssize_t ac_read (struct file *filp, char __user *buf, size_t count, loff_
 
 #ifdef DEBUG
                if (loopcount++ > 2) {
-                       printk("Looping in ac_read. loopcount %d\n", loopcount);
+                       printk(KERN_DEBUG "Looping in ac_read. loopcount %d\n", loopcount);
                }
 #endif
        } 
index d9a02993467873505e71bc3b849bcd3733520cbb..c2b12eab67c9de8361ad8bc839877049bbf3df26 100644 (file)
@@ -6,7 +6,7 @@
 #
 config DRM
        tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
-       depends on AGP || AGP=n
+       depends on (AGP || AGP=n) && PCI
        help
          Kernel-level support for the Direct Rendering Infrastructure (DRI)
          introduced in XFree86 4.0. If you say Y here, you need to select
index 23ab26321e9a6410b5cdc8bdd4320d778ff66dc4..7444dec40b9488cd874c408696694940cdccfdfd 100644 (file)
@@ -19,6 +19,11 @@ radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o
 ffb-objs    := ffb_drv.o ffb_context.o
 sis-objs    := sis_drv.o sis_ds.o sis_mm.o
 
+ifeq ($(CONFIG_COMPAT),y)
+drm-objs    += drm_ioc32.o
+radeon-objs += radeon_ioc32.o
+endif
+
 obj-$(CONFIG_DRM)      += drm.o
 obj-$(CONFIG_DRM_GAMMA) += gamma.o
 obj-$(CONFIG_DRM_TDFX) += tdfx.o
index 21f4c54e1a8d7143c9a102696bccd0bce3e8950b..b04ddf12a0ff7b0890347ad19688a5ee018594f2 100644 (file)
@@ -316,6 +316,9 @@ do {                                                                        \
 typedef int drm_ioctl_t( struct inode *inode, struct file *filp,
                         unsigned int cmd, unsigned long arg );
 
+typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,
+                              unsigned long arg);
+
 typedef struct drm_ioctl_desc {
        drm_ioctl_t          *func;
        int                  auth_needed;
@@ -775,6 +778,8 @@ extern int           drm_version(struct inode *inode, struct file *filp,
                                  unsigned int cmd, unsigned long arg);
 extern int           drm_ioctl(struct inode *inode, struct file *filp,
                                unsigned int cmd, unsigned long arg);
+extern long         drm_compat_ioctl(struct file *filp,
+                               unsigned int cmd, unsigned long arg);
 extern int           drm_takedown(drm_device_t * dev);
 
                                /* Device support (drm_fops.h) */
index 4113bcba67fe080e92adeb7054e089832ec4d571..3407380b865a5953ff4d13b1a086a0c93f315f6d 100644 (file)
@@ -60,6 +60,15 @@ int drm_order( unsigned long size )
 }
 EXPORT_SYMBOL(drm_order);
 
+#ifdef CONFIG_COMPAT
+/*
+ * Used to allocate 32-bit handles for _DRM_SHM regions
+ * The 0x10000000 value is chosen to be out of the way of
+ * FB/register and GART physical addresses.
+ */
+static unsigned int map32_handle = 0x10000000;
+#endif
+
 /**
  * Ioctl to specify a range of memory that is available for mapping by a non-root process.
  *
@@ -187,16 +196,18 @@ int drm_addmap( struct inode *inode, struct file *filp,
 
        down(&dev->struct_sem);
        list_add(&list->head, &dev->maplist->head);
+#ifdef CONFIG_COMPAT
+       /* Assign a 32-bit handle for _DRM_SHM mappings */
+       /* We do it here so that dev->struct_sem protects the increment */
+       if (map->type == _DRM_SHM)
+               map->offset = map32_handle += PAGE_SIZE;
+#endif
        up(&dev->struct_sem);
 
        if ( copy_to_user( argp, map, sizeof(*map) ) )
                return -EFAULT;
-       if ( map->type != _DRM_SHM ) {
-               if ( copy_to_user( &argp->handle,
-                                  &map->offset,
-                                  sizeof(map->offset) ) )
-                       return -EFAULT;
-       }
+       if (copy_to_user(&argp->handle, &map->offset, sizeof(map->offset)))
+               return -EFAULT;
        return 0;
 }
 
@@ -240,7 +251,7 @@ int drm_rmmap(struct inode *inode, struct file *filp,
                r_list = list_entry(list, drm_map_list_t, head);
 
                if(r_list->map &&
-                  r_list->map->handle == request.handle &&
+                  r_list->map->offset == (unsigned long) request.handle &&
                   r_list->map->flags & _DRM_REMOVABLE) break;
        }
 
index f15c86c578757f82ccbeec7e698e57f8c314a0fd..fdf661f234ed304b070cc8fe3e48769c609cca5e 100644 (file)
@@ -225,7 +225,7 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
        map = dev->context_sareas[request.ctx_id];
        up(&dev->struct_sem);
 
-       request.handle = map->handle;
+       request.handle = (void *) map->offset;
        if (copy_to_user(argp, &request, sizeof(request)))
                return -EFAULT;
        return 0;
@@ -261,8 +261,8 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
        down(&dev->struct_sem);
        list_for_each(list, &dev->maplist->head) {
                r_list = list_entry(list, drm_map_list_t, head);
-               if(r_list->map &&
-                  r_list->map->handle == request.handle)
+               if (r_list->map
+                   && r_list->map->offset == (unsigned long) request.handle)
                        goto found;
        }
 bad:
diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c
new file mode 100644 (file)
index 0000000..8087a96
--- /dev/null
@@ -0,0 +1,1069 @@
+/**
+ * \file drm_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the DRM.
+ *
+ * \author Paul Mackerras <paulus@samba.org>
+ *
+ * Copyright (C) Paul Mackerras 2005.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHOR 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/compat.h>
+#include <linux/ioctl32.h>
+
+#include "drmP.h"
+#include "drm_core.h"
+
+#define DRM_IOCTL_VERSION32            DRM_IOWR(0x00, drm_version32_t)
+#define DRM_IOCTL_GET_UNIQUE32         DRM_IOWR(0x01, drm_unique32_t)
+#define DRM_IOCTL_GET_MAP32            DRM_IOWR(0x04, drm_map32_t)
+#define DRM_IOCTL_GET_CLIENT32         DRM_IOWR(0x05, drm_client32_t)
+#define DRM_IOCTL_GET_STATS32          DRM_IOR( 0x06, drm_stats32_t)
+
+#define DRM_IOCTL_SET_UNIQUE32         DRM_IOW( 0x10, drm_unique32_t)
+#define DRM_IOCTL_ADD_MAP32            DRM_IOWR(0x15, drm_map32_t)
+#define DRM_IOCTL_ADD_BUFS32           DRM_IOWR(0x16, drm_buf_desc32_t)
+#define DRM_IOCTL_MARK_BUFS32          DRM_IOW( 0x17, drm_buf_desc32_t)
+#define DRM_IOCTL_INFO_BUFS32          DRM_IOWR(0x18, drm_buf_info32_t)
+#define DRM_IOCTL_MAP_BUFS32           DRM_IOWR(0x19, drm_buf_map32_t)
+#define DRM_IOCTL_FREE_BUFS32          DRM_IOW( 0x1a, drm_buf_free32_t)
+
+#define DRM_IOCTL_RM_MAP32             DRM_IOW( 0x1b, drm_map32_t)
+
+#define DRM_IOCTL_SET_SAREA_CTX32      DRM_IOW( 0x1c, drm_ctx_priv_map32_t)
+#define DRM_IOCTL_GET_SAREA_CTX32      DRM_IOWR(0x1d, drm_ctx_priv_map32_t)
+
+#define DRM_IOCTL_RES_CTX32            DRM_IOWR(0x26, drm_ctx_res32_t)
+#define DRM_IOCTL_DMA32                        DRM_IOWR(0x29, drm_dma32_t)
+
+#define DRM_IOCTL_AGP_ENABLE32         DRM_IOW( 0x32, drm_agp_mode32_t)
+#define DRM_IOCTL_AGP_INFO32           DRM_IOR( 0x33, drm_agp_info32_t)
+#define DRM_IOCTL_AGP_ALLOC32          DRM_IOWR(0x34, drm_agp_buffer32_t)
+#define DRM_IOCTL_AGP_FREE32           DRM_IOW( 0x35, drm_agp_buffer32_t)
+#define DRM_IOCTL_AGP_BIND32           DRM_IOW( 0x36, drm_agp_binding32_t)
+#define DRM_IOCTL_AGP_UNBIND32         DRM_IOW( 0x37, drm_agp_binding32_t)
+
+#define DRM_IOCTL_SG_ALLOC32           DRM_IOW( 0x38, drm_scatter_gather32_t)
+#define DRM_IOCTL_SG_FREE32            DRM_IOW( 0x39, drm_scatter_gather32_t)
+
+#define DRM_IOCTL_WAIT_VBLANK32                DRM_IOWR(0x3a, drm_wait_vblank32_t)
+
+typedef struct drm_version_32 {
+       int     version_major;    /**< Major version */
+       int     version_minor;    /**< Minor version */
+       int     version_patchlevel;/**< Patch level */
+       u32     name_len;         /**< Length of name buffer */
+       u32     name;             /**< Name of driver */
+       u32     date_len;         /**< Length of date buffer */
+       u32     date;             /**< User-space buffer to hold date */
+       u32     desc_len;         /**< Length of desc buffer */
+       u32     desc;             /**< User-space buffer to hold desc */
+} drm_version32_t;
+
+static int compat_drm_version(struct file *file, unsigned int cmd,
+                             unsigned long arg)
+{
+       drm_version32_t v32;
+       drm_version_t __user *version;
+       int err;
+
+       if (copy_from_user(&v32, (void __user *) arg, sizeof(v32)))
+               return -EFAULT;
+
+       version = compat_alloc_user_space(sizeof(*version));
+       if (!access_ok(VERIFY_WRITE, version, sizeof(*version)))
+               return -EFAULT;
+       if (__put_user(v32.name_len, &version->name_len)
+           || __put_user((void __user *)(unsigned long)v32.name,
+                         &version->name)
+           || __put_user(v32.date_len, &version->date_len)
+           || __put_user((void __user *)(unsigned long)v32.date,
+                         &version->date)
+           || __put_user(v32.desc_len, &version->desc_len)
+           || __put_user((void __user *)(unsigned long)v32.desc,
+                         &version->desc))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_VERSION, (unsigned long) version);
+       if (err)
+               return err;
+
+       if (__get_user(v32.version_major, &version->version_major)
+           || __get_user(v32.version_minor, &version->version_minor)
+           || __get_user(v32.version_patchlevel, &version->version_patchlevel)
+           || __get_user(v32.name_len, &version->name_len)
+           || __get_user(v32.date_len, &version->date_len)
+           || __get_user(v32.desc_len, &version->desc_len))
+               return -EFAULT;
+
+       if (copy_to_user((void __user *) arg, &v32, sizeof(v32)))
+               return -EFAULT;
+       return 0;
+}
+
+typedef struct drm_unique32 {
+       u32 unique_len; /**< Length of unique */
+       u32 unique;     /**< Unique name for driver instantiation */
+} drm_unique32_t;
+
+static int compat_drm_getunique(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       drm_unique32_t uq32;
+       drm_unique_t __user *u;
+       int err;
+
+       if (copy_from_user(&uq32, (void __user *) arg, sizeof(uq32)))
+               return -EFAULT;
+
+       u = compat_alloc_user_space(sizeof(*u));
+       if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
+               return -EFAULT;
+       if (__put_user(uq32.unique_len, &u->unique_len)
+           || __put_user((void __user *)(unsigned long) uq32.unique,
+                         &u->unique))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_GET_UNIQUE, (unsigned long) u);
+       if (err)
+               return err;
+
+       if (__get_user(uq32.unique_len, &u->unique_len))
+               return -EFAULT;
+       if (copy_to_user((void __user *) arg, &uq32, sizeof(uq32)))
+               return -EFAULT;
+       return 0;
+}
+
+static int compat_drm_setunique(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       drm_unique32_t uq32;
+       drm_unique_t __user *u;
+
+       if (copy_from_user(&uq32, (void __user *) arg, sizeof(uq32)))
+               return -EFAULT;
+
+       u = compat_alloc_user_space(sizeof(*u));
+       if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
+               return -EFAULT;
+       if (__put_user(uq32.unique_len, &u->unique_len)
+           || __put_user((void __user *)(unsigned long) uq32.unique,
+                         &u->unique))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_SET_UNIQUE, (unsigned long) u);
+}
+
+typedef struct drm_map32 {
+       u32     offset;         /**< Requested physical address (0 for SAREA)*/
+       u32     size;           /**< Requested physical size (bytes) */
+       drm_map_type_t  type;   /**< Type of memory to map */
+       drm_map_flags_t flags;  /**< Flags */
+       u32     handle;         /**< User-space: "Handle" to pass to mmap() */
+       int     mtrr;           /**< MTRR slot used */
+} drm_map32_t;
+
+static int compat_drm_getmap(struct file *file, unsigned int cmd,
+                            unsigned long arg)
+{
+       drm_map32_t __user *argp = (void __user *)arg;
+       drm_map32_t m32;
+       drm_map_t __user *map;
+       int idx, err;
+       void *handle;
+
+       if (get_user(idx, &argp->offset))
+               return -EFAULT;
+
+       map = compat_alloc_user_space(sizeof(*map));
+       if (!access_ok(VERIFY_WRITE, map, sizeof(*map)))
+               return -EFAULT;
+       if (__put_user(idx, &map->offset))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_GET_MAP, (unsigned long) map);
+       if (err)
+               return err;
+
+       if (__get_user(m32.offset, &map->offset)
+           || __get_user(m32.size, &map->size)
+           || __get_user(m32.type, &map->type)
+           || __get_user(m32.flags, &map->flags)
+           || __get_user(handle, &map->handle)
+           || __get_user(m32.mtrr, &map->mtrr))
+               return -EFAULT;
+
+       m32.handle = (unsigned long) handle;
+       if (copy_to_user(argp, &m32, sizeof(m32)))
+               return -EFAULT;
+       return 0;
+
+}
+
+static int compat_drm_addmap(struct file *file, unsigned int cmd,
+                            unsigned long arg)
+{
+       drm_map32_t __user *argp = (void __user *)arg;
+       drm_map32_t m32;
+       drm_map_t __user *map;
+       int err;
+       void *handle;
+
+       if (copy_from_user(&m32, argp, sizeof(m32)))
+               return -EFAULT;
+
+       map = compat_alloc_user_space(sizeof(*map));
+       if (!access_ok(VERIFY_WRITE, map, sizeof(*map)))
+               return -EFAULT;
+       if (__put_user(m32.offset, &map->offset)
+           || __put_user(m32.size, &map->size)
+           || __put_user(m32.type, &map->type)
+           || __put_user(m32.flags, &map->flags))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_ADD_MAP, (unsigned long) map);
+       if (err)
+               return err;
+
+       if (__get_user(m32.offset, &map->offset)
+           || __get_user(m32.mtrr, &map->mtrr)
+           || __get_user(handle, &map->handle))
+               return -EFAULT;
+
+       m32.handle = (unsigned long) handle;
+       if (m32.handle != (unsigned long) handle && printk_ratelimit())
+               printk(KERN_ERR "compat_drm_addmap truncated handle"
+                      " %p for type %d offset %x\n",
+                      handle, m32.type, m32.offset);
+
+       if (copy_to_user(argp, &m32, sizeof(m32)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int compat_drm_rmmap(struct file *file, unsigned int cmd,
+                           unsigned long arg)
+{
+       drm_map32_t __user *argp = (void __user *)arg;
+       drm_map_t __user *map;
+       u32 handle;
+
+       if (get_user(handle, &argp->handle))
+               return -EFAULT;
+
+       map = compat_alloc_user_space(sizeof(*map));
+       if (!access_ok(VERIFY_WRITE, map, sizeof(*map)))
+               return -EFAULT;
+       if (__put_user((void *)(unsigned long) handle, &map->handle))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_RM_MAP, (unsigned long) map);
+}
+
+typedef struct drm_client32 {
+       int     idx;    /**< Which client desired? */
+       int     auth;   /**< Is client authenticated? */
+       u32     pid;    /**< Process ID */
+       u32     uid;    /**< User ID */
+       u32     magic;  /**< Magic */
+       u32     iocs;   /**< Ioctl count */
+} drm_client32_t;
+
+static int compat_drm_getclient(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       drm_client32_t c32;
+       drm_client32_t __user *argp = (void __user *)arg;
+       drm_client_t __user *client;
+       int idx, err;
+
+       if (get_user(idx, &argp->idx))
+               return -EFAULT;
+
+       client = compat_alloc_user_space(sizeof(*client));
+       if (!access_ok(VERIFY_WRITE, client, sizeof(*client)))
+               return -EFAULT;
+       if (__put_user(idx, &client->idx))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_GET_CLIENT, (unsigned long) client);
+       if (err)
+               return err;
+
+       if (__get_user(c32.auth, &client->auth)
+           || __get_user(c32.pid, &client->pid)
+           || __get_user(c32.uid, &client->uid)
+           || __get_user(c32.magic, &client->magic)
+           || __get_user(c32.iocs, &client->iocs))
+               return -EFAULT;
+
+       if (copy_to_user(argp, &c32, sizeof(c32)))
+               return -EFAULT;
+       return 0;
+}
+
+typedef struct drm_stats32 {
+       u32 count;
+       struct {
+               u32 value;
+               drm_stat_type_t type;
+       } data[15];
+} drm_stats32_t;
+
+static int compat_drm_getstats(struct file *file, unsigned int cmd,
+                              unsigned long arg)
+{
+       drm_stats32_t s32;
+       drm_stats32_t __user *argp = (void __user *)arg;
+       drm_stats_t __user *stats;
+       int i, err;
+
+       stats = compat_alloc_user_space(sizeof(*stats));
+       if (!access_ok(VERIFY_WRITE, stats, sizeof(*stats)))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_GET_STATS, (unsigned long) stats);
+       if (err)
+               return err;
+
+       if (__get_user(s32.count, &stats->count))
+               return -EFAULT;
+       for (i = 0; i < 15; ++i)
+               if (__get_user(s32.data[i].value, &stats->data[i].value)
+                   || __get_user(s32.data[i].type, &stats->data[i].type))
+                       return -EFAULT;
+
+       if (copy_to_user(argp, &s32, sizeof(s32)))
+               return -EFAULT;
+       return 0;
+}
+
+typedef struct drm_buf_desc32 {
+       int           count;     /**< Number of buffers of this size */
+       int           size;      /**< Size in bytes */
+       int           low_mark;  /**< Low water mark */
+       int           high_mark; /**< High water mark */
+       int           flags;
+       u32           agp_start; /**< Start address in the AGP aperture */
+} drm_buf_desc32_t;
+
+static int compat_drm_addbufs(struct file *file, unsigned int cmd,
+                             unsigned long arg)
+{
+       drm_buf_desc32_t __user *argp = (void __user *)arg;
+       drm_buf_desc_t __user *buf;
+       int err;
+       unsigned long agp_start;
+
+       buf = compat_alloc_user_space(sizeof(*buf));
+       if (!access_ok(VERIFY_WRITE, buf, sizeof(*buf))
+           || !access_ok(VERIFY_WRITE, argp, sizeof(*argp)))
+               return -EFAULT;
+
+       if (__copy_in_user(buf, argp, offsetof(drm_buf_desc32_t, agp_start))
+           || __get_user(agp_start, &argp->agp_start)
+           || __put_user(agp_start, &buf->agp_start))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_ADD_BUFS, (unsigned long) buf);
+       if (err)
+               return err;
+
+       if (__copy_in_user(argp, buf, offsetof(drm_buf_desc32_t, agp_start))
+           || __get_user(agp_start, &buf->agp_start)
+           || __put_user(agp_start, &argp->agp_start))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int compat_drm_markbufs(struct file *file, unsigned int cmd,
+                              unsigned long arg)
+{
+       drm_buf_desc32_t b32;
+       drm_buf_desc32_t __user *argp = (void __user *)arg;
+       drm_buf_desc_t __user *buf;
+
+       if (copy_from_user(&b32, argp, sizeof(b32)))
+               return -EFAULT;
+
+       buf = compat_alloc_user_space(sizeof(*buf));
+       if (!access_ok(VERIFY_WRITE, buf, sizeof(*buf)))
+               return -EFAULT;
+
+       if (__put_user(b32.size, &buf->size)
+           || __put_user(b32.low_mark, &buf->low_mark)
+           || __put_user(b32.high_mark, &buf->high_mark))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_MARK_BUFS, (unsigned long) buf);
+}
+
+typedef struct drm_buf_info32 {
+       int            count;   /**< Entries in list */
+       u32            list;
+} drm_buf_info32_t;
+
+static int compat_drm_infobufs(struct file *file, unsigned int cmd,
+                              unsigned long arg)
+{
+       drm_buf_info32_t req32;
+       drm_buf_info32_t __user *argp = (void __user *)arg;
+       drm_buf_desc32_t __user *to;
+       drm_buf_info_t __user *request;
+       drm_buf_desc_t __user *list;
+       size_t nbytes;
+       int i, err;
+       int count, actual;
+
+       if (copy_from_user(&req32, argp, sizeof(req32)))
+               return -EFAULT;
+
+       count = req32.count;
+       to = (drm_buf_desc32_t __user *)(unsigned long) req32.list;
+       if (count < 0)
+               count = 0;
+       if (count > 0
+           && !access_ok(VERIFY_WRITE, to, count * sizeof(drm_buf_desc32_t)))
+               return -EFAULT;
+
+       nbytes = sizeof(*request) + count * sizeof(drm_buf_desc_t);
+       request = compat_alloc_user_space(nbytes);
+       if (!access_ok(VERIFY_WRITE, request, nbytes))
+               return -EFAULT;
+       list = (drm_buf_desc_t *) (request + 1);
+
+       if (__put_user(count, &request->count)
+           || __put_user(list, &request->list))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_INFO_BUFS, (unsigned long) request);
+       if (err)
+               return err;
+
+       if (__get_user(actual, &request->count))
+               return -EFAULT;
+       if (count >= actual)
+               for (i = 0; i < actual; ++i)
+                       if (__copy_in_user(&to[i], &list[i],
+                                          offsetof(drm_buf_desc_t, flags)))
+                               return -EFAULT;
+
+       if (__put_user(actual, &argp->count))
+               return -EFAULT;
+
+       return 0;
+}
+
+typedef struct drm_buf_pub32 {
+       int     idx;            /**< Index into the master buffer list */
+       int     total;          /**< Buffer size */
+       int     used;           /**< Amount of buffer in use (for DMA) */
+       u32     address;        /**< Address of buffer */
+} drm_buf_pub32_t;
+
+typedef struct drm_buf_map32 {
+       int     count;          /**< Length of the buffer list */
+       u32     virtual;        /**< Mmap'd area in user-virtual */
+       u32     list;           /**< Buffer information */
+} drm_buf_map32_t;
+
+static int compat_drm_mapbufs(struct file *file, unsigned int cmd,
+                             unsigned long arg)
+{
+       drm_buf_map32_t __user *argp = (void __user *)arg;
+       drm_buf_map32_t req32;
+       drm_buf_pub32_t __user *list32;
+       drm_buf_map_t __user *request;
+       drm_buf_pub_t __user *list;
+       int i, err;
+       int count, actual;
+       size_t nbytes;
+       void __user *addr;
+
+       if (copy_from_user(&req32, argp, sizeof(req32)))
+               return -EFAULT;
+       count = req32.count;
+       list32 = (void __user *)(unsigned long)req32.list;
+
+       if (count < 0)
+               return -EINVAL;
+       nbytes = sizeof(*request) + count * sizeof(drm_buf_pub_t);
+       request = compat_alloc_user_space(nbytes);
+       if (!access_ok(VERIFY_WRITE, request, nbytes))
+               return -EFAULT;
+       list = (drm_buf_pub_t *) (request + 1);
+
+       if (__put_user(count, &request->count)
+           || __put_user(list, &request->list))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_MAP_BUFS, (unsigned long) request);
+       if (err)
+               return err;
+
+       if (__get_user(actual, &request->count))
+               return -EFAULT;
+       if (count >= actual)
+               for (i = 0; i < actual; ++i)
+                       if (__copy_in_user(&list32[i], &list[i],
+                                          offsetof(drm_buf_pub_t, address))
+                           || __get_user(addr, &list[i].address)
+                           || __put_user((unsigned long) addr,
+                                         &list32[i].address))
+                               return -EFAULT;
+
+       if (__put_user(actual, &argp->count)
+           || __get_user(addr, &request->virtual)
+           || __put_user((unsigned long) addr, &argp->virtual))
+               return -EFAULT;
+
+       return 0;
+}
+
+typedef struct drm_buf_free32 {
+       int     count;
+       u32     list;
+} drm_buf_free32_t;
+
+static int compat_drm_freebufs(struct file *file, unsigned int cmd,
+                              unsigned long arg)
+{
+       drm_buf_free32_t req32;
+       drm_buf_free_t __user *request;
+       drm_buf_free32_t __user *argp = (void __user *)arg;
+
+       if (copy_from_user(&req32, argp, sizeof(req32)))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request)))
+               return -EFAULT;
+       if (__put_user(req32.count, &request->count)
+           || __put_user((int __user *)(unsigned long) req32.list,
+                         &request->list))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_FREE_BUFS, (unsigned long) request);
+}
+
+typedef struct drm_ctx_priv_map32 {
+       unsigned int    ctx_id;  /**< Context requesting private mapping */
+       u32             handle; /**< Handle of map */
+} drm_ctx_priv_map32_t;
+
+static int compat_drm_setsareactx(struct file *file, unsigned int cmd,
+                                 unsigned long arg)
+{
+       drm_ctx_priv_map32_t req32;
+       drm_ctx_priv_map_t __user *request;
+       drm_ctx_priv_map32_t __user *argp = (void __user *)arg;
+
+       if (copy_from_user(&req32, argp, sizeof(req32)))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request)))
+               return -EFAULT;
+       if (__put_user(req32.ctx_id, &request->ctx_id)
+           || __put_user((void *)(unsigned long) req32.handle,
+                         &request->handle))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_SET_SAREA_CTX, (unsigned long) request);
+}
+
+static int compat_drm_getsareactx(struct file *file, unsigned int cmd,
+                                 unsigned long arg)
+{
+       drm_ctx_priv_map_t __user *request;
+       drm_ctx_priv_map32_t __user *argp = (void __user *)arg;
+       int err;
+       unsigned int ctx_id;
+       void *handle;
+
+       if (!access_ok(VERIFY_WRITE, argp, sizeof(*argp))
+           || __get_user(ctx_id, &argp->ctx_id))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request)))
+               return -EFAULT;
+       if (__put_user(ctx_id, &request->ctx_id))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_GET_SAREA_CTX, (unsigned long) request);
+       if (err)
+               return err;
+
+       if (__get_user(handle, &request->handle)
+           || __put_user((unsigned long) handle, &argp->handle))
+               return -EFAULT;
+
+       return 0;
+}
+
+typedef struct drm_ctx_res32 {
+       int     count;
+       u32     contexts;
+} drm_ctx_res32_t;
+
+static int compat_drm_resctx(struct file *file, unsigned int cmd,
+                            unsigned long arg)
+{
+       drm_ctx_res32_t __user *argp = (void __user *)arg;
+       drm_ctx_res32_t res32;
+       drm_ctx_res_t __user *res;
+       int err;
+
+       if (copy_from_user(&res32, argp, sizeof(res32)))
+               return -EFAULT;
+
+       res = compat_alloc_user_space(sizeof(*res));
+       if (!access_ok(VERIFY_WRITE, res, sizeof(*res)))
+               return -EFAULT;
+       if (__put_user(res32.count, &res->count)
+           || __put_user((drm_ctx_t __user *)(unsigned long) res32.contexts,
+                         &res->contexts))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_RES_CTX, (unsigned long) res);
+       if (err)
+               return err;
+
+       if (__get_user(res32.count, &res->count)
+           || __put_user(res32.count, &argp->count))
+               return -EFAULT;
+
+       return 0;
+}
+
+typedef struct drm_dma32 {
+       int     context;          /**< Context handle */
+       int     send_count;       /**< Number of buffers to send */
+       u32     send_indices;     /**< List of handles to buffers */
+       u32     send_sizes;       /**< Lengths of data to send */
+       drm_dma_flags_t flags;            /**< Flags */
+       int     request_count;    /**< Number of buffers requested */
+       int     request_size;     /**< Desired size for buffers */
+       u32     request_indices;  /**< Buffer information */
+       u32     request_sizes;
+       int     granted_count;    /**< Number of buffers granted */
+} drm_dma32_t;
+
+static int compat_drm_dma(struct file *file, unsigned int cmd,
+                         unsigned long arg)
+{
+       drm_dma32_t d32;
+       drm_dma32_t __user *argp = (void __user *) arg;
+       drm_dma_t __user *d;
+       int err;
+
+       if (copy_from_user(&d32, argp, sizeof(d32)))
+               return -EFAULT;
+
+       d = compat_alloc_user_space(sizeof(*d));
+       if (!access_ok(VERIFY_WRITE, d, sizeof(*d)))
+               return -EFAULT;
+
+       if (__put_user(d32.context, &d->context)
+           || __put_user(d32.send_count, &d->send_count)
+           || __put_user((int __user *)(unsigned long) d32.send_indices,
+                         &d->send_indices)
+           || __put_user((int __user *)(unsigned long) d32.send_sizes,
+                         &d->send_sizes)
+           || __put_user(d32.flags, &d->flags)
+           || __put_user(d32.request_count, &d->request_count)
+           || __put_user((int __user *)(unsigned long) d32.request_indices,
+                         &d->request_indices)
+           || __put_user((int __user *)(unsigned long) d32.request_sizes,
+                         &d->request_sizes))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_DMA, (unsigned long) d);
+       if (err)
+               return err;
+
+       if (__get_user(d32.request_size, &d->request_size)
+           || __get_user(d32.granted_count, &d->granted_count)
+           || __put_user(d32.request_size, &argp->request_size)
+           || __put_user(d32.granted_count, &argp->granted_count))
+               return -EFAULT;
+
+       return 0;
+}
+
+#if __OS_HAS_AGP
+typedef struct drm_agp_mode32 {
+       u32 mode;       /**< AGP mode */
+} drm_agp_mode32_t;
+
+static int compat_drm_agp_enable(struct file *file, unsigned int cmd,
+                                unsigned long arg)
+{
+       drm_agp_mode32_t __user *argp = (void __user *)arg;
+       drm_agp_mode32_t m32;
+       drm_agp_mode_t __user *mode;
+
+       if (get_user(m32.mode, &argp->mode))
+               return -EFAULT;
+
+       mode = compat_alloc_user_space(sizeof(*mode));
+       if (put_user(m32.mode, &mode->mode))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_AGP_ENABLE, (unsigned long) mode);
+}
+
+typedef struct drm_agp_info32 {
+       int       agp_version_major;
+       int       agp_version_minor;
+       u32       mode;
+       u32       aperture_base;  /* physical address */
+       u32       aperture_size;  /* bytes */
+       u32       memory_allowed; /* bytes */
+       u32       memory_used;
+
+                               /* PCI information */
+       unsigned short id_vendor;
+       unsigned short id_device;
+} drm_agp_info32_t;
+
+static int compat_drm_agp_info(struct file *file, unsigned int cmd,
+                              unsigned long arg)
+{
+       drm_agp_info32_t __user *argp = (void __user *)arg;
+       drm_agp_info32_t i32;
+       drm_agp_info_t __user *info;
+       int err;
+
+       info = compat_alloc_user_space(sizeof(*info));
+       if (!access_ok(VERIFY_WRITE, info, sizeof(*info)))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_AGP_INFO, (unsigned long) info);
+       if (err)
+               return err;
+
+       if (__get_user(i32.agp_version_major, &info->agp_version_major)
+           || __get_user(i32.agp_version_minor, &info->agp_version_minor)
+           || __get_user(i32.mode, &info->mode)
+           || __get_user(i32.aperture_base, &info->aperture_base)
+           || __get_user(i32.aperture_size, &info->aperture_size)
+           || __get_user(i32.memory_allowed, &info->memory_allowed)
+           || __get_user(i32.memory_used, &info->memory_used)
+           || __get_user(i32.id_vendor, &info->id_vendor)
+           || __get_user(i32.id_device, &info->id_device))
+               return -EFAULT;
+
+       if (copy_to_user(argp, &i32, sizeof(i32)))
+               return -EFAULT;
+
+       return 0;
+}
+
+typedef struct drm_agp_buffer32 {
+       u32 size;       /**< In bytes -- will round to page boundary */
+       u32 handle;     /**< Used for binding / unbinding */
+       u32 type;       /**< Type of memory to allocate */
+        u32 physical;  /**< Physical used by i810 */
+} drm_agp_buffer32_t;
+
+static int compat_drm_agp_alloc(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       drm_agp_buffer32_t __user *argp = (void __user *)arg;
+       drm_agp_buffer32_t req32;
+       drm_agp_buffer_t __user *request;
+       int err;
+
+       if (copy_from_user(&req32, argp, sizeof(req32)))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || __put_user(req32.size, &request->size)
+           || __put_user(req32.type, &request->type))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_AGP_ALLOC, (unsigned long) request);
+       if (err)
+               return err;
+
+       if (__get_user(req32.handle, &request->handle)
+           || __get_user(req32.physical, &request->physical)
+           || copy_to_user(argp, &req32, sizeof(req32))) {
+               drm_ioctl(file->f_dentry->d_inode, file,
+                         DRM_IOCTL_AGP_FREE, (unsigned long) request);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+static int compat_drm_agp_free(struct file *file, unsigned int cmd,
+                              unsigned long arg)
+{
+       drm_agp_buffer32_t __user *argp = (void __user *)arg;
+       drm_agp_buffer_t __user *request;
+       u32 handle;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || get_user(handle, &argp->handle)
+           || __put_user(handle, &request->handle))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_AGP_FREE, (unsigned long) request);
+}
+
+typedef struct drm_agp_binding32 {
+       u32 handle;     /**< From drm_agp_buffer */
+       u32 offset;     /**< In bytes -- will round to page boundary */
+} drm_agp_binding32_t;
+
+static int compat_drm_agp_bind(struct file *file, unsigned int cmd,
+                              unsigned long arg)
+{
+       drm_agp_binding32_t __user *argp = (void __user *)arg;
+       drm_agp_binding32_t req32;
+       drm_agp_binding_t __user *request;
+
+       if (copy_from_user(&req32, argp, sizeof(req32)))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || __put_user(req32.handle, &request->handle)
+           || __put_user(req32.offset, &request->offset))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_AGP_BIND, (unsigned long) request);
+}
+
+static int compat_drm_agp_unbind(struct file *file, unsigned int cmd,
+                                unsigned long arg)
+{
+       drm_agp_binding32_t __user *argp = (void __user *)arg;
+       drm_agp_binding_t __user *request;
+       u32 handle;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || get_user(handle, &argp->handle)
+           || __put_user(handle, &request->handle))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_AGP_UNBIND, (unsigned long) request);
+}
+#endif /* __OS_HAS_AGP */
+
+typedef struct drm_scatter_gather32 {
+       u32 size;       /**< In bytes -- will round to page boundary */
+       u32 handle;     /**< Used for mapping / unmapping */
+} drm_scatter_gather32_t;
+
+static int compat_drm_sg_alloc(struct file *file, unsigned int cmd,
+                              unsigned long arg)
+{
+       drm_scatter_gather32_t __user *argp = (void __user *)arg;
+       drm_scatter_gather_t __user *request;
+       int err;
+       unsigned long x;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || !access_ok(VERIFY_WRITE, argp, sizeof(*argp))
+           || __get_user(x, &argp->size)
+           || __put_user(x, &request->size))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_SG_ALLOC, (unsigned long) request);
+       if (err)
+               return err;
+
+       /* XXX not sure about the handle conversion here... */
+       if (__get_user(x, &request->handle)
+           || __put_user(x >> PAGE_SHIFT, &argp->handle))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int compat_drm_sg_free(struct file *file, unsigned int cmd,
+                             unsigned long arg)
+{
+       drm_scatter_gather32_t __user *argp = (void __user *)arg;
+       drm_scatter_gather_t __user *request;
+       unsigned long x;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || !access_ok(VERIFY_WRITE, argp, sizeof(*argp))
+           || __get_user(x, &argp->handle)
+           || __put_user(x << PAGE_SHIFT, &request->handle))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_SG_FREE, (unsigned long) request);
+}
+
+struct drm_wait_vblank_request32 {
+       drm_vblank_seq_type_t type;
+       unsigned int sequence;
+       u32 signal;
+};
+
+struct drm_wait_vblank_reply32 {
+       drm_vblank_seq_type_t type;
+       unsigned int sequence;
+       s32 tval_sec;
+       s32 tval_usec;
+};
+
+typedef union drm_wait_vblank32 {
+       struct drm_wait_vblank_request32 request;
+       struct drm_wait_vblank_reply32 reply;
+} drm_wait_vblank32_t;
+
+static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
+                                 unsigned long arg)
+{
+       drm_wait_vblank32_t __user *argp = (void __user *)arg;
+       drm_wait_vblank32_t req32;
+       drm_wait_vblank_t __user *request;
+       int err;
+
+       if (copy_from_user(&req32, argp, sizeof(req32)))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || __put_user(req32.request.type, &request->request.type)
+           || __put_user(req32.request.sequence, &request->request.sequence)
+           || __put_user(req32.request.signal, &request->request.signal))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_WAIT_VBLANK, (unsigned long) request);
+       if (err)
+               return err;
+
+       if (__get_user(req32.reply.type, &request->reply.type)
+           || __get_user(req32.reply.sequence, &request->reply.sequence)
+           || __get_user(req32.reply.tval_sec, &request->reply.tval_sec)
+           || __get_user(req32.reply.tval_usec, &request->reply.tval_usec))
+               return -EFAULT;
+
+       if (copy_to_user(argp, &req32, sizeof(req32)))
+               return -EFAULT;
+
+       return 0;
+}
+
+drm_ioctl_compat_t *drm_compat_ioctls[] = {
+       [DRM_IOCTL_NR(DRM_IOCTL_VERSION32)] = compat_drm_version,
+       [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE32)] = compat_drm_getunique,
+       [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP32)] = compat_drm_getmap,
+       [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT32)] = compat_drm_getclient,
+       [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS32)] = compat_drm_getstats,
+       [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE32)] = compat_drm_setunique,
+       [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP32)] = compat_drm_addmap,
+       [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS32)] = compat_drm_addbufs,
+       [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS32)] = compat_drm_markbufs,
+       [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS32)] = compat_drm_infobufs,
+       [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS32)] = compat_drm_mapbufs,
+       [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS32)] = compat_drm_freebufs,
+       [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP32)] = compat_drm_rmmap,
+       [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX32)] = compat_drm_setsareactx,
+       [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX32)] = compat_drm_getsareactx,
+       [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX32)] = compat_drm_resctx,
+       [DRM_IOCTL_NR(DRM_IOCTL_DMA32)] = compat_drm_dma,
+#if __OS_HAS_AGP
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE32)] = compat_drm_agp_enable,
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO32)] = compat_drm_agp_info,
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC32)] = compat_drm_agp_alloc,
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE32)] = compat_drm_agp_free,
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND32)] = compat_drm_agp_bind,
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND32)] = compat_drm_agp_unbind,
+#endif
+       [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC32)] = compat_drm_sg_alloc,
+       [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE32)] = compat_drm_sg_free,
+       [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK32)] = compat_drm_wait_vblank,
+};
+
+/**
+ * Called whenever a 32-bit process running under a 64-bit kernel
+ * performs an ioctl on /dev/drm.
+ *
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument.
+ * \return zero on success or negative number on failure.
+ */
+long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       unsigned int nr = DRM_IOCTL_NR(cmd);
+       drm_ioctl_compat_t *fn;
+       int ret;
+
+       if (nr >= DRM_ARRAY_SIZE(drm_compat_ioctls))
+               return -ENOTTY;
+
+       fn = drm_compat_ioctls[nr];
+
+       lock_kernel();          /* XXX for now */
+       if (fn != NULL)
+               ret = (*fn)(filp, cmd, arg);
+       else
+               ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_compat_ioctl);
index 7300a09dbd5c2102b6d3762b854fe8edd5a3d03b..b5903f9f14236a0fe0223db59ab5c0b39241cb43 100644 (file)
@@ -1,10 +1,30 @@
 /* i915_dma.c -- DMA support for the I915 -*- linux-c -*-
  */
 /**************************************************************************
- * 
+ *
  * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
  * All Rights Reserved.
- * 
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
  **************************************************************************/
 
 #include "drmP.h"
index 7e55edf45c4fd8c6fe87dacaa28d6eae3214fa82..23e027d2908069af6f71a8d592669e5adbca3c6b 100644 (file)
@@ -1,3 +1,30 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
 #ifndef _I915_DRM_H_
 #define _I915_DRM_H_
 
index 002b7082e21b00ee633f63889afe488bdfecd0e8..e6a9e1d1d2831a6fa17ff660c12146359a58e33a 100644 (file)
@@ -1,11 +1,30 @@
 /* i915_drv.c -- i830,i845,i855,i865,i915 driver -*- linux-c -*-
  */
-
 /**************************************************************************
- * 
+ *
  * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
  * All Rights Reserved.
- * 
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
  **************************************************************************/
 
 #include "drmP.h"
index f6ca92a565db7bc64ab5d0a50d1e7282747f8255..fa940d64b85d6da335a2ea2a21b84a8079d1ceac 100644 (file)
@@ -1,10 +1,30 @@
 /* i915_drv.h -- Private header for the I915 driver -*- linux-c -*-
  */
 /**************************************************************************
- * 
+ *
  * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
  * All Rights Reserved.
- * 
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
  **************************************************************************/
 
 #ifndef _I915_DRV_H_
index b0239262a84ae9515124afd41517e0c10de05bdf..a101cc9cfd7e1441e0010a501943ae70efb72eae 100644 (file)
@@ -1,10 +1,30 @@
 /* i915_dma.c -- DMA support for the I915 -*- linux-c -*-
  */
 /**************************************************************************
- * 
+ *
  * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
  * All Rights Reserved.
- * 
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
  **************************************************************************/
 
 #include "drmP.h"
index d54a3005946b724a8b3deb1a5f8dbf9188cb8b76..9b1698f521befabc199c8c4ea1bb21b0c968e37e 100644 (file)
@@ -1,10 +1,30 @@
 /* i915_mem.c -- Simple agp/fb memory manager for i915 -*- linux-c -*-
  */
 /**************************************************************************
- * 
+ *
  * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
  * All Rights Reserved.
- * 
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
  **************************************************************************/
 
 #include "drmP.h"
index 7b983d96e53b7a7589bb51a02af90a84539d7f4f..18e4e5b0952f4f60c5143253f57b476949fd23c2 100644 (file)
@@ -101,6 +101,9 @@ static struct drm_driver driver = {
                .mmap = drm_mmap,
                .poll = drm_poll,
                .fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+               .compat_ioctl = radeon_compat_ioctl,
+#endif
        },
        .pci_driver = {
                .name          = DRIVER_NAME,
index 5837098afae81f91e42706dd0fb2f440eae43b1f..771aa80a5e8c24233193b0c73566e03f4ebc1248 100644 (file)
@@ -317,6 +317,9 @@ extern int radeon_preinit( struct drm_device *dev, unsigned long flags );
 extern int radeon_postinit( struct drm_device *dev, unsigned long flags );
 extern int radeon_postcleanup( struct drm_device *dev );
 
+extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
+                               unsigned long arg);
+
 /* Flags for stats.boxes
  */
 #define RADEON_BOX_DMA_IDLE      0x1
diff --git a/drivers/char/drm/radeon_ioc32.c b/drivers/char/drm/radeon_ioc32.c
new file mode 100644 (file)
index 0000000..bfe6122
--- /dev/null
@@ -0,0 +1,395 @@
+/**
+ * \file radeon_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the Radeon DRM.
+ *
+ * \author Paul Mackerras <paulus@samba.org>
+ *
+ * Copyright (C) Paul Mackerras 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHOR 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/compat.h>
+#include <linux/ioctl32.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_drm.h"
+#include "radeon_drv.h"
+
+typedef struct drm_radeon_init32 {
+       int func;
+       u32 sarea_priv_offset;
+       int is_pci;
+       int cp_mode;
+       int gart_size;
+       int ring_size;
+       int usec_timeout;
+
+       unsigned int fb_bpp;
+       unsigned int front_offset, front_pitch;
+       unsigned int back_offset, back_pitch;
+       unsigned int depth_bpp;
+       unsigned int depth_offset, depth_pitch;
+
+       u32 fb_offset;
+       u32 mmio_offset;
+       u32 ring_offset;
+       u32 ring_rptr_offset;
+       u32 buffers_offset;
+       u32 gart_textures_offset;
+} drm_radeon_init32_t;
+
+static int compat_radeon_cp_init(struct file *file, unsigned int cmd,
+                                unsigned long arg)
+{
+       drm_radeon_init32_t init32;
+       drm_radeon_init_t __user *init;
+
+       if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
+               return -EFAULT;
+
+       init = compat_alloc_user_space(sizeof(*init));
+       if (!access_ok(VERIFY_WRITE, init, sizeof(*init))
+           || __put_user(init32.func, &init->func)
+           || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset)
+           || __put_user(init32.is_pci, &init->is_pci)
+           || __put_user(init32.cp_mode, &init->cp_mode)
+           || __put_user(init32.gart_size, &init->gart_size)
+           || __put_user(init32.ring_size, &init->ring_size)
+           || __put_user(init32.usec_timeout, &init->usec_timeout)
+           || __put_user(init32.fb_bpp, &init->fb_bpp)
+           || __put_user(init32.front_offset, &init->front_offset)
+           || __put_user(init32.front_pitch, &init->front_pitch)
+           || __put_user(init32.back_offset, &init->back_offset)
+           || __put_user(init32.back_pitch, &init->back_pitch)
+           || __put_user(init32.depth_bpp, &init->depth_bpp)
+           || __put_user(init32.depth_offset, &init->depth_offset)
+           || __put_user(init32.depth_pitch, &init->depth_pitch)
+           || __put_user(init32.fb_offset, &init->fb_offset)
+           || __put_user(init32.mmio_offset, &init->mmio_offset)
+           || __put_user(init32.ring_offset, &init->ring_offset)
+           || __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset)
+           || __put_user(init32.buffers_offset, &init->buffers_offset)
+           || __put_user(init32.gart_textures_offset,
+                         &init->gart_textures_offset))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_RADEON_CP_INIT, (unsigned long) init);
+}
+
+typedef struct drm_radeon_clear32 {
+       unsigned int flags;
+       unsigned int clear_color;
+       unsigned int clear_depth;
+       unsigned int color_mask;
+       unsigned int depth_mask;   /* misnamed field:  should be stencil */
+       u32          depth_boxes;
+} drm_radeon_clear32_t;
+
+static int compat_radeon_cp_clear(struct file *file, unsigned int cmd,
+                                 unsigned long arg)
+{
+       drm_radeon_clear32_t clr32;
+       drm_radeon_clear_t __user *clr;
+
+       if (copy_from_user(&clr32, (void __user *)arg, sizeof(clr32)))
+               return -EFAULT;
+
+       clr = compat_alloc_user_space(sizeof(*clr));
+       if (!access_ok(VERIFY_WRITE, clr, sizeof(*clr))
+           || __put_user(clr32.flags, &clr->flags)
+           || __put_user(clr32.clear_color, &clr->clear_color)
+           || __put_user(clr32.clear_depth, &clr->clear_depth)
+           || __put_user(clr32.color_mask, &clr->color_mask)
+           || __put_user(clr32.depth_mask, &clr->depth_mask)
+           || __put_user((void __user *)(unsigned long)clr32.depth_boxes,
+                         &clr->depth_boxes))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_RADEON_CLEAR, (unsigned long) clr);
+}
+
+typedef struct drm_radeon_stipple32 {
+       u32 mask;
+} drm_radeon_stipple32_t;
+
+static int compat_radeon_cp_stipple(struct file *file, unsigned int cmd,
+                                   unsigned long arg)
+{
+       drm_radeon_stipple32_t __user *argp = (void __user *) arg;
+       drm_radeon_stipple_t __user *request;
+       u32 mask;
+
+       if (get_user(mask, &argp->mask))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || __put_user((unsigned int __user *)(unsigned long) mask,
+                         &request->mask))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_RADEON_STIPPLE, (unsigned long) request);
+}
+
+typedef struct drm_radeon_tex_image32 {
+       unsigned int x, y;              /* Blit coordinates */
+       unsigned int width, height;
+       u32 data;
+} drm_radeon_tex_image32_t;
+
+typedef struct drm_radeon_texture32 {
+       unsigned int offset;
+       int pitch;
+       int format;
+       int width;                      /* Texture image coordinates */
+       int height;
+       u32 image;
+} drm_radeon_texture32_t;
+
+static int compat_radeon_cp_texture(struct file *file, unsigned int cmd,
+                                   unsigned long arg)
+{
+       drm_radeon_texture32_t req32;
+       drm_radeon_texture_t __user *request;
+       drm_radeon_tex_image32_t img32;
+       drm_radeon_tex_image_t __user *image;
+
+       if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+               return -EFAULT;
+       if (req32.image == 0)
+               return -EINVAL;
+       if (copy_from_user(&img32, (void __user *)(unsigned long)req32.image,
+                          sizeof(img32)))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request) + sizeof(*image));
+       if (!access_ok(VERIFY_WRITE, request,
+                      sizeof(*request) + sizeof(*image)))
+               return -EFAULT;
+       image = (drm_radeon_tex_image_t __user *) (request + 1);
+
+       if (__put_user(req32.offset, &request->offset)
+           || __put_user(req32.pitch, &request->pitch)
+           || __put_user(req32.format, &request->format)
+           || __put_user(req32.width, &request->width)
+           || __put_user(req32.height, &request->height)
+           || __put_user(image, &request->image)
+           || __put_user(img32.x, &image->x)
+           || __put_user(img32.y, &image->y)
+           || __put_user(img32.width, &image->width)
+           || __put_user(img32.height, &image->height)
+           || __put_user((const void __user *)(unsigned long)img32.data,
+                         &image->data))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_RADEON_TEXTURE, (unsigned long) request);
+}
+
+typedef struct drm_radeon_vertex2_32 {
+       int idx;                        /* Index of vertex buffer */
+       int discard;                    /* Client finished with buffer? */
+       int nr_states;
+       u32 state;
+       int nr_prims;
+       u32 prim;
+} drm_radeon_vertex2_32_t;
+
+static int compat_radeon_cp_vertex2(struct file *file, unsigned int cmd,
+                                   unsigned long arg)
+{
+       drm_radeon_vertex2_32_t req32;
+       drm_radeon_vertex2_t __user *request;
+
+       if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || __put_user(req32.idx, &request->idx)
+           || __put_user(req32.discard, &request->discard)
+           || __put_user(req32.nr_states, &request->nr_states)
+           || __put_user((void __user *)(unsigned long)req32.state,
+                         &request->state)
+           || __put_user(req32.nr_prims, &request->nr_prims)
+           || __put_user((void __user *)(unsigned long)req32.prim,
+                         &request->prim))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_RADEON_VERTEX2, (unsigned long) request);
+}
+
+typedef struct drm_radeon_cmd_buffer32 {
+       int bufsz;
+       u32 buf;
+       int nbox;
+       u32 boxes;
+} drm_radeon_cmd_buffer32_t;
+
+static int compat_radeon_cp_cmdbuf(struct file *file, unsigned int cmd,
+                                  unsigned long arg)
+{
+       drm_radeon_cmd_buffer32_t req32;
+       drm_radeon_cmd_buffer_t __user *request;
+
+       if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || __put_user(req32.bufsz, &request->bufsz)
+           || __put_user((void __user *)(unsigned long)req32.buf,
+                         &request->buf)
+           || __put_user(req32.nbox, &request->nbox)
+           || __put_user((void __user *)(unsigned long)req32.boxes,
+                         &request->boxes))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_RADEON_CMDBUF, (unsigned long) request);
+}
+
+typedef struct drm_radeon_getparam32 {
+       int param;
+       u32 value;
+} drm_radeon_getparam32_t;
+
+static int compat_radeon_cp_getparam(struct file *file, unsigned int cmd,
+                                    unsigned long arg)
+{
+       drm_radeon_getparam32_t req32;
+       drm_radeon_getparam_t __user *request;
+
+       if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || __put_user(req32.param, &request->param)
+           || __put_user((void __user *)(unsigned long)req32.value,
+                         &request->value))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_RADEON_GETPARAM, (unsigned long) request);
+}
+
+typedef struct drm_radeon_mem_alloc32 {
+       int region;
+       int alignment;
+       int size;
+       u32 region_offset;      /* offset from start of fb or GART */
+} drm_radeon_mem_alloc32_t;
+
+static int compat_radeon_mem_alloc(struct file *file, unsigned int cmd,
+                                  unsigned long arg)
+{
+       drm_radeon_mem_alloc32_t req32;
+       drm_radeon_mem_alloc_t __user *request;
+
+       if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || __put_user(req32.region, &request->region)
+           || __put_user(req32.alignment, &request->alignment)
+           || __put_user(req32.size, &request->size)
+           || __put_user((int __user *)(unsigned long)req32.region_offset,
+                         &request->region_offset))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_RADEON_ALLOC, (unsigned long) request);
+}
+
+typedef struct drm_radeon_irq_emit32 {
+       u32 irq_seq;
+} drm_radeon_irq_emit32_t;
+
+static int compat_radeon_irq_emit(struct file *file, unsigned int cmd,
+                                 unsigned long arg)
+{
+       drm_radeon_irq_emit32_t req32;
+       drm_radeon_irq_emit_t __user *request;
+
+       if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || __put_user((int __user *)(unsigned long)req32.irq_seq,
+                         &request->irq_seq))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long) request);
+}
+
+drm_ioctl_compat_t *radeon_compat_ioctls[] = {
+       [DRM_RADEON_CP_INIT] = compat_radeon_cp_init,
+       [DRM_RADEON_CLEAR] = compat_radeon_cp_clear,
+       [DRM_RADEON_STIPPLE] = compat_radeon_cp_stipple,
+       [DRM_RADEON_TEXTURE] = compat_radeon_cp_texture,
+       [DRM_RADEON_VERTEX2] = compat_radeon_cp_vertex2,
+       [DRM_RADEON_CMDBUF] = compat_radeon_cp_cmdbuf,
+       [DRM_RADEON_GETPARAM] = compat_radeon_cp_getparam,
+       [DRM_RADEON_ALLOC] = compat_radeon_mem_alloc,
+       [DRM_RADEON_IRQ_EMIT] = compat_radeon_irq_emit,
+};
+
+/**
+ * Called whenever a 32-bit process running under a 64-bit kernel
+ * performs an ioctl on /dev/dri/card<n>.
+ *
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument.
+ * \return zero on success or negative number on failure.
+ */
+long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
+                        unsigned long arg)
+{
+       unsigned int nr = DRM_IOCTL_NR(cmd);
+       drm_ioctl_compat_t *fn = NULL;
+       int ret;
+
+       if (nr < DRM_COMMAND_BASE)
+               return drm_compat_ioctl(filp, cmd, arg);
+
+       if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(radeon_compat_ioctls))
+               fn = radeon_compat_ioctls[nr - DRM_COMMAND_BASE];
+
+       lock_kernel();          /* XXX for now */
+       if (fn != NULL)
+               ret = (*fn)(filp, cmd, arg);
+       else
+               ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
index cd25f28e26a38874738705d935c37d51de4cda42..40474a65f56d1e8dd4d6075d6d4356716560b4e4 100644 (file)
 #include "radeon_drm.h"
 #include "radeon_drv.h"
 
+static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 mask)
+{
+       u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask;
+       if (irqs)
+               RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
+       return irqs;
+}
+
 /* Interrupts - Used for device synchronization and flushing in the
  * following circumstances:
  *
@@ -63,8 +71,8 @@ irqreturn_t radeon_driver_irq_handler( DRM_IRQ_ARGS )
        /* Only consider the bits we're interested in - others could be used
         * outside the DRM
         */
-       stat = RADEON_READ(RADEON_GEN_INT_STATUS)
-            & (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT);
+       stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | 
+                                                 RADEON_CRTC_VBLANK_STAT));
        if (!stat)
                return IRQ_NONE;
 
@@ -80,19 +88,9 @@ irqreturn_t radeon_driver_irq_handler( DRM_IRQ_ARGS )
                drm_vbl_send_signals( dev );
        }
 
-       /* Acknowledge interrupts we handle */
-       RADEON_WRITE(RADEON_GEN_INT_STATUS, stat);
        return IRQ_HANDLED;
 }
 
-static __inline__ void radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv)
-{
-       u32 tmp = RADEON_READ( RADEON_GEN_INT_STATUS )
-               & (RADEON_SW_INT_TEST_ACK | RADEON_CRTC_VBLANK_STAT);
-       if (tmp)
-               RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp );
-}
-
 static int radeon_emit_irq(drm_device_t *dev)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -141,7 +139,7 @@ int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
                return DRM_ERR(EINVAL);
        }
 
-       radeon_acknowledge_irqs( dev_priv );
+       radeon_acknowledge_irqs(dev_priv, RADEON_CRTC_VBLANK_STAT);
 
        dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
 
@@ -219,7 +217,8 @@ void radeon_driver_irq_preinstall( drm_device_t *dev ) {
        RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 );
 
        /* Clear bits if they're already high */
-       radeon_acknowledge_irqs( dev_priv );
+       radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
+                                          RADEON_CRTC_VBLANK_STAT));
 }
 
 void radeon_driver_irq_postinstall( drm_device_t *dev ) {
index 7def6ad517984c27542b8b4942081299119aba2a..62cda25724e30d6501870683c53849f5d8e273a5 100644 (file)
@@ -163,8 +163,7 @@ static void ds1620_out(int cmd, int bits, int value)
        netwinder_ds1620_reset();
        netwinder_unlock(&flags);
 
-       set_current_state(TASK_INTERRUPTIBLE);
-       schedule_timeout(2);
+       msleep(20);
 }
 
 static unsigned int ds1620_in(int cmd, int bits)
index 220a227e606113c8aa4ccd33b2e666daba5d6f03..65ffc0be3df989e30de09e7f8e37b45212d78adc 100644 (file)
@@ -1176,8 +1176,8 @@ KERN_INFO "Compressor for zftape (lzrw3 algorithm)\n");
         }
 #else /* !MODULE */
        /* print a short no-nonsense boot message */
-       printk("zftape compressor v1.00a 970514\n");
-       printk("For use with " FTAPE_VERSION "\n");
+       printk(KERN_INFO "zftape compressor v1.00a 970514\n");
+       printk(KERN_INFO "For use with " FTAPE_VERSION "\n");
 #endif /* MODULE */
        TRACE(ft_t_info, "zft_compressor_init @ 0x%p", zft_compressor_init);
        TRACE(ft_t_info, "installing compressor for zftape ...");
index 5ec732e6ca9221ee3b3ea5fb9aa71c0424e51725..762fa430fb5be3b6a7615eed705e741509475ba7 100644 (file)
@@ -834,7 +834,7 @@ int hpet_alloc(struct hpet_data *hdp)
        printk("\n");
 
        ns = hpetp->hp_period;  /* femptoseconds, 10^-15 */
-       do_div(ns, 1000000);    /* convert to nanoseconds, 10^-9 */
+       ns /= 1000000;          /* convert to nanoseconds, 10^-9 */
        printk(KERN_INFO "hpet%d: %ldns tick, %d %d-bit timers\n",
                hpetp->hp_which, ns, hpetp->hp_ntimer,
                cap & HPET_COUNTER_SIZE_MASK ? 64 : 32);
index a8119764028373dddb9eeffc27b64bfa3cd463de..6c4b3f986d0ccf26828fe08d61a21810786a6287 100644 (file)
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
-#include <linux/apm_bios.h>
+#include <linux/seq_file.h>
+#include <linux/dmi.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
 #include <linux/i8k.h>
 
-#define I8K_VERSION            "1.13 14/05/2002"
+#define I8K_VERSION            "1.14 21/02/2005"
 
 #define I8K_SMM_FN_STATUS      0x0025
 #define I8K_SMM_POWER_STATUS   0x0069
@@ -34,7 +35,8 @@
 #define I8K_SMM_GET_FAN                0x00a3
 #define I8K_SMM_GET_SPEED      0x02a3
 #define I8K_SMM_GET_TEMP       0x10a3
-#define I8K_SMM_GET_DELL_SIG   0xffa3
+#define I8K_SMM_GET_DELL_SIG1  0xfea3
+#define I8K_SMM_GET_DELL_SIG2  0xffa3
 #define I8K_SMM_BIOS_VERSION   0x00a6
 
 #define I8K_FAN_MULT           30
 
 #define I8K_TEMPERATURE_BUG    1
 
-#define DELL_SIGNATURE         "Dell Computer"
-
-static char *supported_models[] = {
-    "Inspiron",
-    "Latitude",
-    NULL
-};
-
-static char system_vendor[48] = "?";
-static char product_name [48] = "?";
-static char bios_version [4]  = "?";
-static char serial_number[16] = "?";
+static char bios_version[4];
 
 MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
 MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
@@ -73,6 +64,10 @@ static int force;
 module_param(force, bool, 0);
 MODULE_PARM_DESC(force, "Force loading without checking for supported models");
 
+static int ignore_dmi;
+module_param(ignore_dmi, bool, 0);
+MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match");
+
 static int restricted;
 module_param(restricted, bool, 0);
 MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set");
@@ -81,69 +76,69 @@ static int power_status;
 module_param(power_status, bool, 0600);
 MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
 
-static ssize_t i8k_read(struct file *, char __user *, size_t, loff_t *);
+static int i8k_open_fs(struct inode *inode, struct file *file);
 static int i8k_ioctl(struct inode *, struct file *, unsigned int,
                     unsigned long);
 
 static struct file_operations i8k_fops = {
-    .read      = i8k_read,
-    .ioctl     = i8k_ioctl,
+       .open           = i8k_open_fs,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .ioctl          = i8k_ioctl,
+};
+
+struct smm_regs {
+       unsigned int eax;
+       unsigned int ebx __attribute__ ((packed));
+       unsigned int ecx __attribute__ ((packed));
+       unsigned int edx __attribute__ ((packed));
+       unsigned int esi __attribute__ ((packed));
+       unsigned int edi __attribute__ ((packed));
 };
 
-typedef struct {
-    unsigned int eax;
-    unsigned int ebx __attribute__ ((packed));
-    unsigned int ecx __attribute__ ((packed));
-    unsigned int edx __attribute__ ((packed));
-    unsigned int esi __attribute__ ((packed));
-    unsigned int edi __attribute__ ((packed));
-} SMMRegisters;
-
-typedef struct {
-    u8 type;
-    u8 length;
-    u16        handle;
-} DMIHeader;
+static inline char *i8k_get_dmi_data(int field)
+{
+       return dmi_get_system_info(field) ? : "N/A";
+}
 
 /*
  * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard.
  */
-static int i8k_smm(SMMRegisters *regs)
+static int i8k_smm(struct smm_regs *regs)
 {
-    int rc;
-    int eax = regs->eax;
-
-    asm("pushl %%eax\n\t" \
-       "movl 0(%%eax),%%edx\n\t" \
-       "push %%edx\n\t" \
-       "movl 4(%%eax),%%ebx\n\t" \
-       "movl 8(%%eax),%%ecx\n\t" \
-       "movl 12(%%eax),%%edx\n\t" \
-       "movl 16(%%eax),%%esi\n\t" \
-       "movl 20(%%eax),%%edi\n\t" \
-       "popl %%eax\n\t" \
-       "out %%al,$0xb2\n\t" \
-       "out %%al,$0x84\n\t" \
-       "xchgl %%eax,(%%esp)\n\t"
-       "movl %%ebx,4(%%eax)\n\t" \
-       "movl %%ecx,8(%%eax)\n\t" \
-       "movl %%edx,12(%%eax)\n\t" \
-       "movl %%esi,16(%%eax)\n\t" \
-       "movl %%edi,20(%%eax)\n\t" \
-       "popl %%edx\n\t" \
-       "movl %%edx,0(%%eax)\n\t" \
-       "lahf\n\t" \
-       "shrl $8,%%eax\n\t" \
-       "andl $1,%%eax\n" \
-       : "=a" (rc)
-       : "a" (regs)
-       : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
-
-    if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) {
-       return -EINVAL;
-    }
-
-    return 0;
+       int rc;
+       int eax = regs->eax;
+
+       asm("pushl %%eax\n\t"
+           "movl 0(%%eax),%%edx\n\t"
+           "push %%edx\n\t"
+           "movl 4(%%eax),%%ebx\n\t"
+           "movl 8(%%eax),%%ecx\n\t"
+           "movl 12(%%eax),%%edx\n\t"
+           "movl 16(%%eax),%%esi\n\t"
+           "movl 20(%%eax),%%edi\n\t"
+           "popl %%eax\n\t"
+           "out %%al,$0xb2\n\t"
+           "out %%al,$0x84\n\t"
+           "xchgl %%eax,(%%esp)\n\t"
+           "movl %%ebx,4(%%eax)\n\t"
+           "movl %%ecx,8(%%eax)\n\t"
+           "movl %%edx,12(%%eax)\n\t"
+           "movl %%esi,16(%%eax)\n\t"
+           "movl %%edi,20(%%eax)\n\t"
+           "popl %%edx\n\t"
+           "movl %%edx,0(%%eax)\n\t"
+           "lahf\n\t"
+           "shrl $8,%%eax\n\t"
+           "andl $1,%%eax\n":"=a"(rc)
+           :    "a"(regs)
+           :    "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
+
+       if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)
+               return -EINVAL;
+
+       return 0;
 }
 
 /*
@@ -152,24 +147,9 @@ static int i8k_smm(SMMRegisters *regs)
  */
 static int i8k_get_bios_version(void)
 {
-    SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
-    int rc;
-
-    regs.eax = I8K_SMM_BIOS_VERSION;
-    if ((rc=i8k_smm(&regs)) < 0) {
-       return rc;
-    }
-
-    return regs.eax;
-}
+       struct smm_regs regs = { .eax = I8K_SMM_BIOS_VERSION, };
 
-/*
- * Read the machine id.
- */
-static int i8k_get_serial_number(unsigned char *buff)
-{
-    strlcpy(buff, serial_number, sizeof(serial_number));
-    return 0;
+       return i8k_smm(&regs) ? : regs.eax;
 }
 
 /*
@@ -177,24 +157,22 @@ static int i8k_get_serial_number(unsigned char *buff)
  */
 static int i8k_get_fn_status(void)
 {
-    SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
-    int rc;
-
-    regs.eax = I8K_SMM_FN_STATUS;
-    if ((rc=i8k_smm(&regs)) < 0) {
-       return rc;
-    }
-
-    switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {
-    case I8K_FN_UP:
-       return I8K_VOL_UP;
-    case I8K_FN_DOWN:
-       return I8K_VOL_DOWN;
-    case I8K_FN_MUTE:
-       return I8K_VOL_MUTE;
-    default:
-       return 0;
-    }
+       struct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, };
+       int rc;
+
+       if ((rc = i8k_smm(&regs)) < 0)
+               return rc;
+
+       switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {
+       case I8K_FN_UP:
+               return I8K_VOL_UP;
+       case I8K_FN_DOWN:
+               return I8K_VOL_DOWN;
+       case I8K_FN_MUTE:
+               return I8K_VOL_MUTE;
+       default:
+               return 0;
+       }
 }
 
 /*
@@ -202,20 +180,13 @@ static int i8k_get_fn_status(void)
  */
 static int i8k_get_power_status(void)
 {
-    SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
-    int rc;
-
-    regs.eax = I8K_SMM_POWER_STATUS;
-    if ((rc=i8k_smm(&regs)) < 0) {
-       return rc;
-    }
-
-    switch (regs.eax & 0xff) {
-    case I8K_POWER_AC:
-       return I8K_AC;
-    default:
-       return I8K_BATTERY;
-    }
+       struct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, };
+       int rc;
+
+       if ((rc = i8k_smm(&regs)) < 0)
+               return rc;
+
+       return (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY;
 }
 
 /*
@@ -223,16 +194,10 @@ static int i8k_get_power_status(void)
  */
 static int i8k_get_fan_status(int fan)
 {
-    SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
-    int rc;
-
-    regs.eax = I8K_SMM_GET_FAN;
-    regs.ebx = fan & 0xff;
-    if ((rc=i8k_smm(&regs)) < 0) {
-       return rc;
-    }
+       struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, };
 
-    return (regs.eax & 0xff);
+       regs.ebx = fan & 0xff;
+       return i8k_smm(&regs) ? : regs.eax & 0xff;
 }
 
 /*
@@ -240,16 +205,10 @@ static int i8k_get_fan_status(int fan)
  */
 static int i8k_get_fan_speed(int fan)
 {
-    SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
-    int rc;
+       struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };
 
-    regs.eax = I8K_SMM_GET_SPEED;
-    regs.ebx = fan & 0xff;
-    if ((rc=i8k_smm(&regs)) < 0) {
-       return rc;
-    }
-
-    return (regs.eax & 0xffff) * I8K_FAN_MULT;
+       regs.ebx = fan & 0xff;
+       return i8k_smm(&regs) ? : (regs.eax & 0xffff) * I8K_FAN_MULT;
 }
 
 /*
@@ -257,532 +216,318 @@ static int i8k_get_fan_speed(int fan)
  */
 static int i8k_set_fan(int fan, int speed)
 {
-    SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
-    int rc;
-
-    speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);
+       struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };
 
-    regs.eax = I8K_SMM_SET_FAN;
-    regs.ebx = (fan & 0xff) | (speed << 8);
-    if ((rc=i8k_smm(&regs)) < 0) {
-       return rc;
-    }
+       speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);
+       regs.ebx = (fan & 0xff) | (speed << 8);
 
-    return (i8k_get_fan_status(fan));
+       return i8k_smm(&regs) ? : i8k_get_fan_status(fan);
 }
 
 /*
  * Read the cpu temperature.
  */
-static int i8k_get_cpu_temp(void)
+static int i8k_get_temp(int sensor)
 {
-    SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
-    int rc;
-    int temp;
+       struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, };
+       int rc;
+       int temp;
 
 #ifdef I8K_TEMPERATURE_BUG
-    static int prev = 0;
+       static int prev;
 #endif
+       regs.ebx = sensor & 0xff;
+       if ((rc = i8k_smm(&regs)) < 0)
+               return rc;
 
-    regs.eax = I8K_SMM_GET_TEMP;
-    if ((rc=i8k_smm(&regs)) < 0) {
-       return rc;
-    }
-    temp = regs.eax & 0xff;
+       temp = regs.eax & 0xff;
 
 #ifdef I8K_TEMPERATURE_BUG
-    /*
-     * Sometimes the temperature sensor returns 0x99, which is out of range.
-     * In this case we return (once) the previous cached value. For example:
-     # 1003655137 00000058 00005a4b
-     # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees
-     # 1003655139 00000054 00005c52
-     */
-    if (temp > I8K_MAX_TEMP) {
-       temp = prev;
-       prev = I8K_MAX_TEMP;
-    } else {
-       prev = temp;
-    }
+       /*
+        * Sometimes the temperature sensor returns 0x99, which is out of range.
+        * In this case we return (once) the previous cached value. For example:
+        # 1003655137 00000058 00005a4b
+        # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees
+        # 1003655139 00000054 00005c52
+        */
+       if (temp > I8K_MAX_TEMP) {
+               temp = prev;
+               prev = I8K_MAX_TEMP;
+       } else {
+               prev = temp;
+       }
 #endif
 
-    return temp;
+       return temp;
 }
 
-static int i8k_get_dell_signature(void)
+static int i8k_get_dell_signature(int req_fn)
 {
-    SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
-    int rc;
+       struct smm_regs regs = { .eax = req_fn, };
+       int rc;
 
-    regs.eax = I8K_SMM_GET_DELL_SIG;
-    if ((rc=i8k_smm(&regs)) < 0) {
-       return rc;
-    }
+       if ((rc = i8k_smm(&regs)) < 0)
+               return rc;
 
-    if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) {
-       return 0;
-    } else {
-       return -1;
-    }
+       return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1;
 }
 
 static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
                     unsigned long arg)
 {
-    int val;
-    int speed;
-    unsigned char buff[16];
-    int __user *argp = (int __user *)arg;
-
-    if (!argp)
-       return -EINVAL;
-
-    switch (cmd) {
-    case I8K_BIOS_VERSION:
-       val = i8k_get_bios_version();
-       break;
-
-    case I8K_MACHINE_ID:
-       memset(buff, 0, 16);
-       val = i8k_get_serial_number(buff);
-       break;
-
-    case I8K_FN_STATUS:
-       val = i8k_get_fn_status();
-       break;
-
-    case I8K_POWER_STATUS:
-       val = i8k_get_power_status();
-       break;
-
-    case I8K_GET_TEMP:
-       val = i8k_get_cpu_temp();
-       break;
-
-    case I8K_GET_SPEED:
-       if (copy_from_user(&val, argp, sizeof(int))) {
-           return -EFAULT;
-       }
-       val = i8k_get_fan_speed(val);
-       break;
-
-    case I8K_GET_FAN:
-       if (copy_from_user(&val, argp, sizeof(int))) {
-           return -EFAULT;
-       }
-       val = i8k_get_fan_status(val);
-       break;
+       int val = 0;
+       int speed;
+       unsigned char buff[16];
+       int __user *argp = (int __user *)arg;
 
-    case I8K_SET_FAN:
-       if (restricted && !capable(CAP_SYS_ADMIN)) {
-           return -EPERM;
-       }
-       if (copy_from_user(&val, argp, sizeof(int))) {
-           return -EFAULT;
-       }
-       if (copy_from_user(&speed, argp+1, sizeof(int))) {
-           return -EFAULT;
-       }
-       val = i8k_set_fan(val, speed);
-       break;
+       if (!argp)
+               return -EINVAL;
 
-    default:
-       return -EINVAL;
-    }
+       switch (cmd) {
+       case I8K_BIOS_VERSION:
+               val = i8k_get_bios_version();
+               break;
 
-    if (val < 0) {
-       return val;
-    }
+       case I8K_MACHINE_ID:
+               memset(buff, 0, 16);
+               strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL), sizeof(buff));
+               break;
 
-    switch (cmd) {
-    case I8K_BIOS_VERSION:
-       if (copy_to_user(argp, &val, 4)) {
-           return -EFAULT;
-       }
-       break;
-    case I8K_MACHINE_ID:
-       if (copy_to_user(argp, buff, 16)) {
-           return -EFAULT;
-       }
-       break;
-    default:
-       if (copy_to_user(argp, &val, sizeof(int))) {
-           return -EFAULT;
-       }
-       break;
-    }
+       case I8K_FN_STATUS:
+               val = i8k_get_fn_status();
+               break;
 
-    return 0;
-}
+       case I8K_POWER_STATUS:
+               val = i8k_get_power_status();
+               break;
 
-/*
- * Print the information for /proc/i8k.
- */
-static int i8k_get_info(char *buffer, char **start, off_t fpos, int length)
-{
-    int n, fn_key, cpu_temp, ac_power;
-    int left_fan, right_fan, left_speed, right_speed;
-
-    cpu_temp     = i8k_get_cpu_temp();                 /* 11100 Âµs */
-    left_fan     = i8k_get_fan_status(I8K_FAN_LEFT);   /*   580 Âµs */
-    right_fan    = i8k_get_fan_status(I8K_FAN_RIGHT);  /*   580 Âµs */
-    left_speed   = i8k_get_fan_speed(I8K_FAN_LEFT);    /*   580 Âµs */
-    right_speed  = i8k_get_fan_speed(I8K_FAN_RIGHT);   /*   580 Âµs */
-    fn_key       = i8k_get_fn_status();                        /*   750 Âµs */
-    if (power_status) {
-       ac_power = i8k_get_power_status();              /* 14700 Âµs */
-    } else {
-       ac_power = -1;
-    }
-
-    /*
-     * Info:
-     *
-     * 1)  Format version (this will change if format changes)
-     * 2)  BIOS version
-     * 3)  BIOS machine ID
-     * 4)  Cpu temperature
-     * 5)  Left fan status
-     * 6)  Right fan status
-     * 7)  Left fan speed
-     * 8)  Right fan speed
-     * 9)  AC power
-     * 10) Fn Key status
-     */
-    n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n",
-               I8K_PROC_FMT,
-               bios_version,
-               serial_number,
-               cpu_temp,
-               left_fan,
-               right_fan,
-               left_speed,
-               right_speed,
-               ac_power,
-               fn_key);
-
-    return n;
-}
+       case I8K_GET_TEMP:
+               val = i8k_get_temp(0);
+               break;
 
-static ssize_t i8k_read(struct file *f, char __user *buffer, size_t len, loff_t *fpos)
-{
-    int n;
-    char info[128];
+       case I8K_GET_SPEED:
+               if (copy_from_user(&val, argp, sizeof(int)))
+                       return -EFAULT;
 
-    n = i8k_get_info(info, NULL, 0, 128);
-    if (n <= 0) {
-       return n;
-    }
+               val = i8k_get_fan_speed(val);
+               break;
 
-    if (*fpos >= n) {
-       return 0;
-    }
+       case I8K_GET_FAN:
+               if (copy_from_user(&val, argp, sizeof(int)))
+                       return -EFAULT;
 
-    if ((*fpos + len) >= n) {
-       len = n - *fpos;
-    }
+               val = i8k_get_fan_status(val);
+               break;
 
-    if (copy_to_user(buffer, info, len) != 0) {
-       return -EFAULT;
-    }
+       case I8K_SET_FAN:
+               if (restricted && !capable(CAP_SYS_ADMIN))
+                       return -EPERM;
 
-    *fpos += len;
-    return len;
-}
+               if (copy_from_user(&val, argp, sizeof(int)))
+                       return -EFAULT;
 
-static char* __init string_trim(char *s, int size)
-{
-    int len;
-    char *p;
+               if (copy_from_user(&speed, argp + 1, sizeof(int)))
+                       return -EFAULT;
 
-    if ((len = strlen(s)) > size) {
-       len = size;
-    }
+               val = i8k_set_fan(val, speed);
+               break;
 
-    for (p=s+len-1; len && (*p==' '); len--,p--) {
-       *p = '\0';
-    }
+       default:
+               return -EINVAL;
+       }
 
-    return s;
-}
+       if (val < 0)
+               return val;
 
-/* DMI code, stolen from arch/i386/kernel/dmi_scan.c */
+       switch (cmd) {
+       case I8K_BIOS_VERSION:
+               if (copy_to_user(argp, &val, 4))
+                       return -EFAULT;
 
-/*
- * |<-- dmi->length -->|
- * |                   |
- * |dmi header    s=N  | string1,\0, ..., stringN,\0, ..., \0
- *                |                       |
- *                +-----------------------+
- */
-static char* __init dmi_string(DMIHeader *dmi, u8 s)
-{
-    u8 *p;
+               break;
+       case I8K_MACHINE_ID:
+               if (copy_to_user(argp, buff, 16))
+                       return -EFAULT;
 
-    if (!s) {
-       return "";
-    }
-    s--;
+               break;
+       default:
+               if (copy_to_user(argp, &val, sizeof(int)))
+                       return -EFAULT;
 
-    p = (u8 *)dmi + dmi->length;
-    while (s > 0) {
-       p += strlen(p);
-       p++;
-       s--;
-    }
+               break;
+       }
 
-    return p;
+       return 0;
 }
 
-static void __init dmi_decode(DMIHeader *dmi)
+/*
+ * Print the information for /proc/i8k.
+ */
+static int i8k_proc_show(struct seq_file *seq, void *offset)
 {
-    u8 *data = (u8 *) dmi;
-    char *p;
-
-#ifdef I8K_DEBUG
-    int i;
-    printk("%08x ", (int)data);
-    for (i=0; i<data[1] && i<64; i++) {
-       printk("%02x ", data[i]);
-    }
-    printk("\n");
-#endif
-
-    switch (dmi->type) {
-    case  0:   /* BIOS Information */
-       p = dmi_string(dmi,data[5]);
-       if (*p) {
-           strlcpy(bios_version, p, sizeof(bios_version));
-           string_trim(bios_version, sizeof(bios_version));
-       }
-       break;  
-    case 1:    /* System Information */
-       p = dmi_string(dmi,data[4]);
-       if (*p) {
-           strlcpy(system_vendor, p, sizeof(system_vendor));
-           string_trim(system_vendor, sizeof(system_vendor));
-       }
-       p = dmi_string(dmi,data[5]);
-       if (*p) {
-           strlcpy(product_name, p, sizeof(product_name));
-           string_trim(product_name, sizeof(product_name));
-       }
-       p = dmi_string(dmi,data[7]);
-       if (*p) {
-           strlcpy(serial_number, p, sizeof(serial_number));
-           string_trim(serial_number, sizeof(serial_number));
-       }
-       break;
-    }
-}
+       int fn_key, cpu_temp, ac_power;
+       int left_fan, right_fan, left_speed, right_speed;
+
+       cpu_temp        = i8k_get_temp(0);                      /* 11100 Âµs */
+       left_fan        = i8k_get_fan_status(I8K_FAN_LEFT);     /*   580 Âµs */
+       right_fan       = i8k_get_fan_status(I8K_FAN_RIGHT);    /*   580 Âµs */
+       left_speed      = i8k_get_fan_speed(I8K_FAN_LEFT);      /*   580 Âµs */
+       right_speed     = i8k_get_fan_speed(I8K_FAN_RIGHT);     /*   580 Âµs */
+       fn_key          = i8k_get_fn_status();                  /*   750 Âµs */
+       if (power_status)
+               ac_power = i8k_get_power_status();              /* 14700 Âµs */
+       else
+               ac_power = -1;
 
-static int __init dmi_table(u32 base, int len, int num, void (*fn)(DMIHeader*))
-{
-    u8 *buf;
-    u8 *data;
-    DMIHeader *dmi;
-    int i = 1;
-
-    buf = ioremap(base, len);
-    if (buf == NULL) {
-       return -1;
-    }
-    data = buf;
-
-    /*
-     * Stop when we see al the items the table claimed to have
-     * or we run off the end of the table (also happens)
-     */
-    while ((i<num) && ((data-buf) < len)) {
-       dmi = (DMIHeader *)data;
-       /*
-        * Avoid misparsing crud if the length of the last
-        * record is crap
-        */
-       if ((data-buf+dmi->length) >= len) {
-           break;
-       }
-       fn(dmi);
-       data += dmi->length;
        /*
-        * Don't go off the end of the data if there is
-        * stuff looking like string fill past the end
+        * Info:
+        *
+        * 1)  Format version (this will change if format changes)
+        * 2)  BIOS version
+        * 3)  BIOS machine ID
+        * 4)  Cpu temperature
+        * 5)  Left fan status
+        * 6)  Right fan status
+        * 7)  Left fan speed
+        * 8)  Right fan speed
+        * 9)  AC power
+        * 10) Fn Key status
         */
-       while (((data-buf) < len) && (*data || data[1])) {
-           data++;
-       }
-       data += 2;
-       i++;
-    }
-    iounmap(buf);
-
-    return 0;
+       return seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n",
+                         I8K_PROC_FMT,
+                         bios_version,
+                         dmi_get_system_info(DMI_PRODUCT_SERIAL) ? : "N/A",
+                         cpu_temp,
+                         left_fan, right_fan, left_speed, right_speed,
+                         ac_power, fn_key);
 }
 
-static int __init dmi_iterate(void (*decode)(DMIHeader *))
+static int i8k_open_fs(struct inode *inode, struct file *file)
 {
-       unsigned char buf[20];
-       void __iomem *p = ioremap(0xe0000, 0x20000), *q;
-
-       if (!p)
-               return -1;
-
-       for (q = p; q < p + 0x20000; q += 16) {
-               memcpy_fromio(buf, q, 20);
-               if (memcmp(buf, "_DMI_", 5)==0) {
-                       u16 num  = buf[13]<<8  | buf[12];
-                       u16 len  = buf [7]<<8  | buf [6];
-                       u32 base = buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8];
-#ifdef I8K_DEBUG
-                       printk(KERN_INFO "DMI %d.%d present.\n",
-                          buf[14]>>4, buf[14]&0x0F);
-                       printk(KERN_INFO "%d structures occupying %d bytes.\n",
-                          buf[13]<<8 | buf[12],
-                          buf [7]<<8 | buf[6]);
-                       printk(KERN_INFO "DMI table at 0x%08X.\n",
-                          buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]);
-#endif
-                       if (dmi_table(base, len, num, decode)==0) {
-                               iounmap(p);
-                               return 0;
-                       }
-               }
-       }
-       iounmap(p);
-       return -1;
+       return single_open(file, i8k_proc_show, NULL);
 }
-/* end of DMI code */
-
-/*
- * Get DMI information.
- */
-static int __init i8k_dmi_probe(void)
-{
-    char **p;
-
-    if (dmi_iterate(dmi_decode) != 0) {
-       printk(KERN_INFO "i8k: unable to get DMI information\n");
-       return -ENODEV;
-    }
-
-    if (strncmp(system_vendor,DELL_SIGNATURE,strlen(DELL_SIGNATURE)) != 0) {
-       printk(KERN_INFO "i8k: not running on a Dell system\n");
-       return -ENODEV;
-    }
-
-    for (p=supported_models; ; p++) {
-       if (!*p) {
-           printk(KERN_INFO "i8k: unsupported model: %s\n", product_name);
-           return -ENODEV;
-       }
-       if (strncmp(product_name,*p,strlen(*p)) == 0) {
-           break;
-       }
-    }
 
-    return 0;
-}
+static struct dmi_system_id __initdata i8k_dmi_table[] = {
+       {
+               .ident = "Dell Inspiron",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"),
+               },
+       },
+       {
+               .ident = "Dell Latitude",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
+               },
+       },
+       {
+               .ident = "Dell Inspiron 2",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"),
+               },
+       },
+       {
+               .ident = "Dell Latitude 2",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
+               },
+       },
+       { }
+};
 
 /*
  * Probe for the presence of a supported laptop.
  */
 static int __init i8k_probe(void)
 {
-    char buff[4];
-    int version;
-    int smm_found = 0;
-
-    /*
-     * Get DMI information
-     */
-    if (i8k_dmi_probe() != 0) {
-       printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n",
-              system_vendor, product_name, bios_version);
-    }
-
-    /*
-     * Get SMM Dell signature
-     */
-    if (i8k_get_dell_signature() != 0) {
-       printk(KERN_INFO "i8k: unable to get SMM Dell signature\n");
-    } else {
-       smm_found = 1;
-    }
-
-    /*
-     * Get SMM BIOS version.
-     */
-    version = i8k_get_bios_version();
-    if (version <= 0) {
-       printk(KERN_INFO "i8k: unable to get SMM BIOS version\n");
-    } else {
-       smm_found = 1;
-       buff[0] = (version >> 16) & 0xff;
-       buff[1] = (version >>  8) & 0xff;
-       buff[2] = (version)       & 0xff;
-       buff[3] = '\0';
+       char buff[4];
+       int version;
+
        /*
-        * If DMI BIOS version is unknown use SMM BIOS version.
+        * Get DMI information
         */
-       if (bios_version[0] == '?') {
-           strcpy(bios_version, buff);
+       if (!dmi_check_system(i8k_dmi_table)) {
+               if (!ignore_dmi && !force)
+                       return -ENODEV;
+
+               printk(KERN_INFO "i8k: not running on a supported Dell system.\n");
+               printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n",
+                       i8k_get_dmi_data(DMI_SYS_VENDOR),
+                       i8k_get_dmi_data(DMI_PRODUCT_NAME),
+                       i8k_get_dmi_data(DMI_BIOS_VERSION));
        }
+
+       strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), sizeof(bios_version));
+
        /*
-        * Check if the two versions match.
+        * Get SMM Dell signature
         */
-       if (strncmp(buff,bios_version,sizeof(bios_version)) != 0) {
-           printk(KERN_INFO "i8k: BIOS version mismatch: %s != %s\n",
-                  buff, bios_version);
+       if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) &&
+           i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) {
+               printk(KERN_ERR "i8k: unable to get SMM Dell signature\n");
+               if (!force)
+                       return -ENODEV;
        }
-    }
 
-    if (!smm_found && !force) {
-       return -ENODEV;
-    }
+       /*
+        * Get SMM BIOS version.
+        */
+       version = i8k_get_bios_version();
+       if (version <= 0) {
+               printk(KERN_WARNING "i8k: unable to get SMM BIOS version\n");
+       } else {
+               buff[0] = (version >> 16) & 0xff;
+               buff[1] = (version >> 8) & 0xff;
+               buff[2] = (version) & 0xff;
+               buff[3] = '\0';
+               /*
+                * If DMI BIOS version is unknown use SMM BIOS version.
+                */
+               if (!dmi_get_system_info(DMI_BIOS_VERSION))
+                       strlcpy(bios_version, buff, sizeof(bios_version));
+
+               /*
+                * Check if the two versions match.
+                */
+               if (strncmp(buff, bios_version, sizeof(bios_version)) != 0)
+                       printk(KERN_WARNING "i8k: BIOS version mismatch: %s != %s\n",
+                               buff, bios_version);
+       }
 
-    return 0;
+       return 0;
 }
 
-#ifdef MODULE
-static
-#endif
-int __init i8k_init(void)
+static int __init i8k_init(void)
 {
-    struct proc_dir_entry *proc_i8k;
-
-    /* Are we running on an supported laptop? */
-    if (i8k_probe() != 0) {
-       return -ENODEV;
-    }
-
-    /* Register the proc entry */
-    proc_i8k = create_proc_info_entry("i8k", 0, NULL, i8k_get_info);
-    if (!proc_i8k) {
-       return -ENOENT;
-    }
-    proc_i8k->proc_fops = &i8k_fops;
-    proc_i8k->owner = THIS_MODULE;
-
-    printk(KERN_INFO
-          "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
-          I8K_VERSION);
-
-    return 0;
-}
+       struct proc_dir_entry *proc_i8k;
 
-#ifdef MODULE
-int init_module(void)
-{
-    return i8k_init();
+       /* Are we running on an supported laptop? */
+       if (i8k_probe())
+               return -ENODEV;
+
+       /* Register the proc entry */
+       proc_i8k = create_proc_entry("i8k", 0, NULL);
+       if (!proc_i8k)
+               return -ENOENT;
+
+       proc_i8k->proc_fops = &i8k_fops;
+       proc_i8k->owner = THIS_MODULE;
+
+       printk(KERN_INFO
+              "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
+              I8K_VERSION);
+
+       return 0;
 }
 
-void cleanup_module(void)
+static void __exit i8k_exit(void)
 {
-    /* Remove the proc entry */
-    remove_proc_entry("i8k", NULL);
-
-    printk(KERN_INFO "i8k: module unloaded\n");
+       remove_proc_entry("i8k", NULL);
 }
-#endif
 
-/* end of file */
+module_init(i8k_init);
+module_exit(i8k_exit);
index fd299d6c42ace5165643511d3ce9441b02d32e31..cb8f4198e9a34291b8cd67e41ee0f969741ac0ad 100644 (file)
@@ -97,7 +97,7 @@ static UCHAR ct41[] = { 1, BYP,     0x29                     }; // RESUME
 //static UCHAR ct44[]={ 2, BTH,     0x2C,0                   }; // MS PING
 //static UCHAR ct45[]={ 1, BTH,     0x2D                     }; // HOTENAB
 //static UCHAR ct46[]={ 1, BTH,     0x2E                     }; // HOTDSAB
-static UCHAR ct47[] = { 7, BTH,     0x2F,0,0,0,0,0,0         }; // UNIX FLAGS
+//static UCHAR ct47[]={ 7, BTH,     0x2F,0,0,0,0,0,0         }; // UNIX FLAGS
 //static UCHAR ct48[]={ 1, BTH,     0x30                     }; // DSRFLOWENAB
 //static UCHAR ct49[]={ 1, BTH,     0x31                     }; // DSRFLOWDSAB
 //static UCHAR ct50[]={ 1, BTH,     0x32                     }; // DTRFLOWENAB
@@ -162,6 +162,7 @@ static UCHAR ct89[]={ 1, BYP,     0x59                     }; // DSS_NOW
 // This routine sets the parameters of command 47 and returns a pointer to the
 // appropriate structure.
 //******************************************************************************
+#if 0
 cmdSyntaxPtr
 i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag)
 {
@@ -175,6 +176,7 @@ i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag)
        pCM->cmd[6] = (unsigned char) (lflag >> 8);
        return pCM;
 }
+#endif  /*  0  */
 
 //******************************************************************************
 // Function:   i2cmdBaudDef(which, rate)
@@ -187,7 +189,7 @@ i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag)
 // This routine sets the parameters of commands 54 or 55 (according to the
 // argument which), and returns a pointer to the appropriate structure.
 //******************************************************************************
-cmdSyntaxPtr
+static cmdSyntaxPtr
 i2cmdBaudDef(int which, unsigned short rate)
 {
        cmdSyntaxPtr pCM;
index c41728a857101062c009eae9286a44ade839b166..baa4e721b758d84b5b5d59c7dc943cb33b1fe2d5 100644 (file)
@@ -64,16 +64,6 @@ typedef struct _cmdSyntax
                                                // directly from user-level
 #define VAR 0x10        // This command is of variable length!
 
-//-----------------------------------
-// External declarations for i2cmd.c
-//-----------------------------------
-// Routine to set up parameters for the "define hot-key sequence" command. Since
-// there is more than one parameter to assign, we must use a function rather
-// than a macro (used usually).
-//
-extern cmdSyntaxPtr i2cmdUnixFlags(USHORT iflag,USHORT cflag,USHORT lflag);
-extern cmdSyntaxPtr i2cmdBaudDef(int which, USHORT rate);
-
 // Declarations for the global arrays used to bear the commands and their
 // arguments.
 //
@@ -433,6 +423,7 @@ static UCHAR cc02[];
 #define CMD_HOT_ENAB (cmdSyntaxPtr)(ct45) // Enable Hot-key checking
 #define CMD_HOT_DSAB (cmdSyntaxPtr)(ct46) // Disable Hot-key checking
 
+#if 0
 // COMMAND 47: Send Protocol info via Unix flags:
 // iflag = Unix tty t_iflag
 // cflag = Unix tty t_cflag
@@ -441,6 +432,7 @@ static UCHAR cc02[];
 // within these flags
 //
 #define CMD_UNIX_FLAGS(iflag,cflag,lflag) i2cmdUnixFlags(iflag,cflag,lflag)
+#endif  /*  0  */
 
 #define CMD_DSRFL_ENAB  (cmdSyntaxPtr)(ct48) // Enable  DSR receiver ctrl
 #define CMD_DSRFL_DSAB  (cmdSyntaxPtr)(ct49) // Disable DSR receiver ctrl
index 3b8314b4249ac902b5da172c20a781191956afa2..cf0cd58d630571c44746cc0d7c073c2f916b164b 100644 (file)
@@ -2691,16 +2691,6 @@ no_xon:
                pCh->flags      |= ASYNC_CHECK_CD;
        }
 
-#ifdef XXX
-do_flags_thing:        // This is a test, we don't do the flags thing
-       
-       if ( (cflag & CRTSCTS) ) {
-               cflag |= 014000000000;
-       }
-       i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, 
-                               CMD_UNIX_FLAGS(iflag,cflag,lflag));
-#endif
-               
 service_it:
        i2DrainOutput( pCh, 100 );              
 }
index 88d1ad656e99a2df138122225992d7cb91f3d728..e0a53570fea1a755485a90f1aa59c8778d753b26 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/semaphore.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/compat.h>
 
 #define IPMI_DEVINTF_VERSION "v33"
 
@@ -500,10 +501,205 @@ static int ipmi_ioctl(struct inode  *inode,
        return rv;
 }
 
+#ifdef CONFIG_COMPAT
+
+/*
+ * The following code contains code for supporting 32-bit compatible
+ * ioctls on 64-bit kernels.  This allows running 32-bit apps on the
+ * 64-bit kernel
+ */
+#define COMPAT_IPMICTL_SEND_COMMAND    \
+       _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
+#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME    \
+       _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
+#define COMPAT_IPMICTL_RECEIVE_MSG     \
+       _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
+#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC       \
+       _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)
+
+struct compat_ipmi_msg {
+       u8              netfn;
+       u8              cmd;
+       u16             data_len;
+       compat_uptr_t   data;
+};
+
+struct compat_ipmi_req {
+       compat_uptr_t           addr;
+       compat_uint_t           addr_len;
+       compat_long_t           msgid;
+       struct compat_ipmi_msg  msg;
+};
+
+struct compat_ipmi_recv {
+       compat_int_t            recv_type;
+       compat_uptr_t           addr;
+       compat_uint_t           addr_len;
+       compat_long_t           msgid;
+       struct compat_ipmi_msg  msg;
+};
+
+struct compat_ipmi_req_settime {
+       struct compat_ipmi_req  req;
+       compat_int_t            retries;
+       compat_uint_t           retry_time_ms;
+};
+
+/*
+ * Define some helper functions for copying IPMI data
+ */
+static long get_compat_ipmi_msg(struct ipmi_msg *p64,
+                               struct compat_ipmi_msg __user *p32)
+{
+       compat_uptr_t tmp;
+
+       if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
+                       __get_user(p64->netfn, &p32->netfn) ||
+                       __get_user(p64->cmd, &p32->cmd) ||
+                       __get_user(p64->data_len, &p32->data_len) ||
+                       __get_user(tmp, &p32->data))
+               return -EFAULT;
+       p64->data = compat_ptr(tmp);
+       return 0;
+}
+
+static long put_compat_ipmi_msg(struct ipmi_msg *p64,
+                               struct compat_ipmi_msg __user *p32)
+{
+       if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
+                       __put_user(p64->netfn, &p32->netfn) ||
+                       __put_user(p64->cmd, &p32->cmd) ||
+                       __put_user(p64->data_len, &p32->data_len))
+               return -EFAULT;
+       return 0;
+}
+
+static long get_compat_ipmi_req(struct ipmi_req *p64,
+                               struct compat_ipmi_req __user *p32)
+{
+
+       compat_uptr_t   tmp;
+
+       if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
+                       __get_user(tmp, &p32->addr) ||
+                       __get_user(p64->addr_len, &p32->addr_len) ||
+                       __get_user(p64->msgid, &p32->msgid) ||
+                       get_compat_ipmi_msg(&p64->msg, &p32->msg))
+               return -EFAULT;
+       p64->addr = compat_ptr(tmp);
+       return 0;
+}
+
+static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
+               struct compat_ipmi_req_settime __user *p32)
+{
+       if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
+                       get_compat_ipmi_req(&p64->req, &p32->req) ||
+                       __get_user(p64->retries, &p32->retries) ||
+                       __get_user(p64->retry_time_ms, &p32->retry_time_ms))
+               return -EFAULT;
+       return 0;
+}
+
+static long get_compat_ipmi_recv(struct ipmi_recv *p64,
+                                struct compat_ipmi_recv __user *p32)
+{
+       compat_uptr_t tmp;
+
+       if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
+                       __get_user(p64->recv_type, &p32->recv_type) ||
+                       __get_user(tmp, &p32->addr) ||
+                       __get_user(p64->addr_len, &p32->addr_len) ||
+                       __get_user(p64->msgid, &p32->msgid) ||
+                       get_compat_ipmi_msg(&p64->msg, &p32->msg))
+               return -EFAULT;
+       p64->addr = compat_ptr(tmp);
+       return 0;
+}
+
+static long put_compat_ipmi_recv(struct ipmi_recv *p64,
+                                struct compat_ipmi_recv __user *p32)
+{
+       if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
+                       __put_user(p64->recv_type, &p32->recv_type) ||
+                       __put_user(p64->addr_len, &p32->addr_len) ||
+                       __put_user(p64->msgid, &p32->msgid) ||
+                       put_compat_ipmi_msg(&p64->msg, &p32->msg))
+               return -EFAULT;
+       return 0;
+}
+
+/*
+ * Handle compatibility ioctls
+ */
+static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
+                             unsigned long arg)
+{
+       int rc;
+       struct ipmi_file_private *priv = filep->private_data;
+
+       switch(cmd) {
+       case COMPAT_IPMICTL_SEND_COMMAND:
+       {
+               struct ipmi_req rp;
+
+               if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
+                       return -EFAULT;
+
+               return handle_send_req(priv->user, &rp,
+                               priv->default_retries,
+                               priv->default_retry_time_ms);
+       }
+       case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
+       {
+               struct ipmi_req_settime sp;
+
+               if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
+                       return -EFAULT;
+
+               return handle_send_req(priv->user, &sp.req,
+                               sp.retries, sp.retry_time_ms);
+       }
+       case COMPAT_IPMICTL_RECEIVE_MSG:
+       case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
+       {
+               struct ipmi_recv   *precv64, recv64;
+
+               if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
+                       return -EFAULT;
+
+               precv64 = compat_alloc_user_space(sizeof(recv64));
+               if (copy_to_user(precv64, &recv64, sizeof(recv64)))
+                       return -EFAULT;
+
+               rc = ipmi_ioctl(filep->f_dentry->d_inode, filep,
+                               ((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
+                                ? IPMICTL_RECEIVE_MSG
+                                : IPMICTL_RECEIVE_MSG_TRUNC),
+                               (long) precv64);
+               if (rc != 0)
+                       return rc;
+
+               if (copy_from_user(&recv64, precv64, sizeof(recv64)))
+                       return -EFAULT;
+
+               if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
+                       return -EFAULT;
+
+               return rc;
+       }
+       default:
+               return ipmi_ioctl(filep->f_dentry->d_inode, filep, cmd, arg);
+       }
+}
+#endif
 
 static struct file_operations ipmi_fops = {
        .owner          = THIS_MODULE,
        .ioctl          = ipmi_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = compat_ipmi_ioctl,
+#endif
        .open           = ipmi_open,
        .release        = ipmi_release,
        .fasync         = ipmi_fasync,
index 0c81652eaba65cc7895cb740a00a4bfdcffbd79f..e16c13fe698dff7c71ad27508d64904f84be80be 100644 (file)
@@ -54,7 +54,9 @@ static int ipmi_init_msghandler(void);
 
 static int initialized = 0;
 
-static struct proc_dir_entry *proc_ipmi_root = NULL;
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *proc_ipmi_root = NULL;
+#endif /* CONFIG_PROC_FS */
 
 #define MAX_EVENTS_IN_QUEUE    25
 
@@ -124,11 +126,13 @@ struct ipmi_channel
        unsigned char protocol;
 };
 
+#ifdef CONFIG_PROC_FS
 struct ipmi_proc_entry
 {
        char                   *name;
        struct ipmi_proc_entry *next;
 };
+#endif
 
 #define IPMI_IPMB_NUM_SEQ      64
 #define IPMI_MAX_CHANNELS       8
@@ -156,10 +160,13 @@ struct ipmi_smi
        struct ipmi_smi_handlers *handlers;
        void                     *send_info;
 
+#ifdef CONFIG_PROC_FS
        /* A list of proc entries for this interface.  This does not
           need a lock, only one thread creates it and only one thread
           destroys it. */
+       spinlock_t             proc_entry_lock;
        struct ipmi_proc_entry *proc_entries;
+#endif
 
        /* A table of sequence numbers for this interface.  We use the
            sequence numbers for IPMB messages that go out of the
@@ -1081,8 +1088,8 @@ static inline int i_ipmi_request(ipmi_user_t          user,
                long                  seqid;
                int                   broadcast = 0;
 
-               if (addr->channel > IPMI_NUM_CHANNELS) {
-                       spin_lock_irqsave(&intf->counter_lock, flags);
+               if (addr->channel >= IPMI_MAX_CHANNELS) {
+                       spin_lock_irqsave(&intf->counter_lock, flags);
                        intf->sent_invalid_commands++;
                        spin_unlock_irqrestore(&intf->counter_lock, flags);
                        rv = -EINVAL;
@@ -1470,8 +1477,9 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
                            read_proc_t *read_proc, write_proc_t *write_proc,
                            void *data, struct module *owner)
 {
-       struct proc_dir_entry  *file;
        int                    rv = 0;
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry  *file;
        struct ipmi_proc_entry *entry;
 
        /* Create a list element. */
@@ -1497,10 +1505,13 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
                file->write_proc = write_proc;
                file->owner = owner;
 
+               spin_lock(&smi->proc_entry_lock);
                /* Stick it on the list. */
                entry->next = smi->proc_entries;
                smi->proc_entries = entry;
+               spin_unlock(&smi->proc_entry_lock);
        }
+#endif /* CONFIG_PROC_FS */
 
        return rv;
 }
@@ -1509,6 +1520,7 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
 {
        int rv = 0;
 
+#ifdef CONFIG_PROC_FS
        sprintf(smi->proc_dir_name, "%d", num);
        smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
        if (!smi->proc_dir)
@@ -1531,14 +1543,17 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
                rv = ipmi_smi_add_proc_entry(smi, "version",
                                             version_file_read_proc, NULL,
                                             smi, THIS_MODULE);
+#endif /* CONFIG_PROC_FS */
 
        return rv;
 }
 
 static void remove_proc_entries(ipmi_smi_t smi)
 {
+#ifdef CONFIG_PROC_FS
        struct ipmi_proc_entry *entry;
 
+       spin_lock(&smi->proc_entry_lock);
        while (smi->proc_entries) {
                entry = smi->proc_entries;
                smi->proc_entries = entry->next;
@@ -1547,7 +1562,9 @@ static void remove_proc_entries(ipmi_smi_t smi)
                kfree(entry->name);
                kfree(entry);
        }
+       spin_unlock(&smi->proc_entry_lock);
        remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
+#endif /* CONFIG_PROC_FS */
 }
 
 static int
@@ -1694,6 +1711,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
                                new_intf->seq_table[j].seqid = 0;
                        }
                        new_intf->curr_seq = 0;
+#ifdef CONFIG_PROC_FS
+                       spin_lock_init(&(new_intf->proc_entry_lock));
+#endif
                        spin_lock_init(&(new_intf->waiting_msgs_lock));
                        INIT_LIST_HEAD(&(new_intf->waiting_msgs));
                        spin_lock_init(&(new_intf->events_lock));
@@ -2747,16 +2767,13 @@ static struct timer_list ipmi_timer;
    the queue and this silliness can go away. */
 #define IPMI_REQUEST_EV_TIME   (1000 / (IPMI_TIMEOUT_TIME))
 
-static volatile int stop_operation = 0;
-static volatile int timer_stopped = 0;
+static atomic_t stop_operation;
 static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
 
 static void ipmi_timeout(unsigned long data)
 {
-       if (stop_operation) {
-               timer_stopped = 1;
+       if (atomic_read(&stop_operation))
                return;
-       }
 
        ticks_to_req_ev--;
        if (ticks_to_req_ev == 0) {
@@ -2766,8 +2783,7 @@ static void ipmi_timeout(unsigned long data)
 
        ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
 
-       ipmi_timer.expires += IPMI_TIMEOUT_JIFFIES;
-       add_timer(&ipmi_timer);
+       mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
 }
 
 
@@ -3089,6 +3105,7 @@ static int ipmi_init_msghandler(void)
                ipmi_interfaces[i] = NULL;
        }
 
+#ifdef CONFIG_PROC_FS
        proc_ipmi_root = proc_mkdir("ipmi", NULL);
        if (!proc_ipmi_root) {
            printk(KERN_ERR PFX "Unable to create IPMI proc dir");
@@ -3096,6 +3113,7 @@ static int ipmi_init_msghandler(void)
        }
 
        proc_ipmi_root->owner = THIS_MODULE;
+#endif /* CONFIG_PROC_FS */
 
        init_timer(&ipmi_timer);
        ipmi_timer.data = 0;
@@ -3130,13 +3148,12 @@ static __exit void cleanup_ipmi(void)
 
        /* Tell the timer to stop, then wait for it to stop.  This avoids
           problems with race conditions removing the timer here. */
-       stop_operation = 1;
-       while (!timer_stopped) {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(1);
-       }
+       atomic_inc(&stop_operation);
+       del_timer_sync(&ipmi_timer);
 
+#ifdef CONFIG_PROC_FS
        remove_proc_entry(proc_ipmi_root->name, &proc_root);
+#endif /* CONFIG_PROC_FS */
 
        initialized = 0;
 
@@ -3177,4 +3194,5 @@ EXPORT_SYMBOL(ipmi_get_my_address);
 EXPORT_SYMBOL(ipmi_set_my_LUN);
 EXPORT_SYMBOL(ipmi_get_my_LUN);
 EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
+EXPORT_SYMBOL(proc_ipmi_root);
 EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
index cb5cdc6f14bf021a43fe9af5996f22f2e84601a2..f951c30236c98aac5ed60473073118793a242924 100644 (file)
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
-#include <asm/semaphore.h>
-#include <linux/kdev_t.h>
+#include <linux/config.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/proc_fs.h>
 #include <linux/string.h>
+#include <linux/completion.h>
+#include <linux/kdev_t.h>
 #include <linux/ipmi.h>
 #include <linux/ipmi_smi.h>
 
 /* Where to we insert our poweroff function? */
 extern void (*pm_power_off)(void);
 
+/* Definitions for controlling power off (if the system supports it).  It
+ * conveniently matches the IPMI chassis control values. */
+#define IPMI_CHASSIS_POWER_DOWN                0       /* power down, the default. */
+#define IPMI_CHASSIS_POWER_CYCLE       0x02    /* power cycle */
+
+/* the IPMI data command */
+static int poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+
+/* parameter definition to allow user to flag power cycle */
+module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN);
+MODULE_PARM_DESC(poweroff_control, " Set to 2 to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down.");
+
 /* Stuff from the get device id command. */
 static unsigned int mfg_id;
 static unsigned int prod_id;
@@ -75,10 +90,10 @@ static struct ipmi_recv_msg halt_recv_msg =
 
 static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data)
 {
-       struct semaphore *sem = recv_msg->user_msg_data;
+       struct completion *comp = recv_msg->user_msg_data;
 
-       if (sem)
-               up(sem);
+       if (comp)
+               complete(comp);
 }
 
 static struct ipmi_user_hndl ipmi_poweroff_handler =
@@ -91,27 +106,27 @@ static int ipmi_request_wait_for_response(ipmi_user_t            user,
                                          struct ipmi_addr       *addr,
                                          struct kernel_ipmi_msg *send_msg)
 {
-       int              rv;
-       struct semaphore sem;
+       int               rv;
+       struct completion comp;
 
-       sema_init (&sem, 0);
+       init_completion(&comp);
 
-       rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &sem,
+       rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &comp,
                                      &halt_smi_msg, &halt_recv_msg, 0);
        if (rv)
                return rv;
 
-       down (&sem);
+       wait_for_completion(&comp);
 
        return halt_recv_msg.msg.data[0];
 }
 
-/* We are in run-to-completion mode, no semaphore is desired. */
+/* We are in run-to-completion mode, no completion is desired. */
 static int ipmi_request_in_rc_mode(ipmi_user_t            user,
                                   struct ipmi_addr       *addr,
                                   struct kernel_ipmi_msg *send_msg)
 {
-       int              rv;
+       int rv;
 
        rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL,
                                      &halt_smi_msg, &halt_recv_msg, 0);
@@ -349,26 +364,38 @@ static void ipmi_poweroff_chassis (ipmi_user_t user)
         smi_addr.channel = IPMI_BMC_CHANNEL;
         smi_addr.lun = 0;
 
-       printk(KERN_INFO PFX "Powering down via IPMI chassis control command\n");
+ powercyclefailed:
+       printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n",
+               ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle"));
 
        /*
         * Power down
         */
        send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
        send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD;
-       data[0] = 0; /* Power down */
+       data[0] = poweroff_control;
        send_msg.data = data;
        send_msg.data_len = sizeof(data);
        rv = ipmi_request_in_rc_mode(user,
                                     (struct ipmi_addr *) &smi_addr,
                                     &send_msg);
        if (rv) {
-               printk(KERN_ERR PFX "Unable to send chassis powerdown message,"
-                      " IPMI error 0x%x\n", rv);
-               goto out;
+               switch (poweroff_control) {
+                       case IPMI_CHASSIS_POWER_CYCLE:
+                               /* power cycle failed, default to power down */
+                               printk(KERN_ERR PFX "Unable to send chassis power " \
+                                       "cycle message, IPMI error 0x%x\n", rv);
+                               poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+                               goto powercyclefailed;
+
+                       case IPMI_CHASSIS_POWER_DOWN:
+                       default:
+                               printk(KERN_ERR PFX "Unable to send chassis power " \
+                                       "down message, IPMI error 0x%x\n", rv);
+                               break;
+               }
        }
 
- out:
        return;
 }
 
@@ -430,7 +457,8 @@ static void ipmi_po_new_smi(int if_num)
        if (ready)
                return;
 
-       rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, &ipmi_user);
+       rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL,
+                             &ipmi_user);
        if (rv) {
                printk(KERN_ERR PFX "could not create IPMI user, error %d\n",
                       rv);
@@ -509,21 +537,84 @@ static struct ipmi_smi_watcher smi_watcher =
 };
 
 
+#ifdef CONFIG_PROC_FS
+/* displays properties to proc */
+static int proc_read_chassctrl(char *page, char **start, off_t off, int count,
+                              int *eof, void *data)
+{
+       return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n",
+                       poweroff_control);
+}
+
+/* process property writes from proc */
+static int proc_write_chassctrl(struct file *file, const char *buffer,
+                               unsigned long count, void *data)
+{
+       int          rv = count;
+       unsigned int newval = 0;
+
+       sscanf(buffer, "%d", &newval);
+       switch (newval) {
+               case IPMI_CHASSIS_POWER_CYCLE:
+                       printk(KERN_INFO PFX "power cycle is now enabled\n");
+                       poweroff_control = newval;
+                       break;
+
+               case IPMI_CHASSIS_POWER_DOWN:
+                       poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+                       break;
+
+               default:
+                       rv = -EINVAL;
+                       break;
+       }
+
+       return rv;
+}
+#endif /* CONFIG_PROC_FS */
+
 /*
  * Startup and shutdown functions.
  */
 static int ipmi_poweroff_init (void)
 {
-       int rv;
+       int                   rv;
+       struct proc_dir_entry *file;
 
        printk ("Copyright (C) 2004 MontaVista Software -"
                " IPMI Powerdown via sys_reboot version "
                IPMI_POWEROFF_VERSION ".\n");
 
+       switch (poweroff_control) {
+               case IPMI_CHASSIS_POWER_CYCLE:
+                       printk(KERN_INFO PFX "Power cycle is enabled.\n");
+                       break;
+
+               case IPMI_CHASSIS_POWER_DOWN:
+               default:
+                       poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+                       break;
+       }
+
        rv = ipmi_smi_watcher_register(&smi_watcher);
-       if (rv)
+       if (rv) {
                printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
+               goto out_err;
+       }
+
+#ifdef CONFIG_PROC_FS
+       file = create_proc_entry("poweroff_control", 0, proc_ipmi_root);
+       if (!file) {
+               printk(KERN_ERR PFX "Unable to create proc power control\n");
+       } else {
+               file->nlink = 1;
+               file->read_proc = proc_read_chassctrl;
+               file->write_proc = proc_write_chassctrl;
+               file->owner = THIS_MODULE;
+       }
+#endif
 
+ out_err:
        return rv;
 }
 
@@ -532,6 +623,10 @@ static __exit void ipmi_poweroff_cleanup(void)
 {
        int rv;
 
+#ifdef CONFIG_PROC_FS
+       remove_proc_entry("poweroff_control", proc_ipmi_root);
+#endif
+
        ipmi_smi_watcher_unregister(&smi_watcher);
 
        if (ready) {
index 601c7fccb4cfbed7a316507a302953467ccf56fd..1bbf507adda5ee2d43b8d5772dd8e7b273577a93 100644 (file)
@@ -1756,7 +1756,7 @@ static void isicom_flush_buffer(struct tty_struct * tty)
 }
 
 
-static int __init register_ioregion(void)
+static int __devinit register_ioregion(void)
 {
        int count, done=0;
        for (count=0; count < BOARD_COUNT; count++ ) {
@@ -1771,7 +1771,7 @@ static int __init register_ioregion(void)
        return done;
 }
 
-static void __exit unregister_ioregion(void)
+static void unregister_ioregion(void)
 {
        int count;
        for (count=0; count < BOARD_COUNT; count++ ) 
@@ -1803,7 +1803,7 @@ static struct tty_operations isicom_ops = {
        .tiocmset       = isicom_tiocmset,
 };
 
-static int __init register_drivers(void)
+static int __devinit register_drivers(void)
 {
        int error;
 
@@ -1834,7 +1834,7 @@ static int __init register_drivers(void)
        return 0;
 }
 
-static void __exit unregister_drivers(void)
+static void unregister_drivers(void)
 {
        int error = tty_unregister_driver(isicom_normal);
        if (error)
@@ -1842,7 +1842,7 @@ static void __exit unregister_drivers(void)
        put_tty_driver(isicom_normal);
 }
 
-static int __init register_isr(void)
+static int __devinit register_isr(void)
 {
        int count, done=0;
        unsigned long irqflags;
@@ -1883,7 +1883,7 @@ static void __exit unregister_isr(void)
        }
 }
 
-static int __init isicom_init(void)
+static int __devinit isicom_init(void)
 {
        int card, channel, base;
        struct isi_port * port;
index c02a21dbad5d516b400f28fa0f2c601aaa8b7136..52a073eee201d697740fc9cad9530cc38f7e659a 100644 (file)
@@ -407,7 +407,6 @@ static unsigned long        stli_eisamemprobeaddrs[] = {
 };
 
 static int     stli_eisamempsize = sizeof(stli_eisamemprobeaddrs) / sizeof(unsigned long);
-int            stli_eisaprobe = STLI_EISAPROBE;
 
 /*
  *     Define the Stallion PCI vendor and device IDs.
@@ -4685,7 +4684,7 @@ static int stli_initbrds(void)
 #ifdef MODULE
        stli_argbrds();
 #endif
-       if (stli_eisaprobe)
+       if (STLI_EISAPROBE)
                stli_findeisabrds();
 #ifdef CONFIG_PCI
        stli_findpcibrds();
index e3085b22a365b7104fbb6e29483cdf7531121e36..42187381506b7d0ff45dcdcc4df5dc2be7a2867f 100644 (file)
 #include <linux/devfs_fs_kernel.h>
 #include <linux/ptrace.h>
 #include <linux/device.h>
+#include <linux/highmem.h>
+#include <linux/crash_dump.h>
 #include <linux/backing-dev.h>
+#include <linux/bootmem.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -273,6 +276,40 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
        return mmap_mem(file, vma);
 }
 
+#ifdef CONFIG_CRASH_DUMP
+/*
+ * Read memory corresponding to the old kernel.
+ */
+static ssize_t read_oldmem(struct file *file, char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       unsigned long pfn, offset;
+       size_t read = 0, csize;
+       int rc = 0;
+
+       while (count) {
+               pfn = *ppos / PAGE_SIZE;
+               if (pfn > saved_max_pfn)
+                       return read;
+
+               offset = (unsigned long)(*ppos % PAGE_SIZE);
+               if (count > PAGE_SIZE - offset)
+                       csize = PAGE_SIZE - offset;
+               else
+                       csize = count;
+
+               rc = copy_oldmem_page(pfn, buf, csize, offset, 1);
+               if (rc < 0)
+                       return rc;
+               buf += csize;
+               *ppos += csize;
+               read += csize;
+               count -= csize;
+       }
+       return read;
+}
+#endif
+
 extern long vread(char *buf, char *addr, unsigned long count);
 extern long vwrite(char *buf, char *addr, unsigned long count);
 
@@ -721,6 +758,7 @@ static int open_port(struct inode * inode, struct file * filp)
 #define read_full       read_zero
 #define open_mem       open_port
 #define open_kmem      open_mem
+#define open_oldmem    open_mem
 
 static struct file_operations mem_fops = {
        .llseek         = memory_lseek,
@@ -770,6 +808,13 @@ static struct file_operations full_fops = {
        .write          = write_full,
 };
 
+#ifdef CONFIG_CRASH_DUMP
+static struct file_operations oldmem_fops = {
+       .read   = read_oldmem,
+       .open   = open_oldmem,
+};
+#endif
+
 static ssize_t kmsg_write(struct file * file, const char __user * buf,
                          size_t count, loff_t *ppos)
 {
@@ -825,6 +870,11 @@ static int memory_open(struct inode * inode, struct file * filp)
                case 11:
                        filp->f_op = &kmsg_fops;
                        break;
+#ifdef CONFIG_CRASH_DUMP
+               case 12:
+                       filp->f_op = &oldmem_fops;
+                       break;
+#endif
                default:
                        return -ENXIO;
        }
@@ -854,6 +904,9 @@ static const struct {
        {8, "random",  S_IRUGO | S_IWUSR,           &random_fops},
        {9, "urandom", S_IRUGO | S_IWUSR,           &urandom_fops},
        {11,"kmsg",    S_IRUGO | S_IWUSR,           &kmsg_fops},
+#ifdef CONFIG_CRASH_DUMP
+       {12,"oldmem",    S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops},
+#endif
 };
 
 static struct class *mem_class;
index 3115d318b9978618784a4ee4f8173070cfcbe023..931efd58f87a2d4270a7180f2fd9b7c22bcbfa81 100644 (file)
@@ -66,8 +66,6 @@ static unsigned char misc_minors[DYNAMIC_MINORS / 8];
 extern int rtc_DP8570A_init(void);
 extern int rtc_MK48T08_init(void);
 extern int pmu_device_init(void);
-extern int tosh_init(void);
-extern int i8k_init(void);
 
 #ifdef CONFIG_PROC_FS
 static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
@@ -310,15 +308,6 @@ static int __init misc_init(void)
 #endif
 #ifdef CONFIG_BVME6000
        rtc_DP8570A_init();
-#endif
-#ifdef CONFIG_PMAC_PBOOK
-       pmu_device_init();
-#endif
-#ifdef CONFIG_TOSHIBA
-       tosh_init();
-#endif
-#ifdef CONFIG_I8K
-       i8k_init();
 #endif
        if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
                printk("unable to get major %d for misc devices\n",
index 7c24fbe831f83847df9eb859ec8d4983305b6fc7..95f7046ff059184c5c7b8024e83881c922c25289 100644 (file)
@@ -451,7 +451,7 @@ static int __init moxa_init(void)
                int n = (sizeof(moxa_pcibrds) / sizeof(moxa_pcibrds[0])) - 1;
                i = 0;
                while (i < n) {
-                       while ((p = pci_find_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL)
+                       while ((p = pci_get_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL)
                        {
                                if (pci_enable_device(p))
                                        continue;
index ab00f51475dfbc46dd1e91fa0fbb3da3dfda4e09..613aed9e1840a15e4843e396591dc205a5ceecf1 100644 (file)
@@ -107,8 +107,8 @@ void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO,
        spin_unlock_irqrestore(&dsp_lock, flags);
 }
 
-void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
-                          unsigned char ucValue)
+static void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
+                                unsigned char ucValue)
 {
        DSP_ISA_SLAVE_CONTROL rSlaveControl;
        DSP_ISA_SLAVE_CONTROL rSlaveControl_Save;
@@ -141,6 +141,7 @@ void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
 
 }
 
+#if 0
 unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO,
                                   unsigned uIndex)
 {
@@ -167,6 +168,7 @@ unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO,
 
        return ucValue;
 }
+#endif  /*  0  */
 
 int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
                        unsigned short *pIrqMap,
index 3e7d020d1bf4f2f4d7861a30240c995695eec904..270431ca7dae1ce4ee3755bd608bf496c4822efa 100644 (file)
@@ -338,10 +338,6 @@ unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
                                    unsigned long ulMsaAddr);
 void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO,
                           unsigned long ulMsaAddr, unsigned short usValue);
-void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
-                          unsigned char ucValue);
-unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO,
-                                  unsigned uIndex);
 int dsp3780I_GetIPCSource(unsigned short usDspBaseIO,
                           unsigned short *pusIPCSource);
 
index ab650cd6efc0d3e867c121c80d4b406bc78f413a..d6c72e0934e23e7bb805ebf852679d09155a6c3d 100644 (file)
@@ -242,20 +242,14 @@ int tp3780I_ClaimResources(THINKPAD_BD_DATA * pBDData)
 {
        int retval = 0;
        DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
        struct resource *pres;
-#endif
 
        PRINTK_2(TRACE_TP3780I,
                "tp3780i::tp3780I_ClaimResources entry pBDData %p\n", pBDData);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
        pres = request_region(pSettings->usDspBaseIO, 16, "mwave_3780i");
        if ( pres == NULL ) retval = -EIO;
-#else
-       retval = check_region(pSettings->usDspBaseIO, 16);
-       if (!retval) request_region(pSettings->usDspBaseIO, 16, "mwave_3780i");
-#endif
+
        if (retval) {
                PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_ClaimResources: Error: Could not claim I/O region starting at %x\n", pSettings->usDspBaseIO);
                retval = -EIO;
@@ -292,7 +286,7 @@ int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData)
 int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
 {
        DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
-       BOOLEAN bDSPPoweredUp = FALSE, bDSPEnabled = FALSE, bInterruptAllocated = FALSE;
+       BOOLEAN bDSPPoweredUp = FALSE, bInterruptAllocated = FALSE;
 
        PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP entry pBDData %p\n", pBDData);
 
@@ -397,8 +391,6 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
        if (dsp3780I_EnableDSP(pSettings, s_ausThinkpadIrqToField, s_ausThinkpadDmaToField)) {
                PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: dsp7880I_EnableDSP() failed\n");
                goto exit_cleanup;
-       } else {
-               bDSPEnabled = TRUE;
        }
 
        EnableSRAM(pBDData);
@@ -411,8 +403,6 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
 
 exit_cleanup:
        PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Cleaning up\n");
-       if (bDSPEnabled)
-               dsp3780I_DisableDSP(pSettings);
        if (bDSPPoweredUp)
                smapi_set_DSP_power_state(FALSE);
        if (bInterruptAllocated) {
index f63a3fd7ca6f18666954f9d2d424926049f7149d..1af733d07321a8f5de4c5412745fd46428ce7332 100644 (file)
@@ -211,12 +211,13 @@ nvram_check_checksum(void)
        return rv;
 }
 
-void
+static void
 __nvram_set_checksum(void)
 {
        mach_set_checksum();
 }
 
+#if 0
 void
 nvram_set_checksum(void)
 {
@@ -226,6 +227,7 @@ nvram_set_checksum(void)
        __nvram_set_checksum();
        spin_unlock_irqrestore(&rtc_lock, flags);
 }
+#endif  /*  0  */
 
 /*
  * The are the file operation function for user access to /dev/nvram
@@ -921,6 +923,4 @@ EXPORT_SYMBOL(__nvram_write_byte);
 EXPORT_SYMBOL(nvram_write_byte);
 EXPORT_SYMBOL(__nvram_check_checksum);
 EXPORT_SYMBOL(nvram_check_checksum);
-EXPORT_SYMBOL(__nvram_set_checksum);
-EXPORT_SYMBOL(nvram_set_checksum);
 MODULE_ALIAS_MISCDEV(NVRAM_MINOR);
index 1c8d866a49dced207ed4364d5b7e151135675956..8f36b1758eb6fa61f783bf72088200b81d1413e9 100644 (file)
@@ -581,7 +581,7 @@ static dev_link_t *mgslpc_attach(void)
 
     /* Interrupt setup */
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-    link->irq.IRQInfo1   = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+    link->irq.IRQInfo1   = IRQ_LEVEL_ID;
     link->irq.Handler = NULL;
     
     link->conf.Attributes = 0;
@@ -3081,6 +3081,12 @@ void mgslpc_remove_device(MGSLPC_INFO *remove_info)
        }
 }
 
+static struct pcmcia_device_id mgslpc_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, mgslpc_ids);
+
 static struct pcmcia_driver mgslpc_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -3088,6 +3094,7 @@ static struct pcmcia_driver mgslpc_driver = {
        },
        .attach         = mgslpc_attach,
        .detach         = mgslpc_detach,
+       .id_table       = mgslpc_ids,
 };
 
 static struct tty_operations mgslpc_ops = {
index e8f3860f4726c76590c82dff6fbd1892af6ac76e..01987c6dc398d8791af4e2c23c61aedef16f70b3 100644 (file)
@@ -147,7 +147,6 @@ struct rio_info * rio_info_store( int cmd, struct rio_info * p);
 extern int    rio_pcicopy(char *src, char *dst, int n);
 extern int rio_minor (struct tty_struct *tty);
 extern int rio_ismodem (struct tty_struct *tty);
-extern void rio_udelay (int usecs);
 
 extern void rio_start_card_running (struct Host * HostP);
 
index 763893e289b35367f6fb94b7a5cbae73f8892070..d7d484024e2bf224b6fd3243f85b59bdc299df3b 100644 (file)
@@ -354,11 +354,6 @@ int rio_ismodem(struct tty_struct *tty)
 }
 
 
-void rio_udelay (int usecs)
-{
-  udelay (usecs);
-}
-
 static int rio_set_real_termios (void *ptr)
 {
   int rv, modem;
@@ -1100,7 +1095,7 @@ static int __init rio_init(void)
 
 #ifdef CONFIG_PCI
     /* First look for the JET devices: */
-    while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, 
+    while ((pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX,
                                     PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, 
                                     pdev))) {
        if (pci_enable_device(pdev)) continue;
@@ -1174,7 +1169,7 @@ static int __init rio_init(void)
   */
 
     /* Then look for the older RIO/PCI devices: */
-    while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, 
+    while ((pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX,
                                     PCI_DEVICE_ID_SPECIALIX_RIO, 
                                     pdev))) {
        if (pci_enable_device(pdev)) continue;
index dca941ed10cfb7e007ae7119b2d4330d086e9a16..898a126ae3e654d0087c41184259127fdc347f97 100644 (file)
@@ -37,6 +37,7 @@ static char *_rioinit_c_sccs_ = "@(#)rioinit.c        1.3";
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/string.h>
@@ -1560,14 +1561,14 @@ uint Slot;
                                          INTERRUPT_DISABLE | BYTE_OPERATION |
                                          SLOW_LINKS | SLOW_AT_BUS);
                        WBYTE(DpRamP->DpResetTpu, 0xFF);
-                       rio_udelay (3);
+                       udelay(3);
 
                        rio_dprintk (RIO_DEBUG_INIT,  "RIOHostReset: Don't know if it worked. Try reset again\n");
                        WBYTE(DpRamP->DpControl,  BOOT_FROM_RAM | EXTERNAL_BUS_OFF |
                                          INTERRUPT_DISABLE | BYTE_OPERATION |
                                          SLOW_LINKS | SLOW_AT_BUS);
                        WBYTE(DpRamP->DpResetTpu, 0xFF);
-                       rio_udelay (3);
+                       udelay(3);
                        break;
 #ifdef FUTURE_RELEASE
        case RIO_EISA:
@@ -1599,7 +1600,7 @@ uint Slot;
                DpRamP->DpControl  = RIO_PCI_BOOT_FROM_RAM;
                DpRamP->DpResetInt = 0xFF;
                DpRamP->DpResetTpu = 0xFF;
-               rio_udelay (100);
+               udelay(100);
                /* for (i=0; i<6000; i++);  */
                /* suspend( 3 ); */
                break;
index db655002671f3e0d11139563aeb9ad7adc004b28..78a321afdf4fec6eba9e754dbb0b461fc633a0ad 100644 (file)
@@ -524,16 +524,16 @@ riotclose(void  *ptr)
        register uint SysPort = dev;
        struct ttystatics *tp;          /* pointer to our ttystruct */
 #endif
-       struct Port *PortP =ptr;        /* pointer to the port structure */
+       struct Port *PortP = ptr;       /* pointer to the port structure */
        int deleted = 0;
        int     try = -1; /* Disable the timeouts by setting them to -1 */
        int     repeat_this = -1; /* Congrats to those having 15 years of 
                                     uptime! (You get to break the driver.) */
-       long end_time;
+       unsigned long end_time;
        struct tty_struct * tty;
        unsigned long flags;
        int Modem;
-       int rv =0;
+       int rv = 0;
        
        rio_dprintk (RIO_DEBUG_TTY, "port close SysPort %d\n",PortP->PortNum);
 
@@ -620,7 +620,7 @@ riotclose(void  *ptr)
                if (repeat_this -- <= 0) {
                        rv = -EINTR;
                        rio_dprintk (RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n");
-                       RIOPreemptiveCmd(p, PortP, FCLOSE ); 
+                       RIOPreemptiveCmd(p, PortP, FCLOSE);
                        goto close_end;
                }
                rio_dprintk (RIO_DEBUG_TTY, "Calling timeout to flush in closing\n");
@@ -656,14 +656,12 @@ riotclose(void  *ptr)
                goto close_end;
        }
 
-       
-
        /* Can't call RIOShortCommand with the port locked. */
        rio_spin_unlock_irqrestore(&PortP->portSem, flags);
 
        if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) {
-         RIOPreemptiveCmd(p, PortP,FCLOSE);
-         goto close_end;
+               RIOPreemptiveCmd(p, PortP, FCLOSE);
+               goto close_end;
        }
 
        if (!deleted)
@@ -698,7 +696,6 @@ riotclose(void  *ptr)
 */
        PortP->Config &= ~(RIO_CTSFLOW|RIO_RTSFLOW);
 
-
 #ifdef STATS
        PortP->Stat.CloseCnt++;
 #endif
index 5bcbeb0cb9ae8988f09174821ad246d287a1d609..f463d6baa685cb59d848a02294c1d20d468f0510 100644 (file)
@@ -161,6 +161,64 @@ static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = {
        UPCI_AIOP_INTR_BIT_3
 };
 
+static Byte_t RData[RDATASIZE] = {
+       0x00, 0x09, 0xf6, 0x82,
+       0x02, 0x09, 0x86, 0xfb,
+       0x04, 0x09, 0x00, 0x0a,
+       0x06, 0x09, 0x01, 0x0a,
+       0x08, 0x09, 0x8a, 0x13,
+       0x0a, 0x09, 0xc5, 0x11,
+       0x0c, 0x09, 0x86, 0x85,
+       0x0e, 0x09, 0x20, 0x0a,
+       0x10, 0x09, 0x21, 0x0a,
+       0x12, 0x09, 0x41, 0xff,
+       0x14, 0x09, 0x82, 0x00,
+       0x16, 0x09, 0x82, 0x7b,
+       0x18, 0x09, 0x8a, 0x7d,
+       0x1a, 0x09, 0x88, 0x81,
+       0x1c, 0x09, 0x86, 0x7a,
+       0x1e, 0x09, 0x84, 0x81,
+       0x20, 0x09, 0x82, 0x7c,
+       0x22, 0x09, 0x0a, 0x0a
+};
+
+static Byte_t RRegData[RREGDATASIZE] = {
+       0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
+       0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
+       0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
+       0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
+       0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
+       0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
+       0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
+       0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
+       0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
+       0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
+       0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
+       0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
+       0x22, 0x09, 0x0a, 0x0a  /* 30: Rx FIFO Enable */
+};
+
+static CONTROLLER_T sController[CTL_SIZE] = {
+       {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
+        {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
+       {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
+        {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
+       {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
+        {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
+       {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
+        {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}
+};
+
+static Byte_t sBitMapClrTbl[8] = {
+       0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f
+};
+
+static Byte_t sBitMapSetTbl[8] = {
+       0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
+};
+
+static int sClockPrescale = 0x14;
+
 /*
  *  Line number is the ttySIx number (x), the Minor number.  We 
  *  assign them sequentially, starting at zero.  The following 
@@ -177,6 +235,26 @@ static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model);
 static unsigned char GetLineNumber(int ctrl, int aiop, int ch);
 static unsigned char SetLineNumber(int ctrl, int aiop, int ch);
 static void rp_start(struct tty_struct *tty);
+static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
+                    int ChanNum);
+static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode);
+static void sFlushRxFIFO(CHANNEL_T * ChP);
+static void sFlushTxFIFO(CHANNEL_T * ChP);
+static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags);
+static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags);
+static void sModemReset(CONTROLLER_T * CtlP, int chan, int on);
+static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on);
+static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data);
+static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
+                             ByteIO_t * AiopIOList, int AiopIOListSize,
+                             WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
+                             int PeriodicOnly, int altChanRingIndicator,
+                             int UPCIRingInd);
+static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
+                          ByteIO_t * AiopIOList, int AiopIOListSize,
+                          int IRQNum, Byte_t Frequency, int PeriodicOnly);
+static int sReadAiopID(ByteIO_t io);
+static int sReadAiopNumChan(WordIO_t io);
 
 #ifdef MODULE
 MODULE_AUTHOR("Theodore Ts'o");
@@ -1798,7 +1876,7 @@ static void rp_flush_buffer(struct tty_struct *tty)
  *  init's aiopic and serial port hardware.
  *  Inputs:  i is the board number (0-n)
  */
-__init int register_PCI(int i, struct pci_dev *dev)
+static __init int register_PCI(int i, struct pci_dev *dev)
 {
        int num_aiops, aiop, max_num_aiops, num_chan, chan;
        unsigned int aiopio[MAX_AIOPS_PER_BOARD];
@@ -2453,72 +2531,6 @@ static void rp_cleanup_module(void)
 }
 #endif
 
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-static Byte_t RData[RDATASIZE] = {
-       0x00, 0x09, 0xf6, 0x82,
-       0x02, 0x09, 0x86, 0xfb,
-       0x04, 0x09, 0x00, 0x0a,
-       0x06, 0x09, 0x01, 0x0a,
-       0x08, 0x09, 0x8a, 0x13,
-       0x0a, 0x09, 0xc5, 0x11,
-       0x0c, 0x09, 0x86, 0x85,
-       0x0e, 0x09, 0x20, 0x0a,
-       0x10, 0x09, 0x21, 0x0a,
-       0x12, 0x09, 0x41, 0xff,
-       0x14, 0x09, 0x82, 0x00,
-       0x16, 0x09, 0x82, 0x7b,
-       0x18, 0x09, 0x8a, 0x7d,
-       0x1a, 0x09, 0x88, 0x81,
-       0x1c, 0x09, 0x86, 0x7a,
-       0x1e, 0x09, 0x84, 0x81,
-       0x20, 0x09, 0x82, 0x7c,
-       0x22, 0x09, 0x0a, 0x0a
-};
-
-static Byte_t RRegData[RREGDATASIZE] = {
-       0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
-       0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
-       0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
-       0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
-       0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
-       0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
-       0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
-       0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
-       0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
-       0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
-       0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
-       0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
-       0x22, 0x09, 0x0a, 0x0a  /* 30: Rx FIFO Enable */
-};
-
-CONTROLLER_T sController[CTL_SIZE] = {
-       {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
-        {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
-       {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
-        {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
-       {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
-        {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
-       {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
-        {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}
-};
-
-Byte_t sBitMapClrTbl[8] = {
-       0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f
-};
-
-Byte_t sBitMapSetTbl[8] = {
-       0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
-};
-
-int sClockPrescale = 0x14;
-
 /***************************************************************************
 Function: sInitController
 Purpose:  Initialization of controller global registers and controller
@@ -2554,22 +2566,22 @@ Call:     sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
                       FREQ_4HZ - 4 Hertz
                    If IRQNum is set to 0 the Frequency parameter is
                    overidden, it is forced to a value of FREQ_DIS.
-          int PeriodicOnly: TRUE if all interrupts except the periodic
+          int PeriodicOnly: 1 if all interrupts except the periodic
                                interrupt are to be blocked.
-                            FALSE is both the periodic interrupt and
+                            0 is both the periodic interrupt and
                                other channel interrupts are allowed.
                             If IRQNum is set to 0 the PeriodicOnly parameter is
-                               overidden, it is forced to a value of FALSE.
+                               overidden, it is forced to a value of 0.
 Return:   int: Number of AIOPs on the controller, or CTLID_NULL if controller
                initialization failed.
 
 Comments:
           If periodic interrupts are to be disabled but AIOP interrupts
-          are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
+          are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
 
           If interrupts are to be completely disabled set IRQNum to 0.
 
-          Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
+          Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
           invalid combination.
 
           This function performs initialization of global interrupt modes,
@@ -2589,9 +2601,9 @@ Warnings: No range checking on any of the parameters is done.
           After this function all AIOPs on the controller are disabled,
           they can be enabled with sEnAiop().
 */
-int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
-                   ByteIO_t * AiopIOList, int AiopIOListSize, int IRQNum,
-                   Byte_t Frequency, int PeriodicOnly)
+static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
+                          ByteIO_t * AiopIOList, int AiopIOListSize,
+                          int IRQNum, Byte_t Frequency, int PeriodicOnly)
 {
        int i;
        ByteIO_t io;
@@ -2687,22 +2699,22 @@ Call:     sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
                       FREQ_4HZ - 4 Hertz
                    If IRQNum is set to 0 the Frequency parameter is
                    overidden, it is forced to a value of FREQ_DIS.
-          int PeriodicOnly: TRUE if all interrupts except the periodic
+          int PeriodicOnly: 1 if all interrupts except the periodic
                                interrupt are to be blocked.
-                            FALSE is both the periodic interrupt and
+                            0 is both the periodic interrupt and
                                other channel interrupts are allowed.
                             If IRQNum is set to 0 the PeriodicOnly parameter is
-                               overidden, it is forced to a value of FALSE.
+                               overidden, it is forced to a value of 0.
 Return:   int: Number of AIOPs on the controller, or CTLID_NULL if controller
                initialization failed.
 
 Comments:
           If periodic interrupts are to be disabled but AIOP interrupts
-          are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
+          are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
 
           If interrupts are to be completely disabled set IRQNum to 0.
 
-          Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
+          Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
           invalid combination.
 
           This function performs initialization of global interrupt modes,
@@ -2722,11 +2734,11 @@ Warnings: No range checking on any of the parameters is done.
           After this function all AIOPs on the controller are disabled,
           they can be enabled with sEnAiop().
 */
-int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
-                      ByteIO_t * AiopIOList, int AiopIOListSize,
-                      WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
-                      int PeriodicOnly, int altChanRingIndicator,
-                      int UPCIRingInd)
+static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
+                             ByteIO_t * AiopIOList, int AiopIOListSize,
+                             WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
+                             int PeriodicOnly, int altChanRingIndicator,
+                             int UPCIRingInd)
 {
        int i;
        ByteIO_t io;
@@ -2784,7 +2796,7 @@ Return:   int: Flag AIOPID_XXXX if a valid AIOP is found, where X
 Warnings: No context switches are allowed while executing this function.
 
 */
-int sReadAiopID(ByteIO_t io)
+static int sReadAiopID(ByteIO_t io)
 {
        Byte_t AiopID;          /* ID byte from AIOP */
 
@@ -2810,7 +2822,7 @@ Comments: The number of channels is determined by write/reads from identical
           AIOP, otherwise it is an 8 channel.
 Warnings: No context switches are allowed while executing this function.
 */
-int sReadAiopNumChan(WordIO_t io)
+static int sReadAiopNumChan(WordIO_t io)
 {
        Word_t x;
        static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 };
@@ -2834,15 +2846,15 @@ Call:     sInitChan(CtlP,ChP,AiopNum,ChanNum)
           CHANNEL_T *ChP; Ptr to channel structure
           int AiopNum; AIOP number within controller
           int ChanNum; Channel number within AIOP
-Return:   int: TRUE if initialization succeeded, FALSE if it fails because channel
+Return:   int: 1 if initialization succeeded, 0 if it fails because channel
                number exceeds number of channels available in AIOP.
 Comments: This function must be called before a channel can be used.
 Warnings: No range checking on any of the parameters is done.
 
           No context switches are allowed while executing this function.
 */
-int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
-             int ChanNum)
+static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
+                    int ChanNum)
 {
        int i;
        WordIO_t AiopIO;
@@ -2853,7 +2865,7 @@ int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
        int brd9600;
 
        if (ChanNum >= CtlP->AiopNumChan[AiopNum])
-               return (FALSE); /* exceeds num chans in AIOP */
+               return 0;       /* exceeds num chans in AIOP */
 
        /* Channel, AIOP, and controller identifiers */
        ChP->CtlP = CtlP;
@@ -2968,7 +2980,7 @@ int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
        ChP->TxPrioBuf = ChOff + _TXP_BUF;
        sEnRxProcessor(ChP);    /* start the Rx processor */
 
-       return (TRUE);
+       return 1;
 }
 
 /***************************************************************************
@@ -2989,7 +3001,7 @@ Warnings: No context switches are allowed while executing this function.
           After calling this function a delay of 4 uS is required to ensure
           that the receive processor is no longer processing this channel.
 */
-void sStopRxProcessor(CHANNEL_T * ChP)
+static void sStopRxProcessor(CHANNEL_T * ChP)
 {
        Byte_t R[4];
 
@@ -3014,18 +3026,18 @@ Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
           this function.
 Warnings: No context switches are allowed while executing this function.
 */
-void sFlushRxFIFO(CHANNEL_T * ChP)
+static void sFlushRxFIFO(CHANNEL_T * ChP)
 {
        int i;
        Byte_t Ch;              /* channel number within AIOP */
-       int RxFIFOEnabled;      /* TRUE if Rx FIFO enabled */
+       int RxFIFOEnabled;      /* 1 if Rx FIFO enabled */
 
        if (sGetRxCnt(ChP) == 0)        /* Rx FIFO empty */
                return;         /* don't need to flush */
 
-       RxFIFOEnabled = FALSE;
+       RxFIFOEnabled = 0;
        if (ChP->R[0x32] == 0x08) {     /* Rx FIFO is enabled */
-               RxFIFOEnabled = TRUE;
+               RxFIFOEnabled = 1;
                sDisRxFIFO(ChP);        /* disable it */
                for (i = 0; i < 2000 / 200; i++)        /* delay 2 uS to allow proc to disable FIFO */
                        sInB(ChP->IntChan);     /* depends on bus i/o timing */
@@ -3056,18 +3068,18 @@ Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
           this function.
 Warnings: No context switches are allowed while executing this function.
 */
-void sFlushTxFIFO(CHANNEL_T * ChP)
+static void sFlushTxFIFO(CHANNEL_T * ChP)
 {
        int i;
        Byte_t Ch;              /* channel number within AIOP */
-       int TxEnabled;          /* TRUE if transmitter enabled */
+       int TxEnabled;          /* 1 if transmitter enabled */
 
        if (sGetTxCnt(ChP) == 0)        /* Tx FIFO empty */
                return;         /* don't need to flush */
 
-       TxEnabled = FALSE;
+       TxEnabled = 0;
        if (ChP->TxControl[3] & TX_ENABLE) {
-               TxEnabled = TRUE;
+               TxEnabled = 1;
                sDisTransmit(ChP);      /* disable transmitter */
        }
        sStopRxProcessor(ChP);  /* stop Rx processor */
@@ -3096,7 +3108,7 @@ Comments: The priority byte is transmitted before any data in the Tx FIFO.
 
 Warnings: No context switches are allowed while executing this function.
 */
-int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data)
+static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data)
 {
        Byte_t DWBuf[4];        /* buffer for double word writes */
        Word_t *WordPtr;        /* must be far because Win SS != DS */
@@ -3158,7 +3170,7 @@ Comments: If an interrupt enable flag is set in Flags, that interrupt will be
           enable channel interrupts.  This would allow the global interrupt
           status register to be used to determine which AIOPs need service.
 */
-void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags)
+static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags)
 {
        Byte_t Mask;            /* Interrupt Mask Register */
 
@@ -3202,7 +3214,7 @@ Comments: If an interrupt flag is set in Flags, that interrupt will be
           this channel's bit from being set in the AIOP's Interrupt Channel
           Register.
 */
-void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
+static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
 {
        Byte_t Mask;            /* Interrupt Mask Register */
 
@@ -3218,7 +3230,7 @@ void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
        }
 }
 
-void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
+static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
 {
        sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum);
 }
@@ -3227,7 +3239,7 @@ void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
  *  Not an official SSCI function, but how to reset RocketModems.
  *  ISA bus version
  */
-void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
+static void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
 {
        ByteIO_t addr;
        Byte_t val;
@@ -3252,7 +3264,7 @@ void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
  *  Not an official SSCI function, but how to reset RocketModems.
  *  PCI bus version
  */
-void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
+static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
 {
        ByteIO_t addr;
 
index 802687290ee1f7d28393e0da74adc5632cc75a0b..3a8bcc85bc14c8bbedbf552a379d0c89cca35b1b 100644 (file)
@@ -1130,46 +1130,6 @@ Warnings: This function writes the data byte without checking to see if
 */
 #define sWriteTxByte(IO,DATA) sOutB(IO,DATA)
 
-int sInitController(CONTROLLER_T * CtlP,
-                   int CtlNum,
-                   ByteIO_t MudbacIO,
-                   ByteIO_t * AiopIOList,
-                   int AiopIOListSize,
-                   int IRQNum, Byte_t Frequency, int PeriodicOnly);
-
-int sPCIInitController(CONTROLLER_T * CtlP,
-                      int CtlNum,
-                      ByteIO_t * AiopIOList,
-                      int AiopIOListSize,
-                      WordIO_t ConfigIO,
-                      int IRQNum,
-                      Byte_t Frequency,
-                      int PeriodicOnly,
-                      int altChanRingIndicator, int UPCIRingInd);
-
-int sReadAiopID(ByteIO_t io);
-int sReadAiopNumChan(WordIO_t io);
-int sInitChan(CONTROLLER_T * CtlP,
-             CHANNEL_T * ChP, int AiopNum, int ChanNum);
-Byte_t sGetRxErrStatus(CHANNEL_T * ChP);
-void sStopRxProcessor(CHANNEL_T * ChP);
-void sStopSWInFlowCtl(CHANNEL_T * ChP);
-void sFlushRxFIFO(CHANNEL_T * ChP);
-void sFlushTxFIFO(CHANNEL_T * ChP);
-int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data);
-void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags);
-void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags);
-void sModemReset(CONTROLLER_T * CtlP, int chan, int on);
-void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on);
-void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode);
-
-extern Byte_t R[RDATASIZE];
-extern CONTROLLER_T sController[CTL_SIZE];
-extern Byte_t sIRQMap[16];
-extern Byte_t sBitMapClrTbl[8];
-extern Byte_t sBitMapSetTbl[8];
-extern int sClockPrescale;
-
 /*
  * Begin Linux specific definitions for the Rocketport driver
  *
index ff4f09804865546527ca6926dc5c4f1ab1317605..d8f9e94ae475703465300750258fbf984a3101a0 100644 (file)
@@ -78,6 +78,7 @@
 #include <linux/sysctl.h>
 #include <linux/wait.h>
 #include <linux/bcd.h>
+#include <linux/delay.h>
 
 #include <asm/current.h>
 #include <asm/uaccess.h>
@@ -894,7 +895,6 @@ static int __init rtc_init(void)
        struct proc_dir_entry *ent;
 #if defined(__alpha__) || defined(__mips__)
        unsigned int year, ctrl;
-       unsigned long uip_watchdog;
        char *guess = NULL;
 #endif
 #ifdef __sparc__
@@ -1000,12 +1000,8 @@ no_irq:
        /* Each operating system on an Alpha uses its own epoch.
           Let's try to guess which one we are using now. */
        
-       uip_watchdog = jiffies;
        if (rtc_is_updating() != 0)
-               while (jiffies - uip_watchdog < 2*HZ/100) { 
-                       barrier();
-                       cpu_relax();
-               }
+               msleep(20);
        
        spin_lock_irq(&rtc_lock);
        year = CMOS_READ(RTC_YEAR);
@@ -1213,7 +1209,6 @@ static int rtc_proc_open(struct inode *inode, struct file *file)
 
 void rtc_get_rtc_time(struct rtc_time *rtc_tm)
 {
-       unsigned long uip_watchdog = jiffies;
        unsigned char ctrl;
 #ifdef CONFIG_MACH_DECSTATION
        unsigned int real_year;
@@ -1221,7 +1216,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
 
        /*
         * read RTC once any update in progress is done. The update
-        * can take just over 2ms. We wait 10 to 20ms. There is no need to
+        * can take just over 2ms. We wait 20ms. There is no need to
         * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
         * If you need to know *exactly* when a second has started, enable
         * periodic update complete interrupts, (via ioctl) and then 
@@ -1230,10 +1225,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
         */
 
        if (rtc_is_updating() != 0)
-               while (jiffies - uip_watchdog < 2*HZ/100) {
-                       barrier();
-                       cpu_relax();
-               }
+               msleep(20);
 
        /*
         * Only the values that we read from the RTC are set. We leave
index f59f7cbd525bcd587ec799b3050aa5d8852e75f8..af79805b5576f4b08ca02b357cd4f3fb96d23ec6 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/spinlock.h>
 #include <linux/vt_kern.h>
 #include <linux/workqueue.h>
+#include <linux/kexec.h>
 
 #include <asm/ptrace.h>
 
@@ -94,6 +95,21 @@ static struct sysrq_key_op sysrq_unraw_op = {
 };
 #endif /* CONFIG_VT */
 
+#ifdef CONFIG_KEXEC
+/* crashdump sysrq handler */
+static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs,
+                               struct tty_struct *tty)
+{
+       crash_kexec(pt_regs);
+}
+static struct sysrq_key_op sysrq_crashdump_op = {
+       .handler        = sysrq_handle_crashdump,
+       .help_msg       = "Crashdump",
+       .action_msg     = "Trigger a crashdump",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+#endif
+
 /* reboot sysrq handler */
 static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
                                struct tty_struct *tty) 
@@ -273,8 +289,12 @@ static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = {
                 it is handled specially on the sparc
                 and will never arrive */
 /* b */        &sysrq_reboot_op,
-/* c */ NULL,
-/* d */        NULL,
+#ifdef CONFIG_KEXEC
+/* c */ &sysrq_crashdump_op,
+#else
+/* c */        NULL,
+#endif
+/* d */ NULL,
 /* e */        &sysrq_term_op,
 /* f */        &sysrq_moom_op,
 /* g */        NULL,
index 659335d80ee73703b6c56b7653e454a34332402a..ec78d2f161f75363b5d971e7ba1713ef3aa4899f 100644 (file)
@@ -396,7 +396,7 @@ static struct file_operations tipar_fops = {
 static int __init
 tipar_setup(char *str)
 {
-       int ints[2];
+       int ints[3];
 
        str = get_options(str, ARRAY_SIZE(ints), ints);
 
index 58e21fe4426243f721001637a6d57f6f6ced7d6e..0c6f521abd0e37ec25c0f726d4fa26661475fcda 100644 (file)
 
 #define TOSH_MINOR_DEV 181
 
-static int tosh_id = 0x0000;
-static int tosh_bios = 0x0000;
-static int tosh_date = 0x0000;
-static int tosh_sci = 0x0000;
-static int tosh_fan = 0;
-
-static int tosh_fn = 0;
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>");
+MODULE_DESCRIPTION("Toshiba laptop SMM driver");
+MODULE_SUPPORTED_DEVICE("toshiba");
 
-module_param(tosh_fn, int, 0);
+static int tosh_fn;
+module_param_named(fn, tosh_fn, int, 0);
+MODULE_PARM_DESC(fn, "User specified Fn key detection port");
 
+static int tosh_id;
+static int tosh_bios;
+static int tosh_date;
+static int tosh_sci;
+static int tosh_fan;
 
 static int tosh_ioctl(struct inode *, struct file *, unsigned int,
        unsigned long);
@@ -359,7 +363,7 @@ static int tosh_get_machine_id(void)
        unsigned long address;
 
        id = (0x100*(int) isa_readb(0xffffe))+((int) isa_readb(0xffffa));
-       
+
        /* do we have a SCTTable machine identication number on our hands */
 
        if (id==0xfc2f) {
@@ -424,7 +428,7 @@ static int tosh_probe(void)
        }
 
        /* call the Toshiba SCI support check routine */
-       
+
        regs.eax = 0xf0f0;
        regs.ebx = 0x0000;
        regs.ecx = 0x0000;
@@ -440,7 +444,7 @@ static int tosh_probe(void)
        /* if we get this far then we are running on a Toshiba (probably)! */
 
        tosh_sci = regs.edx & 0xffff;
-       
+
        /* next get the machine ID of the current laptop */
 
        tosh_id = tosh_get_machine_id();
@@ -475,16 +479,15 @@ static int tosh_probe(void)
        return 0;
 }
 
-int __init tosh_init(void)
+static int __init toshiba_init(void)
 {
        int retval;
        /* are we running on a Toshiba laptop */
 
-       if (tosh_probe()!=0)
-               return -EIO;
+       if (tosh_probe())
+               return -ENODEV;
 
-       printk(KERN_INFO "Toshiba System Managment Mode driver v"
-               TOSH_VERSION"\n");
+       printk(KERN_INFO "Toshiba System Managment Mode driver v" TOSH_VERSION "\n");
 
        /* set the port to use for Fn status if not specified as a parameter */
        if (tosh_fn==0x00)
@@ -492,12 +495,12 @@ int __init tosh_init(void)
 
        /* register the device file */
        retval = misc_register(&tosh_device);
-       if(retval < 0)
+       if (retval < 0)
                return retval;
 
 #ifdef CONFIG_PROC_FS
        /* register the proc entry */
-       if(create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL){
+       if (create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL) {
                misc_deregister(&tosh_device);
                return -ENOMEM;
        }
@@ -506,27 +509,12 @@ int __init tosh_init(void)
        return 0;
 }
 
-#ifdef MODULE
-int init_module(void)
-{
-       return tosh_init();
-}
-
-void cleanup_module(void)
+static void __exit toshiba_exit(void)
 {
-       /* remove the proc entry */
-
        remove_proc_entry("toshiba", NULL);
-
-       /* unregister the device file */
-
        misc_deregister(&tosh_device);
 }
-#endif
 
-MODULE_LICENSE("GPL");
-MODULE_PARM_DESC(tosh_fn, "User specified Fn key detection port");
-MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>");
-MODULE_DESCRIPTION("Toshiba laptop SMM driver");
-MODULE_SUPPORTED_DEVICE("toshiba");
+module_init(toshiba_init);
+module_exit(toshiba_exit);
 
index 8ce508b29865eb866cb21f4575c1cc324b66cda5..049d128ae7f07de2605cd5cd2e3d4c4efdba26ac 100644 (file)
@@ -19,7 +19,7 @@
  * 
  * Note, the TPM chip is not interrupt driven (only polling)
  * and can have very long timeouts (minutes!). Hence the unusual
- * calls to schedule_timeout.
+ * calls to msleep.
  *
  */
 
 #include <linux/spinlock.h>
 #include "tpm.h"
 
-#define        TPM_MINOR                       224     /* officially assigned */
-
-#define        TPM_BUFSIZE                     2048
-
-/* PCI configuration addresses */
-#define        PCI_GEN_PMCON_1                 0xA0
-#define        PCI_GEN1_DEC                    0xE4
-#define        PCI_LPC_EN                      0xE6
-#define        PCI_GEN2_DEC                    0xEC
+enum tpm_const {
+       TPM_MINOR = 224,        /* officially assigned */
+       TPM_BUFSIZE = 2048,
+       TPM_NUM_DEVICES = 256,
+       TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int))
+};
 
 static LIST_HEAD(tpm_chip_list);
 static DEFINE_SPINLOCK(driver_lock);
-static int dev_mask[32];
+static int dev_mask[TPM_NUM_MASK_ENTRIES];
 
 static void user_reader_timeout(unsigned long ptr)
 {
@@ -52,92 +49,17 @@ static void user_reader_timeout(unsigned long ptr)
        up(&chip->buffer_mutex);
 }
 
-void tpm_time_expired(unsigned long ptr)
-{
-       int *exp = (int *) ptr;
-       *exp = 1;
-}
-
-EXPORT_SYMBOL_GPL(tpm_time_expired);
-
-/*
- * Initialize the LPC bus and enable the TPM ports
- */
-int tpm_lpc_bus_init(struct pci_dev *pci_dev, u16 base)
-{
-       u32 lpcenable, tmp;
-       int is_lpcm = 0;
-
-       switch (pci_dev->vendor) {
-       case PCI_VENDOR_ID_INTEL:
-               switch (pci_dev->device) {
-               case PCI_DEVICE_ID_INTEL_82801CA_12:
-               case PCI_DEVICE_ID_INTEL_82801DB_12:
-                       is_lpcm = 1;
-                       break;
-               }
-               /* init ICH (enable LPC) */
-               pci_read_config_dword(pci_dev, PCI_GEN1_DEC, &lpcenable);
-               lpcenable |= 0x20000000;
-               pci_write_config_dword(pci_dev, PCI_GEN1_DEC, lpcenable);
-
-               if (is_lpcm) {
-                       pci_read_config_dword(pci_dev, PCI_GEN1_DEC,
-                                             &lpcenable);
-                       if ((lpcenable & 0x20000000) == 0) {
-                               dev_err(&pci_dev->dev,
-                                       "cannot enable LPC\n");
-                               return -ENODEV;
-                       }
-               }
-
-               /* initialize TPM registers */
-               pci_read_config_dword(pci_dev, PCI_GEN2_DEC, &tmp);
-
-               if (!is_lpcm)
-                       tmp = (tmp & 0xFFFF0000) | (base & 0xFFF0);
-               else
-                       tmp =
-                           (tmp & 0xFFFF0000) | (base & 0xFFF0) |
-                           0x00000001;
-
-               pci_write_config_dword(pci_dev, PCI_GEN2_DEC, tmp);
-
-               if (is_lpcm) {
-                       pci_read_config_dword(pci_dev, PCI_GEN_PMCON_1,
-                                             &tmp);
-                       tmp |= 0x00000004;      /* enable CLKRUN */
-                       pci_write_config_dword(pci_dev, PCI_GEN_PMCON_1,
-                                              tmp);
-               }
-               tpm_write_index(0x0D, 0x55);    /* unlock 4F */
-               tpm_write_index(0x0A, 0x00);    /* int disable */
-               tpm_write_index(0x08, base);    /* base addr lo */
-               tpm_write_index(0x09, (base & 0xFF00) >> 8);    /* base addr hi */
-               tpm_write_index(0x0D, 0xAA);    /* lock 4F */
-               break;
-       case PCI_VENDOR_ID_AMD:
-               /* nothing yet */
-               break;
-       }
-
-       return 0;
-}
-
-EXPORT_SYMBOL_GPL(tpm_lpc_bus_init);
-
 /*
  * Internal kernel interface to transmit TPM commands
  */
 static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
                            size_t bufsiz)
 {
-       ssize_t len;
+       ssize_t rc;
        u32 count;
-       __be32 *native_size;
+       unsigned long stop;
 
-       native_size = (__force __be32 *) (buf + 2);
-       count = be32_to_cpu(*native_size);
+       count = be32_to_cpu(*((__be32 *) (buf + 2)));
 
        if (count == 0)
                return -ENODATA;
@@ -149,53 +71,49 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 
        down(&chip->tpm_mutex);
 
-       if ((len = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
+       if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
                dev_err(&chip->pci_dev->dev,
-                       "tpm_transmit: tpm_send: error %zd\n", len);
-               return len;
+                       "tpm_transmit: tpm_send: error %zd\n", rc);
+               goto out;
        }
 
-       down(&chip->timer_manipulation_mutex);
-       chip->time_expired = 0;
-       init_timer(&chip->device_timer);
-       chip->device_timer.function = tpm_time_expired;
-       chip->device_timer.expires = jiffies + 2 * 60 * HZ;
-       chip->device_timer.data = (unsigned long) &chip->time_expired;
-       add_timer(&chip->device_timer);
-       up(&chip->timer_manipulation_mutex);
-
+       stop = jiffies + 2 * 60 * HZ;
        do {
                u8 status = inb(chip->vendor->base + 1);
                if ((status & chip->vendor->req_complete_mask) ==
                    chip->vendor->req_complete_val) {
-                       down(&chip->timer_manipulation_mutex);
-                       del_singleshot_timer_sync(&chip->device_timer);
-                       up(&chip->timer_manipulation_mutex);
                        goto out_recv;
                }
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(TPM_TIMEOUT);
+
+               if ((status == chip->vendor->req_canceled)) {
+                       dev_err(&chip->pci_dev->dev, "Operation Canceled\n");
+                       rc = -ECANCELED;
+                       goto out;
+               }
+
+               msleep(TPM_TIMEOUT);    /* CHECK */
                rmb();
-       } while (!chip->time_expired);
+       } while (time_before(jiffies, stop));
 
 
        chip->vendor->cancel(chip);
-       dev_err(&chip->pci_dev->dev, "Time expired\n");
-       up(&chip->tpm_mutex);
-       return -EIO;
+       dev_err(&chip->pci_dev->dev, "Operation Timed out\n");
+       rc = -ETIME;
+       goto out;
 
 out_recv:
-       len = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
-       if (len < 0)
+       rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
+       if (rc < 0)
                dev_err(&chip->pci_dev->dev,
-                       "tpm_transmit: tpm_recv: error %zd\n", len);
+                       "tpm_transmit: tpm_recv: error %zd\n", rc);
+out:
        up(&chip->tpm_mutex);
-       return len;
+       return rc;
 }
 
 #define TPM_DIGEST_SIZE 20
 #define CAP_PCR_RESULT_SIZE 18
-static u8 cap_pcr[] = {
+static const u8 cap_pcr[] = {
        0, 193,                 /* TPM_TAG_RQU_COMMAND */
        0, 0, 0, 22,            /* length */
        0, 0, 0, 101,           /* TPM_ORD_GetCapability */
@@ -205,75 +123,94 @@ static u8 cap_pcr[] = {
 };
 
 #define READ_PCR_RESULT_SIZE 30
-static u8 pcrread[] = {
+static const u8 pcrread[] = {
        0, 193,                 /* TPM_TAG_RQU_COMMAND */
        0, 0, 0, 14,            /* length */
        0, 0, 0, 21,            /* TPM_ORD_PcrRead */
        0, 0, 0, 0              /* PCR index */
 };
 
-static ssize_t show_pcrs(struct device *dev, struct device_attribute *attr, char *buf)
+ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
+                     char *buf)
 {
        u8 data[READ_PCR_RESULT_SIZE];
        ssize_t len;
-       int i, j, index, num_pcrs;
+       int i, j, num_pcrs;
+       __be32 index;
        char *str = buf;
 
        struct tpm_chip *chip =
-           pci_get_drvdata(container_of(dev, struct pci_dev, dev));
+           pci_get_drvdata(to_pci_dev(dev));
        if (chip == NULL)
                return -ENODEV;
 
        memcpy(data, cap_pcr, sizeof(cap_pcr));
        if ((len = tpm_transmit(chip, data, sizeof(data)))
-           < CAP_PCR_RESULT_SIZE)
-               return len;
+           < CAP_PCR_RESULT_SIZE) {
+               dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred "
+                               "attempting to determine the number of PCRS\n",
+                       be32_to_cpu(*((__be32 *) (data + 6))));
+               return 0;
+       }
 
-       num_pcrs = be32_to_cpu(*((__force __be32 *) (data + 14)));
+       num_pcrs = be32_to_cpu(*((__be32 *) (data + 14)));
 
        for (i = 0; i < num_pcrs; i++) {
                memcpy(data, pcrread, sizeof(pcrread));
                index = cpu_to_be32(i);
                memcpy(data + 10, &index, 4);
                if ((len = tpm_transmit(chip, data, sizeof(data)))
-                   < READ_PCR_RESULT_SIZE)
-                       return len;
+                   < READ_PCR_RESULT_SIZE){
+                       dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred"
+                               " attempting to read PCR %d of %d\n",
+                               be32_to_cpu(*((__be32 *) (data + 6))), i, num_pcrs);
+                       goto out;
+               }
                str += sprintf(str, "PCR-%02d: ", i);
                for (j = 0; j < TPM_DIGEST_SIZE; j++)
                        str += sprintf(str, "%02X ", *(data + 10 + j));
                str += sprintf(str, "\n");
        }
+out:
        return str - buf;
 }
-
-static DEVICE_ATTR(pcrs, S_IRUGO, show_pcrs, NULL);
+EXPORT_SYMBOL_GPL(tpm_show_pcrs);
 
 #define  READ_PUBEK_RESULT_SIZE 314
-static u8 readpubek[] = {
+static const u8 readpubek[] = {
        0, 193,                 /* TPM_TAG_RQU_COMMAND */
        0, 0, 0, 30,            /* length */
        0, 0, 0, 124,           /* TPM_ORD_ReadPubek */
 };
 
-static ssize_t show_pubek(struct device *dev, struct device_attribute *attr, char *buf)
+ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
+                      char *buf)
 {
-       u8 data[READ_PUBEK_RESULT_SIZE];
+       u8 *data;
        ssize_t len;
-       __be32 *native_val;
-       int i;
+       int i, rc;
        char *str = buf;
 
        struct tpm_chip *chip =
-           pci_get_drvdata(container_of(dev, struct pci_dev, dev));
+           pci_get_drvdata(to_pci_dev(dev));
        if (chip == NULL)
                return -ENODEV;
 
+       data = kmalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
        memcpy(data, readpubek, sizeof(readpubek));
        memset(data + sizeof(readpubek), 0, 20);        /* zero nonce */
 
-       if ((len = tpm_transmit(chip, data, sizeof(data))) <
-           READ_PUBEK_RESULT_SIZE)
-               return len;
+       if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) <
+           READ_PUBEK_RESULT_SIZE) {
+               dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred "
+                               "attempting to read the PUBEK\n",
+                           be32_to_cpu(*((__be32 *) (data + 6))));
+               rc = 0;
+               goto out;
+       }
 
        /* 
           ignore header 10 bytes
@@ -286,8 +223,6 @@ static ssize_t show_pubek(struct device *dev, struct device_attribute *attr, cha
           ignore checksum 20 bytes
         */
 
-       native_val = (__force __be32 *) (data + 34);
-
        str +=
            sprintf(str,
                    "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
@@ -298,21 +233,23 @@ static ssize_t show_pubek(struct device *dev, struct device_attribute *attr, cha
                    data[15], data[16], data[17], data[22], data[23],
                    data[24], data[25], data[26], data[27], data[28],
                    data[29], data[30], data[31], data[32], data[33],
-                   be32_to_cpu(*native_val)
-           );
+                   be32_to_cpu(*((__be32 *) (data + 34))));
 
        for (i = 0; i < 256; i++) {
-               str += sprintf(str, "%02X ", data[i + 39]);
+               str += sprintf(str, "%02X ", data[i + 38]);
                if ((i + 1) % 16 == 0)
                        str += sprintf(str, "\n");
        }
-       return str - buf;
+       rc = str - buf;
+out:
+       kfree(data);
+       return rc;
 }
 
-static DEVICE_ATTR(pubek, S_IRUGO, show_pubek, NULL);
+EXPORT_SYMBOL_GPL(tpm_show_pubek);
 
 #define CAP_VER_RESULT_SIZE 18
-static u8 cap_version[] = {
+static const u8 cap_version[] = {
        0, 193,                 /* TPM_TAG_RQU_COMMAND */
        0, 0, 0, 18,            /* length */
        0, 0, 0, 101,           /* TPM_ORD_GetCapability */
@@ -321,7 +258,7 @@ static u8 cap_version[] = {
 };
 
 #define CAP_MANUFACTURER_RESULT_SIZE 18
-static u8 cap_manufacturer[] = {
+static const u8 cap_manufacturer[] = {
        0, 193,                 /* TPM_TAG_RQU_COMMAND */
        0, 0, 0, 22,            /* length */
        0, 0, 0, 101,           /* TPM_ORD_GetCapability */
@@ -330,14 +267,15 @@ static u8 cap_manufacturer[] = {
        0, 0, 1, 3
 };
 
-static ssize_t show_caps(struct device *dev, struct device_attribute *attr, char *buf)
+ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
+                     char *buf)
 {
-       u8 data[READ_PUBEK_RESULT_SIZE];
+       u8 data[sizeof(cap_manufacturer)];
        ssize_t len;
        char *str = buf;
 
        struct tpm_chip *chip =
-           pci_get_drvdata(container_of(dev, struct pci_dev, dev));
+           pci_get_drvdata(to_pci_dev(dev));
        if (chip == NULL)
                return -ENODEV;
 
@@ -348,7 +286,7 @@ static ssize_t show_caps(struct device *dev, struct device_attribute *attr, char
                return len;
 
        str += sprintf(str, "Manufacturer: 0x%x\n",
-                      be32_to_cpu(*(data + 14)));
+                      be32_to_cpu(*((__be32 *) (data + 14))));
 
        memcpy(data, cap_version, sizeof(cap_version));
 
@@ -363,8 +301,20 @@ static ssize_t show_caps(struct device *dev, struct device_attribute *attr, char
 
        return str - buf;
 }
+EXPORT_SYMBOL_GPL(tpm_show_caps);
+
+ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+       if (chip == NULL)
+               return 0;
+
+       chip->vendor->cancel(chip);
+       return count;
+}
+EXPORT_SYMBOL_GPL(tpm_store_cancel);
 
-static DEVICE_ATTR(caps, S_IRUGO, show_caps, NULL);
 
 /*
  * Device file system interface to the TPM
@@ -422,24 +372,15 @@ EXPORT_SYMBOL_GPL(tpm_open);
 int tpm_release(struct inode *inode, struct file *file)
 {
        struct tpm_chip *chip = file->private_data;
-       
-       file->private_data = NULL;
 
        spin_lock(&driver_lock);
+       file->private_data = NULL;
        chip->num_opens--;
-       spin_unlock(&driver_lock);
-
-       down(&chip->timer_manipulation_mutex);
-       if (timer_pending(&chip->user_read_timer))
-               del_singleshot_timer_sync(&chip->user_read_timer);
-       else if (timer_pending(&chip->device_timer))
-               del_singleshot_timer_sync(&chip->device_timer);
-       up(&chip->timer_manipulation_mutex);
-
-       kfree(chip->data_buffer);
+       del_singleshot_timer_sync(&chip->user_read_timer);
        atomic_set(&chip->data_pending, 0);
-
        pci_dev_put(chip->pci_dev);
+       kfree(chip->data_buffer);
+       spin_unlock(&driver_lock);
        return 0;
 }
 
@@ -453,10 +394,8 @@ ssize_t tpm_write(struct file * file, const char __user * buf,
 
        /* cannot perform a write until the read has cleared
           either via tpm_read or a user_read_timer timeout */
-       while (atomic_read(&chip->data_pending) != 0) {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(TPM_TIMEOUT);
-       }
+       while (atomic_read(&chip->data_pending) != 0)
+               msleep(TPM_TIMEOUT);
 
        down(&chip->buffer_mutex);
 
@@ -476,13 +415,7 @@ ssize_t tpm_write(struct file * file, const char __user * buf,
        up(&chip->buffer_mutex);
 
        /* Set a timeout by which the reader must come claim the result */
-       down(&chip->timer_manipulation_mutex);
-       init_timer(&chip->user_read_timer);
-       chip->user_read_timer.function = user_reader_timeout;
-       chip->user_read_timer.data = (unsigned long) chip;
-       chip->user_read_timer.expires = jiffies + (60 * HZ);
-       add_timer(&chip->user_read_timer);
-       up(&chip->timer_manipulation_mutex);
+       mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
 
        return in_size;
 }
@@ -493,29 +426,19 @@ ssize_t tpm_read(struct file * file, char __user * buf,
                 size_t size, loff_t * off)
 {
        struct tpm_chip *chip = file->private_data;
-       int ret_size = -ENODATA;
+       int ret_size;
 
-       if (atomic_read(&chip->data_pending) != 0) {    /* Result available */
-               down(&chip->timer_manipulation_mutex);
-               del_singleshot_timer_sync(&chip->user_read_timer);
-               up(&chip->timer_manipulation_mutex);
+       del_singleshot_timer_sync(&chip->user_read_timer);
+       ret_size = atomic_read(&chip->data_pending);
+       atomic_set(&chip->data_pending, 0);
+       if (ret_size > 0) {     /* relay data */
+               if (size < ret_size)
+                       ret_size = size;
 
                down(&chip->buffer_mutex);
-
-               ret_size = atomic_read(&chip->data_pending);
-               atomic_set(&chip->data_pending, 0);
-
-               if (ret_size == 0)      /* timeout just occurred */
-                       ret_size = -ETIME;
-               else if (ret_size > 0) {        /* relay data */
-                       if (size < ret_size)
-                               ret_size = size;
-
-                       if (copy_to_user((void __user *) buf,
-                                        chip->data_buffer, ret_size)) {
-                               ret_size = -EFAULT;
-                       }
-               }
+               if (copy_to_user
+                   ((void __user *) buf, chip->data_buffer, ret_size))
+                       ret_size = -EFAULT;
                up(&chip->buffer_mutex);
        }
 
@@ -541,14 +464,13 @@ void __devexit tpm_remove(struct pci_dev *pci_dev)
 
        pci_set_drvdata(pci_dev, NULL);
        misc_deregister(&chip->vendor->miscdev);
+       kfree(chip->vendor->miscdev.name);
 
-       device_remove_file(&pci_dev->dev, &dev_attr_pubek);
-       device_remove_file(&pci_dev->dev, &dev_attr_pcrs);
-       device_remove_file(&pci_dev->dev, &dev_attr_caps);
+       sysfs_remove_group(&pci_dev->dev.kobj, chip->vendor->attr_group);
 
        pci_disable_device(pci_dev);
 
-       dev_mask[chip->dev_num / 32] &= !(1 << (chip->dev_num % 32));
+       dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
 
        kfree(chip);
 
@@ -590,10 +512,6 @@ int tpm_pm_resume(struct pci_dev *pci_dev)
        if (chip == NULL)
                return -ENODEV;
 
-       spin_lock(&driver_lock);
-       tpm_lpc_bus_init(pci_dev, chip->vendor->base);
-       spin_unlock(&driver_lock);
-
        return 0;
 }
 
@@ -609,7 +527,9 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume);
 int tpm_register_hardware(struct pci_dev *pci_dev,
                          struct tpm_vendor_specific *entry)
 {
-       char devname[7];
+#define DEVNAME_SIZE 7
+
+       char *devname;
        struct tpm_chip *chip;
        int i, j;
 
@@ -622,17 +542,21 @@ int tpm_register_hardware(struct pci_dev *pci_dev,
 
        init_MUTEX(&chip->buffer_mutex);
        init_MUTEX(&chip->tpm_mutex);
-       init_MUTEX(&chip->timer_manipulation_mutex);
        INIT_LIST_HEAD(&chip->list);
 
+       init_timer(&chip->user_read_timer);
+       chip->user_read_timer.function = user_reader_timeout;
+       chip->user_read_timer.data = (unsigned long) chip;
+
        chip->vendor = entry;
 
        chip->dev_num = -1;
 
-       for (i = 0; i < 32; i++)
-               for (j = 0; j < 8; j++)
+       for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++)
+               for (j = 0; j < 8 * sizeof(int); j++)
                        if ((dev_mask[i] & (1 << j)) == 0) {
-                               chip->dev_num = i * 32 + j;
+                               chip->dev_num =
+                                   i * TPM_NUM_MASK_ENTRIES + j;
                                dev_mask[i] |= 1 << j;
                                goto dev_num_search_complete;
                        }
@@ -648,7 +572,8 @@ dev_num_search_complete:
        else
                chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR;
 
-       snprintf(devname, sizeof(devname), "%s%d", "tpm", chip->dev_num);
+       devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
+       scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num);
        chip->vendor->miscdev.name = devname;
 
        chip->vendor->miscdev.dev = &(pci_dev->dev);
@@ -665,31 +590,20 @@ dev_num_search_complete:
                return -ENODEV;
        }
 
+       spin_lock(&driver_lock);
+
        pci_set_drvdata(pci_dev, chip);
 
        list_add(&chip->list, &tpm_chip_list);
 
-       device_create_file(&pci_dev->dev, &dev_attr_pubek);
-       device_create_file(&pci_dev->dev, &dev_attr_pcrs);
-       device_create_file(&pci_dev->dev, &dev_attr_caps);
-
-       return 0;
-}
+       spin_unlock(&driver_lock);
 
-EXPORT_SYMBOL_GPL(tpm_register_hardware);
+       sysfs_create_group(&pci_dev->dev.kobj, chip->vendor->attr_group);
 
-static int __init init_tpm(void)
-{
        return 0;
 }
 
-static void __exit cleanup_tpm(void)
-{
-
-}
-
-module_init(init_tpm);
-module_exit(cleanup_tpm);
+EXPORT_SYMBOL_GPL(tpm_register_hardware);
 
 MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
 MODULE_DESCRIPTION("TPM Driver");
index de0c796fce8000004b9d0d1eabc9b08cd875a16b..373b41f6b4604168fc24b0e73c2eff2a8ec6aaca 100644 (file)
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
 
-#define TPM_TIMEOUT msecs_to_jiffies(5)
+enum tpm_timeout {
+       TPM_TIMEOUT = 5,        /* msecs */
+};
 
 /* TPM addresses */
-#define        TPM_ADDR                        0x4E
-#define        TPM_DATA                        0x4F
+enum tpm_addr {
+       TPM_SUPERIO_ADDR = 0x2E,
+       TPM_ADDR = 0x4E,
+};
+
+extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
+                               char *);
+extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr,
+                               char *);
+extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr,
+                               char *);
+extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr,
+                               const char *, size_t);
 
 struct tpm_chip;
 
 struct tpm_vendor_specific {
        u8 req_complete_mask;
        u8 req_complete_val;
+       u8 req_canceled;
        u16 base;               /* TPM base address */
 
        int (*recv) (struct tpm_chip *, u8 *, size_t);
        int (*send) (struct tpm_chip *, u8 *, size_t);
        void (*cancel) (struct tpm_chip *);
        struct miscdevice miscdev;
+       struct attribute_group *attr_group;
 };
 
 struct tpm_chip {
@@ -58,29 +73,24 @@ struct tpm_chip {
 
        struct timer_list user_read_timer;      /* user needs to claim result */
        struct semaphore tpm_mutex;     /* tpm is processing */
-       struct timer_list device_timer; /* tpm is processing */
-       struct semaphore timer_manipulation_mutex;
 
        struct tpm_vendor_specific *vendor;
 
        struct list_head list;
 };
 
-static inline int tpm_read_index(int index)
+static inline int tpm_read_index(int base, int index)
 {
-       outb(index, TPM_ADDR);
-       return inb(TPM_DATA) & 0xFF;
+       outb(index, base);
+       return inb(base+1) & 0xFF;
 }
 
-static inline void tpm_write_index(int index, int value)
+static inline void tpm_write_index(int base, int index, int value)
 {
-       outb(index, TPM_ADDR);
-       outb(value & 0xFF, TPM_DATA);
+       outb(index, base);
+       outb(value & 0xFF, base+1);
 }
 
-extern void tpm_time_expired(unsigned long);
-extern int tpm_lpc_bus_init(struct pci_dev *, u16);
-
 extern int tpm_register_hardware(struct pci_dev *,
                                 struct tpm_vendor_specific *);
 extern int tpm_open(struct inode *, struct file *);
index f9333e729b623308618606222f673ba0b8897074..cc2cc77fd174c2e825938c5d436aa7e3db2a39ce 100644 (file)
 #include "tpm.h"
 
 /* Atmel definitions */
-#define        TPM_ATML_BASE                   0x400
+enum tpm_atmel_addr {
+       TPM_ATMEL_BASE_ADDR_LO = 0x08,
+       TPM_ATMEL_BASE_ADDR_HI = 0x09
+};
 
 /* write status bits */
-#define        ATML_STATUS_ABORT               0x01
-#define        ATML_STATUS_LASTBYTE            0x04
-
+enum tpm_atmel_write_status {
+       ATML_STATUS_ABORT = 0x01,
+       ATML_STATUS_LASTBYTE = 0x04
+};
 /* read status bits */
-#define        ATML_STATUS_BUSY                0x01
-#define        ATML_STATUS_DATA_AVAIL          0x02
-#define        ATML_STATUS_REWRITE             0x04
-
+enum tpm_atmel_read_status {
+       ATML_STATUS_BUSY = 0x01,
+       ATML_STATUS_DATA_AVAIL = 0x02,
+       ATML_STATUS_REWRITE = 0x04,
+       ATML_STATUS_READY = 0x08
+};
 
 static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count)
 {
@@ -121,13 +127,29 @@ static struct file_operations atmel_ops = {
        .release = tpm_release,
 };
 
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute* atmel_attrs[] = {
+       &dev_attr_pubek.attr,
+       &dev_attr_pcrs.attr,
+       &dev_attr_caps.attr,
+       &dev_attr_cancel.attr,
+       0,
+};
+
+static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs };
+
 static struct tpm_vendor_specific tpm_atmel = {
        .recv = tpm_atml_recv,
        .send = tpm_atml_send,
        .cancel = tpm_atml_cancel,
        .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
        .req_complete_val = ATML_STATUS_DATA_AVAIL,
-       .base = TPM_ATML_BASE,
+       .req_canceled = ATML_STATUS_READY,
+       .attr_group = &atmel_attr_grp,
        .miscdev = { .fops = &atmel_ops, },
 };
 
@@ -136,27 +158,29 @@ static int __devinit tpm_atml_init(struct pci_dev *pci_dev,
 {
        u8 version[4];
        int rc = 0;
+       int lo, hi;
 
        if (pci_enable_device(pci_dev))
                return -EIO;
 
-       if (tpm_lpc_bus_init(pci_dev, TPM_ATML_BASE)) {
-               rc = -ENODEV;
-               goto out_err;
-       }
+       lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
+       hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
+
+       tpm_atmel.base = (hi<<8)|lo;
+       dev_dbg( &pci_dev->dev, "Operating with base: 0x%x\n", tpm_atmel.base);
 
        /* verify that it is an Atmel part */
-       if (tpm_read_index(4) != 'A' || tpm_read_index(5) != 'T'
-           || tpm_read_index(6) != 'M' || tpm_read_index(7) != 'L') {
+       if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T'
+           || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') {
                rc = -ENODEV;
                goto out_err;
        }
 
        /* query chip for its version number */
-       if ((version[0] = tpm_read_index(0x00)) != 0xFF) {
-               version[1] = tpm_read_index(0x01);
-               version[2] = tpm_read_index(0x02);
-               version[3] = tpm_read_index(0x03);
+       if ((version[0] = tpm_read_index(TPM_ADDR, 0x00)) != 0xFF) {
+               version[1] = tpm_read_index(TPM_ADDR, 0x01);
+               version[2] = tpm_read_index(TPM_ADDR, 0x02);
+               version[3] = tpm_read_index(TPM_ADDR, 0x03);
        } else {
                dev_info(&pci_dev->dev, "version query failed\n");
                rc = -ENODEV;
@@ -183,6 +207,7 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
        {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
+       {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)},
        {0,}
 };
 
index 9cce833a09237861067231f04b144aa02740afbf..b4127348c063279ada48d3af60056e036318ae45 100644 (file)
 #include "tpm.h"
 
 /* National definitions */
-#define        TPM_NSC_BASE                    0x360
-#define        TPM_NSC_IRQ                     0x07
+enum tpm_nsc_addr{
+       TPM_NSC_IRQ = 0x07,
+       TPM_NSC_BASE0_HI = 0x60,
+       TPM_NSC_BASE0_LO = 0x61,
+       TPM_NSC_BASE1_HI = 0x62,
+       TPM_NSC_BASE1_LO = 0x63
+};
 
-#define        NSC_LDN_INDEX                   0x07
-#define        NSC_SID_INDEX                   0x20
-#define        NSC_LDC_INDEX                   0x30
-#define        NSC_DIO_INDEX                   0x60
-#define        NSC_CIO_INDEX                   0x62
-#define        NSC_IRQ_INDEX                   0x70
-#define        NSC_ITS_INDEX                   0x71
+enum tpm_nsc_index {
+       NSC_LDN_INDEX = 0x07,
+       NSC_SID_INDEX = 0x20,
+       NSC_LDC_INDEX = 0x30,
+       NSC_DIO_INDEX = 0x60,
+       NSC_CIO_INDEX = 0x62,
+       NSC_IRQ_INDEX = 0x70,
+       NSC_ITS_INDEX = 0x71
+};
 
-#define        NSC_STATUS                      0x01
-#define        NSC_COMMAND                     0x01
-#define        NSC_DATA                        0x00
+enum tpm_nsc_status_loc {
+       NSC_STATUS = 0x01,
+       NSC_COMMAND = 0x01,
+       NSC_DATA = 0x00
+};
 
 /* status bits */
-#define        NSC_STATUS_OBF                  0x01    /* output buffer full */
-#define        NSC_STATUS_IBF                  0x02    /* input buffer full */
-#define        NSC_STATUS_F0                   0x04    /* F0 */
-#define        NSC_STATUS_A2                   0x08    /* A2 */
-#define        NSC_STATUS_RDY                  0x10    /* ready to receive command */
-#define        NSC_STATUS_IBR                  0x20    /* ready to receive data */
+enum tpm_nsc_status {
+       NSC_STATUS_OBF = 0x01,  /* output buffer full */
+       NSC_STATUS_IBF = 0x02,  /* input buffer full */
+       NSC_STATUS_F0 = 0x04,   /* F0 */
+       NSC_STATUS_A2 = 0x08,   /* A2 */
+       NSC_STATUS_RDY = 0x10,  /* ready to receive command */
+       NSC_STATUS_IBR = 0x20   /* ready to receive data */
+};
 
 /* command bits */
-#define        NSC_COMMAND_NORMAL              0x01    /* normal mode */
-#define        NSC_COMMAND_EOC                 0x03
-#define        NSC_COMMAND_CANCEL              0x22
-
+enum tpm_nsc_cmd_mode {
+       NSC_COMMAND_NORMAL = 0x01,      /* normal mode */
+       NSC_COMMAND_EOC = 0x03,
+       NSC_COMMAND_CANCEL = 0x22
+};
 /*
  * Wait for a certain status to appear
  */
 static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
 {
-       int expired = 0;
-       struct timer_list status_timer =
-           TIMER_INITIALIZER(tpm_time_expired, jiffies + 10 * HZ,
-                             (unsigned long) &expired);
+       unsigned long stop;
 
        /* status immediately available check */
        *data = inb(chip->vendor->base + NSC_STATUS);
@@ -66,17 +75,14 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
                return 0;
 
        /* wait for status */
-       add_timer(&status_timer);
+       stop = jiffies + 10 * HZ;
        do {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(TPM_TIMEOUT);
+               msleep(TPM_TIMEOUT);
                *data = inb(chip->vendor->base + 1);
-               if ((*data & mask) == val) {
-                       del_singleshot_timer_sync(&status_timer);
+               if ((*data & mask) == val)
                        return 0;
-               }
        }
-       while (!expired);
+       while (time_before(jiffies, stop));
 
        return -EBUSY;
 }
@@ -84,10 +90,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
 static int nsc_wait_for_ready(struct tpm_chip *chip)
 {
        int status;
-       int expired = 0;
-       struct timer_list status_timer =
-           TIMER_INITIALIZER(tpm_time_expired, jiffies + 100,
-                             (unsigned long) &expired);
+       unsigned long stop;
 
        /* status immediately available check */
        status = inb(chip->vendor->base + NSC_STATUS);
@@ -97,19 +100,16 @@ static int nsc_wait_for_ready(struct tpm_chip *chip)
                return 0;
 
        /* wait for status */
-       add_timer(&status_timer);
+       stop = jiffies + 100;
        do {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(TPM_TIMEOUT);
+               msleep(TPM_TIMEOUT);
                status = inb(chip->vendor->base + NSC_STATUS);
                if (status & NSC_STATUS_OBF)
                        status = inb(chip->vendor->base + NSC_DATA);
-               if (status & NSC_STATUS_RDY) {
-                       del_singleshot_timer_sync(&status_timer);
+               if (status & NSC_STATUS_RDY)
                        return 0;
-               }
        }
-       while (!expired);
+       while (time_before(jiffies, stop));
 
        dev_info(&chip->pci_dev->dev, "wait for ready failed\n");
        return -EBUSY;
@@ -150,7 +150,8 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
                *p = inb(chip->vendor->base + NSC_DATA);
        }
 
-       if ((data & NSC_STATUS_F0) == 0) {
+       if ((data & NSC_STATUS_F0) == 0 &&
+       (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) {
                dev_err(&chip->pci_dev->dev, "F0 not set\n");
                return -EIO;
        }
@@ -228,100 +229,95 @@ static struct file_operations nsc_ops = {
        .release = tpm_release,
 };
 
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR|S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute * nsc_attrs[] = {
+       &dev_attr_pubek.attr,
+       &dev_attr_pcrs.attr,
+       &dev_attr_caps.attr,
+       &dev_attr_cancel.attr,
+       0,
+};
+
+static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs };
+
 static struct tpm_vendor_specific tpm_nsc = {
        .recv = tpm_nsc_recv,
        .send = tpm_nsc_send,
        .cancel = tpm_nsc_cancel,
        .req_complete_mask = NSC_STATUS_OBF,
        .req_complete_val = NSC_STATUS_OBF,
-       .base = TPM_NSC_BASE,
+       .req_canceled = NSC_STATUS_RDY,
+       .attr_group = &nsc_attr_grp,
        .miscdev = { .fops = &nsc_ops, },
-       
 };
 
 static int __devinit tpm_nsc_init(struct pci_dev *pci_dev,
                                  const struct pci_device_id *pci_id)
 {
        int rc = 0;
+       int lo, hi;
+       int nscAddrBase = TPM_ADDR;
+
 
        if (pci_enable_device(pci_dev))
                return -EIO;
 
-       if (tpm_lpc_bus_init(pci_dev, TPM_NSC_BASE)) {
-               rc = -ENODEV;
-               goto out_err;
-       }
+       /* select PM channel 1 */
+       tpm_write_index(nscAddrBase,NSC_LDN_INDEX, 0x12);
 
        /* verify that it is a National part (SID) */
-       if (tpm_read_index(NSC_SID_INDEX) != 0xEF) {
-               rc = -ENODEV;
-               goto out_err;
+       if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) {
+               nscAddrBase = (tpm_read_index(TPM_SUPERIO_ADDR, 0x2C)<<8)|
+                       (tpm_read_index(TPM_SUPERIO_ADDR, 0x2B)&0xFE);
+               if (tpm_read_index(nscAddrBase, NSC_SID_INDEX) != 0xF6) {
+                       rc = -ENODEV;
+                       goto out_err;
+               }
        }
 
+       hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI);
+       lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO);
+       tpm_nsc.base = (hi<<8) | lo;
+
        dev_dbg(&pci_dev->dev, "NSC TPM detected\n");
        dev_dbg(&pci_dev->dev,
                "NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
-               tpm_read_index(0x07), tpm_read_index(0x20),
-               tpm_read_index(0x27));
+               tpm_read_index(nscAddrBase,0x07), tpm_read_index(nscAddrBase,0x20),
+               tpm_read_index(nscAddrBase,0x27));
        dev_dbg(&pci_dev->dev,
                "NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n",
-               tpm_read_index(0x21), tpm_read_index(0x25),
-               tpm_read_index(0x26), tpm_read_index(0x28));
+               tpm_read_index(nscAddrBase,0x21), tpm_read_index(nscAddrBase,0x25),
+               tpm_read_index(nscAddrBase,0x26), tpm_read_index(nscAddrBase,0x28));
        dev_dbg(&pci_dev->dev, "NSC IO Base0 0x%x\n",
-               (tpm_read_index(0x60) << 8) | tpm_read_index(0x61));
+               (tpm_read_index(nscAddrBase,0x60) << 8) | tpm_read_index(nscAddrBase,0x61));
        dev_dbg(&pci_dev->dev, "NSC IO Base1 0x%x\n",
-               (tpm_read_index(0x62) << 8) | tpm_read_index(0x63));
+               (tpm_read_index(nscAddrBase,0x62) << 8) | tpm_read_index(nscAddrBase,0x63));
        dev_dbg(&pci_dev->dev, "NSC Interrupt number and wakeup 0x%x\n",
-               tpm_read_index(0x70));
+               tpm_read_index(nscAddrBase,0x70));
        dev_dbg(&pci_dev->dev, "NSC IRQ type select 0x%x\n",
-               tpm_read_index(0x71));
+               tpm_read_index(nscAddrBase,0x71));
        dev_dbg(&pci_dev->dev,
                "NSC DMA channel select0 0x%x, select1 0x%x\n",
-               tpm_read_index(0x74), tpm_read_index(0x75));
+               tpm_read_index(nscAddrBase,0x74), tpm_read_index(nscAddrBase,0x75));
        dev_dbg(&pci_dev->dev,
                "NSC Config "
                "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
-               tpm_read_index(0xF0), tpm_read_index(0xF1),
-               tpm_read_index(0xF2), tpm_read_index(0xF3),
-               tpm_read_index(0xF4), tpm_read_index(0xF5),
-               tpm_read_index(0xF6), tpm_read_index(0xF7),
-               tpm_read_index(0xF8), tpm_read_index(0xF9));
+               tpm_read_index(nscAddrBase,0xF0), tpm_read_index(nscAddrBase,0xF1),
+               tpm_read_index(nscAddrBase,0xF2), tpm_read_index(nscAddrBase,0xF3),
+               tpm_read_index(nscAddrBase,0xF4), tpm_read_index(nscAddrBase,0xF5),
+               tpm_read_index(nscAddrBase,0xF6), tpm_read_index(nscAddrBase,0xF7),
+               tpm_read_index(nscAddrBase,0xF8), tpm_read_index(nscAddrBase,0xF9));
 
        dev_info(&pci_dev->dev,
-                "NSC PC21100 TPM revision %d\n",
-                tpm_read_index(0x27) & 0x1F);
-
-       if (tpm_read_index(NSC_LDC_INDEX) == 0)
-               dev_info(&pci_dev->dev, ": NSC TPM not active\n");
-
-       /* select PM channel 1 */
-       tpm_write_index(NSC_LDN_INDEX, 0x12);
-       tpm_read_index(NSC_LDN_INDEX);
-
-       /* disable the DPM module */
-       tpm_write_index(NSC_LDC_INDEX, 0);
-       tpm_read_index(NSC_LDC_INDEX);
-
-       /* set the data register base addresses */
-       tpm_write_index(NSC_DIO_INDEX, TPM_NSC_BASE >> 8);
-       tpm_write_index(NSC_DIO_INDEX + 1, TPM_NSC_BASE);
-       tpm_read_index(NSC_DIO_INDEX);
-       tpm_read_index(NSC_DIO_INDEX + 1);
-
-       /* set the command register base addresses */
-       tpm_write_index(NSC_CIO_INDEX, (TPM_NSC_BASE + 1) >> 8);
-       tpm_write_index(NSC_CIO_INDEX + 1, (TPM_NSC_BASE + 1));
-       tpm_read_index(NSC_DIO_INDEX);
-       tpm_read_index(NSC_DIO_INDEX + 1);
-
-       /* set the interrupt number to be used for the host interface */
-       tpm_write_index(NSC_IRQ_INDEX, TPM_NSC_IRQ);
-       tpm_write_index(NSC_ITS_INDEX, 0x00);
-       tpm_read_index(NSC_IRQ_INDEX);
+                "NSC TPM revision %d\n",
+                tpm_read_index(nscAddrBase, 0x27) & 0x1F);
 
        /* enable the DPM module */
-       tpm_write_index(NSC_LDC_INDEX, 0x01);
-       tpm_read_index(NSC_LDC_INDEX);
+       tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01);
 
        if ((rc = tpm_register_hardware(pci_dev, &tpm_nsc)) < 0)
                goto out_err;
@@ -339,6 +335,9 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)},
        {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
        {0,}
 };
index cc4b43bad703c1da6aaf444f0ee3acbca3d4d7c3..6e4be3bb2d89d56b95792bf98e08bb3d201cc3ae 100644 (file)
@@ -94,6 +94,7 @@
 #include <linux/idr.h>
 #include <linux/wait.h>
 #include <linux/bitops.h>
+#include <linux/delay.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -2180,12 +2181,11 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
        return tty_set_ldisc(tty, ldisc);
 }
 
-static int send_break(struct tty_struct *tty, int duration)
+static int send_break(struct tty_struct *tty, unsigned int duration)
 {
        tty->driver->break_ctl(tty, -1);
        if (!signal_pending(current)) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(duration);
+               msleep_interruptible(duration);
        }
        tty->driver->break_ctl(tty, 0);
        if (signal_pending(current))
@@ -2366,10 +2366,10 @@ int tty_ioctl(struct inode * inode, struct file * file,
                         * all by anyone?
                         */
                        if (!arg)
-                               return send_break(tty, HZ/4);
+                               return send_break(tty, 250);
                        return 0;
                case TCSBRKP:   /* support for POSIX tcsendbreak() */   
-                       return send_break(tty, arg ? arg*(HZ/10) : HZ/4);
+                       return send_break(tty, arg ? arg*100 : 250);
 
                case TIOCMGET:
                        return tty_tiocmget(tty, file, p);
index 58597993954f7e8fea638d065afdc7a5362e2ed5..f19cf9d7792d57816b53cf0e697bda80fe07a50e 100644 (file)
@@ -476,11 +476,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
                        ld = tty_ldisc_ref(tty);
                        switch (arg) {
                        case TCIFLUSH:
-                               if (ld->flush_buffer)
+                               if (ld && ld->flush_buffer)
                                        ld->flush_buffer(tty);
                                break;
                        case TCIOFLUSH:
-                               if (ld->flush_buffer)
+                               if (ld && ld->flush_buffer)
                                        ld->flush_buffer(tty);
                                /* fall through */
                        case TCOFLUSH:
index 8971484b956b11c8b6072ab163aaeb87d5945117..1d44f69e1fda12bfb0abd092435d53ab04d9c610 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/fs.h>
 #include <linux/console.h>
 #include <linux/signal.h>
+#include <linux/timex.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -386,7 +387,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                if (!perm)
                        return -EPERM;
                if (arg)
-                       arg = 1193182 / arg;
+                       arg = CLOCK_TICK_RATE / arg;
                kd_mksound(arg, 0);
                return 0;
 
@@ -403,7 +404,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
                count = ticks ? (arg & 0xffff) : 0;
                if (count)
-                       count = 1193182 / count;
+                       count = CLOCK_TICK_RATE / count;
                kd_mksound(count, ticks);
                return 0;
        }
index 4e98c215e5b1bd63788ff031638191e0024045e8..4b039516cc866c9f03f5fe82a964faf7cc995af1 100644 (file)
@@ -162,7 +162,7 @@ ixp2000_wdt_release(struct inode *inode, struct file *file)
        if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
                wdt_disable();
        } else {
-               printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - "
+               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
                                        "timer will not stop\n");
        }
 
index 82396e06c8a89fffbf812cd1fc0edb0e9d6e1b0a..83df369113a42e3ead7a5bb43bbf013dc5a1b473 100644 (file)
@@ -156,7 +156,7 @@ ixp4xx_wdt_release(struct inode *inode, struct file *file)
        if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
                wdt_disable();
        } else {
-               printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - "
+               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
                                        "timer will not stop\n");
        }
 
index a3451cb94004dc3a876f5032e6a440b8c6800df5..33b17c6a46fb9a32e7c84b94b6b7970f9862fe45 100644 (file)
@@ -618,8 +618,8 @@ efivar_create_sysfs_entry(unsigned long variable_name_size,
        new_efivar = kmalloc(sizeof(struct efivar_entry), GFP_KERNEL);
 
        if (!short_name || !new_efivar)  {
-               if (short_name)        kfree(short_name);
-               if (new_efivar)        kfree(new_efivar);
+               kfree(short_name);
+               kfree(new_efivar);
                return 1;
        }
        memset(short_name, 0, short_name_size+1);
@@ -644,7 +644,8 @@ efivar_create_sysfs_entry(unsigned long variable_name_size,
        kobj_set_kset_s(new_efivar, vars_subsys);
        kobject_register(&new_efivar->kobj);
 
-       kfree(short_name); short_name = NULL;
+       kfree(short_name);
+       short_name = NULL;
 
        spin_lock(&efivars_lock);
        list_add(&new_efivar->list, &efivar_list);
index 839b44a7e08bea58dba9ad8e1e459dff30c44afe..53c95c0bbf46506826553d0e413c22cfa1c08c1e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/console.h>
 #include <linux/efi.h>
 #include <linux/serial.h>
+#include <asm/vga.h>
 #include "pcdp.h"
 
 static int __init
@@ -40,10 +41,27 @@ setup_serial_console(struct pcdp_uart *uart)
 }
 
 static int __init
-setup_vga_console(struct pcdp_vga *vga)
+setup_vga_console(struct pcdp_device *dev)
 {
 #if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
-       if (efi_mem_type(0xA0000) == EFI_CONVENTIONAL_MEMORY) {
+       u8 *if_ptr;
+
+       if_ptr = ((u8 *)dev + sizeof(struct pcdp_device));
+       if (if_ptr[0] == PCDP_IF_PCI) {
+               struct pcdp_if_pci if_pci;
+
+               /* struct copy since ifptr might not be correctly aligned */
+
+               memcpy(&if_pci, if_ptr, sizeof(if_pci));
+
+               if (if_pci.trans & PCDP_PCI_TRANS_IOPORT)
+                       vga_console_iobase = if_pci.ioport_tra;
+
+               if (if_pci.trans & PCDP_PCI_TRANS_MMIO)
+                       vga_console_membase = if_pci.mmio_tra;
+       }
+
+       if (efi_mem_type(vga_console_membase + 0xA0000) == EFI_CONVENTIONAL_MEMORY) {
                printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n");
                return -ENODEV;
        }
@@ -95,7 +113,7 @@ efi_setup_pcdp_console(char *cmdline)
             dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) {
                if (dev->flags & PCDP_PRIMARY_CONSOLE) {
                        if (dev->type == PCDP_CONSOLE_VGA) {
-                               return setup_vga_console((struct pcdp_vga *) dev);
+                               return setup_vga_console(dev);
                        }
                }
        }
index 1dc7c88b7b4dd06e37f74e0766a8c208c8b41218..e72cc47de33b64eb8bf1d5664b861fe79e090f57 100644 (file)
@@ -52,11 +52,34 @@ struct pcdp_uart {
        u32                             clock_rate;
        u8                              pci_prog_intfc;
        u8                              flags;
-};
+} __attribute__((packed));
+
+#define PCDP_IF_PCI    1
+
+/* pcdp_if_pci.trans */
+#define PCDP_PCI_TRANS_IOPORT  0x02
+#define PCDP_PCI_TRANS_MMIO    0x01
+
+struct pcdp_if_pci {
+       u8                      interconnect;
+       u8                      reserved;
+       u16                     length;
+       u8                      segment;
+       u8                      bus;
+       u8                      dev;
+       u8                      fun;
+       u16                     dev_id;
+       u16                     vendor_id;
+       u32                     acpi_interrupt;
+       u64                     mmio_tra;
+       u64                     ioport_tra;
+       u8                      flags;
+       u8                      trans;
+} __attribute__((packed));
 
 struct pcdp_vga {
        u8                      count;          /* address space descriptors */
-};
+} __attribute__((packed));
 
 /* pcdp_device.flags */
 #define PCDP_PRIMARY_CONSOLE   1
@@ -66,7 +89,9 @@ struct pcdp_device {
        u8                      flags;
        u16                     length;
        u16                     efi_index;
-};
+       /* next data is pcdp_if_pci or pcdp_if_acpi (not yet supported) */
+       /* next data is device specific type (currently only pcdp_vga) */
+} __attribute__((packed));
 
 struct pcdp {
        u8                      signature[4];
@@ -81,4 +106,4 @@ struct pcdp {
        u32                     num_uarts;
        struct pcdp_uart        uart[0];        /* actual size is num_uarts */
        /* remainder of table is pcdp_device structures */
-};
+} __attribute__((packed));
index ec943cad23147524c917c1fe5d93de97ad6e90c6..1956af382cd896d8421db7373c2d7c395d30a8ad 100644 (file)
@@ -33,7 +33,8 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 
-#include <asm/hardware.h>      /* Pick up IXP42000-specific bits */
+#include <asm/hardware.h>      /* Pick up IXP2000-specific bits */
+#include <asm/arch/gpio.h>
 
 static inline int ixp2000_scl_pin(void *data)
 {
index d41ca31dbcb2357cf4a37c2028aefae144c966be..03c23ce98edbc6d38c7da10fbf981904b72a1395 100644 (file)
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <asm/io.h>
-#ifdef CONFIG_FSL_OCP
-#include <asm/ocp.h>
-#define FSL_I2C_DEV_SEPARATE_DFSRR FS_I2C_SEPARATE_DFSRR
-#define FSL_I2C_DEV_CLOCK_5200 FS_I2C_CLOCK_5200
-#else
 #include <linux/fsl_devices.h>
-#endif
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
@@ -294,204 +288,6 @@ static struct i2c_adapter mpc_ops = {
        .retries = 1
 };
 
-#ifdef CONFIG_FSL_OCP
-static int __devinit mpc_i2c_probe(struct ocp_device *ocp)
-{
-       int result = 0;
-       struct mpc_i2c *i2c;
-
-       if (!(i2c = kmalloc(sizeof(*i2c), GFP_KERNEL))) {
-               return -ENOMEM;
-       }
-       memset(i2c, 0, sizeof(*i2c));
-
-       i2c->irq = ocp->def->irq;
-       i2c->flags = ((struct ocp_fs_i2c_data *)ocp->def->additions)->flags;
-       init_waitqueue_head(&i2c->queue);
-
-       if (!request_mem_region(ocp->def->paddr, MPC_I2C_REGION, "i2c-mpc")) {
-               printk(KERN_ERR "i2c-mpc - resource unavailable\n");
-               return -ENODEV;
-       }
-
-       i2c->base = ioremap(ocp->def->paddr, MPC_I2C_REGION);
-
-       if (!i2c->base) {
-               printk(KERN_ERR "i2c-mpc - failed to map controller\n");
-               result = -ENOMEM;
-               goto fail_map;
-       }
-
-       if (i2c->irq != OCP_IRQ_NA)
-       {
-               if ((result = request_irq(ocp->def->irq, mpc_i2c_isr,
-                                         SA_SHIRQ, "i2c-mpc", i2c)) < 0) {
-                       printk(KERN_ERR
-                              "i2c-mpc - failed to attach interrupt\n");
-                       goto fail_irq;
-               }
-       } else
-               i2c->irq = 0;
-
-       mpc_i2c_setclock(i2c);
-       ocp_set_drvdata(ocp, i2c);
-
-       i2c->adap = mpc_ops;
-       i2c_set_adapdata(&i2c->adap, i2c);
-
-       if ((result = i2c_add_adapter(&i2c->adap)) < 0) {
-               printk(KERN_ERR "i2c-mpc - failed to add adapter\n");
-               goto fail_add;
-       }
-
-       return result;
-
-      fail_add:
-       if (ocp->def->irq != OCP_IRQ_NA)
-               free_irq(ocp->def->irq, 0);
-      fail_irq:
-       iounmap(i2c->base);
-      fail_map:
-       release_mem_region(ocp->def->paddr, MPC_I2C_REGION);
-       kfree(i2c);
-       return result;
-}
-static void __devexit mpc_i2c_remove(struct ocp_device *ocp)
-{
-       struct mpc_i2c *i2c = ocp_get_drvdata(ocp);
-       i2c_del_adapter(&i2c->adap);
-       ocp_set_drvdata(ocp, NULL);
-
-       if (ocp->def->irq != OCP_IRQ_NA)
-               free_irq(i2c->irq, i2c);
-       iounmap(i2c->base);
-       release_mem_region(ocp->def->paddr, MPC_I2C_REGION);
-       kfree(i2c);
-}
-
-static struct ocp_device_id mpc_iic_ids[] __devinitdata = {
-       {.vendor = OCP_VENDOR_FREESCALE,.function = OCP_FUNC_IIC},
-       {.vendor = OCP_VENDOR_INVALID}
-};
-
-MODULE_DEVICE_TABLE(ocp, mpc_iic_ids);
-
-static struct ocp_driver mpc_iic_driver = {
-       .name = "iic",
-       .id_table = mpc_iic_ids,
-       .probe = mpc_i2c_probe,
-       .remove = __devexit_p(mpc_i2c_remove)
-};
-
-static int __init iic_init(void)
-{
-       return ocp_register_driver(&mpc_iic_driver);
-}
-
-static void __exit iic_exit(void)
-{
-       ocp_unregister_driver(&mpc_iic_driver);
-}
-
-module_init(iic_init);
-module_exit(iic_exit);
-#else
-static int fsl_i2c_probe(struct device *device)
-{
-       int result = 0;
-       struct mpc_i2c *i2c;
-       struct platform_device *pdev = to_platform_device(device);
-       struct fsl_i2c_platform_data *pdata;
-       struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-       pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data;
-
-       if (!(i2c = kmalloc(sizeof(*i2c), GFP_KERNEL))) {
-               return -ENOMEM;
-       }
-       memset(i2c, 0, sizeof(*i2c));
-
-       i2c->irq = platform_get_irq(pdev, 0);
-       i2c->flags = pdata->device_flags;
-       init_waitqueue_head(&i2c->queue);
-
-       i2c->base = ioremap((phys_addr_t)r->start, MPC_I2C_REGION);
-
-       if (!i2c->base) {
-               printk(KERN_ERR "i2c-mpc - failed to map controller\n");
-               result = -ENOMEM;
-               goto fail_map;
-       }
-
-       if (i2c->irq != 0)
-               if ((result = request_irq(i2c->irq, mpc_i2c_isr,
-                                         SA_SHIRQ, "i2c-mpc", i2c)) < 0) {
-                       printk(KERN_ERR
-                              "i2c-mpc - failed to attach interrupt\n");
-                       goto fail_irq;
-               }
-
-       mpc_i2c_setclock(i2c);
-       dev_set_drvdata(device, i2c);
-
-       i2c->adap = mpc_ops;
-       i2c_set_adapdata(&i2c->adap, i2c);
-       i2c->adap.dev.parent = &pdev->dev;
-       if ((result = i2c_add_adapter(&i2c->adap)) < 0) {
-               printk(KERN_ERR "i2c-mpc - failed to add adapter\n");
-               goto fail_add;
-       }
-
-       return result;
-
-      fail_add:
-       if (i2c->irq != 0)
-               free_irq(i2c->irq, NULL);
-      fail_irq:
-       iounmap(i2c->base);
-      fail_map:
-       kfree(i2c);
-       return result;
-};
-
-static int fsl_i2c_remove(struct device *device)
-{
-       struct mpc_i2c *i2c = dev_get_drvdata(device);
-
-       i2c_del_adapter(&i2c->adap);
-       dev_set_drvdata(device, NULL);
-
-       if (i2c->irq != 0)
-               free_irq(i2c->irq, i2c);
-
-       iounmap(i2c->base);
-       kfree(i2c);
-       return 0;
-};
-
-/* Structure for a device driver */
-static struct device_driver fsl_i2c_driver = {
-       .name = "fsl-i2c",
-       .bus = &platform_bus_type,
-       .probe = fsl_i2c_probe,
-       .remove = fsl_i2c_remove,
-};
-
-static int __init fsl_i2c_init(void)
-{
-       return driver_register(&fsl_i2c_driver);
-}
-
-static void __exit fsl_i2c_exit(void)
-{
-       driver_unregister(&fsl_i2c_driver);
-}
-
-module_init(fsl_i2c_init);
-module_exit(fsl_i2c_exit);
-
-#endif /* CONFIG_FSL_OCP */
-
 MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
 MODULE_DESCRIPTION
     ("I2C-Bus adapter for MPC107 bridge and MPC824x/85xx/52xx processors");
index 5c6597aa2c7f2fdc7a2c3758bafa87e98b1725c7..0bcf82b4c07bda60c7bcb08345a5a2bcb2b23ed9 100644 (file)
@@ -144,7 +144,7 @@ static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *att
        if (vid == cvid)
                return count;
 
-       dev_info(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid);
+       dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid);
 
        /* Write every 25 mV step to increase stability */
        if (cvid > vid) {
index 0273f124a4f723bafa7889a9bb36fc10b56a14a9..5f33df47aa7432806e6f97ba6de93f74b6ea1f9a 100644 (file)
@@ -606,6 +606,12 @@ config BLK_DEV_IT8172
          <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
          board at <http://www.mvista.com/partners/semiconductor/ite.html>.
 
+config BLK_DEV_IT821X
+       tristate "IT821X IDE support"
+       help
+         This driver adds support for the ITE 8211 IDE controller and the
+         IT 8212 IDE RAID controller in both RAID and pass-through mode.
+
 config BLK_DEV_NS87415
        tristate "NS87415 chipset support"
        help
index d6f934886b04da6f41eb9f7c4d9eabdde824c0de..f9c1acb4ed6a438c5518a22de4697aa13c88a3ee 100644 (file)
@@ -119,6 +119,10 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
 {
        unsigned long lba_sects, chs_sects, head, tail;
 
+       /* No non-LBA info .. so valid! */
+       if (id->cyls == 0)
+               return 1;
+
        /*
         * The ATA spec tells large drives to return
         * C/H/S = 16383/16/63 independent of their size.
index 2d2eefb610dd805de35954a36e9e3cd76b8970a1..1e1531334c251579cac44d980973942f1df9391b 100644 (file)
@@ -132,7 +132,6 @@ static const struct drive_list_entry drive_blacklist [] = {
        { "SAMSUNG CD-ROM SC-148C",     "ALL"           },
        { "SAMSUNG CD-ROM SC",  "ALL"           },
        { "SanDisk SDP3B-64"    ,       "ALL"           },
-       { "SAMSUNG CD-ROM SN-124",      "ALL"           },
        { "ATAPI CD-ROM DRIVE 40X MAXIMUM",     "ALL"           },
        { "_NEC DV5800A",               "ALL"           },  
        { NULL                  ,       NULL            }
index 53024942a7ebf2c5d98e2d6e545921eacd214724..b443b04a4c5a7c1de5263dc4c2120655d88b38c4 100644 (file)
@@ -1181,7 +1181,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
                pre_reset(drive);
                SELECT_DRIVE(drive);
                udelay (20);
-               hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
+               hwif->OUTBSYNC(drive, WIN_SRST, IDE_COMMAND_REG);
+               ndelay(400);
                hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
                hwgroup->polling = 1;
                __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
index e884cd4b22fdeaccab4310a801d1296ee3b73ff3..242029c9c0ca9a5e9e61b64011a3cd9dce7c31fd 100644 (file)
@@ -156,11 +156,13 @@ else \
 
 
 #if (HD_DELAY > 0)
+
+#include <asm/i8253.h>
+
 unsigned long last_req;
 
 unsigned long read_timer(void)
 {
-        extern spinlock_t i8253_lock;
        unsigned long t, flags;
        int i;
 
index e20327e54b1a21676b46d2bf03d2dbb441daf13c..978d27d6452dd5b7e13216fdc3bf11711c0232c3 100644 (file)
@@ -457,6 +457,40 @@ int ide_event(event_t event, int priority,
     return 0;
 } /* ide_event */
 
+static struct pcmcia_device_id ide_ids[] = {
+       PCMCIA_DEVICE_FUNC_ID(4),
+       PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
+       PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
+       PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
+       PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),
+       PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0),
+       PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74),
+       PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
+       PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
+       PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
+       PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
+       PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
+       PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
+       PCMCIA_DEVICE_PROD_ID12("EXP", "CD", 0x6f58c983, 0xaae5994f),
+       PCMCIA_DEVICE_PROD_ID12("EXP   ", "CD-ROM", 0x0a5c52fd, 0x66536591),
+       PCMCIA_DEVICE_PROD_ID12("EXP   ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
+       PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
+       PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+       PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2      ", 0x547e66dc, 0x8671043b),
+       PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
+       PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
+       PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2      ", 0xe37be2b5, 0x8671043b),
+       PCMCIA_DEVICE_PROD_ID12(" ", "NinjaATA-", 0x3b6e20c8, 0xebe0bd79),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728),
+       PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1),
+       PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
+       PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
+       PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, ide_ids);
+
 static struct pcmcia_driver ide_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -464,6 +498,7 @@ static struct pcmcia_driver ide_cs_driver = {
        },
        .attach         = ide_attach,
        .detach         = ide_detach,
+       .id_table       = ide_ids,
 };
 
 static int __init init_ide_cs(void)
index 55e6e553e4979a3995ae9526f5e3720bc99639fe..af46226c1796413159bb9b63ec75df14f9681837 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_BLK_DEV_HPT34X)          += hpt34x.o
 obj-$(CONFIG_BLK_DEV_HPT366)           += hpt366.o
 #obj-$(CONFIG_BLK_DEV_HPT37X)          += hpt37x.o
 obj-$(CONFIG_BLK_DEV_IT8172)           += it8172.o
+obj-$(CONFIG_BLK_DEV_IT821X)           += it821x.o
 obj-$(CONFIG_BLK_DEV_NS87415)          += ns87415.o
 obj-$(CONFIG_BLK_DEV_OPTI621)          += opti621.o
 obj-$(CONFIG_BLK_DEV_PDC202XX_OLD)     += pdc202xx_old.o
index 4565cc311ff3942cd0a8be18f6831f388c3fb6c3..da46577380f327dacd56a68afa9a369bd51882fe 100644 (file)
 
 #include <asm/io.h>
 
+static int ide_generic_all;            /* Set to claim all devices */
+
+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;
+}
+
+__setup("all-generic-ide", ide_generic_all_on);
+
 static void __devinit init_hwif_generic (ide_hwif_t *hwif)
 {
        switch(hwif->pci_dev->device) {
@@ -78,79 +89,85 @@ static void __devinit init_hwif_generic (ide_hwif_t *hwif)
 
 static ide_pci_device_t generic_chipsets[] __devinitdata = {
        {       /* 0 */
+               .name           = "Unknown",
+               .init_hwif      = init_hwif_generic,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .bootable       = ON_BOARD,
+       },{     /* 1 */
                .name           = "NS87410",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
                .bootable       = ON_BOARD,
-        },{    /* 1 */
+        },{    /* 2 */
                .name           = "SAMURAI",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
-       },{     /* 2 */
+       },{     /* 3 */
                .name           = "HT6565",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
-       },{     /* 3 */
+       },{     /* 4 */
                .name           = "UM8673F",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = NODMA,
                .bootable       = ON_BOARD,
-       },{     /* 4 */
+       },{     /* 5 */
                .name           = "UM8886A",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = NODMA,
                .bootable       = ON_BOARD,
-       },{     /* 5 */
+       },{     /* 6 */
                .name           = "UM8886BF",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = NODMA,
                .bootable       = ON_BOARD,
-       },{     /* 6 */
+       },{     /* 7 */
                .name           = "HINT_IDE",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
-       },{     /* 7 */
+       },{     /* 8 */
                .name           = "VIA_IDE",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = ON_BOARD,
-       },{     /* 8 */
+       },{     /* 9 */
                .name           = "OPTI621V",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = ON_BOARD,
-       },{     /* 9 */
+       },{     /* 10 */
                .name           = "VIA8237SATA",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
-       },{     /* 10 */
+       },{     /* 11 */
                .name           = "Piccolo0102",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = ON_BOARD,
-       },{     /* 11 */
+       },{     /* 12 */
                .name           = "Piccolo0103",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = ON_BOARD,
-       },{     /* 12 */
+       },{     /* 13 */
                .name           = "Piccolo0105",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
@@ -174,6 +191,10 @@ static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_devi
        u16 command;
        int ret = -ENODEV;
 
+       /* Don't use the generic entry unless instructed to do so */
+       if (id->driver_data == 0 && ide_generic_all == 0)
+                       goto out;
+
        if (dev->vendor == PCI_VENDOR_ID_UMC &&
            dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
            (!(PCI_FUNC(dev->devfn) & 1)))
@@ -195,21 +216,23 @@ out:
 }
 
 static struct pci_device_id generic_pci_tbl[] = {
-       { PCI_VENDOR_ID_NS,     PCI_DEVICE_ID_NS_87410,            PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
-       { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
-       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8673F,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
-       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886A,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
-       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886BF,        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
-       { PCI_VENDOR_ID_HINT,   PCI_DEVICE_ID_HINT_VXPROII_IDE,    PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
-       { PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C561,          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
-       { PCI_VENDOR_ID_OPTI,   PCI_DEVICE_ID_OPTI_82C558,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+       { PCI_VENDOR_ID_NS,     PCI_DEVICE_ID_NS_87410,            PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+       { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+       { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8673F,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886A,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886BF,        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+       { PCI_VENDOR_ID_HINT,   PCI_DEVICE_ID_HINT_VXPROII_IDE,    PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+       { PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C561,          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+       { PCI_VENDOR_ID_OPTI,   PCI_DEVICE_ID_OPTI_82C558,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
 #ifdef CONFIG_BLK_DEV_IDE_SATA
-       { PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8237_SATA,       PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
+       { PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8237_SATA,       PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
 #endif
-       { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO,     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
-       { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
-       { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
+       { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO,     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
+       { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
+       { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13},
+       /* Must come last. If you add entries adjust this table appropriately and the init_one code */
+       { PCI_ANY_ID,           PCI_ANY_ID,                        PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0},
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, generic_pci_tbl);
index c8ee0b8c0292606b518ad4d3c848d77208df2b95..7b64db10d1b03cd82786cbb8ca34852c7df6e518 100644 (file)
  * donation of an ABit BP6 mainboard, processor, and memory acellerated
  * development and support.
  *
+ *
+ * Highpoint have their own driver (source except for the raid part)
+ * available from http://www.highpoint-tech.com/hpt3xx-opensource-v131.tgz
+ * This may be useful to anyone wanting to work on the mainstream hpt IDE.
+ *
  * Note that final HPT370 support was done by force extraction of GPL.
  *
  * - add function for getting/setting power status of drive
@@ -446,44 +451,29 @@ static struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
 #define F_LOW_PCI_50   0x2d
 #define F_LOW_PCI_66   0x42
 
-/* FIXME: compare with driver's code before removing */
-#if 0
-               if (hpt_minimum_revision(dev, 3)) {
-                       u8 cbl;
-                       cbl = inb(iobase + 0x7b);
-                       outb(cbl | 1, iobase + 0x7b);
-                       outb(cbl & ~1, iobase + 0x7b);
-                       cbl = inb(iobase + 0x7a);
-                       p += sprintf(p, "Cable:          ATA-%d"
-                                       "                          ATA-%d\n",
-                               (cbl & 0x02) ? 33 : 66,
-                               (cbl & 0x01) ? 33 : 66);
-                       p += sprintf(p, "\n");
-               }
-               {
-                       u8 c2, c3;
-                       /* older revs don't have these registers mapped 
-                        * into io space */
-                       pci_read_config_byte(dev, 0x43, &c0);
-                       pci_read_config_byte(dev, 0x47, &c1);
-                       pci_read_config_byte(dev, 0x4b, &c2);
-                       pci_read_config_byte(dev, 0x4f, &c3);
-
-                       p += sprintf(p, "Mode:           %s             %s"
-                                       "           %s              %s\n",
-                               (c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
-                                       (c0 & 0x80) ? "PIO " : "off ",
-                               (c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
-                                       (c1 & 0x80) ? "PIO " : "off ",
-                               (c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
-                                       (c2 & 0x80) ? "PIO " : "off ",
-                               (c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
-                                       (c3 & 0x80) ? "PIO " : "off ");
-               }
-       }
-#endif
+/*
+ *     Hold all the highpoint quirks and revision information in one
+ *     place.
+ */
 
-static u32 hpt_revision (struct pci_dev *dev)
+struct hpt_info
+{
+       u8 max_mode;            /* Speeds allowed */
+       int revision;           /* Chipset revision */
+       int flags;              /* Chipset properties */
+#define PLL_MODE       1
+#define IS_372N                2
+                               /* Speed table */
+       struct chipset_bus_clock_list_entry *speed;
+};
+
+/*
+ *     This wants fixing so that we do everything not by classrev
+ *     (which breaks on the newest chips) but by creating an
+ *     enumeration of chip variants and using that
+ */
+
+static __devinit u32 hpt_revision (struct pci_dev *dev)
 {
        u32 class_rev;
        pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
@@ -507,37 +497,33 @@ static u32 hpt_revision (struct pci_dev *dev)
        return class_rev;
 }
 
-static u32 hpt_minimum_revision (struct pci_dev *dev, int revision)
-{
-       unsigned int class_rev = hpt_revision(dev);
-       revision--;
-       return ((int) (class_rev > revision) ? 1 : 0);
-}
-
 static int check_in_drive_lists(ide_drive_t *drive, const char **list);
 
 static u8 hpt3xx_ratemask (ide_drive_t *drive)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       ide_hwif_t *hwif        = drive->hwif;
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
        u8 mode                 = 0;
 
-       if (hpt_minimum_revision(dev, 8)) {             /* HPT374 */
+       /* FIXME: TODO - move this to set info->mode once at boot */
+
+       if (info->revision >= 8) {              /* HPT374 */
                mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
-       } else if (hpt_minimum_revision(dev, 7)) {      /* HPT371 */
+       } else if (info->revision >= 7) {       /* HPT371 */
                mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
-       } else if (hpt_minimum_revision(dev, 6)) {      /* HPT302 */
+       } else if (info->revision >= 6) {       /* HPT302 */
                mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
-       } else if (hpt_minimum_revision(dev, 5)) {      /* HPT372 */
+       } else if (info->revision >= 5) {       /* HPT372 */
                mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
-       } else if (hpt_minimum_revision(dev, 4)) {      /* HPT370A */
+       } else if (info->revision >= 4) {       /* HPT370A */
                mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
-       } else if (hpt_minimum_revision(dev, 3)) {      /* HPT370 */
+       } else if (info->revision >= 3) {       /* HPT370 */
                mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
                mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
        } else {                                /* HPT366 and HPT368 */
                mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
        }
-       if (!eighty_ninty_three(drive) && (mode))
+       if (!eighty_ninty_three(drive) && mode)
                mode = min(mode, (u8)1);
        return mode;
 }
@@ -549,7 +535,8 @@ static u8 hpt3xx_ratemask (ide_drive_t *drive)
  
 static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       ide_hwif_t *hwif        = drive->hwif;
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
        u8 mode                 = hpt3xx_ratemask(drive);
 
        if (drive->media != ide_disk)
@@ -561,7 +548,7 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
                        break;
                case 0x03:
                        speed = min(speed, (u8)XFER_UDMA_5);
-                       if (hpt_minimum_revision(dev, 5))
+                       if (info->revision >= 5)
                                break;
                        if (check_in_drive_lists(drive, bad_ata100_5))
                                speed = min(speed, (u8)XFER_UDMA_4);
@@ -571,7 +558,7 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
        /*
         * CHECK ME, Does this need to be set to 5 ??
         */
-                       if (hpt_minimum_revision(dev, 3))
+                       if (info->revision >= 3)
                                break;
                        if ((check_in_drive_lists(drive, bad_ata66_4)) ||
                            (!(HPT366_ALLOW_ATA66_4)))
@@ -585,7 +572,7 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
        /*
         * CHECK ME, Does this need to be set to 5 ??
         */
-                       if (hpt_minimum_revision(dev, 3))
+                       if (info->revision >= 3)
                                break;
                        if (check_in_drive_lists(drive, bad_ata33))
                                speed = min(speed, (u8)XFER_MW_DMA_2);
@@ -624,11 +611,12 @@ static unsigned int pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_
 
 static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       ide_hwif_t *hwif        = drive->hwif;
+       struct pci_dev *dev     = hwif->pci_dev;
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
        u8 speed                = hpt3xx_ratefilter(drive, xferspeed);
-//     u8 speed                = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
        u8 regtime              = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
-       u8 regfast              = (HWIF(drive)->channel) ? 0x55 : 0x51;
+       u8 regfast              = (hwif->channel) ? 0x55 : 0x51;
        u8 drive_fast           = 0;
        u32 reg1 = 0, reg2      = 0;
 
@@ -636,16 +624,11 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
         * Disable the "fast interrupt" prediction.
         */
        pci_read_config_byte(dev, regfast, &drive_fast);
-#if 0
-       if (drive_fast & 0x02)
-               pci_write_config_byte(dev, regfast, drive_fast & ~0x20);
-#else
        if (drive_fast & 0x80)
                pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
-#endif
 
-       reg2 = pci_bus_clock_list(speed,
-               (struct chipset_bus_clock_list_entry *) pci_get_drvdata(dev));
+       reg2 = pci_bus_clock_list(speed, info->speed);
+
        /*
         * Disable on-chip PIO FIFO/buffer
         *  (to avoid problems handling I/O errors later)
@@ -665,10 +648,11 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 
 static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 {
-       struct pci_dev *dev = HWIF(drive)->pci_dev;
+       ide_hwif_t *hwif        = drive->hwif;
+       struct pci_dev *dev = hwif->pci_dev;
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
        u8 speed        = hpt3xx_ratefilter(drive, xferspeed);
-//     u8 speed        = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
-       u8 regfast      = (HWIF(drive)->channel) ? 0x55 : 0x51;
+       u8 regfast      = (drive->hwif->channel) ? 0x55 : 0x51;
        u8 drive_pci    = 0x40 + (drive->dn * 4);
        u8 new_fast     = 0, drive_fast = 0;
        u32 list_conf   = 0, drive_conf = 0;
@@ -693,17 +677,13 @@ static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
        if (new_fast != drive_fast)
                pci_write_config_byte(dev, regfast, new_fast);
 
-       list_conf = pci_bus_clock_list(speed, 
-                                      (struct chipset_bus_clock_list_entry *)
-                                      pci_get_drvdata(dev));
+       list_conf = pci_bus_clock_list(speed, info->speed);
 
        pci_read_config_dword(dev, drive_pci, &drive_conf);
        list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
        
-       if (speed < XFER_MW_DMA_0) {
+       if (speed < XFER_MW_DMA_0)
                list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-       }
-
        pci_write_config_dword(dev, drive_pci, list_conf);
 
        return ide_config_drive_speed(drive, speed);
@@ -711,10 +691,11 @@ static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 
 static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       ide_hwif_t *hwif        = drive->hwif;
+       struct pci_dev *dev     = hwif->pci_dev;
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
        u8 speed        = hpt3xx_ratefilter(drive, xferspeed);
-//     u8 speed        = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
-       u8 regfast      = (HWIF(drive)->channel) ? 0x55 : 0x51;
+       u8 regfast      = (drive->hwif->channel) ? 0x55 : 0x51;
        u8 drive_fast   = 0, drive_pci = 0x40 + (drive->dn * 4);
        u32 list_conf   = 0, drive_conf = 0;
        u32 conf_mask   = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
@@ -726,10 +707,8 @@ static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
        pci_read_config_byte(dev, regfast, &drive_fast);
        drive_fast &= ~0x07;
        pci_write_config_byte(dev, regfast, drive_fast);
-                                       
-       list_conf = pci_bus_clock_list(speed,
-                       (struct chipset_bus_clock_list_entry *)
-                                       pci_get_drvdata(dev));
+
+       list_conf = pci_bus_clock_list(speed, info->speed);
        pci_read_config_dword(dev, drive_pci, &drive_conf);
        list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
        if (speed < XFER_MW_DMA_0)
@@ -741,19 +720,14 @@ static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 
 static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       ide_hwif_t *hwif        = drive->hwif;
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
 
-       if (hpt_minimum_revision(dev, 8))
+       if (info->revision >= 8)
                return hpt372_tune_chipset(drive, speed); /* not a typo */
-#if 0
-       else if (hpt_minimum_revision(dev, 7))
-               hpt371_tune_chipset(drive, speed);
-       else if (hpt_minimum_revision(dev, 6))
-               hpt302_tune_chipset(drive, speed);
-#endif
-       else if (hpt_minimum_revision(dev, 5))
+       else if (info->revision >= 5)
                return hpt372_tune_chipset(drive, speed);
-       else if (hpt_minimum_revision(dev, 3))
+       else if (info->revision >= 3)
                return hpt370_tune_chipset(drive, speed);
        else    /* hpt368: hpt_minimum_revision(dev, 2) */
                return hpt36x_tune_chipset(drive, speed);
@@ -779,8 +753,14 @@ static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
        u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
+       ide_hwif_t *hwif = drive->hwif;
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
 
-       if (!(speed))
+       if (!speed)
+               return 0;
+
+       /* If we don't have any timings we can't do a lot */
+       if (info->speed == NULL)
                return 0;
 
        (void) hpt3xx_tune_chipset(drive, speed);
@@ -794,7 +774,7 @@ static int hpt3xx_quirkproc (ide_drive_t *drive)
 
 static void hpt3xx_intrproc (ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = HWIF(drive);
+       ide_hwif_t *hwif = drive->hwif;
 
        if (drive->quirk_list)
                return;
@@ -804,24 +784,26 @@ static void hpt3xx_intrproc (ide_drive_t *drive)
 
 static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
 {
-       struct pci_dev *dev = HWIF(drive)->pci_dev;
+       ide_hwif_t *hwif = drive->hwif;
+       struct hpt_info *info = ide_get_hwifdata(hwif);
+       struct pci_dev *dev = hwif->pci_dev;
 
        if (drive->quirk_list) {
-               if (hpt_minimum_revision(dev,3)) {
+               if (info->revision >= 3) {
                        u8 reg5a = 0;
                        pci_read_config_byte(dev, 0x5a, &reg5a);
                        if (((reg5a & 0x10) >> 4) != mask)
                                pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
                } else {
                        if (mask) {
-                               disable_irq(HWIF(drive)->irq);
+                               disable_irq(hwif->irq);
                        } else {
-                               enable_irq(HWIF(drive)->irq);
+                               enable_irq(hwif->irq);
                        }
                }
        } else {
                if (IDE_CONTROL_REG)
-                       HWIF(drive)->OUTB(mask ? (drive->ctl | 2) :
+                       hwif->OUTB(mask ? (drive->ctl | 2) :
                                                 (drive->ctl & ~2),
                                                 IDE_CONTROL_REG);
        }
@@ -829,12 +811,12 @@ static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
 
 static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
+       ide_hwif_t *hwif        = drive->hwif;
        struct hd_driveid *id   = drive->id;
 
        drive->init_speed = 0;
 
-       if (id && (id->capability & 1) && drive->autodma) {
+       if ((id->capability & 1) && drive->autodma) {
 
                if (ide_use_dma(drive)) {
                        if (config_chipset_for_dma(drive))
@@ -868,15 +850,6 @@ static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
                drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
        if (reg5ah & 0x10)
                pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
-#if 0
-       /* how about we flush and reset, mmmkay? */
-       pci_write_config_byte(dev, 0x51, 0x1F);
-       /* fall through to a reset */
-       case dma_start:
-       case ide_dma_end:
-       /* reset the chips state over and over.. */
-       pci_write_config_byte(dev, 0x51, 0x13);
-#endif
        return __ide_dma_lostirq(drive);
 }
 
@@ -919,7 +892,7 @@ static void hpt370_lostirq_timeout (ide_drive_t *drive)
        u8 dma_stat = 0, dma_cmd = 0;
 
        pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
-       printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
+       printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo);
        hpt370_clear_engine(drive);
        /* get dma command mode */
        dma_cmd = hwif->INB(hwif->dma_command);
@@ -1047,15 +1020,6 @@ static void hpt372n_rw_disk(ide_drive_t *drive, struct request *rq)
 
 static void hpt3xx_reset (ide_drive_t *drive)
 {
-#if 0
-       unsigned long high_16   = pci_resource_start(HWIF(drive)->pci_dev, 4);
-       u8 reset        = (HWIF(drive)->channel) ? 0x80 : 0x40;
-       u8 reg59h       = 0;
-
-       pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
-       pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
-       pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
-#endif
 }
 
 static int hpt3xx_tristate (ide_drive_t * drive, int state)
@@ -1065,8 +1029,6 @@ static int hpt3xx_tristate (ide_drive_t * drive, int state)
        u8 reg59h = 0, reset    = (hwif->channel) ? 0x80 : 0x40;
        u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53;
 
-//     hwif->bus_state = state;
-
        pci_read_config_byte(dev, 0x59, &reg59h);
        pci_read_config_byte(dev, state_reg, &regXXh);
 
@@ -1093,7 +1055,7 @@ static int hpt3xx_tristate (ide_drive_t * drive, int state)
 #define TRISTATE_BIT  0x8000
 static int hpt370_busproc(ide_drive_t * drive, int state)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
+       ide_hwif_t *hwif        = drive->hwif;
        struct pci_dev *dev     = hwif->pci_dev;
        u8 tristate = 0, resetmask = 0, bus_reg = 0;
        u16 tri_reg;
@@ -1148,33 +1110,44 @@ static int hpt370_busproc(ide_drive_t * drive, int state)
        return 0;
 }
 
-static int __devinit init_hpt37x(struct pci_dev *dev)
+static void __devinit hpt366_clocking(ide_hwif_t *hwif)
 {
+       u32 reg1        = 0;
+       struct hpt_info *info = ide_get_hwifdata(hwif);
+
+       pci_read_config_dword(hwif->pci_dev, 0x40, &reg1);
+
+       /* detect bus speed by looking at control reg timing: */
+       switch((reg1 >> 8) & 7) {
+               case 5:
+                       info->speed = forty_base_hpt366;
+                       break;
+               case 9:
+                       info->speed = twenty_five_base_hpt366;
+                       break;
+               case 7:
+               default:
+                       info->speed = thirty_three_base_hpt366;
+                       break;
+       }
+}
+
+static void __devinit hpt37x_clocking(ide_hwif_t *hwif)
+{
+       struct hpt_info *info = ide_get_hwifdata(hwif);
+       struct pci_dev *dev = hwif->pci_dev;
        int adjust, i;
        u16 freq;
        u32 pll;
        u8 reg5bh;
-       u8 reg5ah = 0;
-       unsigned long dmabase = pci_resource_start(dev, 4);
-       u8 did, rid;    
-       int is_372n = 0;
        
-       pci_read_config_byte(dev, 0x5a, &reg5ah);
-       /* interrupt force enable */
-       pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
-
-       if(dmabase)
-       {
-               did = inb(dmabase + 0x22);
-               rid = inb(dmabase + 0x28);
-       
-               if((did == 4 && rid == 6) || (did == 5 && rid > 1))
-                       is_372n = 1;
-       }
-
        /*
         * default to pci clock. make sure MA15/16 are set to output
-        * to prevent drives having problems with 40-pin cables.
+        * to prevent drives having problems with 40-pin cables. Needed
+        * for some drives such as IBM-DTLA which will not enter ready
+        * state on reset when PDIAG is a input.
+        *
+        * ToDo: should we set 0x21 when using PLL mode ?
         */
        pci_write_config_byte(dev, 0x5b, 0x23);
 
@@ -1197,9 +1170,7 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
         * Currently we always set up the PLL for the 372N
         */
         
-       pci_set_drvdata(dev, NULL);
-       
-       if(is_372n)
+       if(info->flags & IS_372N)
        {
                printk(KERN_INFO "hpt: HPT372N detected, using 372N timing.\n");
                if(freq < 0x55)
@@ -1227,39 +1198,38 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
                        pll = F_LOW_PCI_66;
        
                if (pll == F_LOW_PCI_33) {
-                       if (hpt_minimum_revision(dev,8))
-                               pci_set_drvdata(dev, (void *) thirty_three_base_hpt374);
-                       else if (hpt_minimum_revision(dev,5))
-                               pci_set_drvdata(dev, (void *) thirty_three_base_hpt372);
-                       else if (hpt_minimum_revision(dev,4))
-                               pci_set_drvdata(dev, (void *) thirty_three_base_hpt370a);
+                       if (info->revision >= 8)
+                               info->speed = thirty_three_base_hpt374;
+                       else if (info->revision >= 5)
+                               info->speed = thirty_three_base_hpt372;
+                       else if (info->revision >= 4)
+                               info->speed = thirty_three_base_hpt370a;
                        else
-                               pci_set_drvdata(dev, (void *) thirty_three_base_hpt370);
-                       printk("HPT37X: using 33MHz PCI clock\n");
+                               info->speed = thirty_three_base_hpt370;
+                       printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n");
                } else if (pll == F_LOW_PCI_40) {
                        /* Unsupported */
                } else if (pll == F_LOW_PCI_50) {
-                       if (hpt_minimum_revision(dev,8))
-                               pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
-                       else if (hpt_minimum_revision(dev,5))
-                               pci_set_drvdata(dev, (void *) fifty_base_hpt372);
-                       else if (hpt_minimum_revision(dev,4))
-                               pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+                       if (info->revision >= 8)
+                               info->speed = fifty_base_hpt370a;
+                       else if (info->revision >= 5)
+                               info->speed = fifty_base_hpt372;
+                       else if (info->revision >= 4)
+                               info->speed = fifty_base_hpt370a;
                        else
-                               pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
-                       printk("HPT37X: using 50MHz PCI clock\n");
+                               info->speed = fifty_base_hpt370a;
+                       printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n");
                } else {
-                       if (hpt_minimum_revision(dev,8))
-                       {
+                       if (info->revision >= 8) {
                                printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n");
                        }
-                       else if (hpt_minimum_revision(dev,5))
-                               pci_set_drvdata(dev, (void *) sixty_six_base_hpt372);
-                       else if (hpt_minimum_revision(dev,4))
-                               pci_set_drvdata(dev, (void *) sixty_six_base_hpt370a);
+                       else if (info->revision >= 5)
+                               info->speed = sixty_six_base_hpt372;
+                       else if (info->revision >= 4)
+                               info->speed = sixty_six_base_hpt370a;
                        else
-                               pci_set_drvdata(dev, (void *) sixty_six_base_hpt370);
-                       printk("HPT37X: using 66MHz PCI clock\n");
+                               info->speed = sixty_six_base_hpt370;
+                       printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n");
                }
        }
        
@@ -1269,11 +1239,19 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
         * result in slow reads when using a 33MHz PCI clock. we also
         * don't like to use the PLL because it will cause glitches
         * on PRST/SRST when the HPT state engine gets reset.
+        *
+        * ToDo: Use 66MHz PLL when ATA133 devices are present on a
+        * 372 device so we can get ATA133 support
         */
-       if (pci_get_drvdata(dev)) 
+       if (info->speed)
                goto init_hpt37X_done;
+
+       info->flags |= PLL_MODE;
        
        /*
+        * FIXME: make this work correctly, esp with 372N as per
+        * reference driver code.
+        *
         * adjust PLL based upon PCI clock, enable it, and wait for
         * stabilization.
         */
@@ -1298,14 +1276,14 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
                                pci_write_config_dword(dev, 0x5c, 
                                                       pll & ~0x100);
                                pci_write_config_byte(dev, 0x5b, 0x21);
-                               if (hpt_minimum_revision(dev,8))
-                                       pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
-                               else if (hpt_minimum_revision(dev,5))
-                                       pci_set_drvdata(dev, (void *) fifty_base_hpt372);
-                               else if (hpt_minimum_revision(dev,4))
-                                       pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+                               if (info->revision >= 8)
+                                       info->speed = fifty_base_hpt370a;
+                               else if (info->revision >= 5)
+                                       info->speed = fifty_base_hpt372;
+                               else if (info->revision >= 4)
+                                       info->speed = fifty_base_hpt370a;
                                else
-                                       pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+                                       info->speed = fifty_base_hpt370a;
                                printk("HPT37X: using 50MHz internal PLL\n");
                                goto init_hpt37X_done;
                        }
@@ -1318,10 +1296,22 @@ pll_recal:
        } 
 
 init_hpt37X_done:
+       if (!info->speed)
+               printk(KERN_ERR "HPT37X%s: unknown bus timing [%d %d].\n",
+                       (info->flags & IS_372N)?"N":"", pll, freq);
        /* reset state engine */
        pci_write_config_byte(dev, 0x50, 0x37); 
        pci_write_config_byte(dev, 0x54, 0x37); 
        udelay(100);
+}
+
+static int __devinit init_hpt37x(struct pci_dev *dev)
+{
+       u8 reg5ah;
+
+       pci_read_config_byte(dev, 0x5a, &reg5ah);
+       /* interrupt force enable */
+       pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
        return 0;
 }
 
@@ -1338,59 +1328,27 @@ static int __devinit init_hpt366(struct pci_dev *dev)
                pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
        pci_read_config_dword(dev, 0x40, &reg1);
                                                                        
-       /* detect bus speed by looking at control reg timing: */
-       switch((reg1 >> 8) & 7) {
-               case 5:
-                       pci_set_drvdata(dev, (void *) forty_base_hpt366);
-                       break;
-               case 9:
-                       pci_set_drvdata(dev, (void *) twenty_five_base_hpt366);
-                       break;
-               case 7:
-               default:
-                       pci_set_drvdata(dev, (void *) thirty_three_base_hpt366);
-                       break;
-       }
-
-       if (!pci_get_drvdata(dev))
-       {
-               printk(KERN_ERR "hpt366: unknown bus timing.\n");
-               pci_set_drvdata(dev, NULL);
-       }
        return 0;
 }
 
 static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
 {
        int ret = 0;
-       u8 test = 0;
-
+       /* FIXME: Not portable */
        if (dev->resource[PCI_ROM_RESOURCE].start)
                pci_write_config_byte(dev, PCI_ROM_ADDRESS,
                        dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
 
-       pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
-       if (test != (L1_CACHE_BYTES / 4))
-               pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
-                       (L1_CACHE_BYTES / 4));
-
-       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
-       if (test != 0x78)
-               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+       pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+       pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
 
-       pci_read_config_byte(dev, PCI_MIN_GNT, &test);
-       if (test != 0x08)
-               pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
-
-       pci_read_config_byte(dev, PCI_MAX_LAT, &test);
-       if (test != 0x08)
-               pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
-
-       if (hpt_minimum_revision(dev, 3)) {
+       if (hpt_revision(dev) >= 3)
                ret = init_hpt37x(dev);
-       } else {
-               ret =init_hpt366(dev);
-       }
+       else
+               ret = init_hpt366(dev);
+
        if (ret)
                return ret;
 
@@ -1400,27 +1358,16 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
 static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 {
        struct pci_dev *dev             = hwif->pci_dev;
+       struct hpt_info *info           = ide_get_hwifdata(hwif);
        u8 ata66 = 0, regmask           = (hwif->channel) ? 0x01 : 0x02;
-       u8 did, rid;
-       unsigned long dmabase           = hwif->dma_base;
-       int is_372n = 0;
        
-       if(dmabase)
-       {
-               did = inb(dmabase + 0x22);
-               rid = inb(dmabase + 0x28);
-       
-               if((did == 4 && rid == 6) || (did == 5 && rid > 1))
-                       is_372n = 1;
-       }
-               
        hwif->tuneproc                  = &hpt3xx_tune_drive;
        hwif->speedproc                 = &hpt3xx_tune_chipset;
        hwif->quirkproc                 = &hpt3xx_quirkproc;
        hwif->intrproc                  = &hpt3xx_intrproc;
        hwif->maskproc                  = &hpt3xx_maskproc;
        
-       if(is_372n)
+       if(info->flags & IS_372N)
                hwif->rw_disk = &hpt372n_rw_disk;
 
        /*
@@ -1428,7 +1375,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
         * address lines to access an external eeprom.  To read valid
         * cable detect state the pins must be enabled as inputs.
         */
-       if (hpt_minimum_revision(dev, 8) && PCI_FUNC(dev->devfn) & 1) {
+       if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) {
                /*
                 * HPT374 PCI function 1
                 * - set bit 15 of reg 0x52 to enable TCBLID as input
@@ -1443,7 +1390,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
                pci_read_config_byte(dev, 0x5a, &ata66);
                pci_write_config_word(dev, 0x52, mcr3);
                pci_write_config_word(dev, 0x56, mcr6);
-       } else if (hpt_minimum_revision(dev, 3)) {
+       } else if (info->revision >= 3) {
                /*
                 * HPT370/372 and 374 pcifn 0
                 * - clear bit 0 of 0x5b to enable P/SCBLID as inputs
@@ -1470,7 +1417,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
                hwif->serialized = hwif->mate->serialized = 1;
 #endif
 
-       if (hpt_minimum_revision(dev,3)) {
+       if (info->revision >= 3) {
                u8 reg5ah = 0;
                        pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
                /*
@@ -1480,8 +1427,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
                 */
                hwif->resetproc = &hpt3xx_reset;
                hwif->busproc   = &hpt370_busproc;
-//             hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
-       } else if (hpt_minimum_revision(dev,2)) {
+       } else if (info->revision >= 2) {
                hwif->resetproc = &hpt3xx_reset;
                hwif->busproc   = &hpt3xx_tristate;
        } else {
@@ -1502,18 +1448,18 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
                hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
        hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
 
-       if (hpt_minimum_revision(dev,8)) {
+       if (info->revision >= 8) {
                hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
                hwif->ide_dma_end = &hpt374_ide_dma_end;
-       } else if (hpt_minimum_revision(dev,5)) {
+       } else if (info->revision >= 5) {
                hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
                hwif->ide_dma_end = &hpt374_ide_dma_end;
-       } else if (hpt_minimum_revision(dev,3)) {
+       } else if (info->revision >= 3) {
                hwif->dma_start = &hpt370_ide_dma_start;
                hwif->ide_dma_end = &hpt370_ide_dma_end;
                hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
                hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
-       } else if (hpt_minimum_revision(dev,2))
+       } else if (info->revision >= 2)
                hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
        else
                hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
@@ -1526,6 +1472,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 hpt_info *info   = ide_get_hwifdata(hwif);
        u8 masterdma    = 0, slavedma = 0;
        u8 dma_new      = 0, dma_old = 0;
        u8 primary      = hwif->channel ? 0x4b : 0x43;
@@ -1535,8 +1482,7 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
        if (!dmabase)
                return;
                
-       if(pci_get_drvdata(hwif->pci_dev) == NULL)
-       {
+       if(info->speed == NULL) {
                printk(KERN_WARNING "hpt: no known IDE timings, disabling DMA.\n");
                return;
        }
@@ -1559,6 +1505,40 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
        ide_setup_dma(hwif, dmabase, 8);
 }
 
+/*
+ *     We "borrow" this hook in order to set the data structures
+ *     up early enough before dma or init_hwif calls are made.
+ */
+
+static void __devinit init_iops_hpt366(ide_hwif_t *hwif)
+{
+       struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL);
+       unsigned long dmabase = pci_resource_start(hwif->pci_dev, 4);
+       u8 did, rid;
+
+       if(info == NULL) {
+               printk(KERN_WARNING "hpt366: out of memory.\n");
+               return;
+       }
+       memset(info, 0, sizeof(struct hpt_info));
+       ide_set_hwifdata(hwif, info);
+
+       if(dmabase) {
+               did = inb(dmabase + 0x22);
+               rid = inb(dmabase + 0x28);
+
+               if((did == 4 && rid == 6) || (did == 5 && rid > 1))
+                       info->flags |= IS_372N;
+       }
+
+       info->revision = hpt_revision(hwif->pci_dev);
+
+       if (info->revision >= 3)
+               hpt37x_clocking(hwif);
+       else
+               hpt366_clocking(hwif);
+}
+
 static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
 {
        struct pci_dev *findev = NULL;
@@ -1646,6 +1626,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .name           = "HPT366",
                .init_setup     = init_setup_hpt366,
                .init_chipset   = init_chipset_hpt366,
+               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,
@@ -1656,6 +1637,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .name           = "HPT372A",
                .init_setup     = init_setup_hpt37x,
                .init_chipset   = init_chipset_hpt366,
+               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,
@@ -1665,6 +1647,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .name           = "HPT302",
                .init_setup     = init_setup_hpt37x,
                .init_chipset   = init_chipset_hpt366,
+               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,
@@ -1674,6 +1657,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .name           = "HPT371",
                .init_setup     = init_setup_hpt37x,
                .init_chipset   = init_chipset_hpt366,
+               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,
@@ -1683,6 +1667,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .name           = "HPT374",
                .init_setup     = init_setup_hpt374,
                .init_chipset   = init_chipset_hpt366,
+               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,    /* 4 */
@@ -1692,6 +1677,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .name           = "HPT372N",
                .init_setup     = init_setup_hpt37x,
                .init_chipset   = init_chipset_hpt366,
+               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,    /* 4 */
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
new file mode 100644 (file)
index 0000000..e440036
--- /dev/null
@@ -0,0 +1,812 @@
+
+/*
+ * linux/drivers/ide/pci/it821x.c              Version 0.09    December 2004
+ *
+ * Copyright (C) 2004          Red Hat <alan@redhat.com>
+ *
+ *  May be copied or modified under the terms of the GNU General Public License
+ *  Based in part on the ITE vendor provided SCSI driver.
+ *
+ *  Documentation available from
+ *     http://www.ite.com.tw/pc/IT8212F_V04.pdf
+ *  Some other documents are NDA.
+ *
+ *  The ITE8212 isn't exactly a standard IDE controller. It has two
+ *  modes. In pass through mode then it is an IDE controller. In its smart
+ *  mode its actually quite a capable hardware raid controller disguised
+ *  as an IDE controller. Smart mode only understands DMA read/write and
+ *  identify, none of the fancier commands apply. The IT8211 is identical
+ *  in other respects but lacks the raid mode.
+ *
+ *  Errata:
+ *  o  Rev 0x10 also requires master/slave hold the same DMA timings and
+ *     cannot do ATAPI MWDMA.
+ *  o  The identify data for raid volumes lacks CHS info (technically ok)
+ *     but also fails to set the LBA28 and other bits. We fix these in
+ *     the IDE probe quirk code.
+ *  o  If you write LBA48 sized I/O's (ie > 256 sector) in smart mode
+ *     raid then the controller firmware dies
+ *  o  Smart mode without RAID doesn't clear all the necessary identify
+ *     bits to reduce the command set to the one used
+ *
+ *  This has a few impacts on the driver
+ *  - In pass through mode we do all the work you would expect
+ *  - In smart mode the clocking set up is done by the controller generally
+ *    but we must watch the other limits and filter.
+ *  - There are a few extra vendor commands that actually talk to the
+ *    controller but only work PIO with no IRQ.
+ *
+ *  Vendor areas of the identify block in smart mode are used for the
+ *  timing and policy set up. Each HDD in raid mode also has a serial
+ *  block on the disk. The hardware extra commands are get/set chip status,
+ *  rebuild, get rebuild status.
+ *
+ *  In Linux the driver supports pass through mode as if the device was
+ *  just another IDE controller. If the smart mode is running then
+ *  volumes are managed by the controller firmware and each IDE "disk"
+ *  is a raid volume. Even more cute - the controller can do automated
+ *  hotplug and rebuild.
+ *
+ *  The pass through controller itself is a little demented. It has a
+ *  flaw that it has a single set of PIO/MWDMA timings per channel so
+ *  non UDMA devices restrict each others performance. It also has a
+ *  single clock source per channel so mixed UDMA100/133 performance
+ *  isn't perfect and we have to pick a clock. Thankfully none of this
+ *  matters in smart mode. ATAPI DMA is not currently supported.
+ *
+ *  It seems the smart mode is a win for RAID1/RAID10 but otherwise not.
+ *
+ *  TODO
+ *     -       ATAPI UDMA is ok but not MWDMA it seems
+ *     -       RAID configuration ioctls
+ *     -       Move to libata once it grows up
+ */
+
+#include <linux/config.h>
+#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 */
+               timing10:1;             /* Rev 0x10 */
+       u8      clock_mode;             /* 0, ATA_50 or ATA_66 */
+       u8      want[2][2];             /* Mode/Pri log for master slave */
+       /* We need these for switching the clock when DMA goes on/off
+          The high byte is the 66Mhz timing */
+       u16     pio[2];                 /* Cached PIO values */
+       u16     mwdma[2];               /* Cached MWDMA values */
+       u16     udma[2];                /* Cached UDMA values (per drive) */
+};
+
+#define ATA_66         0
+#define ATA_50         1
+#define ATA_ANY                2
+
+#define UDMA_OFF       0
+#define MWDMA_OFF      0
+
+/*
+ *     We allow users to force the card into non raid mode without
+ *     flashing the alternative BIOS. This is also neccessary right now
+ *     for embedded platforms that cannot run a PC BIOS but are using this
+ *     device.
+ */
+
+static int it8212_noraid;
+
+/**
+ *     it821x_program  -       program the PIO/MWDMA registers
+ *     @drive: drive to tune
+ *
+ *     Program the PIO/MWDMA timing for this channel according to the
+ *     current clock.
+ */
+
+static void it821x_program(ide_drive_t *drive, u16 timing)
+{
+       ide_hwif_t *hwif        = drive->hwif;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       int channel = hwif->channel;
+       u8 conf;
+
+       /* Program PIO/MWDMA timing bits */
+       if(itdev->clock_mode == ATA_66)
+               conf = timing >> 8;
+       else
+               conf = timing & 0xFF;
+       pci_write_config_byte(hwif->pci_dev, 0x54 + 4 * channel, conf);
+}
+
+/**
+ *     it821x_program_udma     -       program the UDMA registers
+ *     @drive: drive to tune
+ *
+ *     Program the UDMA timing for this drive according to the
+ *     current clock.
+ */
+
+static void it821x_program_udma(ide_drive_t *drive, u16 timing)
+{
+       ide_hwif_t *hwif        = drive->hwif;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       int channel = hwif->channel;
+       int unit = drive->select.b.unit;
+       u8 conf;
+
+       /* Program UDMA timing bits */
+       if(itdev->clock_mode == ATA_66)
+               conf = timing >> 8;
+       else
+               conf = timing & 0xFF;
+       if(itdev->timing10 == 0)
+               pci_write_config_byte(hwif->pci_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);
+       }
+}
+
+
+/**
+ *     it821x_clock_strategy
+ *     @hwif: hardware interface
+ *
+ *     Select between the 50 and 66Mhz base clocks to get the best
+ *     results for this interface.
+ */
+
+static void it821x_clock_strategy(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+
+       u8 unit = drive->select.b.unit;
+       ide_drive_t *pair = &hwif->drives[1-unit];
+
+       int clock, altclock;
+       u8 v;
+       int sel = 0;
+
+       if(itdev->want[0][0] > itdev->want[1][0]) {
+               clock = itdev->want[0][1];
+               altclock = itdev->want[1][1];
+       } else {
+               clock = itdev->want[1][1];
+               altclock = itdev->want[0][1];
+       }
+
+       /* Master doesn't care does the slave ? */
+       if(clock == ATA_ANY)
+               clock = altclock;
+
+       /* Nobody cares - keep the same clock */
+       if(clock == ATA_ANY)
+               return;
+       /* No change */
+       if(clock == itdev->clock_mode)
+               return;
+
+       /* Load this into the controller ? */
+       if(clock == ATA_66)
+               itdev->clock_mode = ATA_66;
+       else {
+               itdev->clock_mode = ATA_50;
+               sel = 1;
+       }
+       pci_read_config_byte(hwif->pci_dev, 0x50, &v);
+       v &= ~(1 << (1 + hwif->channel));
+       v |= sel << (1 + hwif->channel);
+       pci_write_config_byte(hwif->pci_dev, 0x50, v);
+
+       /*
+        *      Reprogram the UDMA/PIO of the pair drive for the switch
+        *      MWDMA will be dealt with by the dma switcher
+        */
+       if(pair && itdev->udma[1-unit] != UDMA_OFF) {
+               it821x_program_udma(pair, itdev->udma[1-unit]);
+               it821x_program(pair, itdev->pio[1-unit]);
+       }
+       /*
+        *      Reprogram the UDMA/PIO of our drive for the switch.
+        *      MWDMA will be dealt with by the dma switcher
+        */
+       if(itdev->udma[unit] != UDMA_OFF) {
+               it821x_program_udma(drive, itdev->udma[unit]);
+               it821x_program(drive, itdev->pio[unit]);
+       }
+}
+
+/**
+ *     it821x_ratemask -       Compute available modes
+ *     @drive: IDE drive
+ *
+ *     Compute the available speeds for the devices on the interface. This
+ *     is all modes to ATA133 clipped by drive cable setup.
+ */
+
+static u8 it821x_ratemask (ide_drive_t *drive)
+{
+       u8 mode = 4;
+       if (!eighty_ninty_three(drive))
+               mode = min(mode, (u8)1);
+       return mode;
+}
+
+/**
+ *     it821x_tuneproc -       tune a drive
+ *     @drive: drive to tune
+ *     @mode_wanted: the target operating mode
+ *
+ *     Load the timing settings for this device mode into the
+ *     controller. By the time we are called the mode has been
+ *     modified as neccessary to handle the absence of seperate
+ *     master/slave timers for MWDMA/PIO.
+ *
+ *     This code is only used in pass through mode.
+ */
+
+static void it821x_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+       ide_hwif_t *hwif        = drive->hwif;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       int unit = drive->select.b.unit;
+
+       /* Spec says 89 ref driver uses 88 */
+       static u16 pio[]        = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
+       static u8 pio_want[]    = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
+
+       if(itdev->smart)
+               return;
+
+       /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
+       itdev->want[unit][1] = pio_want[mode_wanted];
+       itdev->want[unit][0] = 1;       /* PIO is lowest priority */
+       itdev->pio[unit] = pio[mode_wanted];
+       it821x_clock_strategy(drive);
+       it821x_program(drive, itdev->pio[unit]);
+}
+
+/**
+ *     it821x_tune_mwdma       -       tune a channel for MWDMA
+ *     @drive: drive to set up
+ *     @mode_wanted: the target operating mode
+ *
+ *     Load the timing settings for this device mode into the
+ *     controller when doing MWDMA in pass through mode. The caller
+ *     must manage the whole lack of per device MWDMA/PIO timings and
+ *     the shared MWDMA/PIO timing register.
+ */
+
+static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted)
+{
+       ide_hwif_t *hwif        = drive->hwif;
+       struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif);
+       int unit = drive->select.b.unit;
+       int channel = hwif->channel;
+       u8 conf;
+
+       static u16 dma[]        = { 0x8866, 0x3222, 0x3121 };
+       static u8 mwdma_want[]  = { ATA_ANY, ATA_66, ATA_ANY };
+
+       itdev->want[unit][1] = mwdma_want[mode_wanted];
+       itdev->want[unit][0] = 2;       /* MWDMA is low priority */
+       itdev->mwdma[unit] = dma[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)
+               conf |= channel ? 0x60: 0x18;
+       else
+               conf |= 1 << (3 + 2 * channel + unit);
+       pci_write_config_byte(hwif->pci_dev, 0x50, conf);
+
+       it821x_clock_strategy(drive);
+       /* FIXME: do we need to program this ? */
+       /* it821x_program(drive, itdev->mwdma[unit]); */
+}
+
+/**
+ *     it821x_tune_udma        -       tune a channel for UDMA
+ *     @drive: drive to set up
+ *     @mode_wanted: the target operating mode
+ *
+ *     Load the timing settings for this device mode into the
+ *     controller when doing UDMA modes in pass through.
+ */
+
+static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted)
+{
+       ide_hwif_t *hwif        = drive->hwif;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       int unit = drive->select.b.unit;
+       int channel = hwif->channel;
+       u8 conf;
+
+       static u16 udma[]       = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 };
+       static u8 udma_want[]   = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 };
+
+       itdev->want[unit][1] = udma_want[mode_wanted];
+       itdev->want[unit][0] = 3;       /* UDMA is high priority */
+       itdev->mwdma[unit] = MWDMA_OFF;
+       itdev->udma[unit] = udma[mode_wanted];
+       if(mode_wanted >= 5)
+               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)
+               conf &= channel ? 0x9F: 0xE7;
+       else
+               conf &= ~ (1 << (3 + 2 * channel + unit));
+       pci_write_config_byte(hwif->pci_dev, 0x50, conf);
+
+       it821x_clock_strategy(drive);
+       it821x_program_udma(drive, itdev->udma[unit]);
+
+}
+
+/**
+ *     config_it821x_chipset_for_pio   -       set drive timings
+ *     @drive: drive to tune
+ *     @speed we want
+ *
+ *     Compute the best pio mode we can for a given device. We must
+ *     pick a speed that does not cause problems with the other device
+ *     on the cable.
+ */
+
+static void config_it821x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+       u8 unit = drive->select.b.unit;
+       ide_hwif_t *hwif = drive->hwif;
+       ide_drive_t *pair = &hwif->drives[1-unit];
+       u8 speed = 0, set_pio   = ide_get_best_pio_mode(drive, 255, 5, NULL);
+       u8 pair_pio;
+
+       /* We have to deal with this mess in pairs */
+       if(pair != NULL) {
+               pair_pio = ide_get_best_pio_mode(pair, 255, 5, NULL);
+               /* Trim PIO to the slowest of the master/slave */
+               if(pair_pio < set_pio)
+                       set_pio = pair_pio;
+       }
+       it821x_tuneproc(drive, set_pio);
+       speed = XFER_PIO_0 + set_pio;
+       /* XXX - We trim to the lowest of the pair so the other drive
+          will always be fine at this point until we do hotplug passthru */
+
+       if (set_speed)
+               (void) ide_config_drive_speed(drive, speed);
+}
+
+/**
+ *     it821x_dma_read -       DMA hook
+ *     @drive: drive for DMA
+ *
+ *     The IT821x has a single timing register for MWDMA and for PIO
+ *     operations. As we flip back and forth we have to reload the
+ *     clock. In addition the rev 0x10 device only works if the same
+ *     timing value is loaded into the master and slave UDMA clock
+ *     so we must also reload that.
+ *
+ *     FIXME: we could figure out in advance if we need to do reloads
+ */
+
+static void it821x_dma_start(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       int unit = drive->select.b.unit;
+       if(itdev->mwdma[unit] != MWDMA_OFF)
+               it821x_program(drive, itdev->mwdma[unit]);
+       else if(itdev->udma[unit] != UDMA_OFF && itdev->timing10)
+               it821x_program_udma(drive, itdev->udma[unit]);
+       ide_dma_start(drive);
+}
+
+/**
+ *     it821x_dma_write        -       DMA hook
+ *     @drive: drive for DMA stop
+ *
+ *     The IT821x has a single timing register for MWDMA and for PIO
+ *     operations. As we flip back and forth we have to reload the
+ *     clock.
+ */
+
+static int it821x_dma_end(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       int unit = drive->select.b.unit;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       int ret = __ide_dma_end(drive);
+       if(itdev->mwdma[unit] != MWDMA_OFF)
+               it821x_program(drive, itdev->pio[unit]);
+       return ret;
+}
+
+
+/**
+ *     it821x_tune_chipset     -       set controller timings
+ *     @drive: Drive to set up
+ *     @xferspeed: speed we want to achieve
+ *
+ *     Tune the ITE chipset for the desired mode. If we can't achieve
+ *     the desired mode then tune for a lower one, but ultimately
+ *     make the thing work.
+ */
+
+static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+
+       ide_hwif_t *hwif        = drive->hwif;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       u8 speed                = ide_rate_filter(it821x_ratemask(drive), xferspeed);
+
+       if(!itdev->smart) {
+               switch(speed) {
+                       case XFER_PIO_4:
+                       case XFER_PIO_3:
+                       case XFER_PIO_2:
+                       case XFER_PIO_1:
+                       case XFER_PIO_0:
+                               it821x_tuneproc(drive, (speed - XFER_PIO_0));
+                               break;
+                       /* MWDMA tuning is really hard because our MWDMA and PIO
+                          timings are kept in the same place. We can switch in the
+                          host dma on/off callbacks */
+                       case XFER_MW_DMA_2:
+                       case XFER_MW_DMA_1:
+                       case XFER_MW_DMA_0:
+                               it821x_tune_mwdma(drive, (speed - XFER_MW_DMA_0));
+                               break;
+                       case XFER_UDMA_6:
+                       case XFER_UDMA_5:
+                       case XFER_UDMA_4:
+                       case XFER_UDMA_3:
+                       case XFER_UDMA_2:
+                       case XFER_UDMA_1:
+                       case XFER_UDMA_0:
+                               it821x_tune_udma(drive, (speed - XFER_UDMA_0));
+                               break;
+                       default:
+                               return 1;
+               }
+       }
+       /*
+        *      In smart mode the clocking is done by the host controller
+        *      snooping the mode we picked. The rest of it is not our problem
+        */
+       return ide_config_drive_speed(drive, speed);
+}
+
+/**
+ *     config_chipset_for_dma  -       configure for DMA
+ *     @drive: drive to configure
+ *
+ *     Called by the IDE layer when it wants the timings set up.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+       u8 speed        = ide_dma_speed(drive, it821x_ratemask(drive));
+
+       config_it821x_chipset_for_pio(drive, !speed);
+       it821x_tune_chipset(drive, speed);
+       return ide_dma_enable(drive);
+}
+
+/**
+ *     it821x_configure_drive_for_dma  -       set up for DMA transfers
+ *     @drive: drive we are going to set up
+ *
+ *     Set up the drive for DMA, tune the controller and drive as
+ *     required. If the drive isn't suitable for DMA or we hit
+ *     other problems then we will drop down to PIO and set up
+ *     PIO appropriately
+ */
+
+static int it821x_config_drive_for_dma (ide_drive_t *drive)
+{
+       ide_hwif_t *hwif        = drive->hwif;
+
+       if (ide_use_dma(drive)) {
+               if (config_chipset_for_dma(drive))
+                       return hwif->ide_dma_on(drive);
+       }
+       config_it821x_chipset_for_pio(drive, 1);
+       return hwif->ide_dma_off_quietly(drive);
+}
+
+/**
+ *     ata66_it821x    -       check for 80 pin cable
+ *     @hwif: interface to check
+ *
+ *     Check for the presence of an ATA66 capable cable on the
+ *     interface. Problematic as it seems some cards don't have
+ *     the needed logic onboard.
+ */
+
+static unsigned int __devinit ata66_it821x(ide_hwif_t *hwif)
+{
+       /* The reference driver also only does disk side */
+       return 1;
+}
+
+/**
+ *     it821x_fixup    -       post init callback
+ *     @hwif: interface
+ *
+ *     This callback is run after the drives have been probed but
+ *     before anything gets attached. It allows drivers to do any
+ *     final tuning that is needed, or fixups to work around bugs.
+ */
+
+static void __devinit it821x_fixups(ide_hwif_t *hwif)
+{
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       int i;
+
+       if(!itdev->smart) {
+               /*
+                *      If we are in pass through mode then not much
+                *      needs to be done, but we do bother to clear the
+                *      IRQ mask as we may well be in PIO (eg rev 0x10)
+                *      for now and we know unmasking is safe on this chipset.
+                */
+               for (i = 0; i < 2; i++) {
+                       ide_drive_t *drive = &hwif->drives[i];
+                       if(drive->present)
+                               drive->unmask = 1;
+               }
+               return;
+       }
+       /*
+        *      Perform fixups on smart mode. We need to "lose" some
+        *      capabilities the firmware lacks but does not filter, and
+        *      also patch up some capability bits that it forgets to set
+        *      in RAID mode.
+        */
+
+       for(i = 0; i < 2; i++) {
+               ide_drive_t *drive = &hwif->drives[i];
+               struct hd_driveid *id;
+               u16 *idbits;
+
+               if(!drive->present)
+                       continue;
+               id = drive->id;
+               idbits = (u16 *)drive->id;
+
+               /* Check for RAID v native */
+               if(strstr(id->model, "Integrated Technology Express")) {
+                       /* In raid mode the ident block is slightly buggy
+                          We need to set the bits so that the IDE layer knows
+                          LBA28. LBA48 and DMA ar valid */
+                       id->capability |= 3;            /* LBA28, DMA */
+                       id->command_set_2 |= 0x0400;    /* LBA48 valid */
+                       id->cfs_enable_2 |= 0x0400;     /* LBA48 on */
+                       /* Reporting logic */
+                       printk(KERN_INFO "%s: IT8212 %sRAID %d volume",
+                               drive->name,
+                               idbits[147] ? "Bootable ":"",
+                               idbits[129]);
+                               if(idbits[129] != 1)
+                                       printk("(%dK stripe)", idbits[146]);
+                               printk(".\n");
+                       /* Now the core code will have wrongly decided no DMA
+                          so we need to fix this */
+                       hwif->ide_dma_off_quietly(drive);
+#ifdef CONFIG_IDEDMA_ONLYDISK
+                       if (drive->media == ide_disk)
+#endif
+                               hwif->ide_dma_check(drive);
+               } else {
+                       /* Non RAID volume. Fixups to stop the core code
+                          doing unsupported things */
+                       id->field_valid &= 1;
+                       id->queue_depth = 0;
+                       id->command_set_1 = 0;
+                       id->command_set_2 &= 0xC400;
+                       id->cfsse &= 0xC000;
+                       id->cfs_enable_1 = 0;
+                       id->cfs_enable_2 &= 0xC400;
+                       id->csf_default &= 0xC000;
+                       id->word127 = 0;
+                       id->dlf = 0;
+                       id->csfo = 0;
+                       id->cfa_power = 0;
+                       printk(KERN_INFO "%s: Performing identify fixups.\n",
+                               drive->name);
+               }
+       }
+
+}
+
+/**
+ *     init_hwif_it821x        -       set up hwif structs
+ *     @hwif: interface to set up
+ *
+ *     We do the basic set up of the interface structure. The IT8212
+ *     requires several custom handlers so we override the default
+ *     ide DMA handlers appropriately
+ */
+
+static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
+{
+       struct it821x_dev *idev = kmalloc(sizeof(struct it821x_dev), GFP_KERNEL);
+       u8 conf;
+
+       if(idev == NULL) {
+               printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n");
+               goto fallback;
+       }
+       memset(idev, 0, sizeof(struct it821x_dev));
+       ide_set_hwifdata(hwif, idev);
+
+       pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
+       if(conf & 1) {
+               idev->smart = 1;
+               hwif->atapi_dma = 0;
+               /* Long I/O's although allowed in LBA48 space cause the
+                  onboard firmware to enter the twighlight zone */
+               hwif->rqsize = 256;
+       }
+
+       /* Pull the current clocks from 0x50 also */
+       if (conf & (1 << (1 + hwif->channel)))
+               idev->clock_mode = ATA_50;
+       else
+               idev->clock_mode = ATA_66;
+
+       idev->want[0][1] = ATA_ANY;
+       idev->want[1][1] = ATA_ANY;
+
+       /*
+        *      Not in the docs but according to the reference driver
+        *      this is neccessary.
+        */
+
+       pci_read_config_byte(hwif->pci_dev, 0x08, &conf);
+       if(conf == 0x10) {
+               idev->timing10 = 1;
+               hwif->atapi_dma = 0;
+               if(!idev->smart)
+                       printk(KERN_WARNING "it821x: Revision 0x10, workarounds activated.\n");
+       }
+
+       hwif->speedproc = &it821x_tune_chipset;
+       hwif->tuneproc  = &it821x_tuneproc;
+
+       /* MWDMA/PIO clock switching for pass through mode */
+       if(!idev->smart) {
+               hwif->dma_start = &it821x_dma_start;
+               hwif->ide_dma_end = &it821x_dma_end;
+       }
+
+       hwif->drives[0].autotune = 1;
+       hwif->drives[1].autotune = 1;
+
+       if (!hwif->dma_base)
+               goto fallback;
+
+       hwif->ultra_mask = 0x7f;
+       hwif->mwdma_mask = 0x07;
+       hwif->swdma_mask = 0x07;
+
+       hwif->ide_dma_check = &it821x_config_drive_for_dma;
+       if (!(hwif->udma_four))
+               hwif->udma_four = ata66_it821x(hwif);
+
+       /*
+        *      The BIOS often doesn't set up DMA on this controller
+        *      so we always do it.
+        */
+
+       hwif->autodma = 1;
+       hwif->drives[0].autodma = hwif->autodma;
+       hwif->drives[1].autodma = hwif->autodma;
+       return;
+fallback:
+       hwif->autodma = 0;
+       return;
+}
+
+static void __devinit it8212_disable_raid(struct pci_dev *dev)
+{
+       /* Reset local CPU, and set BIOS not ready */
+       pci_write_config_byte(dev, 0x5E, 0x01);
+
+       /* Set to bypass mode, and reset PCI bus */
+       pci_write_config_byte(dev, 0x50, 0x00);
+       pci_write_config_word(dev, PCI_COMMAND,
+                             PCI_COMMAND_PARITY | PCI_COMMAND_IO |
+                             PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+       pci_write_config_word(dev, 0x40, 0xA0F3);
+
+       pci_write_config_dword(dev,0x4C, 0x02040204);
+       pci_write_config_byte(dev, 0x42, 0x36);
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0);
+}
+
+static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const char *name)
+{
+       u8 conf;
+       static char *mode[2] = { "pass through", "smart" };
+
+       /* Force the card into bypass mode if so requested */
+       if (it8212_noraid) {
+               printk(KERN_INFO "it8212: forcing bypass mode.\n");
+               it8212_disable_raid(dev);
+       }
+       pci_read_config_byte(dev, 0x50, &conf);
+       printk(KERN_INFO "it821x: controller in %s mode.\n", mode[conf & 1]);
+       return 0;
+}
+
+
+#define DECLARE_ITE_DEV(name_str)                      \
+       {                                               \
+               .name           = name_str,             \
+               .init_chipset   = init_chipset_it821x,  \
+               .init_hwif      = init_hwif_it821x,     \
+               .channels       = 2,                    \
+               .autodma        = AUTODMA,              \
+               .bootable       = ON_BOARD,             \
+               .fixup          = it821x_fixups         \
+       }
+
+static ide_pci_device_t it821x_chipsets[] __devinitdata = {
+       /* 0 */ DECLARE_ITE_DEV("IT8212"),
+};
+
+/**
+ *     it821x_init_one -       pci layer discovery entry
+ *     @dev: PCI device
+ *     @id: ident table entry
+ *
+ *     Called by the PCI code when it finds an ITE821x controller.
+ *     We then use the IDE PCI generic helper to do most of the work.
+ */
+
+static int __devinit it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       ide_setup_pci_device(dev, &it821x_chipsets[id->driver_data]);
+       return 0;
+}
+
+static struct pci_device_id it821x_pci_tbl[] = {
+       { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, it821x_pci_tbl);
+
+static struct pci_driver driver = {
+       .name           = "ITE821x IDE",
+       .id_table       = it821x_pci_tbl,
+       .probe          = it821x_init_one,
+};
+
+static int __init it821x_ide_init(void)
+{
+       return ide_pci_register_driver(&driver);
+}
+
+module_init(it821x_ide_init);
+
+module_param_named(noraid, it8212_noraid, int, S_IRUGO);
+MODULE_PARM_DESC(it8212_noraid, "Force card into bypass mode");
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for the ITE 821x");
+MODULE_LICENSE("GPL");
index 82a1103b24130f8bd9084bcf51d23d0b534a645a..c6f5fa4b4ca6b74b1ab3dc77cc5775d5a3c08b6a 100644 (file)
@@ -442,7 +442,7 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
        return (dev->irq) ? dev->irq : 0;
 }
 
-static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks_svwks (ide_hwif_t *hwif)
 {
        return 1;
 }
@@ -454,7 +454,7 @@ static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
  * Bit 14 clear = primary IDE channel does not have 80-pin cable.
  * Bit 14 set   = primary IDE channel has 80-pin cable.
  */
-static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks_dell (ide_hwif_t *hwif)
 {
        struct pci_dev *dev = hwif->pci_dev;
        if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
@@ -472,7 +472,7 @@ static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
  *
  * WARNING: this only works on Alpine hardware!
  */
-static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks_cobalt (ide_hwif_t *hwif)
 {
        struct pci_dev *dev = hwif->pci_dev;
        if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
@@ -483,7 +483,7 @@ static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
        return 0;
 }
 
-static unsigned int __init ata66_svwks (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks (ide_hwif_t *hwif)
 {
        struct pci_dev *dev = hwif->pci_dev;
 
@@ -573,7 +573,7 @@ static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
        return ide_setup_pci_device(dev, d);
 }
 
-static int __init init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
+static int __devinit init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
 {
        if (!(PCI_FUNC(dev->devfn) & 1)) {
                d->bootable = NEVER_BOARD;
index 569f16767442bf7fc0193425579a33b0eb4fb289..818380b5fd277e402b2da9a51c419ce0c601c3d6 100644 (file)
@@ -1324,9 +1324,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
        /* XXX FIXME: Media bay stuff need re-organizing */
        if (np->parent && np->parent->name
            && strcasecmp(np->parent->name, "media-bay") == 0) {
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PMAC_MEDIABAY
                media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq, hwif->index);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PMAC_MEDIABAY */
                pmif->mediabay = 1;
                if (!bidp)
                        pmif->aapl_bus_id = 1;
@@ -1382,10 +1382,10 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
               hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
               pmif->mediabay ? " (mediabay)" : "", hwif->irq);
                        
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PMAC_MEDIABAY
        if (pmif->mediabay && check_media_bay_by_base(pmif->regbase, MB_CD) == 0)
                hwif->noprobe = 0;
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PMAC_MEDIABAY */
 
        hwif->sg_max_nents = MAX_DCMDS;
 
index 2d9a9b74e687ce51a19b7d026ca4b73155083d5f..629070b83a3360c03abc5a76a752e4ed7ba57902 100644 (file)
@@ -1041,10 +1041,8 @@ static int hpsbpkt_thread(void *__hi)
 
        while (1) {
                if (down_interruptible(&khpsbpkt_sig)) {
-                       if (current->flags & PF_FREEZE) {
-                               refrigerator(0);
+                       if (try_to_freeze())
                                continue;
-                       }
                        printk("khpsbpkt: received unexpected signal?!\n" );
                        break;
                }
index 32abb6dda888cbbb480b1ebf19ab3a5f45f24b17..9a46c3b44bf8b616aaf9c8755725b90af433610c 100644 (file)
@@ -1510,7 +1510,7 @@ static int nodemgr_host_thread(void *__hi)
 
                if (down_interruptible(&hi->reset_sem) ||
                    down_interruptible(&nodemgr_serialize)) {
-                       if (try_to_freeze(PF_FREEZE))
+                       if (try_to_freeze())
                                continue;
                        printk("NodeMgr: received unexpected signal?!\n" );
                        break;
index 36e25ac823dc73c2f69c58e391dd4382af59de55..b3d3d22fde64d4262a2aae4fe194a2ac4b067d11 100644 (file)
@@ -3538,8 +3538,8 @@ static void ohci1394_pci_remove(struct pci_dev *pdev)
 
 static int ohci1394_pci_resume (struct pci_dev *pdev)
 {
-#ifdef CONFIG_PMAC_PBOOK
-       {
+#ifdef CONFIG_PPC_PMAC
+       if (_machine == _MACH_Pmac) {
                struct device_node *of_node;
 
                /* Re-enable 1394 */
@@ -3547,7 +3547,7 @@ static int ohci1394_pci_resume (struct pci_dev *pdev)
                if (of_node)
                        pmac_call_feature (PMAC_FTR_1394_ENABLE, of_node, 0, 1);
        }
-#endif
+#endif /* CONFIG_PPC_PMAC */
 
        pci_enable_device(pdev);
 
@@ -3557,8 +3557,8 @@ static int ohci1394_pci_resume (struct pci_dev *pdev)
 
 static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
 {
-#ifdef CONFIG_PMAC_PBOOK
-       {
+#ifdef CONFIG_PPC_PMAC
+       if (_machine == _MACH_Pmac) {
                struct device_node *of_node;
 
                /* Disable 1394 */
index 5f15feffeae2d8ba20d938e135fdd5b7ad129300..eb5ff54c10d75e758088f2e594167a18a4f3fabc 100644 (file)
@@ -96,7 +96,7 @@ void ib_pack(const struct ib_field        *desc,
                        else
                                val = 0;
 
-                       mask = cpu_to_be64(((1ull << desc[i].size_bits) - 1) << shift);
+                       mask = cpu_to_be64((~0ull >> (64 - desc[i].size_bits)) << shift);
                        addr = (__be64 *) ((__be32 *) buf + desc[i].offset_words);
                        *addr = (*addr & ~mask) | (cpu_to_be64(val) & mask);
                } else {
@@ -176,7 +176,7 @@ void ib_unpack(const struct ib_field        *desc,
                        __be64 *addr;
 
                        shift = 64 - desc[i].offset_bits - desc[i].size_bits;
-                       mask = ((1ull << desc[i].size_bits) - 1) << shift;
+                       mask = (~0ull >> (64 - desc[i].size_bits)) << shift;
                        addr = (__be64 *) buf + desc[i].offset_words;
                        val = (be64_to_cpup(addr) & mask) >> shift;
                        value_write(desc[i].struct_offset_bytes,
index 276e1a53010ddc19a312b067caccf89c3c6b6c00..5a08e81fa82704e7496ecf2705e0325933f1d2eb 100644 (file)
@@ -507,7 +507,13 @@ retry:
                spin_unlock_irqrestore(&idr_lock, flags);
        }
 
-       return ret;
+       /*
+        * It's not safe to dereference query any more, because the
+        * send may already have completed and freed the query in
+        * another context.  So use wr.wr_id, which has a copy of the
+        * query's id.
+        */
+       return ret ? ret : wr.wr_id;
 }
 
 static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
@@ -598,14 +604,15 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,
                rec, query->sa_query.mad->data);
 
        *sa_query = &query->sa_query;
+
        ret = send_mad(&query->sa_query, timeout_ms);
-       if (ret) {
+       if (ret < 0) {
                *sa_query = NULL;
                kfree(query->sa_query.mad);
                kfree(query);
        }
 
-       return ret ? ret : query->sa_query.id;
+       return ret;
 }
 EXPORT_SYMBOL(ib_sa_path_rec_get);
 
@@ -674,14 +681,15 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num,
                rec, query->sa_query.mad->data);
 
        *sa_query = &query->sa_query;
+
        ret = send_mad(&query->sa_query, timeout_ms);
-       if (ret) {
+       if (ret < 0) {
                *sa_query = NULL;
                kfree(query->sa_query.mad);
                kfree(query);
        }
 
-       return ret ? ret : query->sa_query.id;
+       return ret;
 }
 EXPORT_SYMBOL(ib_sa_mcmember_rec_query);
 
index 085baf393ca4f5921ba4efc939006f18fdd06d6c..d58dcbe66488080b3ccdfc497cfb7fdc19822aae 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, 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
index cd9ed958d92fedc8b993b24347c00d2f57336247..1557a522d8319a8e3e2c1bc497a933094a056f87 100644 (file)
@@ -431,6 +431,36 @@ static int mthca_cmd_imm(struct mthca_dev *dev,
                                      timeout, status);
 }
 
+int mthca_cmd_init(struct mthca_dev *dev)
+{
+       sema_init(&dev->cmd.hcr_sem, 1);
+       sema_init(&dev->cmd.poll_sem, 1);
+       dev->cmd.use_events = 0;
+
+       dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE,
+                          MTHCA_HCR_SIZE);
+       if (!dev->hcr) {
+               mthca_err(dev, "Couldn't map command register.");
+               return -ENOMEM;
+       }
+
+       dev->cmd.pool = pci_pool_create("mthca_cmd", dev->pdev,
+                                       MTHCA_MAILBOX_SIZE,
+                                       MTHCA_MAILBOX_SIZE, 0);
+       if (!dev->cmd.pool) {
+               iounmap(dev->hcr);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+void mthca_cmd_cleanup(struct mthca_dev *dev)
+{
+       pci_pool_destroy(dev->cmd.pool);
+       iounmap(dev->hcr);
+}
+
 /*
  * Switch to using events to issue FW commands (should be called after
  * event queue to command events has been initialized).
@@ -489,6 +519,33 @@ void mthca_cmd_use_polling(struct mthca_dev *dev)
        up(&dev->cmd.poll_sem);
 }
 
+struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
+                                         unsigned int gfp_mask)
+{
+       struct mthca_mailbox *mailbox;
+
+       mailbox = kmalloc(sizeof *mailbox, gfp_mask);
+       if (!mailbox)
+               return ERR_PTR(-ENOMEM);
+
+       mailbox->buf = pci_pool_alloc(dev->cmd.pool, gfp_mask, &mailbox->dma);
+       if (!mailbox->buf) {
+               kfree(mailbox);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       return mailbox;
+}
+
+void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox)
+{
+       if (!mailbox)
+               return;
+
+       pci_pool_free(dev->cmd.pool, mailbox->buf, mailbox->dma);
+       kfree(mailbox);
+}
+
 int mthca_SYS_EN(struct mthca_dev *dev, u8 *status)
 {
        u64 out;
@@ -513,20 +570,20 @@ int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status)
 static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
                         u64 virt, u8 *status)
 {
-       u32 *inbox;
-       dma_addr_t indma;
+       struct mthca_mailbox *mailbox;
        struct mthca_icm_iter iter;
+       __be64 *pages;
        int lg;
        int nent = 0;
        int i;
        int err = 0;
        int ts = 0, tc = 0;
 
-       inbox = pci_alloc_consistent(dev->pdev, PAGE_SIZE, &indma);
-       if (!inbox)
-               return -ENOMEM;
-
-       memset(inbox, 0, PAGE_SIZE);
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       memset(mailbox->buf, 0, MTHCA_MAILBOX_SIZE);
+       pages = mailbox->buf;
 
        for (mthca_icm_first(icm, &iter);
             !mthca_icm_last(&iter);
@@ -546,19 +603,17 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
                }
                for (i = 0; i < mthca_icm_size(&iter) / (1 << lg); ++i, ++nent) {
                        if (virt != -1) {
-                               *((__be64 *) (inbox + nent * 4)) =
-                                       cpu_to_be64(virt);
+                               pages[nent * 2] = cpu_to_be64(virt);
                                virt += 1 << lg;
                        }
 
-                       *((__be64 *) (inbox + nent * 4 + 2)) =
-                               cpu_to_be64((mthca_icm_addr(&iter) +
-                                            (i << lg)) | (lg - 12));
+                       pages[nent * 2 + 1] = cpu_to_be64((mthca_icm_addr(&iter) +
+                                                          (i << lg)) | (lg - 12));
                        ts += 1 << (lg - 10);
                        ++tc;
 
-                       if (nent == PAGE_SIZE / 16) {
-                               err = mthca_cmd(dev, indma, nent, 0, op,
+                       if (nent == MTHCA_MAILBOX_SIZE / 16) {
+                               err = mthca_cmd(dev, mailbox->dma, nent, 0, op,
                                                CMD_TIME_CLASS_B, status);
                                if (err || *status)
                                        goto out;
@@ -568,7 +623,7 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
        }
 
        if (nent)
-               err = mthca_cmd(dev, indma, nent, 0, op,
+               err = mthca_cmd(dev, mailbox->dma, nent, 0, op,
                                CMD_TIME_CLASS_B, status);
 
        switch (op) {
@@ -585,7 +640,7 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
        }
 
 out:
-       pci_free_consistent(dev->pdev, PAGE_SIZE, inbox, indma);
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
@@ -606,8 +661,8 @@ int mthca_RUN_FW(struct mthca_dev *dev, u8 *status)
 
 int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 {
+       struct mthca_mailbox *mailbox;
        u32 *outbox;
-       dma_addr_t outdma;
        int err = 0;
        u8 lg;
 
@@ -625,12 +680,12 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 #define QUERY_FW_EQ_ARM_BASE_OFFSET    0x40
 #define QUERY_FW_EQ_SET_CI_BASE_OFFSET 0x48
 
-       outbox = pci_alloc_consistent(dev->pdev, QUERY_FW_OUT_SIZE, &outdma);
-       if (!outbox) {
-               return -ENOMEM;
-       }
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       outbox = mailbox->buf;
 
-       err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_FW,
+       err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_FW,
                            CMD_TIME_CLASS_A, status);
 
        if (err)
@@ -681,15 +736,15 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
        }
 
 out:
-       pci_free_consistent(dev->pdev, QUERY_FW_OUT_SIZE, outbox, outdma);
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
 int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
 {
+       struct mthca_mailbox *mailbox;
        u8 info;
        u32 *outbox;
-       dma_addr_t outdma;
        int err = 0;
 
 #define ENABLE_LAM_OUT_SIZE         0x100
@@ -700,11 +755,12 @@ int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
 #define ENABLE_LAM_INFO_HIDDEN_FLAG (1 << 4)
 #define ENABLE_LAM_INFO_ECC_MASK    0x3
 
-       outbox = pci_alloc_consistent(dev->pdev, ENABLE_LAM_OUT_SIZE, &outdma);
-       if (!outbox)
-               return -ENOMEM;
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       outbox = mailbox->buf;
 
-       err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_ENABLE_LAM,
+       err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_ENABLE_LAM,
                            CMD_TIME_CLASS_C, status);
 
        if (err)
@@ -733,7 +789,7 @@ int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
                  (unsigned long long) dev->ddr_end);
 
 out:
-       pci_free_consistent(dev->pdev, ENABLE_LAM_OUT_SIZE, outbox, outdma);
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
@@ -744,9 +800,9 @@ int mthca_DISABLE_LAM(struct mthca_dev *dev, u8 *status)
 
 int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
 {
+       struct mthca_mailbox *mailbox;
        u8 info;
        u32 *outbox;
-       dma_addr_t outdma;
        int err = 0;
 
 #define QUERY_DDR_OUT_SIZE         0x100
@@ -757,11 +813,12 @@ int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
 #define QUERY_DDR_INFO_HIDDEN_FLAG (1 << 4)
 #define QUERY_DDR_INFO_ECC_MASK    0x3
 
-       outbox = pci_alloc_consistent(dev->pdev, QUERY_DDR_OUT_SIZE, &outdma);
-       if (!outbox)
-               return -ENOMEM;
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       outbox = mailbox->buf;
 
-       err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_DDR,
+       err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DDR,
                            CMD_TIME_CLASS_A, status);
 
        if (err)
@@ -787,15 +844,15 @@ int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
                  (unsigned long long) dev->ddr_end);
 
 out:
-       pci_free_consistent(dev->pdev, QUERY_DDR_OUT_SIZE, outbox, outdma);
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
 int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
                        struct mthca_dev_lim *dev_lim, u8 *status)
 {
+       struct mthca_mailbox *mailbox;
        u32 *outbox;
-       dma_addr_t outdma;
        u8 field;
        u16 size;
        int err;
@@ -860,11 +917,12 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
 #define QUERY_DEV_LIM_LAMR_OFFSET           0x9f
 #define QUERY_DEV_LIM_MAX_ICM_SZ_OFFSET     0xa0
 
-       outbox = pci_alloc_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, &outdma);
-       if (!outbox)
-               return -ENOMEM;
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       outbox = mailbox->buf;
 
-       err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_DEV_LIM,
+       err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DEV_LIM,
                            CMD_TIME_CLASS_A, status);
 
        if (err)
@@ -1020,15 +1078,15 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
        }
 
 out:
-       pci_free_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, outbox, outdma);
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
 int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
                        struct mthca_adapter *adapter, u8 *status)
 {
+       struct mthca_mailbox *mailbox;
        u32 *outbox;
-       dma_addr_t outdma;
        int err;
 
 #define QUERY_ADAPTER_OUT_SIZE             0x100
@@ -1037,23 +1095,24 @@ int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
 #define QUERY_ADAPTER_REVISION_ID_OFFSET   0x08
 #define QUERY_ADAPTER_INTA_PIN_OFFSET      0x10
 
-       outbox = pci_alloc_consistent(dev->pdev, QUERY_ADAPTER_OUT_SIZE, &outdma);
-       if (!outbox)
-               return -ENOMEM;
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       outbox = mailbox->buf;
 
-       err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_ADAPTER,
+       err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_ADAPTER,
                            CMD_TIME_CLASS_A, status);
 
        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->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);
+       MTHCA_GET(adapter->inta_pin, outbox,    QUERY_ADAPTER_INTA_PIN_OFFSET);
 
 out:
-       pci_free_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, outbox, outdma);
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
@@ -1061,8 +1120,8 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
                   struct mthca_init_hca_param *param,
                   u8 *status)
 {
+       struct mthca_mailbox *mailbox;
        u32 *inbox;
-       dma_addr_t indma;
        int err;
 
 #define INIT_HCA_IN_SIZE                0x200
@@ -1102,9 +1161,10 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
 #define  INIT_HCA_UAR_SCATCH_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x10)
 #define  INIT_HCA_UAR_CTX_BASE_OFFSET    (INIT_HCA_UAR_OFFSET + 0x18)
 
-       inbox = pci_alloc_consistent(dev->pdev, INIT_HCA_IN_SIZE, &indma);
-       if (!inbox)
-               return -ENOMEM;
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       inbox = mailbox->buf;
 
        memset(inbox, 0, INIT_HCA_IN_SIZE);
 
@@ -1167,10 +1227,9 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
                MTHCA_PUT(inbox, param->uarc_base,   INIT_HCA_UAR_CTX_BASE_OFFSET);
        }
 
-       err = mthca_cmd(dev, indma, 0, 0, CMD_INIT_HCA,
-                       HZ, status);
+       err = mthca_cmd(dev, mailbox->dma, 0, 0, CMD_INIT_HCA, HZ, status);
 
-       pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
@@ -1178,8 +1237,8 @@ int mthca_INIT_IB(struct mthca_dev *dev,
                  struct mthca_init_ib_param *param,
                  int port, u8 *status)
 {
+       struct mthca_mailbox *mailbox;
        u32 *inbox;
-       dma_addr_t indma;
        int err;
        u32 flags;
 
@@ -1199,9 +1258,10 @@ int mthca_INIT_IB(struct mthca_dev *dev,
 #define INIT_IB_NODE_GUID_OFFSET 0x18
 #define INIT_IB_SI_GUID_OFFSET   0x20
 
-       inbox = pci_alloc_consistent(dev->pdev, INIT_IB_IN_SIZE, &indma);
-       if (!inbox)
-               return -ENOMEM;
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       inbox = mailbox->buf;
 
        memset(inbox, 0, INIT_IB_IN_SIZE);
 
@@ -1221,10 +1281,10 @@ int mthca_INIT_IB(struct mthca_dev *dev,
        MTHCA_PUT(inbox, param->node_guid, INIT_IB_NODE_GUID_OFFSET);
        MTHCA_PUT(inbox, param->si_guid,   INIT_IB_SI_GUID_OFFSET);
 
-       err = mthca_cmd(dev, indma, port, 0, CMD_INIT_IB,
+       err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_INIT_IB,
                        CMD_TIME_CLASS_A, status);
 
-       pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
@@ -1241,8 +1301,8 @@ int mthca_CLOSE_HCA(struct mthca_dev *dev, int panic, u8 *status)
 int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
                 int port, u8 *status)
 {
+       struct mthca_mailbox *mailbox;
        u32 *inbox;
-       dma_addr_t indma;
        int err;
        u32 flags = 0;
 
@@ -1253,9 +1313,10 @@ int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
 #define SET_IB_CAP_MASK_OFFSET 0x04
 #define SET_IB_SI_GUID_OFFSET  0x08
 
-       inbox = pci_alloc_consistent(dev->pdev, SET_IB_IN_SIZE, &indma);
-       if (!inbox)
-               return -ENOMEM;
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       inbox = mailbox->buf;
 
        memset(inbox, 0, SET_IB_IN_SIZE);
 
@@ -1266,10 +1327,10 @@ int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
        MTHCA_PUT(inbox, param->cap_mask, SET_IB_CAP_MASK_OFFSET);
        MTHCA_PUT(inbox, param->si_guid,  SET_IB_SI_GUID_OFFSET);
 
-       err = mthca_cmd(dev, indma, port, 0, CMD_SET_IB,
+       err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_SET_IB,
                        CMD_TIME_CLASS_B, status);
 
-       pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
@@ -1280,20 +1341,22 @@ int mthca_MAP_ICM(struct mthca_dev *dev, struct mthca_icm *icm, u64 virt, u8 *st
 
 int mthca_MAP_ICM_page(struct mthca_dev *dev, u64 dma_addr, u64 virt, u8 *status)
 {
+       struct mthca_mailbox *mailbox;
        u64 *inbox;
-       dma_addr_t indma;
        int err;
 
-       inbox = pci_alloc_consistent(dev->pdev, 16, &indma);
-       if (!inbox)
-               return -ENOMEM;
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       inbox = mailbox->buf;
 
        inbox[0] = cpu_to_be64(virt);
        inbox[1] = cpu_to_be64(dma_addr);
 
-       err = mthca_cmd(dev, indma, 1, 0, CMD_MAP_ICM, CMD_TIME_CLASS_B, status);
+       err = mthca_cmd(dev, mailbox->dma, 1, 0, CMD_MAP_ICM,
+                       CMD_TIME_CLASS_B, status);
 
-       pci_free_consistent(dev->pdev, 16, inbox, indma);
+       mthca_free_mailbox(dev, mailbox);
 
        if (!err)
                mthca_dbg(dev, "Mapped page at %llx to %llx for ICM.\n",
@@ -1338,69 +1401,26 @@ int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
        return 0;
 }
 
-int mthca_SW2HW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                    int mpt_index, u8 *status)
 {
-       dma_addr_t indma;
-       int err;
-
-       indma = pci_map_single(dev->pdev, mpt_entry,
-                              MTHCA_MPT_ENTRY_SIZE,
-                              PCI_DMA_TODEVICE);
-       if (pci_dma_mapping_error(indma))
-               return -ENOMEM;
-
-       err = mthca_cmd(dev, indma, mpt_index, 0, CMD_SW2HW_MPT,
-                       CMD_TIME_CLASS_B, status);
-
-       pci_unmap_single(dev->pdev, indma,
-                        MTHCA_MPT_ENTRY_SIZE, PCI_DMA_TODEVICE);
-       return err;
+       return mthca_cmd(dev, mailbox->dma, mpt_index, 0, CMD_SW2HW_MPT,
+                        CMD_TIME_CLASS_B, status);
 }
 
-int mthca_HW2SW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                    int mpt_index, u8 *status)
 {
-       dma_addr_t outdma = 0;
-       int err;
-
-       if (mpt_entry) {
-               outdma = pci_map_single(dev->pdev, mpt_entry,
-                                       MTHCA_MPT_ENTRY_SIZE,
-                                       PCI_DMA_FROMDEVICE);
-               if (pci_dma_mapping_error(outdma))
-                       return -ENOMEM;
-       }
-
-       err = mthca_cmd_box(dev, 0, outdma, mpt_index, !mpt_entry,
-                           CMD_HW2SW_MPT,
-                           CMD_TIME_CLASS_B, status);
-
-       if (mpt_entry)
-               pci_unmap_single(dev->pdev, outdma,
-                                MTHCA_MPT_ENTRY_SIZE,
-                                PCI_DMA_FROMDEVICE);
-       return err;
+       return mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index,
+                            !mailbox, CMD_HW2SW_MPT,
+                            CMD_TIME_CLASS_B, status);
 }
 
-int mthca_WRITE_MTT(struct mthca_dev *dev, u64 *mtt_entry,
+int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                    int num_mtt, u8 *status)
 {
-       dma_addr_t indma;
-       int err;
-
-       indma = pci_map_single(dev->pdev, mtt_entry,
-                              (num_mtt + 2) * 8,
-                              PCI_DMA_TODEVICE);
-       if (pci_dma_mapping_error(indma))
-               return -ENOMEM;
-
-       err = mthca_cmd(dev, indma, num_mtt, 0, CMD_WRITE_MTT,
-                       CMD_TIME_CLASS_B, status);
-
-       pci_unmap_single(dev->pdev, indma,
-                        (num_mtt + 2) * 8, PCI_DMA_TODEVICE);
-       return err;
+       return mthca_cmd(dev, mailbox->dma, num_mtt, 0, CMD_WRITE_MTT,
+                        CMD_TIME_CLASS_B, status);
 }
 
 int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status)
@@ -1418,92 +1438,38 @@ int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
                         0, CMD_MAP_EQ, CMD_TIME_CLASS_B, status);
 }
 
-int mthca_SW2HW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                   int eq_num, u8 *status)
 {
-       dma_addr_t indma;
-       int err;
-
-       indma = pci_map_single(dev->pdev, eq_context,
-                              MTHCA_EQ_CONTEXT_SIZE,
-                              PCI_DMA_TODEVICE);
-       if (pci_dma_mapping_error(indma))
-               return -ENOMEM;
-
-       err = mthca_cmd(dev, indma, eq_num, 0, CMD_SW2HW_EQ,
-                       CMD_TIME_CLASS_A, status);
-
-       pci_unmap_single(dev->pdev, indma,
-                        MTHCA_EQ_CONTEXT_SIZE, PCI_DMA_TODEVICE);
-       return err;
+       return mthca_cmd(dev, mailbox->dma, eq_num, 0, CMD_SW2HW_EQ,
+                        CMD_TIME_CLASS_A, status);
 }
 
-int mthca_HW2SW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                   int eq_num, u8 *status)
 {
-       dma_addr_t outdma = 0;
-       int err;
-
-       outdma = pci_map_single(dev->pdev, eq_context,
-                               MTHCA_EQ_CONTEXT_SIZE,
-                               PCI_DMA_FROMDEVICE);
-       if (pci_dma_mapping_error(outdma))
-               return -ENOMEM;
-
-       err = mthca_cmd_box(dev, 0, outdma, eq_num, 0,
-                           CMD_HW2SW_EQ,
-                           CMD_TIME_CLASS_A, status);
-
-       pci_unmap_single(dev->pdev, outdma,
-                        MTHCA_EQ_CONTEXT_SIZE,
-                        PCI_DMA_FROMDEVICE);
-       return err;
+       return mthca_cmd_box(dev, 0, mailbox->dma, eq_num, 0,
+                            CMD_HW2SW_EQ,
+                            CMD_TIME_CLASS_A, status);
 }
 
-int mthca_SW2HW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                   int cq_num, u8 *status)
 {
-       dma_addr_t indma;
-       int err;
-
-       indma = pci_map_single(dev->pdev, cq_context,
-                              MTHCA_CQ_CONTEXT_SIZE,
-                              PCI_DMA_TODEVICE);
-       if (pci_dma_mapping_error(indma))
-               return -ENOMEM;
-
-       err = mthca_cmd(dev, indma, cq_num, 0, CMD_SW2HW_CQ,
+       return mthca_cmd(dev, mailbox->dma, cq_num, 0, CMD_SW2HW_CQ,
                        CMD_TIME_CLASS_A, status);
-
-       pci_unmap_single(dev->pdev, indma,
-                        MTHCA_CQ_CONTEXT_SIZE, PCI_DMA_TODEVICE);
-       return err;
 }
 
-int mthca_HW2SW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                   int cq_num, u8 *status)
 {
-       dma_addr_t outdma = 0;
-       int err;
-
-       outdma = pci_map_single(dev->pdev, cq_context,
-                               MTHCA_CQ_CONTEXT_SIZE,
-                               PCI_DMA_FROMDEVICE);
-       if (pci_dma_mapping_error(outdma))
-               return -ENOMEM;
-
-       err = mthca_cmd_box(dev, 0, outdma, cq_num, 0,
-                           CMD_HW2SW_CQ,
-                           CMD_TIME_CLASS_A, status);
-
-       pci_unmap_single(dev->pdev, outdma,
-                        MTHCA_CQ_CONTEXT_SIZE,
-                        PCI_DMA_FROMDEVICE);
-       return err;
+       return mthca_cmd_box(dev, 0, mailbox->dma, cq_num, 0,
+                            CMD_HW2SW_CQ,
+                            CMD_TIME_CLASS_A, status);
 }
 
 int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
-                   int is_ee, void *qp_context, u32 optmask,
+                   int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
                    u8 *status)
 {
        static const u16 op[] = {
@@ -1520,36 +1486,34 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
                [MTHCA_TRANS_ANY2RST]   = CMD_ERR2RST_QPEE
        };
        u8 op_mod = 0;
-
-       dma_addr_t indma;
+       int my_mailbox = 0;
        int err;
 
        if (trans < 0 || trans >= ARRAY_SIZE(op))
                return -EINVAL;
 
        if (trans == MTHCA_TRANS_ANY2RST) {
-               indma  = 0;
                op_mod = 3;     /* don't write outbox, any->reset */
 
                /* For debugging */
-               qp_context = pci_alloc_consistent(dev->pdev, MTHCA_QP_CONTEXT_SIZE,
-                                                 &indma);
-               op_mod = 2;     /* write outbox, any->reset */
+               if (!mailbox) {
+                       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+                       if (!IS_ERR(mailbox)) {
+                               my_mailbox = 1;
+                               op_mod     = 2; /* write outbox, any->reset */
+                       } else
+                               mailbox = NULL;
+               }
        } else {
-               indma = pci_map_single(dev->pdev, qp_context,
-                                      MTHCA_QP_CONTEXT_SIZE,
-                                      PCI_DMA_TODEVICE);
-               if (pci_dma_mapping_error(indma))
-                       return -ENOMEM;
-
                if (0) {
                        int i;
                        mthca_dbg(dev, "Dumping QP context:\n");
-                       printk("  opt param mask: %08x\n", be32_to_cpup(qp_context));
+                       printk("  opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
                        for (i = 0; i < 0x100 / 4; ++i) {
                                if (i % 8 == 0)
                                        printk("  [%02x] ", i * 4);
-                               printk(" %08x", be32_to_cpu(((u32 *) qp_context)[i + 2]));
+                               printk(" %08x",
+                                      be32_to_cpu(((u32 *) mailbox->buf)[i + 2]));
                                if ((i + 1) % 8 == 0)
                                        printk("\n");
                        }
@@ -1557,55 +1521,39 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
        }
 
        if (trans == MTHCA_TRANS_ANY2RST) {
-               err = mthca_cmd_box(dev, 0, indma, (!!is_ee << 24) | num,
-                                   op_mod, op[trans], CMD_TIME_CLASS_C, status);
+               err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
+                                   (!!is_ee << 24) | num, op_mod,
+                                   op[trans], CMD_TIME_CLASS_C, status);
 
-               if (0) {
+               if (0 && mailbox) {
                        int i;
                        mthca_dbg(dev, "Dumping QP context:\n");
-                       printk(" %08x\n", be32_to_cpup(qp_context));
+                       printk(" %08x\n", be32_to_cpup(mailbox->buf));
                        for (i = 0; i < 0x100 / 4; ++i) {
                                if (i % 8 == 0)
                                        printk("[%02x] ", i * 4);
-                               printk(" %08x", be32_to_cpu(((u32 *) qp_context)[i + 2]));
+                               printk(" %08x",
+                                      be32_to_cpu(((u32 *) mailbox->buf)[i + 2]));
                                if ((i + 1) % 8 == 0)
                                        printk("\n");
                        }
                }
 
        } else
-               err = mthca_cmd(dev, indma, (!!is_ee << 24) | num,
+               err = mthca_cmd(dev, mailbox->dma, (!!is_ee << 24) | num,
                                op_mod, op[trans], CMD_TIME_CLASS_C, status);
 
-       if (trans != MTHCA_TRANS_ANY2RST)
-               pci_unmap_single(dev->pdev, indma,
-                                MTHCA_QP_CONTEXT_SIZE, PCI_DMA_TODEVICE);
-       else
-               pci_free_consistent(dev->pdev, MTHCA_QP_CONTEXT_SIZE,
-                                   qp_context, indma);
+       if (my_mailbox)
+               mthca_free_mailbox(dev, mailbox);
+
        return err;
 }
 
 int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
-                  void *qp_context, u8 *status)
+                  struct mthca_mailbox *mailbox, u8 *status)
 {
-       dma_addr_t outdma = 0;
-       int err;
-
-       outdma = pci_map_single(dev->pdev, qp_context,
-                               MTHCA_QP_CONTEXT_SIZE,
-                               PCI_DMA_FROMDEVICE);
-       if (pci_dma_mapping_error(outdma))
-               return -ENOMEM;
-
-       err = mthca_cmd_box(dev, 0, outdma, (!!is_ee << 24) | num, 0,
-                           CMD_QUERY_QPEE,
-                           CMD_TIME_CLASS_A, status);
-
-       pci_unmap_single(dev->pdev, outdma,
-                        MTHCA_QP_CONTEXT_SIZE,
-                        PCI_DMA_FROMDEVICE);
-       return err;
+       return mthca_cmd_box(dev, 0, mailbox->dma, (!!is_ee << 24) | num, 0,
+                            CMD_QUERY_QPEE, CMD_TIME_CLASS_A, status);
 }
 
 int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
@@ -1635,11 +1583,11 @@ int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
 }
 
 int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
-                 int port, struct ib_wc* in_wc, struct ib_grh* in_grh,
+                 int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
                  void *in_mad, void *response_mad, u8 *status)
 {
-       void *box;
-       dma_addr_t dma;
+       struct mthca_mailbox *inmailbox, *outmailbox;
+       void *inbox;
        int err;
        u32 in_modifier = port;
        u8 op_modifier = 0;
@@ -1653,11 +1601,18 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
 #define MAD_IFC_PKEY_OFFSET   0x10e
 #define MAD_IFC_GRH_OFFSET    0x140
 
-       box = pci_alloc_consistent(dev->pdev, MAD_IFC_BOX_SIZE, &dma);
-       if (!box)
-               return -ENOMEM;
+       inmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(inmailbox))
+               return PTR_ERR(inmailbox);
+       inbox = inmailbox->buf;
 
-       memcpy(box, in_mad, 256);
+       outmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(outmailbox)) {
+               mthca_free_mailbox(dev, inmailbox);
+               return PTR_ERR(outmailbox);
+       }
+
+       memcpy(inbox, in_mad, 256);
 
        /*
         * Key check traps can't be generated unless we have in_wc to
@@ -1671,97 +1626,65 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
        if (in_wc) {
                u8 val;
 
-               memset(box + 256, 0, 256);
+               memset(inbox + 256, 0, 256);
 
-               MTHCA_PUT(box, in_wc->qp_num,     MAD_IFC_MY_QPN_OFFSET);
-               MTHCA_PUT(box, in_wc->src_qp,     MAD_IFC_RQPN_OFFSET);
+               MTHCA_PUT(inbox, in_wc->qp_num,     MAD_IFC_MY_QPN_OFFSET);
+               MTHCA_PUT(inbox, in_wc->src_qp,     MAD_IFC_RQPN_OFFSET);
 
                val = in_wc->sl << 4;
-               MTHCA_PUT(box, val,               MAD_IFC_SL_OFFSET);
+               MTHCA_PUT(inbox, val,               MAD_IFC_SL_OFFSET);
 
                val = in_wc->dlid_path_bits |
                        (in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0);
-               MTHCA_PUT(box, val,               MAD_IFC_GRH_OFFSET);
+               MTHCA_PUT(inbox, val,               MAD_IFC_GRH_OFFSET);
 
-               MTHCA_PUT(box, in_wc->slid,       MAD_IFC_RLID_OFFSET);
-               MTHCA_PUT(box, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET);
+               MTHCA_PUT(inbox, in_wc->slid,       MAD_IFC_RLID_OFFSET);
+               MTHCA_PUT(inbox, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET);
 
                if (in_grh)
-                       memcpy((u8 *) box + MAD_IFC_GRH_OFFSET, in_grh, 40);
+                       memcpy(inbox + MAD_IFC_GRH_OFFSET, in_grh, 40);
 
                op_modifier |= 0x10;
 
                in_modifier |= in_wc->slid << 16;
        }
 
-       err = mthca_cmd_box(dev, dma, dma + 512, in_modifier, op_modifier,
+       err = mthca_cmd_box(dev, inmailbox->dma, outmailbox->dma,
+                           in_modifier, op_modifier,
                            CMD_MAD_IFC, CMD_TIME_CLASS_C, status);
 
        if (!err && !*status)
-               memcpy(response_mad, box + 512, 256);
+               memcpy(response_mad, outmailbox->buf, 256);
 
-       pci_free_consistent(dev->pdev, MAD_IFC_BOX_SIZE, box, dma);
+       mthca_free_mailbox(dev, inmailbox);
+       mthca_free_mailbox(dev, outmailbox);
        return err;
 }
 
-int mthca_READ_MGM(struct mthca_dev *dev, int index, void *mgm,
-                  u8 *status)
+int mthca_READ_MGM(struct mthca_dev *dev, int index,
+                  struct mthca_mailbox *mailbox, u8 *status)
 {
-       dma_addr_t outdma = 0;
-       int err;
-
-       outdma = pci_map_single(dev->pdev, mgm,
-                               MTHCA_MGM_ENTRY_SIZE,
-                               PCI_DMA_FROMDEVICE);
-       if (pci_dma_mapping_error(outdma))
-               return -ENOMEM;
-
-       err = mthca_cmd_box(dev, 0, outdma, index, 0,
-                           CMD_READ_MGM,
-                           CMD_TIME_CLASS_A, status);
-
-       pci_unmap_single(dev->pdev, outdma,
-                        MTHCA_MGM_ENTRY_SIZE,
-                        PCI_DMA_FROMDEVICE);
-       return err;
+       return mthca_cmd_box(dev, 0, mailbox->dma, index, 0,
+                            CMD_READ_MGM, CMD_TIME_CLASS_A, status);
 }
 
-int mthca_WRITE_MGM(struct mthca_dev *dev, int index, void *mgm,
-                   u8 *status)
+int mthca_WRITE_MGM(struct mthca_dev *dev, int index,
+                   struct mthca_mailbox *mailbox, u8 *status)
 {
-       dma_addr_t indma;
-       int err;
-
-       indma = pci_map_single(dev->pdev, mgm,
-                              MTHCA_MGM_ENTRY_SIZE,
-                              PCI_DMA_TODEVICE);
-       if (pci_dma_mapping_error(indma))
-               return -ENOMEM;
-
-       err = mthca_cmd(dev, indma, index, 0, CMD_WRITE_MGM,
-                       CMD_TIME_CLASS_A, status);
-
-       pci_unmap_single(dev->pdev, indma,
-                        MTHCA_MGM_ENTRY_SIZE, PCI_DMA_TODEVICE);
-       return err;
+       return mthca_cmd(dev, mailbox->dma, index, 0, CMD_WRITE_MGM,
+                        CMD_TIME_CLASS_A, status);
 }
 
-int mthca_MGID_HASH(struct mthca_dev *dev, void *gid, u16 *hash,
-                   u8 *status)
+int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
+                   u16 *hash, u8 *status)
 {
-       dma_addr_t indma;
        u64 imm;
        int err;
 
-       indma = pci_map_single(dev->pdev, gid, 16, PCI_DMA_TODEVICE);
-       if (pci_dma_mapping_error(indma))
-               return -ENOMEM;
-
-       err = mthca_cmd_imm(dev, indma, &imm, 0, 0, CMD_MGID_HASH,
+       err = mthca_cmd_imm(dev, mailbox->dma, &imm, 0, 0, CMD_MGID_HASH,
                            CMD_TIME_CLASS_A, status);
-       *hash = imm;
 
-       pci_unmap_single(dev->pdev, indma, 16, PCI_DMA_TODEVICE);
+       *hash = imm;
        return err;
 }
 
index adf039b3c54036703de251c4e25bf2e284589932..ed517f175dd6e68aee23bdbf8a4d97af82deab38 100644 (file)
@@ -37,8 +37,7 @@
 
 #include <ib_verbs.h>
 
-#define MTHCA_CMD_MAILBOX_ALIGN 16UL
-#define MTHCA_CMD_MAILBOX_EXTRA (MTHCA_CMD_MAILBOX_ALIGN - 1)
+#define MTHCA_MAILBOX_SIZE 4096
 
 enum {
        /* command completed successfully: */
@@ -112,6 +111,11 @@ enum {
        DEV_LIM_FLAG_UD_MULTI           = 1 << 21,
 };
 
+struct mthca_mailbox {
+       dma_addr_t dma;
+       void      *buf;
+};
+
 struct mthca_dev_lim {
        int max_srq_sz;
        int max_qp_sz;
@@ -235,11 +239,17 @@ struct mthca_set_ib_param {
        u32 cap_mask;
 };
 
+int mthca_cmd_init(struct mthca_dev *dev);
+void mthca_cmd_cleanup(struct mthca_dev *dev);
 int mthca_cmd_use_events(struct mthca_dev *dev);
 void mthca_cmd_use_polling(struct mthca_dev *dev);
 void mthca_cmd_event(struct mthca_dev *dev, u16 token,
                     u8  status, u64 out_param);
 
+struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
+                                         unsigned int gfp_mask);
+void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox);
+
 int mthca_SYS_EN(struct mthca_dev *dev, u8 *status);
 int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status);
 int mthca_MAP_FA(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status);
@@ -270,41 +280,39 @@ int mthca_MAP_ICM_AUX(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status);
 int mthca_UNMAP_ICM_AUX(struct mthca_dev *dev, u8 *status);
 int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
                       u8 *status);
-int mthca_SW2HW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                    int mpt_index, u8 *status);
-int mthca_HW2SW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                    int mpt_index, u8 *status);
-int mthca_WRITE_MTT(struct mthca_dev *dev, u64 *mtt_entry,
+int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                    int num_mtt, u8 *status);
 int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status);
 int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
                 int eq_num, u8 *status);
-int mthca_SW2HW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                   int eq_num, u8 *status);
-int mthca_HW2SW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                   int eq_num, u8 *status);
-int mthca_SW2HW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                   int cq_num, u8 *status);
-int mthca_HW2SW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                   int cq_num, u8 *status);
 int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
-                   int is_ee, void *qp_context, u32 optmask,
+                   int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
                    u8 *status);
 int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
-                  void *qp_context, u8 *status);
+                  struct mthca_mailbox *mailbox, u8 *status);
 int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
                          u8 *status);
 int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
-                 int port, struct ib_wc* in_wc, struct ib_grh* in_grh,
+                 int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
                  void *in_mad, void *response_mad, u8 *status);
-int mthca_READ_MGM(struct mthca_dev *dev, int index, void *mgm,
-                  u8 *status);
-int mthca_WRITE_MGM(struct mthca_dev *dev, int index, void *mgm,
-                   u8 *status);
-int mthca_MGID_HASH(struct mthca_dev *dev, void *gid, u16 *hash,
-                   u8 *status);
+int mthca_READ_MGM(struct mthca_dev *dev, int index,
+                  struct mthca_mailbox *mailbox, u8 *status);
+int mthca_WRITE_MGM(struct mthca_dev *dev, int index,
+                   struct mthca_mailbox *mailbox, u8 *status);
+int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
+                   u16 *hash, u8 *status);
 int mthca_NOP(struct mthca_dev *dev, u8 *status);
 
-#define MAILBOX_ALIGN(x) ((void *) ALIGN((unsigned long) (x), MTHCA_CMD_MAILBOX_ALIGN))
-
 #endif /* MTHCA_CMD_H */
index 2bf347b84c3142b3deb59de03a77b39cc7370118..766e9031ec4581bd05a4a727ee880b8689eeab3d 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, 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
@@ -171,6 +172,17 @@ static inline void set_cqe_hw(struct mthca_cqe *cqe)
        cqe->owner = MTHCA_CQ_ENTRY_OWNER_HW;
 }
 
+static void dump_cqe(struct mthca_dev *dev, void *cqe_ptr)
+{
+       __be32 *cqe = cqe_ptr;
+
+       (void) cqe;     /* avoid warning if mthca_dbg compiled away... */
+       mthca_dbg(dev, "CQE contents %08x %08x %08x %08x %08x %08x %08x %08x\n",
+                 be32_to_cpu(cqe[0]), be32_to_cpu(cqe[1]), be32_to_cpu(cqe[2]),
+                 be32_to_cpu(cqe[3]), be32_to_cpu(cqe[4]), be32_to_cpu(cqe[5]),
+                 be32_to_cpu(cqe[6]), be32_to_cpu(cqe[7]));
+}
+
 /*
  * incr is ignored in native Arbel (mem-free) mode, so cq->cons_index
  * should be correct before calling update_cons_index().
@@ -280,16 +292,12 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
        int dbd;
        u32 new_wqe;
 
-       if (1 && cqe->syndrome != SYNDROME_WR_FLUSH_ERR) {
-               int j;
-
-               mthca_dbg(dev, "%x/%d: error CQE -> QPN %06x, WQE @ %08x\n",
-                         cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
-                         be32_to_cpu(cqe->wqe));
-
-               for (j = 0; j < 8; ++j)
-                       printk(KERN_DEBUG "  [%2x] %08x\n",
-                              j * 4, be32_to_cpu(((u32 *) cqe)[j]));
+       if (cqe->syndrome == SYNDROME_LOCAL_QP_OP_ERR) {
+               mthca_dbg(dev, "local QP operation err "
+                         "(QPN %06x, WQE @ %08x, CQN %06x, index %d)\n",
+                         be32_to_cpu(cqe->my_qpn), be32_to_cpu(cqe->wqe),
+                         cq->cqn, cq->cons_index);
+               dump_cqe(dev, cqe);
        }
 
        /*
@@ -377,15 +385,6 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
        return 0;
 }
 
-static void dump_cqe(struct mthca_cqe *cqe)
-{
-       int j;
-
-       for (j = 0; j < 8; ++j)
-               printk(KERN_DEBUG "  [%2x] %08x\n",
-                      j * 4, be32_to_cpu(((u32 *) cqe)[j]));
-}
-
 static inline int mthca_poll_one(struct mthca_dev *dev,
                                 struct mthca_cq *cq,
                                 struct mthca_qp **cur_qp,
@@ -414,8 +413,7 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
                mthca_dbg(dev, "%x/%d: CQE -> QPN %06x, WQE @ %08x\n",
                          cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
                          be32_to_cpu(cqe->wqe));
-
-               dump_cqe(cqe);
+               dump_cqe(dev, cqe);
        }
 
        is_error = (cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) ==
@@ -638,19 +636,19 @@ static void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq *cq)
        int size;
 
        if (cq->is_direct)
-               pci_free_consistent(dev->pdev,
-                                   (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
-                                   cq->queue.direct.buf,
-                                   pci_unmap_addr(&cq->queue.direct,
-                                                  mapping));
+               dma_free_coherent(&dev->pdev->dev,
+                                 (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
+                                 cq->queue.direct.buf,
+                                 pci_unmap_addr(&cq->queue.direct,
+                                                mapping));
        else {
                size = (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE;
                for (i = 0; i < (size + PAGE_SIZE - 1) / PAGE_SIZE; ++i)
                        if (cq->queue.page_list[i].buf)
-                               pci_free_consistent(dev->pdev, PAGE_SIZE,
-                                                   cq->queue.page_list[i].buf,
-                                                   pci_unmap_addr(&cq->queue.page_list[i],
-                                                                  mapping));
+                               dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+                                                 cq->queue.page_list[i].buf,
+                                                 pci_unmap_addr(&cq->queue.page_list[i],
+                                                                mapping));
 
                kfree(cq->queue.page_list);
        }
@@ -670,8 +668,8 @@ static int mthca_alloc_cq_buf(struct mthca_dev *dev, int size,
                npages        = 1;
                shift         = get_order(size) + PAGE_SHIFT;
 
-               cq->queue.direct.buf = pci_alloc_consistent(dev->pdev,
-                                                           size, &t);
+               cq->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev,
+                                                         size, &t, GFP_KERNEL);
                if (!cq->queue.direct.buf)
                        return -ENOMEM;
 
@@ -709,7 +707,8 @@ static int mthca_alloc_cq_buf(struct mthca_dev *dev, int size,
 
                for (i = 0; i < npages; ++i) {
                        cq->queue.page_list[i].buf =
-                               pci_alloc_consistent(dev->pdev, PAGE_SIZE, &t);
+                               dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
+                                                  &t, GFP_KERNEL);
                        if (!cq->queue.page_list[i].buf)
                                goto err_free;
 
@@ -746,7 +745,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
                  struct mthca_cq *cq)
 {
        int size = nent * MTHCA_CQ_ENTRY_SIZE;
-       void *mailbox = NULL;
+       struct mthca_mailbox *mailbox;
        struct mthca_cq_context *cq_context;
        int err = -ENOMEM;
        u8 status;
@@ -780,12 +779,11 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
                        goto err_out_ci;
        }
 
-       mailbox = kmalloc(sizeof (struct mthca_cq_context) + MTHCA_CMD_MAILBOX_EXTRA,
-                         GFP_KERNEL);
-       if (!mailbox)
-               goto err_out_mailbox;
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               goto err_out_arm;
 
-       cq_context = MAILBOX_ALIGN(mailbox);
+       cq_context = mailbox->buf;
 
        err = mthca_alloc_cq_buf(dev, size, cq);
        if (err)
@@ -816,7 +814,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
                cq_context->state_db = cpu_to_be32(cq->arm_db_index);
        }
 
-       err = mthca_SW2HW_CQ(dev, cq_context, cq->cqn, &status);
+       err = mthca_SW2HW_CQ(dev, mailbox, cq->cqn, &status);
        if (err) {
                mthca_warn(dev, "SW2HW_CQ failed (%d)\n", err);
                goto err_out_free_mr;
@@ -840,7 +838,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
 
        cq->cons_index = 0;
 
-       kfree(mailbox);
+       mthca_free_mailbox(dev, mailbox);
 
        return 0;
 
@@ -849,8 +847,9 @@ err_out_free_mr:
        mthca_free_cq_buf(dev, cq);
 
 err_out_mailbox:
-       kfree(mailbox);
+       mthca_free_mailbox(dev, mailbox);
 
+err_out_arm:
        if (mthca_is_memfree(dev))
                mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
 
@@ -870,28 +869,26 @@ err_out:
 void mthca_free_cq(struct mthca_dev *dev,
                   struct mthca_cq *cq)
 {
-       void *mailbox;
+       struct mthca_mailbox *mailbox;
        int err;
        u8 status;
 
        might_sleep();
 
-       mailbox = kmalloc(sizeof (struct mthca_cq_context) + MTHCA_CMD_MAILBOX_EXTRA,
-                         GFP_KERNEL);
-       if (!mailbox) {
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox)) {
                mthca_warn(dev, "No memory for mailbox to free CQ.\n");
                return;
        }
 
-       err = mthca_HW2SW_CQ(dev, MAILBOX_ALIGN(mailbox), cq->cqn, &status);
+       err = mthca_HW2SW_CQ(dev, mailbox, cq->cqn, &status);
        if (err)
                mthca_warn(dev, "HW2SW_CQ failed (%d)\n", err);
        else if (status)
-               mthca_warn(dev, "HW2SW_CQ returned status 0x%02x\n",
-                          status);
+               mthca_warn(dev, "HW2SW_CQ returned status 0x%02x\n", status);
 
        if (0) {
-               u32 *ctx = MAILBOX_ALIGN(mailbox);
+               u32 *ctx = mailbox->buf;
                int j;
 
                printk(KERN_ERR "context for CQN %x (cons index %x, next sw %d)\n",
@@ -919,11 +916,11 @@ void mthca_free_cq(struct mthca_dev *dev,
        if (mthca_is_memfree(dev)) {
                mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM,    cq->arm_db_index);
                mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
-               mthca_table_put(dev, dev->cq_table.table, cq->cqn);
        }
 
+       mthca_table_put(dev, dev->cq_table.table, cq->cqn);
        mthca_free(&dev->cq_table.alloc, cq->cqn);
-       kfree(mailbox);
+       mthca_free_mailbox(dev, mailbox);
 }
 
 int __devinit mthca_init_cq_table(struct mthca_dev *dev)
index e3d79e267dc9ef6e4d9a772decbb158c7ddda208..4127f09dc5ec5cce6ffdb6133cc33a4e6904e3d7 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, 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
@@ -46,8 +47,8 @@
 
 #define DRV_NAME       "ib_mthca"
 #define PFX            DRV_NAME ": "
-#define DRV_VERSION    "0.06-pre"
-#define DRV_RELDATE    "November 8, 2004"
+#define DRV_VERSION    "0.06"
+#define DRV_RELDATE    "June 23, 2005"
 
 enum {
        MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
@@ -98,6 +99,7 @@ enum {
 };
 
 struct mthca_cmd {
+       struct pci_pool          *pool;
        int                       use_events;
        struct semaphore          hcr_sem;
        struct semaphore          poll_sem;
@@ -379,6 +381,12 @@ void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar);
 int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd);
 void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd);
 
+struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size);
+void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt);
+int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
+                   int start_index, u64 *buffer_list, int list_len);
+int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
+                  u64 iova, u64 total_size, u32 access, struct mthca_mr *mr);
 int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
                           u32 access, struct mthca_mr *mr);
 int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
index 821039a490499c8c4d39d1f55b36bd4a057bafd1..535fad7710fb7129e7d9b2cea96c981cc1d9436e 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, 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
index f46d615d396f5e94a35ee5bdcb200a8f1522b902..cbcf2b4722e4598e7f520add89dbb6868329fde7 100644 (file)
@@ -469,7 +469,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
                PAGE_SIZE;
        u64 *dma_list = NULL;
        dma_addr_t t;
-       void *mailbox = NULL;
+       struct mthca_mailbox *mailbox;
        struct mthca_eq_context *eq_context;
        int err = -ENOMEM;
        int i;
@@ -494,17 +494,16 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
        if (!dma_list)
                goto err_out_free;
 
-       mailbox = kmalloc(sizeof *eq_context + MTHCA_CMD_MAILBOX_EXTRA,
-                         GFP_KERNEL);
-       if (!mailbox)
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
                goto err_out_free;
-       eq_context = MAILBOX_ALIGN(mailbox);
+       eq_context = mailbox->buf;
 
        for (i = 0; i < npages; ++i) {
-               eq->page_list[i].buf = pci_alloc_consistent(dev->pdev,
-                                                           PAGE_SIZE, &t);
+               eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev,
+                                                         PAGE_SIZE, &t, GFP_KERNEL);
                if (!eq->page_list[i].buf)
-                       goto err_out_free;
+                       goto err_out_free_pages;
 
                dma_list[i] = t;
                pci_unmap_addr_set(&eq->page_list[i], mapping, t);
@@ -517,7 +516,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 
        eq->eqn = mthca_alloc(&dev->eq_table.alloc);
        if (eq->eqn == -1)
-               goto err_out_free;
+               goto err_out_free_pages;
 
        err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num,
                                  dma_list, PAGE_SHIFT, npages,
@@ -548,7 +547,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
        eq_context->intr            = intr;
        eq_context->lkey            = cpu_to_be32(eq->mr.ibmr.lkey);
 
-       err = mthca_SW2HW_EQ(dev, eq_context, eq->eqn, &status);
+       err = mthca_SW2HW_EQ(dev, mailbox, eq->eqn, &status);
        if (err) {
                mthca_warn(dev, "SW2HW_EQ failed (%d)\n", err);
                goto err_out_free_mr;
@@ -561,7 +560,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
        }
 
        kfree(dma_list);
-       kfree(mailbox);
+       mthca_free_mailbox(dev, mailbox);
 
        eq->eqn_mask   = swab32(1 << eq->eqn);
        eq->cons_index = 0;
@@ -579,17 +578,19 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
  err_out_free_eq:
        mthca_free(&dev->eq_table.alloc, eq->eqn);
 
- err_out_free:
+ err_out_free_pages:
        for (i = 0; i < npages; ++i)
                if (eq->page_list[i].buf)
-                       pci_free_consistent(dev->pdev, PAGE_SIZE,
-                                           eq->page_list[i].buf,
-                                           pci_unmap_addr(&eq->page_list[i],
-                                                          mapping));
+                       dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+                                         eq->page_list[i].buf,
+                                         pci_unmap_addr(&eq->page_list[i],
+                                                        mapping));
+
+       mthca_free_mailbox(dev, mailbox);
 
+ err_out_free:
        kfree(eq->page_list);
        kfree(dma_list);
-       kfree(mailbox);
 
  err_out:
        return err;
@@ -598,25 +599,22 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 static void mthca_free_eq(struct mthca_dev *dev,
                          struct mthca_eq *eq)
 {
-       void *mailbox = NULL;
+       struct mthca_mailbox *mailbox;
        int err;
        u8 status;
        int npages = (eq->nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) /
                PAGE_SIZE;
        int i;
 
-       mailbox = kmalloc(sizeof (struct mthca_eq_context) + MTHCA_CMD_MAILBOX_EXTRA,
-                         GFP_KERNEL);
-       if (!mailbox)
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
                return;
 
-       err = mthca_HW2SW_EQ(dev, MAILBOX_ALIGN(mailbox),
-                            eq->eqn, &status);
+       err = mthca_HW2SW_EQ(dev, mailbox, eq->eqn, &status);
        if (err)
                mthca_warn(dev, "HW2SW_EQ failed (%d)\n", err);
        if (status)
-               mthca_warn(dev, "HW2SW_EQ returned status 0x%02x\n",
-                          status);
+               mthca_warn(dev, "HW2SW_EQ returned status 0x%02x\n", status);
 
        dev->eq_table.arm_mask &= ~eq->eqn_mask;
 
@@ -625,7 +623,7 @@ static void mthca_free_eq(struct mthca_dev *dev,
                for (i = 0; i < sizeof (struct mthca_eq_context) / 4; ++i) {
                        if (i % 4 == 0)
                                printk("[%02x] ", i * 4);
-                       printk(" %08x", be32_to_cpup(MAILBOX_ALIGN(mailbox) + i * 4));
+                       printk(" %08x", be32_to_cpup(mailbox->buf + i * 4));
                        if ((i + 1) % 4 == 0)
                                printk("\n");
                }
@@ -638,7 +636,7 @@ static void mthca_free_eq(struct mthca_dev *dev,
                                    pci_unmap_addr(&eq->page_list[i], mapping));
 
        kfree(eq->page_list);
-       kfree(mailbox);
+       mthca_free_mailbox(dev, mailbox);
 }
 
 static void mthca_free_irqs(struct mthca_dev *dev)
@@ -709,8 +707,7 @@ static int __devinit mthca_map_eq_regs(struct mthca_dev *dev)
                if (mthca_map_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
                                        dev->fw.arbel.eq_arm_base) + 4, 4,
                                  &dev->eq_regs.arbel.eq_arm)) {
-                       mthca_err(dev, "Couldn't map interrupt clear register, "
-                                 "aborting.\n");
+                       mthca_err(dev, "Couldn't map EQ arm register, aborting.\n");
                        mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
                                        dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
                                        dev->clr_base);
@@ -721,8 +718,7 @@ static int __devinit mthca_map_eq_regs(struct mthca_dev *dev)
                                  dev->fw.arbel.eq_set_ci_base,
                                  MTHCA_EQ_SET_CI_SIZE,
                                  &dev->eq_regs.arbel.eq_set_ci_base)) {
-                       mthca_err(dev, "Couldn't map interrupt clear register, "
-                                 "aborting.\n");
+                       mthca_err(dev, "Couldn't map EQ CI register, aborting.\n");
                        mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
                                              dev->fw.arbel.eq_arm_base) + 4, 4,
                                        dev->eq_regs.arbel.eq_arm);
index d40590356df81123d5312eacdf4450f3bca78e6b..09519b604c087bd11856d96cab5c4021b78aa3b6 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, 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
@@ -69,7 +70,7 @@ MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero");
 #endif /* CONFIG_PCI_MSI */
 
 static const char mthca_version[] __devinitdata =
-       "ib_mthca: Mellanox InfiniBand HCA driver v"
+       DRV_NAME ": Mellanox InfiniBand HCA driver v"
        DRV_VERSION " (" DRV_RELDATE ")\n";
 
 static struct mthca_profile default_profile = {
@@ -927,13 +928,13 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
         */
        if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
            pci_resource_len(pdev, 0) != 1 << 20) {
-               dev_err(&pdev->dev, "Missing DCS, aborting.");
+               dev_err(&pdev->dev, "Missing DCS, aborting.\n");
                err = -ENODEV;
                goto err_disable_pdev;
        }
        if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM) ||
            pci_resource_len(pdev, 2) != 1 << 23) {
-               dev_err(&pdev->dev, "Missing UAR, aborting.");
+               dev_err(&pdev->dev, "Missing UAR, aborting.\n");
                err = -ENODEV;
                goto err_disable_pdev;
        }
@@ -1004,25 +1005,18 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
            !pci_enable_msi(pdev))
                mdev->mthca_flags |= MTHCA_FLAG_MSI;
 
-       sema_init(&mdev->cmd.hcr_sem, 1);
-       sema_init(&mdev->cmd.poll_sem, 1);
-       mdev->cmd.use_events = 0;
-
-       mdev->hcr = ioremap(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, MTHCA_HCR_SIZE);
-       if (!mdev->hcr) {
-               mthca_err(mdev, "Couldn't map command register, "
-                         "aborting.\n");
-               err = -ENOMEM;
+       if (mthca_cmd_init(mdev)) {
+               mthca_err(mdev, "Failed to init command interface, aborting.\n");
                goto err_free_dev;
        }
 
        err = mthca_tune_pci(mdev);
        if (err)
-               goto err_iounmap;
+               goto err_cmd;
 
        err = mthca_init_hca(mdev);
        if (err)
-               goto err_iounmap;
+               goto err_cmd;
 
        if (mdev->fw_ver < mthca_hca_table[id->driver_data].latest_fw) {
                mthca_warn(mdev, "HCA FW version %x.%x.%x is old (%x.%x.%x is current).\n",
@@ -1070,8 +1064,8 @@ err_cleanup:
 err_close:
        mthca_close_hca(mdev);
 
-err_iounmap:
-       iounmap(mdev->hcr);
+err_cmd:
+       mthca_cmd_cleanup(mdev);
 
 err_free_dev:
        if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
@@ -1118,10 +1112,8 @@ static void __devexit mthca_remove_one(struct pci_dev *pdev)
                iounmap(mdev->kar);
                mthca_uar_free(mdev, &mdev->driver_uar);
                mthca_cleanup_uar_table(mdev);
-
                mthca_close_hca(mdev);
-
-               iounmap(mdev->hcr);
+               mthca_cmd_cleanup(mdev);
 
                if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
                        pci_disable_msix(pdev);
@@ -1163,7 +1155,7 @@ static struct pci_device_id mthca_pci_table[] = {
 MODULE_DEVICE_TABLE(pci, mthca_pci_table);
 
 static struct pci_driver mthca_driver = {
-       .name           = "ib_mthca",
+       .name           = DRV_NAME,
        .id_table       = mthca_pci_table,
        .probe          = mthca_init_one,
        .remove         = __devexit_p(mthca_remove_one)
index 70a6553a588e8385334f7afd719b6cb80124ec57..5be7d949dbf61b74e06dc2a73931a05cf27fd38c 100644 (file)
@@ -66,22 +66,23 @@ static const u8 zero_gid[16];       /* automatically initialized to 0 */
  * entry in hash chain and *mgm holds end of hash chain.
  */
 static int find_mgm(struct mthca_dev *dev,
-                   u8 *gid, struct mthca_mgm *mgm,
+                   u8 *gid, struct mthca_mailbox *mgm_mailbox,
                    u16 *hash, int *prev, int *index)
 {
-       void *mailbox;
+       struct mthca_mailbox *mailbox;
+       struct mthca_mgm *mgm = mgm_mailbox->buf;
        u8 *mgid;
        int err;
        u8 status;
 
-       mailbox = kmalloc(16 + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
-       if (!mailbox)
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
                return -ENOMEM;
-       mgid = MAILBOX_ALIGN(mailbox);
+       mgid = mailbox->buf;
 
        memcpy(mgid, gid, 16);
 
-       err = mthca_MGID_HASH(dev, mgid, hash, &status);
+       err = mthca_MGID_HASH(dev, mailbox, hash, &status);
        if (err)
                goto out;
        if (status) {
@@ -103,7 +104,7 @@ static int find_mgm(struct mthca_dev *dev,
        *prev  = -1;
 
        do {
-               err = mthca_READ_MGM(dev, *index, mgm, &status);
+               err = mthca_READ_MGM(dev, *index, mgm_mailbox, &status);
                if (err)
                        goto out;
                if (status) {
@@ -129,14 +130,14 @@ static int find_mgm(struct mthca_dev *dev,
        *index = -1;
 
  out:
-       kfree(mailbox);
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
 int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 {
        struct mthca_dev *dev = to_mdev(ibqp->device);
-       void *mailbox;
+       struct mthca_mailbox *mailbox;
        struct mthca_mgm *mgm;
        u16 hash;
        int index, prev;
@@ -145,15 +146,15 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        int err;
        u8 status;
 
-       mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
-       if (!mailbox)
-               return -ENOMEM;
-       mgm = MAILBOX_ALIGN(mailbox);
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       mgm = mailbox->buf;
 
        if (down_interruptible(&dev->mcg_table.sem))
                return -EINTR;
 
-       err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index);
+       err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
        if (err)
                goto out;
 
@@ -170,7 +171,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                        goto out;
                }
 
-               err = mthca_READ_MGM(dev, index, mgm, &status);
+               err = mthca_READ_MGM(dev, index, mailbox, &status);
                if (err)
                        goto out;
                if (status) {
@@ -195,7 +196,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                goto out;
        }
 
-       err = mthca_WRITE_MGM(dev, index, mgm, &status);
+       err = mthca_WRITE_MGM(dev, index, mailbox, &status);
        if (err)
                goto out;
        if (status) {
@@ -206,7 +207,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        if (!link)
                goto out;
 
-       err = mthca_READ_MGM(dev, prev, mgm, &status);
+       err = mthca_READ_MGM(dev, prev, mailbox, &status);
        if (err)
                goto out;
        if (status) {
@@ -217,7 +218,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 
        mgm->next_gid_index = cpu_to_be32(index << 5);
 
-       err = mthca_WRITE_MGM(dev, prev, mgm, &status);
+       err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
        if (err)
                goto out;
        if (status) {
@@ -227,14 +228,14 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 
  out:
        up(&dev->mcg_table.sem);
-       kfree(mailbox);
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
 int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 {
        struct mthca_dev *dev = to_mdev(ibqp->device);
-       void *mailbox;
+       struct mthca_mailbox *mailbox;
        struct mthca_mgm *mgm;
        u16 hash;
        int prev, index;
@@ -242,15 +243,15 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        int err;
        u8 status;
 
-       mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
-       if (!mailbox)
-               return -ENOMEM;
-       mgm = MAILBOX_ALIGN(mailbox);
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       mgm = mailbox->buf;
 
        if (down_interruptible(&dev->mcg_table.sem))
                return -EINTR;
 
-       err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index);
+       err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
        if (err)
                goto out;
 
@@ -285,7 +286,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        mgm->qp[loc]   = mgm->qp[i - 1];
        mgm->qp[i - 1] = 0;
 
-       err = mthca_WRITE_MGM(dev, index, mgm, &status);
+       err = mthca_WRITE_MGM(dev, index, mailbox, &status);
        if (err)
                goto out;
        if (status) {
@@ -304,7 +305,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                if (be32_to_cpu(mgm->next_gid_index) >> 5) {
                        err = mthca_READ_MGM(dev,
                                             be32_to_cpu(mgm->next_gid_index) >> 5,
-                                            mgm, &status);
+                                            mailbox, &status);
                        if (err)
                                goto out;
                        if (status) {
@@ -316,7 +317,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                } else
                        memset(mgm->gid, 0, 16);
 
-               err = mthca_WRITE_MGM(dev, index, mgm, &status);
+               err = mthca_WRITE_MGM(dev, index, mailbox, &status);
                if (err)
                        goto out;
                if (status) {
@@ -327,7 +328,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        } else {
                /* Remove entry from AMGM */
                index = be32_to_cpu(mgm->next_gid_index) >> 5;
-               err = mthca_READ_MGM(dev, prev, mgm, &status);
+               err = mthca_READ_MGM(dev, prev, mailbox, &status);
                if (err)
                        goto out;
                if (status) {
@@ -338,7 +339,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 
                mgm->next_gid_index = cpu_to_be32(index << 5);
 
-               err = mthca_WRITE_MGM(dev, prev, mgm, &status);
+               err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
                if (err)
                        goto out;
                if (status) {
@@ -350,7 +351,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 
  out:
        up(&dev->mcg_table.sem);
-       kfree(mailbox);
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
index 637b30e355928756be4ea01c160bed02f5c346aa..6d3b05dd9e3f1d9ee779b9f16808df7bf9f01ad7 100644 (file)
@@ -179,9 +179,14 @@ out:
 
 void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj)
 {
-       int i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
+       int i;
        u8 status;
 
+       if (!mthca_is_memfree(dev))
+               return;
+
+       i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
+
        down(&table->mutex);
 
        if (--table->icm[i]->refcount == 0) {
@@ -256,6 +261,9 @@ void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table,
 {
        int i;
 
+       if (!mthca_is_memfree(dev))
+               return;
+
        for (i = start; i <= end; i += MTHCA_TABLE_CHUNK_SIZE / table->obj_size)
                mthca_table_put(dev, table, i);
 }
index 8960fc2306beb1c0052950e87288e5b7f6e469fa..cbe50feaf68073967c76b0e58569fde0de16e513 100644 (file)
 #include "mthca_cmd.h"
 #include "mthca_memfree.h"
 
+struct mthca_mtt {
+       struct mthca_buddy *buddy;
+       int                 order;
+       u32                 first_seg;
+};
+
 /*
  * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits.
  */
@@ -173,8 +179,8 @@ static void __devexit mthca_buddy_cleanup(struct mthca_buddy *buddy)
        kfree(buddy->bits);
 }
 
-static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order,
-                          struct mthca_buddy *buddy)
+static u32 mthca_alloc_mtt_range(struct mthca_dev *dev, int order,
+                                struct mthca_buddy *buddy)
 {
        u32 seg = mthca_buddy_alloc(buddy, order);
 
@@ -191,14 +197,102 @@ static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order,
        return seg;
 }
 
-static void mthca_free_mtt(struct mthca_dev *dev, u32 seg, int order,
-                          struct mthca_buddy* buddy)
+static struct mthca_mtt *__mthca_alloc_mtt(struct mthca_dev *dev, int size,
+                                          struct mthca_buddy *buddy)
 {
-       mthca_buddy_free(buddy, seg, order);
+       struct mthca_mtt *mtt;
+       int i;
 
-       if (mthca_is_memfree(dev))
-               mthca_table_put_range(dev, dev->mr_table.mtt_table, seg,
-                                     seg + (1 << order) - 1);
+       if (size <= 0)
+               return ERR_PTR(-EINVAL);
+
+       mtt = kmalloc(sizeof *mtt, GFP_KERNEL);
+       if (!mtt)
+               return ERR_PTR(-ENOMEM);
+
+       mtt->buddy = buddy;
+       mtt->order = 0;
+       for (i = MTHCA_MTT_SEG_SIZE / 8; i < size; i <<= 1)
+               ++mtt->order;
+
+       mtt->first_seg = mthca_alloc_mtt_range(dev, mtt->order, buddy);
+       if (mtt->first_seg == -1) {
+               kfree(mtt);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       return mtt;
+}
+
+struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size)
+{
+       return __mthca_alloc_mtt(dev, size, &dev->mr_table.mtt_buddy);
+}
+
+void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt)
+{
+       if (!mtt)
+               return;
+
+       mthca_buddy_free(mtt->buddy, mtt->first_seg, mtt->order);
+
+       mthca_table_put_range(dev, dev->mr_table.mtt_table,
+                             mtt->first_seg,
+                             mtt->first_seg + (1 << mtt->order) - 1);
+
+       kfree(mtt);
+}
+
+int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
+                   int start_index, u64 *buffer_list, int list_len)
+{
+       struct mthca_mailbox *mailbox;
+       u64 *mtt_entry;
+       int err = 0;
+       u8 status;
+       int i;
+
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       mtt_entry = mailbox->buf;
+
+       while (list_len > 0) {
+               mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
+                                          mtt->first_seg * MTHCA_MTT_SEG_SIZE +
+                                          start_index * 8);
+               mtt_entry[1] = 0;
+               for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; ++i)
+                       mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |
+                                                      MTHCA_MTT_FLAG_PRESENT);
+
+               /*
+                * If we have an odd number of entries to write, add
+                * one more dummy entry for firmware efficiency.
+                */
+               if (i & 1)
+                       mtt_entry[i + 2] = 0;
+
+               err = mthca_WRITE_MTT(dev, mailbox, (i + 1) & ~1, &status);
+               if (err) {
+                       mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);
+                       goto out;
+               }
+               if (status) {
+                       mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",
+                                  status);
+                       err = -EINVAL;
+                       goto out;
+               }
+
+               list_len    -= i;
+               start_index += i;
+               buffer_list += i;
+       }
+
+out:
+       mthca_free_mailbox(dev, mailbox);
+       return err;
 }
 
 static inline u32 tavor_hw_index_to_key(u32 ind)
@@ -237,91 +331,18 @@ static inline u32 key_to_hw_index(struct mthca_dev *dev, u32 key)
                return tavor_key_to_hw_index(key);
 }
 
-int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
-                          u32 access, struct mthca_mr *mr)
+int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
+                  u64 iova, u64 total_size, u32 access, struct mthca_mr *mr)
 {
-       void *mailbox = NULL;
+       struct mthca_mailbox *mailbox;
        struct mthca_mpt_entry *mpt_entry;
        u32 key;
+       int i;
        int err;
        u8 status;
 
        might_sleep();
 
-       mr->order = -1;
-       key = mthca_alloc(&dev->mr_table.mpt_alloc);
-       if (key == -1)
-               return -ENOMEM;
-       mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
-
-       if (mthca_is_memfree(dev)) {
-               err = mthca_table_get(dev, dev->mr_table.mpt_table, key);
-               if (err)
-                       goto err_out_mpt_free;
-       }
-
-       mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
-                         GFP_KERNEL);
-       if (!mailbox) {
-               err = -ENOMEM;
-               goto err_out_table;
-       }
-       mpt_entry = MAILBOX_ALIGN(mailbox);
-
-       mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
-                                      MTHCA_MPT_FLAG_MIO         |
-                                      MTHCA_MPT_FLAG_PHYSICAL    |
-                                      MTHCA_MPT_FLAG_REGION      |
-                                      access);
-       mpt_entry->page_size = 0;
-       mpt_entry->key       = cpu_to_be32(key);
-       mpt_entry->pd        = cpu_to_be32(pd);
-       mpt_entry->start     = 0;
-       mpt_entry->length    = ~0ULL;
-
-       memset(&mpt_entry->lkey, 0,
-              sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
-
-       err = mthca_SW2HW_MPT(dev, mpt_entry,
-                             key & (dev->limits.num_mpts - 1),
-                             &status);
-       if (err) {
-               mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
-               goto err_out_table;
-       } else if (status) {
-               mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
-                          status);
-               err = -EINVAL;
-               goto err_out_table;
-       }
-
-       kfree(mailbox);
-       return err;
-
-err_out_table:
-       if (mthca_is_memfree(dev))
-               mthca_table_put(dev, dev->mr_table.mpt_table, key);
-
-err_out_mpt_free:
-       mthca_free(&dev->mr_table.mpt_alloc, key);
-       kfree(mailbox);
-       return err;
-}
-
-int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
-                       u64 *buffer_list, int buffer_size_shift,
-                       int list_len, u64 iova, u64 total_size,
-                       u32 access, struct mthca_mr *mr)
-{
-       void *mailbox;
-       u64 *mtt_entry;
-       struct mthca_mpt_entry *mpt_entry;
-       u32 key;
-       int err = -ENOMEM;
-       u8 status;
-       int i;
-
-       might_sleep();
        WARN_ON(buffer_size_shift >= 32);
 
        key = mthca_alloc(&dev->mr_table.mpt_alloc);
@@ -335,75 +356,33 @@ int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
                        goto err_out_mpt_free;
        }
 
-       for (i = MTHCA_MTT_SEG_SIZE / 8, mr->order = 0;
-            i < list_len;
-            i <<= 1, ++mr->order)
-               ; /* nothing */
-
-       mr->first_seg = mthca_alloc_mtt(dev, mr->order,
-                                       &dev->mr_table.mtt_buddy);
-       if (mr->first_seg == -1)
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox)) {
+               err = PTR_ERR(mailbox);
                goto err_out_table;
-
-       /*
-        * If list_len is odd, we add one more dummy entry for
-        * firmware efficiency.
-        */
-       mailbox = kmalloc(max(sizeof *mpt_entry,
-                             (size_t) 8 * (list_len + (list_len & 1) + 2)) +
-                         MTHCA_CMD_MAILBOX_EXTRA,
-                         GFP_KERNEL);
-       if (!mailbox)
-               goto err_out_free_mtt;
-
-       mtt_entry = MAILBOX_ALIGN(mailbox);
-
-       mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
-                                  mr->first_seg * MTHCA_MTT_SEG_SIZE);
-       mtt_entry[1] = 0;
-       for (i = 0; i < list_len; ++i)
-               mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |
-                                              MTHCA_MTT_FLAG_PRESENT);
-       if (list_len & 1) {
-               mtt_entry[i + 2] = 0;
-               ++list_len;
-       }
-
-       if (0) {
-               mthca_dbg(dev, "Dumping MPT entry\n");
-               for (i = 0; i < list_len + 2; ++i)
-                       printk(KERN_ERR "[%2d] %016llx\n",
-                              i, (unsigned long long) be64_to_cpu(mtt_entry[i]));
-       }
-
-       err = mthca_WRITE_MTT(dev, mtt_entry, list_len, &status);
-       if (err) {
-               mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);
-               goto err_out_mailbox_free;
-       }
-       if (status) {
-               mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",
-                          status);
-               err = -EINVAL;
-               goto err_out_mailbox_free;
        }
-
-       mpt_entry = MAILBOX_ALIGN(mailbox);
+       mpt_entry = mailbox->buf;
 
        mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
                                       MTHCA_MPT_FLAG_MIO         |
                                       MTHCA_MPT_FLAG_REGION      |
                                       access);
+       if (!mr->mtt)
+               mpt_entry->flags |= cpu_to_be32(MTHCA_MPT_FLAG_PHYSICAL);
 
        mpt_entry->page_size = cpu_to_be32(buffer_size_shift - 12);
        mpt_entry->key       = cpu_to_be32(key);
        mpt_entry->pd        = cpu_to_be32(pd);
        mpt_entry->start     = cpu_to_be64(iova);
        mpt_entry->length    = cpu_to_be64(total_size);
+
        memset(&mpt_entry->lkey, 0,
               sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
-       mpt_entry->mtt_seg   = cpu_to_be64(dev->mr_table.mtt_base +
-                                          mr->first_seg * MTHCA_MTT_SEG_SIZE);
+
+       if (mr->mtt)
+               mpt_entry->mtt_seg =
+                       cpu_to_be64(dev->mr_table.mtt_base +
+                                   mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE);
 
        if (0) {
                mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey);
@@ -416,45 +395,70 @@ int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
                }
        }
 
-       err = mthca_SW2HW_MPT(dev, mpt_entry,
+       err = mthca_SW2HW_MPT(dev, mailbox,
                              key & (dev->limits.num_mpts - 1),
                              &status);
-       if (err)
+       if (err) {
                mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
-       else if (status) {
+               goto err_out_mailbox;
+       } else if (status) {
                mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
                           status);
                err = -EINVAL;
+               goto err_out_mailbox;
        }
 
-       kfree(mailbox);
+       mthca_free_mailbox(dev, mailbox);
        return err;
 
-err_out_mailbox_free:
-       kfree(mailbox);
-
-err_out_free_mtt:
-       mthca_free_mtt(dev, mr->first_seg, mr->order, &dev->mr_table.mtt_buddy);
+err_out_mailbox:
+       mthca_free_mailbox(dev, mailbox);
 
 err_out_table:
-       if (mthca_is_memfree(dev))
-               mthca_table_put(dev, dev->mr_table.mpt_table, key);
+       mthca_table_put(dev, dev->mr_table.mpt_table, key);
 
 err_out_mpt_free:
        mthca_free(&dev->mr_table.mpt_alloc, key);
        return err;
 }
 
-/* Free mr or fmr */
-static void mthca_free_region(struct mthca_dev *dev, u32 lkey, int order,
-                             u32 first_seg, struct mthca_buddy *buddy)
+int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
+                          u32 access, struct mthca_mr *mr)
 {
-       if (order >= 0)
-               mthca_free_mtt(dev, first_seg, order, buddy);
+       mr->mtt = NULL;
+       return mthca_mr_alloc(dev, pd, 12, 0, ~0ULL, access, mr);
+}
 
-       if (mthca_is_memfree(dev))
-               mthca_table_put(dev, dev->mr_table.mpt_table,
-                               arbel_key_to_hw_index(lkey));
+int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
+                       u64 *buffer_list, int buffer_size_shift,
+                       int list_len, u64 iova, u64 total_size,
+                       u32 access, struct mthca_mr *mr)
+{
+       int err;
+
+       mr->mtt = mthca_alloc_mtt(dev, list_len);
+       if (IS_ERR(mr->mtt))
+               return PTR_ERR(mr->mtt);
+
+       err = mthca_write_mtt(dev, mr->mtt, 0, buffer_list, list_len);
+       if (err) {
+               mthca_free_mtt(dev, mr->mtt);
+               return err;
+       }
+
+       err = mthca_mr_alloc(dev, pd, buffer_size_shift, iova,
+                            total_size, access, mr);
+       if (err)
+               mthca_free_mtt(dev, mr->mtt);
+
+       return err;
+}
+
+/* Free mr or fmr */
+static void mthca_free_region(struct mthca_dev *dev, u32 lkey)
+{
+       mthca_table_put(dev, dev->mr_table.mpt_table,
+                       arbel_key_to_hw_index(lkey));
 
        mthca_free(&dev->mr_table.mpt_alloc, key_to_hw_index(dev, lkey));
 }
@@ -476,15 +480,15 @@ void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr)
                mthca_warn(dev, "HW2SW_MPT returned status 0x%02x\n",
                           status);
 
-       mthca_free_region(dev, mr->ibmr.lkey, mr->order, mr->first_seg,
-                         &dev->mr_table.mtt_buddy);
+       mthca_free_region(dev, mr->ibmr.lkey);
+       mthca_free_mtt(dev, mr->mtt);
 }
 
 int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
                    u32 access, struct mthca_fmr *mr)
 {
        struct mthca_mpt_entry *mpt_entry;
-       void *mailbox;
+       struct mthca_mailbox *mailbox;
        u64 mtt_seg;
        u32 key, idx;
        u8 status;
@@ -522,31 +526,24 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
                mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base +
                        sizeof *(mr->mem.tavor.mpt) * idx;
 
-       for (i = MTHCA_MTT_SEG_SIZE / 8, mr->order = 0;
-            i < list_len;
-            i <<= 1, ++mr->order)
-               ; /* nothing */
-
-       mr->first_seg = mthca_alloc_mtt(dev, mr->order,
-                                       dev->mr_table.fmr_mtt_buddy);
-       if (mr->first_seg == -1)
+       mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy);
+       if (IS_ERR(mr->mtt))
                goto err_out_table;
 
-       mtt_seg = mr->first_seg * MTHCA_MTT_SEG_SIZE;
+       mtt_seg = mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE;
 
        if (mthca_is_memfree(dev)) {
                mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table,
-                                                     mr->first_seg);
+                                                     mr->mtt->first_seg);
                BUG_ON(!mr->mem.arbel.mtts);
        } else
                mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg;
 
-       mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
-                         GFP_KERNEL);
-       if (!mailbox)
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
                goto err_out_free_mtt;
 
-       mpt_entry = MAILBOX_ALIGN(mailbox);
+       mpt_entry = mailbox->buf;
 
        mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
                                       MTHCA_MPT_FLAG_MIO         |
@@ -571,7 +568,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
                }
        }
 
-       err = mthca_SW2HW_MPT(dev, mpt_entry,
+       err = mthca_SW2HW_MPT(dev, mailbox,
                              key & (dev->limits.num_mpts - 1),
                              &status);
        if (err) {
@@ -585,19 +582,17 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
                goto err_out_mailbox_free;
        }
 
-       kfree(mailbox);
+       mthca_free_mailbox(dev, mailbox);
        return 0;
 
 err_out_mailbox_free:
-       kfree(mailbox);
+       mthca_free_mailbox(dev, mailbox);
 
 err_out_free_mtt:
-       mthca_free_mtt(dev, mr->first_seg, mr->order,
-                      dev->mr_table.fmr_mtt_buddy);
+       mthca_free_mtt(dev, mr->mtt);
 
 err_out_table:
-       if (mthca_is_memfree(dev))
-               mthca_table_put(dev, dev->mr_table.mpt_table, key);
+       mthca_table_put(dev, dev->mr_table.mpt_table, key);
 
 err_out_mpt_free:
        mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);
@@ -609,8 +604,9 @@ int mthca_free_fmr(struct mthca_dev *dev, struct mthca_fmr *fmr)
        if (fmr->maps)
                return -EBUSY;
 
-       mthca_free_region(dev, fmr->ibmr.lkey, fmr->order, fmr->first_seg,
-                         dev->mr_table.fmr_mtt_buddy);
+       mthca_free_region(dev, fmr->ibmr.lkey);
+       mthca_free_mtt(dev, fmr->mtt);
+
        return 0;
 }
 
@@ -826,7 +822,8 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev)
        if (dev->limits.reserved_mtts) {
                i = fls(dev->limits.reserved_mtts - 1);
 
-               if (mthca_alloc_mtt(dev, i, dev->mr_table.fmr_mtt_buddy) == -1) {
+               if (mthca_alloc_mtt_range(dev, i,
+                                         dev->mr_table.fmr_mtt_buddy) == -1) {
                        mthca_warn(dev, "MTT table of order %d is too small.\n",
                                  dev->mr_table.fmr_mtt_buddy->max_order);
                        err = -ENOMEM;
index 159f4e6c312d40f2c087fecfe86e118a150523b6..0b5adfd91597a1ec376bd895d55a3b781b21f22d 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, 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
@@ -52,7 +53,7 @@ static int mthca_query_device(struct ib_device *ibdev,
        if (!in_mad || !out_mad)
                goto out;
 
-       memset(props, 0, sizeof props);
+       memset(props, 0, sizeof *props);
 
        props->fw_ver              = mdev->fw_ver;
 
@@ -558,6 +559,7 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd       *pd,
                                  convert_access(acc), mr);
 
        if (err) {
+               kfree(page_list);
                kfree(mr);
                return ERR_PTR(err);
        }
index 619710f95a879cb01e094027c52905e8c688853e..4d976cccb1a8126acd97096821d92808b698a114 100644 (file)
@@ -54,18 +54,18 @@ struct mthca_uar {
        int           index;
 };
 
+struct mthca_mtt;
+
 struct mthca_mr {
-       struct ib_mr ibmr;
-       int order;
-       u32 first_seg;
+       struct ib_mr      ibmr;
+       struct mthca_mtt *mtt;
 };
 
 struct mthca_fmr {
-       struct ib_fmr ibmr;
+       struct ib_fmr      ibmr;
        struct ib_fmr_attr attr;
-       int order;
-       u32 first_seg;
-       int maps;
+       struct mthca_mtt  *mtt;
+       int                maps;
        union {
                struct {
                        struct mthca_mpt_entry __iomem *mpt;
index ca73bab11a0288f8538d3991011c84ddf903034d..163a8ef4186f690b94f58f9f6600bfb12ac780b3 100644 (file)
@@ -357,6 +357,9 @@ static const struct {
                                [UD]  = (IB_QP_PKEY_INDEX |
                                         IB_QP_PORT       |
                                         IB_QP_QKEY),
+                               [UC]  = (IB_QP_PKEY_INDEX |
+                                        IB_QP_PORT       |
+                                        IB_QP_ACCESS_FLAGS),
                                [RC]  = (IB_QP_PKEY_INDEX |
                                         IB_QP_PORT       |
                                         IB_QP_ACCESS_FLAGS),
@@ -378,6 +381,9 @@ static const struct {
                                [UD]  = (IB_QP_PKEY_INDEX |
                                         IB_QP_PORT       |
                                         IB_QP_QKEY),
+                               [UC]  = (IB_QP_PKEY_INDEX |
+                                        IB_QP_PORT       |
+                                        IB_QP_ACCESS_FLAGS),
                                [RC]  = (IB_QP_PKEY_INDEX |
                                         IB_QP_PORT       |
                                         IB_QP_ACCESS_FLAGS),
@@ -388,6 +394,11 @@ static const struct {
                [IB_QPS_RTR]   = {
                        .trans = MTHCA_TRANS_INIT2RTR,
                        .req_param = {
+                               [UC]  = (IB_QP_AV                  |
+                                        IB_QP_PATH_MTU            |
+                                        IB_QP_DEST_QPN            |
+                                        IB_QP_RQ_PSN              |
+                                        IB_QP_MAX_DEST_RD_ATOMIC),
                                [RC]  = (IB_QP_AV                  |
                                         IB_QP_PATH_MTU            |
                                         IB_QP_DEST_QPN            |
@@ -398,6 +409,9 @@ static const struct {
                        .opt_param = {
                                [UD]  = (IB_QP_PKEY_INDEX |
                                         IB_QP_QKEY),
+                               [UC]  = (IB_QP_ALT_PATH     |
+                                        IB_QP_ACCESS_FLAGS |
+                                        IB_QP_PKEY_INDEX),
                                [RC]  = (IB_QP_ALT_PATH     |
                                         IB_QP_ACCESS_FLAGS |
                                         IB_QP_PKEY_INDEX),
@@ -413,6 +427,8 @@ static const struct {
                        .trans = MTHCA_TRANS_RTR2RTS,
                        .req_param = {
                                [UD]  = IB_QP_SQ_PSN,
+                               [UC]  = (IB_QP_SQ_PSN            |
+                                        IB_QP_MAX_QP_RD_ATOMIC),
                                [RC]  = (IB_QP_TIMEOUT           |
                                         IB_QP_RETRY_CNT         |
                                         IB_QP_RNR_RETRY         |
@@ -423,6 +439,11 @@ static const struct {
                        .opt_param = {
                                [UD]  = (IB_QP_CUR_STATE             |
                                         IB_QP_QKEY),
+                               [UC]  = (IB_QP_CUR_STATE             |
+                                        IB_QP_ALT_PATH              |
+                                        IB_QP_ACCESS_FLAGS          |
+                                        IB_QP_PKEY_INDEX            |
+                                        IB_QP_PATH_MIG_STATE),
                                [RC]  = (IB_QP_CUR_STATE             |
                                         IB_QP_ALT_PATH              |
                                         IB_QP_ACCESS_FLAGS          |
@@ -442,6 +463,9 @@ static const struct {
                        .opt_param = {
                                [UD]  = (IB_QP_CUR_STATE             |
                                         IB_QP_QKEY),
+                               [UC]  = (IB_QP_ACCESS_FLAGS          |
+                                        IB_QP_ALT_PATH              |
+                                        IB_QP_PATH_MIG_STATE),
                                [RC]  = (IB_QP_ACCESS_FLAGS          |
                                         IB_QP_ALT_PATH              |
                                         IB_QP_PATH_MIG_STATE        |
@@ -462,6 +486,10 @@ static const struct {
                        .opt_param = {
                                [UD]  = (IB_QP_CUR_STATE             |
                                         IB_QP_QKEY),
+                               [UC]  = (IB_QP_CUR_STATE             |
+                                        IB_QP_ALT_PATH              |
+                                        IB_QP_ACCESS_FLAGS          |
+                                        IB_QP_PATH_MIG_STATE),
                                [RC]  = (IB_QP_CUR_STATE             |
                                         IB_QP_ALT_PATH              |
                                         IB_QP_ACCESS_FLAGS          |
@@ -476,6 +504,14 @@ static const struct {
                        .opt_param = {
                                [UD]  = (IB_QP_PKEY_INDEX            |
                                         IB_QP_QKEY),
+                               [UC]  = (IB_QP_AV                    |
+                                        IB_QP_MAX_QP_RD_ATOMIC      |
+                                        IB_QP_MAX_DEST_RD_ATOMIC    |
+                                        IB_QP_CUR_STATE             |
+                                        IB_QP_ALT_PATH              |
+                                        IB_QP_ACCESS_FLAGS          |
+                                        IB_QP_PKEY_INDEX            |
+                                        IB_QP_PATH_MIG_STATE),
                                [RC]  = (IB_QP_AV                    |
                                         IB_QP_TIMEOUT               |
                                         IB_QP_RETRY_CNT             |
@@ -501,6 +537,7 @@ static const struct {
                        .opt_param = {
                                [UD]  = (IB_QP_CUR_STATE             |
                                         IB_QP_QKEY),
+                               [UC]  = (IB_QP_CUR_STATE),
                                [RC]  = (IB_QP_CUR_STATE             |
                                         IB_QP_MIN_RNR_TIMER),
                                [MLX] = (IB_QP_CUR_STATE             |
@@ -552,7 +589,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
        struct mthca_dev *dev = to_mdev(ibqp->device);
        struct mthca_qp *qp = to_mqp(ibqp);
        enum ib_qp_state cur_state, new_state;
-       void *mailbox = NULL;
+       struct mthca_mailbox *mailbox;
        struct mthca_qp_param *qp_param;
        struct mthca_qp_context *qp_context;
        u32 req_param, opt_param;
@@ -609,10 +646,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
                return -EINVAL;
        }
 
-       mailbox = kmalloc(sizeof (*qp_param) + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
-       if (!mailbox)
-               return -ENOMEM;
-       qp_param = MAILBOX_ALIGN(mailbox);
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       qp_param = mailbox->buf;
        qp_context = &qp_param->context;
        memset(qp_param, 0, sizeof *qp_param);
 
@@ -683,7 +720,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
        if (attr_mask & IB_QP_AV) {
                qp_context->pri_path.g_mylmc     = attr->ah_attr.src_path_bits & 0x7f;
                qp_context->pri_path.rlid        = cpu_to_be16(attr->ah_attr.dlid);
-               qp_context->pri_path.static_rate = (!!attr->ah_attr.static_rate) << 3;
+               qp_context->pri_path.static_rate = !!attr->ah_attr.static_rate;
                if (attr->ah_attr.ah_flags & IB_AH_GRH) {
                        qp_context->pri_path.g_mylmc |= 1 << 7;
                        qp_context->pri_path.mgid_index = attr->ah_attr.grh.sgid_index;
@@ -724,9 +761,9 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
                qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RETRY_COUNT);
        }
 
-       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
-               qp_context->params1 |= cpu_to_be32(min(attr->max_dest_rd_atomic ?
-                                                      ffs(attr->max_dest_rd_atomic) - 1 : 0,
+       if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+               qp_context->params1 |= cpu_to_be32(min(attr->max_rd_atomic ?
+                                                      ffs(attr->max_rd_atomic) - 1 : 0,
                                                       7) << 21);
                qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_SRA_MAX);
        }
@@ -764,10 +801,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
                qp->atomic_rd_en = attr->qp_access_flags;
        }
 
-       if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
                u8 rra_max;
 
-               if (qp->resp_depth && !attr->max_rd_atomic) {
+               if (qp->resp_depth && !attr->max_dest_rd_atomic) {
                        /*
                         * Lowering our responder resources to zero.
                         * Turn off RDMA/atomics as responder.
@@ -778,7 +815,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
                                                                MTHCA_QP_OPTPAR_RAE);
                }
 
-               if (!qp->resp_depth && attr->max_rd_atomic) {
+               if (!qp->resp_depth && attr->max_dest_rd_atomic) {
                        /*
                         * Increasing our responder resources from
                         * zero.  Turn on RDMA/atomics as appropriate.
@@ -799,7 +836,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
                }
 
                for (rra_max = 0;
-                    1 << rra_max < attr->max_rd_atomic &&
+                    1 << rra_max < attr->max_dest_rd_atomic &&
                             rra_max < dev->qp_table.rdb_shift;
                     ++rra_max)
                        ; /* nothing */
@@ -807,7 +844,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
                qp_context->params2      |= cpu_to_be32(rra_max << 21);
                qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRA_MAX);
 
-               qp->resp_depth = attr->max_rd_atomic;
+               qp->resp_depth = attr->max_dest_rd_atomic;
        }
 
        qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC);
@@ -835,7 +872,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
        }
 
        err = mthca_MODIFY_QP(dev, state_table[cur_state][new_state].trans,
-                             qp->qpn, 0, qp_param, 0, &status);
+                             qp->qpn, 0, mailbox, 0, &status);
        if (status) {
                mthca_warn(dev, "modify QP %d returned status %02x.\n",
                           state_table[cur_state][new_state].trans, status);
@@ -845,7 +882,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
        if (!err)
                qp->state = new_state;
 
-       kfree(mailbox);
+       mthca_free_mailbox(dev, mailbox);
 
        if (is_sqp(dev, qp))
                store_attrs(to_msqp(qp), attr, attr_mask);
@@ -934,7 +971,8 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
                        mthca_dbg(dev, "Creating direct QP of size %d (shift %d)\n",
                                  size, shift);
 
-               qp->queue.direct.buf = pci_alloc_consistent(dev->pdev, size, &t);
+               qp->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev, size,
+                                                         &t, GFP_KERNEL);
                if (!qp->queue.direct.buf)
                        goto err_out;
 
@@ -973,7 +1011,8 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
 
                for (i = 0; i < npages; ++i) {
                        qp->queue.page_list[i].buf =
-                               pci_alloc_consistent(dev->pdev, PAGE_SIZE, &t);
+                               dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
+                                                  &t, GFP_KERNEL);
                        if (!qp->queue.page_list[i].buf)
                                goto err_out_free;
 
@@ -996,16 +1035,15 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
 
  err_out_free:
        if (qp->is_direct) {
-               pci_free_consistent(dev->pdev, size,
-                                   qp->queue.direct.buf,
-                                   pci_unmap_addr(&qp->queue.direct, mapping));
+               dma_free_coherent(&dev->pdev->dev, size, qp->queue.direct.buf,
+                                 pci_unmap_addr(&qp->queue.direct, mapping));
        } else
                for (i = 0; i < npages; ++i) {
                        if (qp->queue.page_list[i].buf)
-                               pci_free_consistent(dev->pdev, PAGE_SIZE,
-                                                   qp->queue.page_list[i].buf,
-                                                   pci_unmap_addr(&qp->queue.page_list[i],
-                                                                  mapping));
+                               dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+                                                 qp->queue.page_list[i].buf,
+                                                 pci_unmap_addr(&qp->queue.page_list[i],
+                                                                mapping));
 
                }
 
@@ -1073,11 +1111,12 @@ static void mthca_free_memfree(struct mthca_dev *dev,
        if (mthca_is_memfree(dev)) {
                mthca_free_db(dev, MTHCA_DB_TYPE_SQ, qp->sq.db_index);
                mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
-               mthca_table_put(dev, dev->qp_table.rdb_table,
-                               qp->qpn << dev->qp_table.rdb_shift);
-               mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
-               mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
        }
+
+       mthca_table_put(dev, dev->qp_table.rdb_table,
+                       qp->qpn << dev->qp_table.rdb_shift);
+       mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
+       mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
 }
 
 static void mthca_wq_init(struct mthca_wq* wq)
@@ -1529,6 +1568,26 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 
                        break;
 
+               case UC:
+                       switch (wr->opcode) {
+                       case IB_WR_RDMA_WRITE:
+                       case IB_WR_RDMA_WRITE_WITH_IMM:
+                               ((struct mthca_raddr_seg *) wqe)->raddr =
+                                       cpu_to_be64(wr->wr.rdma.remote_addr);
+                               ((struct mthca_raddr_seg *) wqe)->rkey =
+                                       cpu_to_be32(wr->wr.rdma.rkey);
+                               ((struct mthca_raddr_seg *) wqe)->reserved = 0;
+                               wqe += sizeof (struct mthca_raddr_seg);
+                               size += sizeof (struct mthca_raddr_seg) / 16;
+                               break;
+
+                       default:
+                               /* No extra segments required for sends */
+                               break;
+                       }
+
+                       break;
+
                case UD:
                        ((struct mthca_tavor_ud_seg *) wqe)->lkey =
                                cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
@@ -1814,9 +1873,29 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                        sizeof (struct mthca_atomic_seg);
                                break;
 
+                       case IB_WR_RDMA_READ:
+                       case IB_WR_RDMA_WRITE:
+                       case IB_WR_RDMA_WRITE_WITH_IMM:
+                               ((struct mthca_raddr_seg *) wqe)->raddr =
+                                       cpu_to_be64(wr->wr.rdma.remote_addr);
+                               ((struct mthca_raddr_seg *) wqe)->rkey =
+                                       cpu_to_be32(wr->wr.rdma.rkey);
+                               ((struct mthca_raddr_seg *) wqe)->reserved = 0;
+                               wqe += sizeof (struct mthca_raddr_seg);
+                               size += sizeof (struct mthca_raddr_seg) / 16;
+                               break;
+
+                       default:
+                               /* No extra segments required for sends */
+                               break;
+                       }
+
+                       break;
+
+               case UC:
+                       switch (wr->opcode) {
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                       case IB_WR_RDMA_READ:
                                ((struct mthca_raddr_seg *) wqe)->raddr =
                                        cpu_to_be64(wr->wr.rdma.remote_addr);
                                ((struct mthca_raddr_seg *) wqe)->rkey =
index 556264b43425ce89a0079154c0be8479a78d0a5d..374f404e81da32592596953b4403fc6571ca9f41 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/compat.h>
 
 struct evdev {
        int exist;
@@ -145,6 +146,41 @@ static int evdev_open(struct inode * inode, struct file * file)
        return 0;
 }
 
+#ifdef CONFIG_COMPAT
+struct input_event_compat {
+       struct compat_timeval time;
+       __u16 type;
+       __u16 code;
+       __s32 value;
+};
+
+#ifdef CONFIG_X86_64
+#  define COMPAT_TEST test_thread_flag(TIF_IA32)
+#elif defined(CONFIG_IA64)
+#  define COMPAT_TEST IS_IA32_PROCESS(ia64_task_regs(current))
+#elif defined(CONFIG_ARCH_S390)
+#  define COMPAT_TEST test_thread_flag(TIF_31BIT)
+#else
+#  define COMPAT_TEST test_thread_flag(TIF_32BIT)
+#endif
+
+static ssize_t evdev_write_compat(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+{
+       struct evdev_list *list = file->private_data;
+       struct input_event_compat event;
+       int retval = 0;
+
+       while (retval < count) {
+               if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat)))
+                       return -EFAULT;
+               input_event(list->evdev->handle.dev, event.type, event.code, event.value);
+               retval += sizeof(struct input_event_compat);
+       }
+
+       return retval;
+}
+#endif
+
 static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
 {
        struct evdev_list *list = file->private_data;
@@ -153,6 +189,11 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
 
        if (!list->evdev->exist) return -ENODEV;
 
+#ifdef CONFIG_COMPAT
+       if (COMPAT_TEST)
+               return evdev_write_compat(file, buffer, count, ppos);
+#endif
+
        while (retval < count) {
 
                if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
@@ -164,11 +205,56 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
        return retval;
 }
 
+#ifdef CONFIG_COMPAT
+static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
+{
+       struct evdev_list *list = file->private_data;
+       int retval;
+
+       if (count < sizeof(struct input_event_compat))
+               return -EINVAL;
+
+       if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
+               return -EAGAIN;
+
+       retval = wait_event_interruptible(list->evdev->wait,
+               list->head != list->tail || (!list->evdev->exist));
+
+       if (retval)
+               return retval;
+
+       if (!list->evdev->exist)
+               return -ENODEV;
+
+       while (list->head != list->tail && retval + sizeof(struct input_event_compat) <= count) {
+               struct input_event *event = (struct input_event *) list->buffer + list->tail;
+               struct input_event_compat event_compat;
+               event_compat.time.tv_sec = event->time.tv_sec;
+               event_compat.time.tv_usec = event->time.tv_usec;
+               event_compat.type = event->type;
+               event_compat.code = event->code;
+               event_compat.value = event->value;
+
+               if (copy_to_user(buffer + retval, &event_compat,
+                       sizeof(struct input_event_compat))) return -EFAULT;
+               list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
+               retval += sizeof(struct input_event_compat);
+       }
+
+       return retval;
+}
+#endif
+
 static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
 {
        struct evdev_list *list = file->private_data;
        int retval;
 
+#ifdef CONFIG_COMPAT
+       if (COMPAT_TEST)
+               return evdev_read_compat(file, buffer, count, ppos);
+#endif
+
        if (count < sizeof(struct input_event))
                return -EINVAL;
 
@@ -186,7 +272,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count
 
        while (list->head != list->tail && retval + sizeof(struct input_event) <= count) {
                if (copy_to_user(buffer + retval, list->buffer + list->tail,
-                        sizeof(struct input_event))) return -EFAULT;
+                       sizeof(struct input_event))) return -EFAULT;
                list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
                retval += sizeof(struct input_event);
        }
@@ -203,7 +289,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
                (list->evdev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
-static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct evdev_list *list = file->private_data;
        struct evdev *evdev = list->evdev;
@@ -285,109 +371,267 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 
                default:
 
-                       if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
+                       if (_IOC_TYPE(cmd) != 'E')
                                return -EINVAL;
 
-                       if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
-
-                               long *bits;
-                               int len;
-
-                               switch (_IOC_NR(cmd) & EV_MAX) {
-                                       case      0: bits = dev->evbit;  len = EV_MAX;  break;
-                                       case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
-                                       case EV_REL: bits = dev->relbit; len = REL_MAX; break;
-                                       case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
-                                       case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
-                                       case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
-                                       case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
-                                       case EV_FF:  bits = dev->ffbit;  len = FF_MAX;  break;
-                                       default: return -EINVAL;
+                       if (_IOC_DIR(cmd) == _IOC_READ) {
+
+                               if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+
+                                       long *bits;
+                                       int len;
+
+                                       switch (_IOC_NR(cmd) & EV_MAX) {
+                                               case      0: bits = dev->evbit;  len = EV_MAX;  break;
+                                               case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
+                                               case EV_REL: bits = dev->relbit; len = REL_MAX; break;
+                                               case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+                                               case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
+                                               case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
+                                               case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
+                                               case EV_FF:  bits = dev->ffbit;  len = FF_MAX;  break;
+                                               default: return -EINVAL;
+                                       }
+                                       len = NBITS(len) * sizeof(long);
+                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+                                       return copy_to_user(p, bits, len) ? -EFAULT : len;
                                }
-                               len = NBITS(len) * sizeof(long);
-                               if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                               return copy_to_user(p, bits, len) ? -EFAULT : len;
-                       }
 
-                       if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
-                               int len;
-                               len = NBITS(KEY_MAX) * sizeof(long);
-                               if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                               return copy_to_user(p, dev->key, len) ? -EFAULT : len;
-                       }
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
+                                       int len;
+                                       len = NBITS(KEY_MAX) * sizeof(long);
+                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+                                       return copy_to_user(p, dev->key, len) ? -EFAULT : len;
+                               }
 
-                       if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
-                               int len;
-                               len = NBITS(LED_MAX) * sizeof(long);
-                               if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                               return copy_to_user(p, dev->led, len) ? -EFAULT : len;
-                       }
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
+                                       int len;
+                                       len = NBITS(LED_MAX) * sizeof(long);
+                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+                                       return copy_to_user(p, dev->led, len) ? -EFAULT : len;
+                               }
 
-                       if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
-                               int len;
-                               len = NBITS(SND_MAX) * sizeof(long);
-                               if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                               return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
-                       }
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
+                                       int len;
+                                       len = NBITS(SND_MAX) * sizeof(long);
+                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+                                       return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
+                               }
 
-                       if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
-                               int len;
-                               if (!dev->name) return -ENOENT;
-                               len = strlen(dev->name) + 1;
-                               if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                               return copy_to_user(p, dev->name, len) ? -EFAULT : len;
-                       }
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
+                                       int len;
+                                       if (!dev->name) return -ENOENT;
+                                       len = strlen(dev->name) + 1;
+                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+                                       return copy_to_user(p, dev->name, len) ? -EFAULT : len;
+                               }
+
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
+                                       int len;
+                                       if (!dev->phys) return -ENOENT;
+                                       len = strlen(dev->phys) + 1;
+                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+                                       return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
+                               }
+
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
+                                       int len;
+                                       if (!dev->uniq) return -ENOENT;
+                                       len = strlen(dev->uniq) + 1;
+                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+                                       return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
+                               }
+
+                               if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+
+                                       int t = _IOC_NR(cmd) & ABS_MAX;
+
+                                       abs.value = dev->abs[t];
+                                       abs.minimum = dev->absmin[t];
+                                       abs.maximum = dev->absmax[t];
+                                       abs.fuzz = dev->absfuzz[t];
+                                       abs.flat = dev->absflat[t];
+
+                                       if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
+                                               return -EFAULT;
+
+                                       return 0;
+                               }
 
-                       if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
-                               int len;
-                               if (!dev->phys) return -ENOENT;
-                               len = strlen(dev->phys) + 1;
-                               if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                               return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
                        }
 
-                       if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
-                               int len;
-                               if (!dev->uniq) return -ENOENT;
-                               len = strlen(dev->uniq) + 1;
-                               if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                               return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
+                       if (_IOC_DIR(cmd) == _IOC_WRITE) {
+
+                               if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
+
+                                       int t = _IOC_NR(cmd) & ABS_MAX;
+
+                                       if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
+                                               return -EFAULT;
+
+                                       dev->abs[t] = abs.value;
+                                       dev->absmin[t] = abs.minimum;
+                                       dev->absmax[t] = abs.maximum;
+                                       dev->absfuzz[t] = abs.fuzz;
+                                       dev->absflat[t] = abs.flat;
+
+                                       return 0;
+                               }
                        }
+       }
+       return -EINVAL;
+}
 
-                       if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+#ifdef CONFIG_COMPAT
+
+#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
+#define NBITS_COMPAT(x) ((((x)-1)/BITS_PER_LONG_COMPAT)+1)
+#define OFF_COMPAT(x)  ((x)%BITS_PER_LONG_COMPAT)
+#define BIT_COMPAT(x)  (1UL<<OFF_COMPAT(x))
+#define LONG_COMPAT(x) ((x)/BITS_PER_LONG_COMPAT)
+#define test_bit_compat(bit, array) ((array[LONG_COMPAT(bit)] >> OFF_COMPAT(bit)) & 1)
+
+#ifdef __BIG_ENDIAN
+#define bit_to_user(bit, max) \
+do { \
+       int i; \
+       int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
+       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
+       for (i = 0; i < len / sizeof(compat_long_t); i++) \
+               if (copy_to_user((compat_long_t*) p + i, \
+                                (compat_long_t*) (bit) + i + 1 - ((i % 2) << 1), \
+                                sizeof(compat_long_t))) \
+                       return -EFAULT; \
+       return len; \
+} while (0)
+#else
+#define bit_to_user(bit, max) \
+do { \
+       int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
+       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
+       return copy_to_user(p, (bit), len) ? -EFAULT : len; \
+} while (0)
+#endif
+
+static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct evdev_list *list = file->private_data;
+       struct evdev *evdev = list->evdev;
+       struct input_dev *dev = evdev->handle.dev;
+       struct input_absinfo abs;
+       void __user *p = compat_ptr(arg);
 
-                               int t = _IOC_NR(cmd) & ABS_MAX;
+       if (!evdev->exist) return -ENODEV;
 
-                               abs.value = dev->abs[t];
-                               abs.minimum = dev->absmin[t];
-                               abs.maximum = dev->absmax[t];
-                               abs.fuzz = dev->absfuzz[t];
-                               abs.flat = dev->absflat[t];
+       switch (cmd) {
 
-                               if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
-                                       return -EFAULT;
+               case EVIOCGVERSION:
+               case EVIOCGID:
+               case EVIOCGKEYCODE:
+               case EVIOCSKEYCODE:
+               case EVIOCSFF:
+               case EVIOCRMFF:
+               case EVIOCGEFFECTS:
+               case EVIOCGRAB:
+                       return evdev_ioctl(file, cmd, (unsigned long) p);
 
-                               return 0;
+               default:
+
+                       if (_IOC_TYPE(cmd) != 'E')
+                               return -EINVAL;
+
+                       if (_IOC_DIR(cmd) == _IOC_READ) {
+
+                               if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+                                       long *bits;
+                                       int max;
+
+                                       switch (_IOC_NR(cmd) & EV_MAX) {
+                                               case      0: bits = dev->evbit;  max = EV_MAX;  break;
+                                               case EV_KEY: bits = dev->keybit; max = KEY_MAX; break;
+                                               case EV_REL: bits = dev->relbit; max = REL_MAX; break;
+                                               case EV_ABS: bits = dev->absbit; max = ABS_MAX; break;
+                                               case EV_MSC: bits = dev->mscbit; max = MSC_MAX; break;
+                                               case EV_LED: bits = dev->ledbit; max = LED_MAX; break;
+                                               case EV_SND: bits = dev->sndbit; max = SND_MAX; break;
+                                               case EV_FF:  bits = dev->ffbit;  max = FF_MAX;  break;
+                                               default: return -EINVAL;
+                                       }
+                                       bit_to_user(bits, max);
+                               }
+
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
+                                       bit_to_user(dev->key, KEY_MAX);
+
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
+                                       bit_to_user(dev->led, LED_MAX);
+
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
+                                       bit_to_user(dev->snd, SND_MAX);
+
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
+                                       int len;
+                                       if (!dev->name) return -ENOENT;
+                                       len = strlen(dev->name) + 1;
+                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+                                       return copy_to_user(p, dev->name, len) ? -EFAULT : len;
+                               }
+
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
+                                       int len;
+                                       if (!dev->phys) return -ENOENT;
+                                       len = strlen(dev->phys) + 1;
+                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+                                       return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
+                               }
+
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
+                                       int len;
+                                       if (!dev->uniq) return -ENOENT;
+                                       len = strlen(dev->uniq) + 1;
+                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+                                       return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
+                               }
+
+                               if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+
+                                       int t = _IOC_NR(cmd) & ABS_MAX;
+
+                                       abs.value = dev->abs[t];
+                                       abs.minimum = dev->absmin[t];
+                                       abs.maximum = dev->absmax[t];
+                                       abs.fuzz = dev->absfuzz[t];
+                                       abs.flat = dev->absflat[t];
+
+                                       if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
+                                               return -EFAULT;
+
+                                       return 0;
+                               }
                        }
 
-                       if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
+                       if (_IOC_DIR(cmd) == _IOC_WRITE) {
 
-                               int t = _IOC_NR(cmd) & ABS_MAX;
+                               if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
 
-                               if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
-                                       return -EFAULT;
+                                       int t = _IOC_NR(cmd) & ABS_MAX;
 
-                               dev->abs[t] = abs.value;
-                               dev->absmin[t] = abs.minimum;
-                               dev->absmax[t] = abs.maximum;
-                               dev->absfuzz[t] = abs.fuzz;
-                               dev->absflat[t] = abs.flat;
+                                       if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
+                                               return -EFAULT;
 
-                               return 0;
+                                       dev->abs[t] = abs.value;
+                                       dev->absmin[t] = abs.minimum;
+                                       dev->absmax[t] = abs.maximum;
+                                       dev->absfuzz[t] = abs.fuzz;
+                                       dev->absflat[t] = abs.flat;
+
+                                       return 0;
+                               }
                        }
        }
        return -EINVAL;
 }
+#endif
 
 static struct file_operations evdev_fops = {
        .owner =        THIS_MODULE,
@@ -396,7 +640,10 @@ static struct file_operations evdev_fops = {
        .poll =         evdev_poll,
        .open =         evdev_open,
        .release =      evdev_release,
-       .ioctl =        evdev_ioctl,
+       .unlocked_ioctl = evdev_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = evdev_ioctl_compat,
+#endif
        .fasync =       evdev_fasync,
        .flush =        evdev_flush
 };
index 1d93f50929049332e9ec2397cd67dfce9dfb2fe9..7524bd7d8b8f7c602db8c16b649333b0b53cd7d4 100644 (file)
@@ -49,22 +49,8 @@ config GAMEPORT_EMU10K1
          To compile this driver as a module, choose M here: the
          module will be called emu10k1-gp.
 
-config GAMEPORT_VORTEX
-       tristate "Aureal Vortex, Vortex 2 gameport support"
-       depends on PCI
-       help
-         Say Y here if you have an Aureal Vortex 1 or 2  card and want
-         to use its gameport.
-
-         To compile this driver as a module, choose M here: the
-         module will be called vortex.
-
 config GAMEPORT_FM801
        tristate "ForteMedia FM801 gameport support"
        depends on PCI
 
-config GAMEPORT_CS461X
-       tristate "Crystal SoundFusion gameport support"
-       depends on PCI
-
 endif
index 5367b4267adf8401fdc6840b1bb50e66b25b1dfd..b6f6097bd8c4f005cd031f2d7b9ddcccb94712b6 100644 (file)
@@ -5,9 +5,7 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_GAMEPORT)         += gameport.o
-obj-$(CONFIG_GAMEPORT_CS461X)  += cs461x.o
 obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o
 obj-$(CONFIG_GAMEPORT_FM801)   += fm801-gp.o
 obj-$(CONFIG_GAMEPORT_L4)      += lightning.o
 obj-$(CONFIG_GAMEPORT_NS558)   += ns558.o
-obj-$(CONFIG_GAMEPORT_VORTEX)  += vortex.o
diff --git a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c
deleted file mode 100644 (file)
index d4013ff..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
-       The all defines and part of code (such as cs461x_*) are
-       contributed from ALSA 0.5.8 sources.
-       See http://www.alsa-project.org/ for sources
-
-       Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
-*/
-
-#include <asm/io.h>
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-
-MODULE_AUTHOR("Victor Krapivin");
-MODULE_LICENSE("GPL");
-
-/*
-       These options are experimental
-
-#define CS461X_FULL_MAP
-*/
-
-
-#ifndef PCI_VENDOR_ID_CIRRUS
-#define PCI_VENDOR_ID_CIRRUS            0x1013
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4610
-#define PCI_DEVICE_ID_CIRRUS_4610       0x6001
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4612
-#define PCI_DEVICE_ID_CIRRUS_4612       0x6003
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4615
-#define PCI_DEVICE_ID_CIRRUS_4615       0x6004
-#endif
-
-/* Registers */
-
-#define BA0_JSPT                                0x00000480
-#define BA0_JSCTL                               0x00000484
-#define BA0_JSC1                                0x00000488
-#define BA0_JSC2                                0x0000048C
-#define BA0_JSIO                                0x000004A0
-
-/* Bits for JSPT */
-
-#define JSPT_CAX                                0x00000001
-#define JSPT_CAY                                0x00000002
-#define JSPT_CBX                                0x00000004
-#define JSPT_CBY                                0x00000008
-#define JSPT_BA1                                0x00000010
-#define JSPT_BA2                                0x00000020
-#define JSPT_BB1                                0x00000040
-#define JSPT_BB2                                0x00000080
-
-/* Bits for JSCTL */
-
-#define JSCTL_SP_MASK                           0x00000003
-#define JSCTL_SP_SLOW                           0x00000000
-#define JSCTL_SP_MEDIUM_SLOW                    0x00000001
-#define JSCTL_SP_MEDIUM_FAST                    0x00000002
-#define JSCTL_SP_FAST                           0x00000003
-#define JSCTL_ARE                               0x00000004
-
-/* Data register pairs masks */
-
-#define JSC1_Y1V_MASK                           0x0000FFFF
-#define JSC1_X1V_MASK                           0xFFFF0000
-#define JSC1_Y1V_SHIFT                          0
-#define JSC1_X1V_SHIFT                          16
-#define JSC2_Y2V_MASK                           0x0000FFFF
-#define JSC2_X2V_MASK                           0xFFFF0000
-#define JSC2_Y2V_SHIFT                          0
-#define JSC2_X2V_SHIFT                          16
-
-/* JS GPIO */
-
-#define JSIO_DAX                                0x00000001
-#define JSIO_DAY                                0x00000002
-#define JSIO_DBX                                0x00000004
-#define JSIO_DBY                                0x00000008
-#define JSIO_AXOE                               0x00000010
-#define JSIO_AYOE                               0x00000020
-#define JSIO_BXOE                               0x00000040
-#define JSIO_BYOE                               0x00000080
-
-/*
-   The card initialization code is obfuscated; the module cs461x
-   need to be loaded after ALSA modules initialized and something
-   played on the CS 4610 chip (see sources for details of CS4610
-   initialization code from ALSA)
-*/
-
-/* Card specific definitions */
-
-#define CS461X_BA0_SIZE         0x2000
-#define CS461X_BA1_DATA0_SIZE   0x3000
-#define CS461X_BA1_DATA1_SIZE   0x3800
-#define CS461X_BA1_PRG_SIZE     0x7000
-#define CS461X_BA1_REG_SIZE     0x0100
-
-#define BA1_SP_DMEM0                            0x00000000
-#define BA1_SP_DMEM1                            0x00010000
-#define BA1_SP_PMEM                             0x00020000
-#define BA1_SP_REG                              0x00030000
-
-#define BA1_DWORD_SIZE          (13 * 1024 + 512)
-#define BA1_MEMORY_COUNT        3
-
-/*
-   Only one CS461x card is still suppoted; the code requires
-   redesign to avoid this limitatuion.
-*/
-
-static unsigned long ba0_addr;
-static unsigned int __iomem *ba0;
-
-#ifdef CS461X_FULL_MAP
-static unsigned long ba1_addr;
-static union ba1_t {
-        struct {
-                unsigned int __iomem *data0;
-                unsigned int __iomem *data1;
-                unsigned int __iomem *pmem;
-                unsigned int __iomem *reg;
-        } name;
-        unsigned int __iomem *idx[4];
-} ba1;
-
-static void cs461x_poke(unsigned long reg, unsigned int val)
-{
-        writel(val, &ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
-}
-
-static unsigned int cs461x_peek(unsigned long reg)
-{
-        return readl(&ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
-}
-
-#endif
-
-static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
-{
-        writel(val, &ba0[reg >> 2]);
-}
-
-static unsigned int cs461x_peekBA0(unsigned long reg)
-{
-        return readl(&ba0[reg >> 2]);
-}
-
-static int cs461x_free(struct pci_dev *pdev)
-{
-       struct gameport *port = pci_get_drvdata(pdev);
-
-       if (port)
-           gameport_unregister_port(port);
-
-       if (ba0) iounmap(ba0);
-#ifdef CS461X_FULL_MAP
-       if (ba1.name.data0) iounmap(ba1.name.data0);
-       if (ba1.name.data1) iounmap(ba1.name.data1);
-       if (ba1.name.pmem)  iounmap(ba1.name.pmem);
-       if (ba1.name.reg)   iounmap(ba1.name.reg);
-#endif
-       return 0;
-}
-
-static void cs461x_gameport_trigger(struct gameport *gameport)
-{
-       cs461x_pokeBA0(BA0_JSPT, 0xFF);  //outb(gameport->io, 0xFF);
-}
-
-static unsigned char cs461x_gameport_read(struct gameport *gameport)
-{
-       return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
-}
-
-static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
-       unsigned js1, js2, jst;
-
-       js1 = cs461x_peekBA0(BA0_JSC1);
-       js2 = cs461x_peekBA0(BA0_JSC2);
-       jst = cs461x_peekBA0(BA0_JSPT);
-
-       *buttons = (~jst >> 4) & 0x0F;
-
-       axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
-       axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
-       axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
-       axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
-
-       for(jst=0;jst<4;++jst)
-               if(axes[jst]==0xFFFF) axes[jst] = -1;
-       return 0;
-}
-
-static int cs461x_gameport_open(struct gameport *gameport, int mode)
-{
-       switch (mode) {
-               case GAMEPORT_MODE_COOKED:
-               case GAMEPORT_MODE_RAW:
-                       return 0;
-               default:
-                       return -1;
-       }
-       return 0;
-}
-
-static struct pci_device_id cs461x_pci_tbl[] = {
-       { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
-       { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
-       { PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
-       { 0, }
-};
-MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
-
-static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-       int rc;
-       struct gameport* port;
-
-       rc = pci_enable_device(pdev);
-       if (rc) {
-               printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
-                       pdev->bus->number, pdev->devfn, rc);
-               return rc;
-       }
-
-       ba0_addr = pci_resource_start(pdev, 0);
-#ifdef CS461X_FULL_MAP
-       ba1_addr = pci_resource_start(pdev, 1);
-#endif
-       if (ba0_addr == 0 || ba0_addr == ~0
-#ifdef CS461X_FULL_MAP
-            || ba1_addr == 0 || ba1_addr == ~0
-#endif
-           ) {
-                printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
-#ifdef CS461X_FULL_MAP
-                printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
-#endif
-               cs461x_free(pdev);
-                return -ENOMEM;
-        }
-
-       ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
-#ifdef CS461X_FULL_MAP
-       ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
-       ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
-       ba1.name.pmem  = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
-       ba1.name.reg   = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
-
-       if (ba0 == NULL || ba1.name.data0 == NULL ||
-            ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
-            ba1.name.reg == NULL) {
-               cs461x_free(pdev);
-                return -ENOMEM;
-        }
-#else
-       if (ba0 == NULL) {
-               cs461x_free(pdev);
-               return -ENOMEM;
-       }
-#endif
-
-       if (!(port = gameport_allocate_port())) {
-               printk(KERN_ERR "cs461x: Memory allocation failed\n");
-               cs461x_free(pdev);
-               return -ENOMEM;
-       }
-
-       pci_set_drvdata(pdev, port);
-
-       port->open = cs461x_gameport_open;
-       port->trigger = cs461x_gameport_trigger;
-       port->read = cs461x_gameport_read;
-       port->cooked_read = cs461x_gameport_cooked_read;
-
-       gameport_set_name(port, "CS416x");
-       gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
-       port->dev.parent = &pdev->dev;
-
-       cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
-       cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
-
-       gameport_register_port(port);
-
-       return 0;
-}
-
-static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
-{
-       cs461x_free(pdev);
-}
-
-static struct pci_driver cs461x_pci_driver = {
-        .name =         "CS461x_gameport",
-        .id_table =     cs461x_pci_tbl,
-        .probe =        cs461x_pci_probe,
-        .remove =       __devexit_p(cs461x_pci_remove),
-};
-
-static int __init cs461x_init(void)
-{
-        return pci_register_driver(&cs461x_pci_driver);
-}
-
-static void __exit cs461x_exit(void)
-{
-        pci_unregister_driver(&cs461x_pci_driver);
-}
-
-module_init(cs461x_init);
-module_exit(cs461x_exit);
-
index e152d0fa0cdd25d4d4ac4de364eaf80b9502a0cc..ab09cf4093e32595cbd84824db790e73f91d2881 100644 (file)
 #include <linux/init.h>
 #include <linux/gameport.h>
 #include <linux/wait.h>
-#include <linux/completion.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/kthread.h>
 
 /*#include <asm/io.h>*/
 
@@ -61,12 +60,13 @@ static void gameport_disconnect_port(struct gameport *gameport);
 
 #if defined(__i386__)
 
+#include <asm/i8253.h>
+
 #define DELTA(x,y)      ((y)-(x)+((y)<(x)?1193182/HZ:0))
 #define GET_TIME(x)     do { x = get_time_pit(); } while (0)
 
 static unsigned int get_time_pit(void)
 {
-       extern spinlock_t i8253_lock;
        unsigned long flags;
        unsigned int count;
 
@@ -238,8 +238,7 @@ struct gameport_event {
 static DEFINE_SPINLOCK(gameport_event_lock);   /* protects gameport_event_list */
 static LIST_HEAD(gameport_event_list);
 static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
-static DECLARE_COMPLETION(gameport_exited);
-static int gameport_pid;
+static struct task_struct *gameport_task;
 
 static void gameport_queue_event(void *object, struct module *owner,
                              enum gameport_event_type event_type)
@@ -250,12 +249,12 @@ static void gameport_queue_event(void *object, struct module *owner,
        spin_lock_irqsave(&gameport_event_lock, flags);
 
        /*
-        * Scan event list for the other events for the same gameport port,
+        * Scan event list for the other events for the same gameport port,
         * starting with the most recent one. If event is the same we
         * do not need add new one. If event is of different type we
         * need to add this event and should not look further because
         * we need to preseve sequence of distinct events.
-        */
+        */
        list_for_each_entry_reverse(event, &gameport_event_list, node) {
                if (event->object == object) {
                        if (event->type == event_type)
@@ -432,20 +431,15 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent)
 
 static int gameport_thread(void *nothing)
 {
-       lock_kernel();
-       daemonize("kgameportd");
-       allow_signal(SIGTERM);
-
        do {
                gameport_handle_events();
-               wait_event_interruptible(gameport_wait, !list_empty(&gameport_event_list));
-               try_to_freeze(PF_FREEZE);
-       } while (!signal_pending(current));
+               wait_event_interruptible(gameport_wait,
+                       kthread_should_stop() || !list_empty(&gameport_event_list));
+               try_to_freeze();
+       } while (!kthread_should_stop());
 
        printk(KERN_DEBUG "gameport: kgameportd exiting\n");
-
-       unlock_kernel();
-       complete_and_exit(&gameport_exited, 0);
+       return 0;
 }
 
 
@@ -773,9 +767,10 @@ void gameport_close(struct gameport *gameport)
 
 static int __init gameport_init(void)
 {
-       if (!(gameport_pid = kernel_thread(gameport_thread, NULL, CLONE_KERNEL))) {
+       gameport_task = kthread_run(gameport_thread, NULL, "kgameportd");
+       if (IS_ERR(gameport_task)) {
                printk(KERN_ERR "gameport: Failed to start kgameportd\n");
-               return -1;
+               return PTR_ERR(gameport_task);
        }
 
        gameport_bus.dev_attrs = gameport_device_attrs;
@@ -789,8 +784,7 @@ static int __init gameport_init(void)
 static void __exit gameport_exit(void)
 {
        bus_unregister(&gameport_bus);
-       kill_proc(gameport_pid, SIGTERM, 1);
-       wait_for_completion(&gameport_exited);
+       kthread_stop(gameport_task);
 }
 
 module_init(gameport_init);
index 7c5c6318eeb9ffad3b1798fca4e1a13b8239689e..1ab5f2dc8a2a4a8fde91f56847165fa39312d9a1 100644 (file)
@@ -258,18 +258,18 @@ static int __init ns558_init(void)
 {
        int i = 0;
 
+       if (pnp_register_driver(&ns558_pnp_driver) >= 0)
+               pnp_registered = 1;
+
 /*
- * Probe ISA ports first so that PnP gets to choose free port addresses
- * not occupied by the ISA ports.
+ * Probe ISA ports after PnP, so that PnP ports that are already
+ * enabled get detected as PnP. This may be suboptimal in multi-device
+ * configurations, but saves hassle with simple setups.
  */
 
        while (ns558_isa_portlist[i])
                ns558_isa_probe(ns558_isa_portlist[i++]);
 
-       if (pnp_register_driver(&ns558_pnp_driver) >= 0)
-               pnp_registered = 1;
-
-
        return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0;
 }
 
diff --git a/drivers/input/gameport/vortex.c b/drivers/input/gameport/vortex.c
deleted file mode 100644 (file)
index 36b0309..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * $Id: vortex.c,v 1.5 2002/07/01 15:39:30 vojtech Exp $
- *
- *  Copyright (c) 2000-2001 Vojtech Pavlik
- *
- *  Based on the work of:
- *     Raymond Ingles
- */
-
-/*
- * Trident 4DWave and Aureal Vortex gameport driver for Linux
- */
-
-/*
- * 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
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/gameport.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver");
-MODULE_LICENSE("GPL");
-
-#define VORTEX_GCR             0x0c    /* Gameport control register */
-#define VORTEX_LEG             0x08    /* Legacy port location */
-#define VORTEX_AXD             0x10    /* Axes start */
-#define VORTEX_DATA_WAIT       20      /* 20 ms */
-
-struct vortex {
-       struct gameport *gameport;
-       struct pci_dev *dev;
-       unsigned char __iomem *base;
-       unsigned char __iomem *io;
-};
-
-static unsigned char vortex_read(struct gameport *gameport)
-{
-       struct vortex *vortex = gameport->port_data;
-       return readb(vortex->io + VORTEX_LEG);
-}
-
-static void vortex_trigger(struct gameport *gameport)
-{
-       struct vortex *vortex = gameport->port_data;
-       writeb(0xff, vortex->io + VORTEX_LEG);
-}
-
-static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
-       struct vortex *vortex = gameport->port_data;
-       int i;
-
-       *buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf;
-
-       for (i = 0; i < 4; i++) {
-               axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32));
-               if (axes[i] == 0x1fff) axes[i] = -1;
-       }
-
-        return 0;
-}
-
-static int vortex_open(struct gameport *gameport, int mode)
-{
-       struct vortex *vortex = gameport->port_data;
-
-       switch (mode) {
-               case GAMEPORT_MODE_COOKED:
-                       writeb(0x40, vortex->io + VORTEX_GCR);
-                       msleep(VORTEX_DATA_WAIT);
-                       return 0;
-               case GAMEPORT_MODE_RAW:
-                       writeb(0x00, vortex->io + VORTEX_GCR);
-                       return 0;
-               default:
-                       return -1;
-       }
-
-       return 0;
-}
-
-static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       struct vortex *vortex;
-       struct gameport *port;
-       int i;
-
-       vortex = kcalloc(1, sizeof(struct vortex), GFP_KERNEL);
-       port = gameport_allocate_port();
-       if (!vortex || !port) {
-               printk(KERN_ERR "vortex: Memory allocation failed.\n");
-               kfree(vortex);
-               gameport_free_port(port);
-               return -ENOMEM;
-       }
-
-       for (i = 0; i < 6; i++)
-               if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
-                       break;
-
-       pci_enable_device(dev);
-
-       vortex->dev = dev;
-       vortex->gameport = port;
-       vortex->base = ioremap(pci_resource_start(vortex->dev, i),
-                               pci_resource_len(vortex->dev, i));
-       vortex->io = vortex->base + id->driver_data;
-
-       pci_set_drvdata(dev, vortex);
-
-       port->port_data = vortex;
-       port->fuzz = 64;
-
-       gameport_set_name(port, "AU88x0");
-       gameport_set_phys(port, "pci%s/gameport0", pci_name(dev));
-       port->dev.parent = &dev->dev;
-       port->read = vortex_read;
-       port->trigger = vortex_trigger;
-       port->cooked_read = vortex_cooked_read;
-       port->open = vortex_open;
-
-       gameport_register_port(port);
-
-       return 0;
-}
-
-static void __devexit vortex_remove(struct pci_dev *dev)
-{
-       struct vortex *vortex = pci_get_drvdata(dev);
-
-       gameport_unregister_port(vortex->gameport);
-       iounmap(vortex->base);
-       kfree(vortex);
-}
-
-static struct pci_device_id vortex_id_table[] = {
-       { 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
-       { 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
-       { 0 }
-};
-
-static struct pci_driver vortex_driver = {
-       .name =         "vortex_gameport",
-       .id_table =     vortex_id_table,
-       .probe =        vortex_probe,
-       .remove =       __devexit_p(vortex_remove),
-};
-
-static int __init vortex_init(void)
-{
-       return pci_register_driver(&vortex_driver);
-}
-
-static void __exit vortex_exit(void)
-{
-       pci_unregister_driver(&vortex_driver);
-}
-
-module_init(vortex_init);
-module_exit(vortex_exit);
index 83c77c990ddab8b8e6a6e17e4f360d3d2d0b40d1..7c4b4d37b3e657698808baf1e8366f056bc64065 100644 (file)
@@ -219,10 +219,24 @@ void input_release_device(struct input_handle *handle)
 
 int input_open_device(struct input_handle *handle)
 {
+       struct input_dev *dev = handle->dev;
+       int err;
+
+       err = down_interruptible(&dev->sem);
+       if (err)
+               return err;
+
        handle->open++;
-       if (handle->dev->open)
-               return handle->dev->open(handle->dev);
-       return 0;
+
+       if (!dev->users++ && dev->open)
+               err = dev->open(dev);
+
+       if (err)
+               handle->open--;
+
+       up(&dev->sem);
+
+       return err;
 }
 
 int input_flush_device(struct input_handle* handle, struct file* file)
@@ -235,10 +249,17 @@ int input_flush_device(struct input_handle* handle, struct file* file)
 
 void input_close_device(struct input_handle *handle)
 {
+       struct input_dev *dev = handle->dev;
+
        input_release_device(handle);
-       if (handle->dev->close)
-               handle->dev->close(handle->dev);
+
+       down(&dev->sem);
+
+       if (!--dev->users && dev->close)
+               dev->close(dev);
        handle->open--;
+
+       up(&dev->sem);
 }
 
 static void input_link_handle(struct input_handle *handle)
@@ -415,6 +436,8 @@ void input_register_device(struct input_dev *dev)
 
        set_bit(EV_SYN, dev->evbit);
 
+       init_MUTEX(&dev->sem);
+
        /*
         * If delay and period are pre-set by the driver, then autorepeating
         * is handled by the driver itself and we don't do it in input.c.
@@ -674,6 +697,8 @@ static int input_handlers_read(char *buf, char **start, off_t pos, int count, in
        return (count > cnt) ? cnt : count;
 }
 
+static struct file_operations input_fileops;
+
 static int __init input_proc_init(void)
 {
        struct proc_dir_entry *entry;
@@ -688,6 +713,8 @@ static int __init input_proc_init(void)
                return -ENOMEM;
        }
        entry->owner = THIS_MODULE;
+       input_fileops = *entry->proc_fops;
+       entry->proc_fops = &input_fileops;
        entry->proc_fops->poll = input_devices_poll;
        entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL);
        if (entry == NULL) {
index 39775fc380c77446e258fd6927760ee21974798a..ff8e1bbd0e13e215926e4f133e589184bd23c52d 100644 (file)
@@ -285,48 +285,33 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
                (POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
-static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
 {
-       struct joydev_list *list = file->private_data;
-       struct joydev *joydev = list->joydev;
        struct input_dev *dev = joydev->handle.dev;
-       void __user *argp = (void __user *)arg;
        int i, j;
 
-       if (!joydev->exist) return -ENODEV;
-
        switch (cmd) {
 
                case JS_SET_CAL:
                        return copy_from_user(&joydev->glue.JS_CORR, argp,
-                               sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+                               sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
                case JS_GET_CAL:
                        return copy_to_user(argp, &joydev->glue.JS_CORR,
-                               sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+                               sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
                case JS_SET_TIMEOUT:
-                       return get_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
+                       return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
                case JS_GET_TIMEOUT:
-                       return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
-               case JS_SET_TIMELIMIT:
-                       return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
-               case JS_GET_TIMELIMIT:
-                       return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
-               case JS_SET_ALL:
-                       return copy_from_user(&joydev->glue, argp,
-                                               sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
-               case JS_GET_ALL:
-                       return copy_to_user(argp, &joydev->glue,
-                                               sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
+                       return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
 
                case JSIOCGVERSION:
-                       return put_user(JS_VERSION, (__u32 __user *) arg);
+                       return put_user(JS_VERSION, (__u32 __user *) argp);
                case JSIOCGAXES:
-                       return put_user(joydev->nabs, (__u8 __user *) arg);
+                       return put_user(joydev->nabs, (__u8 __user *) argp);
                case JSIOCGBUTTONS:
-                       return put_user(joydev->nkey, (__u8 __user *) arg);
+                       return put_user(joydev->nkey, (__u8 __user *) argp);
                case JSIOCSCORR:
                        if (copy_from_user(joydev->corr, argp,
-                                     sizeof(struct js_corr) * joydev->nabs))
+                                     sizeof(joydev->corr[0]) * joydev->nabs))
                            return -EFAULT;
                        for (i = 0; i < joydev->nabs; i++) {
                                j = joydev->abspam[i];
@@ -335,7 +320,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                        return 0;
                case JSIOCGCORR:
                        return copy_to_user(argp, joydev->corr,
-                                               sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
+                                               sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
                case JSIOCSAXMAP:
                        if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
                                return -EFAULT;
@@ -371,6 +356,84 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
        return -EINVAL;
 }
 
+#ifdef CONFIG_COMPAT
+static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct joydev_list *list = file->private_data;
+       struct joydev *joydev = list->joydev;
+       void __user *argp = (void __user *)arg;
+       s32 tmp32;
+       struct JS_DATA_SAVE_TYPE_32 ds32;
+       int err;
+
+       if (!joydev->exist) return -ENODEV;
+       switch(cmd) {
+       case JS_SET_TIMELIMIT:
+               err = get_user(tmp32, (s32 __user *) arg);
+               if (err == 0)
+                       joydev->glue.JS_TIMELIMIT = tmp32;
+               break;
+       case JS_GET_TIMELIMIT:
+               tmp32 = joydev->glue.JS_TIMELIMIT;
+               err = put_user(tmp32, (s32 __user *) arg);
+               break;
+
+       case JS_SET_ALL:
+               err = copy_from_user(&ds32, argp,
+                                    sizeof(ds32)) ? -EFAULT : 0;
+               if (err == 0) {
+                       joydev->glue.JS_TIMEOUT    = ds32.JS_TIMEOUT;
+                       joydev->glue.BUSY          = ds32.BUSY;
+                       joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
+                       joydev->glue.JS_TIMELIMIT  = ds32.JS_TIMELIMIT;
+                       joydev->glue.JS_SAVE       = ds32.JS_SAVE;
+                       joydev->glue.JS_CORR       = ds32.JS_CORR;
+               }
+               break;
+
+       case JS_GET_ALL:
+               ds32.JS_TIMEOUT    = joydev->glue.JS_TIMEOUT;
+               ds32.BUSY          = joydev->glue.BUSY;
+               ds32.JS_EXPIRETIME = joydev->glue.JS_EXPIRETIME;
+               ds32.JS_TIMELIMIT  = joydev->glue.JS_TIMELIMIT;
+               ds32.JS_SAVE       = joydev->glue.JS_SAVE;
+               ds32.JS_CORR       = joydev->glue.JS_CORR;
+
+               err = copy_to_user(argp, &ds32,
+                                         sizeof(ds32)) ? -EFAULT : 0;
+               break;
+
+       default:
+               err = joydev_ioctl_common(joydev, cmd, argp);
+       }
+       return err;
+}
+#endif /* CONFIG_COMPAT */
+
+static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct joydev_list *list = file->private_data;
+       struct joydev *joydev = list->joydev;
+       void __user *argp = (void __user *)arg;
+
+       if (!joydev->exist) return -ENODEV;
+
+       switch(cmd) {
+               case JS_SET_TIMELIMIT:
+                       return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+               case JS_GET_TIMELIMIT:
+                       return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+               case JS_SET_ALL:
+                       return copy_from_user(&joydev->glue, argp,
+                                               sizeof(joydev->glue)) ? -EFAULT : 0;
+               case JS_GET_ALL:
+                       return copy_to_user(argp, &joydev->glue,
+                                               sizeof(joydev->glue)) ? -EFAULT : 0;
+               default:
+                       return joydev_ioctl_common(joydev, cmd, argp);
+       }
+}
+
 static struct file_operations joydev_fops = {
        .owner =        THIS_MODULE,
        .read =         joydev_read,
@@ -379,6 +442,9 @@ static struct file_operations joydev_fops = {
        .open =         joydev_open,
        .release =      joydev_release,
        .ioctl =        joydev_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = joydev_compat_ioctl,
+#endif
        .fasync =       joydev_fasync,
 };
 
index ad39fe4bf35f58d26b56aa7e046904fba3816787..bf34f75b9467f6650c5447a020f562787bccacfb 100644 (file)
@@ -185,7 +185,7 @@ static void a3d_poll(struct gameport *gameport)
        a3d->reads++;
        if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length ||
            data[0] != a3d->mode || a3d_csum(data, a3d->length))
-               a3d->bads++;
+               a3d->bads++;
        else
                a3d_read(a3d, data);
 }
index 83f6dafc171697ae1ed9e0898dfd7038c15200c2..265962956c63cbf9d924f8bd8518981d10cf2ea5 100644 (file)
@@ -82,7 +82,7 @@ static char adi_cm2_abs[] =   { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
 static char adi_wmf_abs[] =    { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
 
 static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,  BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
-static short adi_wmi_key[] =   { BTN_TRIGGER,  BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
+static short adi_wmi_key[] =   { BTN_TRIGGER,  BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
 static short adi_wmed3d_key[] =        { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
 static short adi_cm2_key[] =   { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
 
@@ -183,7 +183,7 @@ static void adi_move_bits(struct adi_port *port, int length)
        int i;
        struct adi *adi = port->adi;
 
-       adi[0].idx = adi[1].idx = 0;
+       adi[0].idx = adi[1].idx = 0;
 
        if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
        if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
index cf36ca9b92f3f3e703edb5b93c3e2d9ee76033e9..033456bb9fe0d70faa00ea0fa0fced045d9b6a02 100644 (file)
@@ -51,7 +51,8 @@ MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is
 
 __obsolete_setup("amijoy=");
 
-static int amijoy_used[2] = { 0, 0 };
+static int amijoy_used;
+static DECLARE_MUTEX(amijoy_sem);
 static struct input_dev amijoy_dev[2];
 static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
 
@@ -84,26 +85,30 @@ static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
 
 static int amijoy_open(struct input_dev *dev)
 {
-       int *used = dev->private;
+       int err;
 
-       if ((*used)++)
-               return 0;
+       err = down_interruptible(&amijoy_sem);
+       if (err)
+               return err;
 
-       if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
-               (*used)--;
+       if (!amijoy_used && request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
                printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
-               return -EBUSY;
+               err = -EBUSY;
+               goto out;
        }
 
-       return 0;
+       amijoy_used++;
+out:
+       up(&amijoy_sem);
+       return err;
 }
 
 static void amijoy_close(struct input_dev *dev)
 {
-       int *used = dev->private;
-
-       if (!--(*used))
+       down(&amijoysem);
+       if (!--amijoy_used)
                free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
+       up(&amijoy_sem);
 }
 
 static int __init amijoy_init(void)
@@ -138,8 +143,6 @@ static int __init amijoy_init(void)
                        amijoy_dev[i].id.product = 0x0003;
                        amijoy_dev[i].id.version = 0x0100;
 
-                       amijoy_dev[i].private = amijoy_used + i;
-
                        input_register_device(amijoy_dev + i);
                        printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
                }
index 504b7d5505671e066a3425c1037c87cec5252c3e..c3a5739030c3ba45d8dd1dda01cd79382faf3478 100644 (file)
@@ -140,12 +140,14 @@ struct analog_port {
  */
 
 #ifdef __i386__
+
+#include <asm/i8253.h>
+
 #define GET_TIME(x)    do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0)
 #define DELTA(x,y)     (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? CLOCK_TICK_RATE / HZ : 0)))
 #define TIME_NAME      (cpu_has_tsc?"TSC":"PIT")
 static unsigned int get_time_pit(void)
 {
-        extern spinlock_t i8253_lock;
         unsigned long flags;
         unsigned int count;
 
index cfdd3acf06a1cbb4a2584ca697ff6ca518a19643..fbd3eed07f90403806e1bce3212781a638e35241 100644 (file)
@@ -87,7 +87,7 @@ __obsolete_setup("db9_3=");
 #define DB9_NORMAL             0x0a
 #define DB9_NOSELECT           0x08
 
-#define DB9_MAX_DEVICES 2
+#define DB9_MAX_DEVICES                2
 
 #define DB9_GENESIS6_DELAY     14
 #define DB9_REFRESH_TIME       HZ/100
@@ -98,6 +98,7 @@ struct db9 {
        struct pardevice *pd;
        int mode;
        int used;
+       struct semaphore sem;
        char phys[2][32];
 };
 
@@ -503,6 +504,11 @@ static int db9_open(struct input_dev *dev)
 {
        struct db9 *db9 = dev->private;
        struct parport *port = db9->pd->port;
+       int err;
+
+       err = down_interruptible(&db9->sem);
+       if (err)
+               return err;
 
        if (!db9->used++) {
                parport_claim(db9->pd);
@@ -514,6 +520,7 @@ static int db9_open(struct input_dev *dev)
                mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
        }
 
+       up(&db9->sem);
        return 0;
 }
 
@@ -522,12 +529,14 @@ static void db9_close(struct input_dev *dev)
        struct db9 *db9 = dev->private;
        struct parport *port = db9->pd->port;
 
+       down(&db9->sem);
        if (!--db9->used) {
-               del_timer(&db9->timer);
+               del_timer_sync(&db9->timer);
                parport_write_control(port, 0x00);
                parport_data_forward(port);
                parport_release(db9->pd);
        }
+       up(&db9->sem);
 }
 
 static struct db9 __init *db9_probe(int *config, int nargs)
@@ -563,12 +572,12 @@ static struct db9 __init *db9_probe(int *config, int nargs)
                }
        }
 
-       if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL))) {
+       if (!(db9 = kcalloc(1, sizeof(struct db9), GFP_KERNEL))) {
                parport_put_port(pp);
                return NULL;
        }
-       memset(db9, 0, sizeof(struct db9));
 
+       init_MUTEX(&db9->sem);
        db9->mode = config[1];
        init_timer(&db9->timer);
        db9->timer.data = (long) db9;
index 8732f52bdd0889fb65f56bbdfca09d07f7ff25a5..95bbdd302aad8639bacc4817e6f49b472e749211 100644 (file)
@@ -1,12 +1,12 @@
 /*
  * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
  *
- *  Copyright (c) 1999-2004    Vojtech Pavlik <vojtech@suse.cz>
- *  Copyright (c) 2004                 Peter Nelson <rufus-kernel@hackish.org>
+ *  Copyright (c) 1999-2004    Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2004         Peter Nelson <rufus-kernel@hackish.org>
  *
  *  Based on the work of:
- *     Andree Borrmann         John Dahlstrom
- *     David Kuder             Nathan Hand
+ *     Andree Borrmann         John Dahlstrom
+ *     David Kuder             Nathan Hand
  */
 
 /*
@@ -81,6 +81,7 @@ struct gc {
        struct timer_list timer;
        unsigned char pads[GC_MAX + 1];
        int used;
+       struct semaphore sem;
        char phys[5][32];
 };
 
@@ -433,7 +434,7 @@ static void gc_timer(unsigned long private)
                gc_psx_read_packet(gc, data_psx, data);
 
                for (i = 0; i < 5; i++) {
-                       switch (data[i]) {
+                       switch (data[i]) {
 
                                case GC_PSX_RUMBLE:
 
@@ -503,22 +504,33 @@ static void gc_timer(unsigned long private)
 static int gc_open(struct input_dev *dev)
 {
        struct gc *gc = dev->private;
+       int err;
+
+       err = down_interruptible(&gc->sem);
+       if (err)
+               return err;
+
        if (!gc->used++) {
                parport_claim(gc->pd);
                parport_write_control(gc->pd->port, 0x04);
                mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
        }
+
+       up(&gc->sem);
        return 0;
 }
 
 static void gc_close(struct input_dev *dev)
 {
        struct gc *gc = dev->private;
+
+       down(&gc->sem);
        if (!--gc->used) {
-               del_timer(&gc->timer);
+               del_timer_sync(&gc->timer);
                parport_write_control(gc->pd->port, 0x00);
                parport_release(gc->pd);
        }
+       up(&gc->sem);
 }
 
 static struct gc __init *gc_probe(int *config, int nargs)
@@ -542,11 +554,12 @@ static struct gc __init *gc_probe(int *config, int nargs)
                return NULL;
        }
 
-       if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) {
+       if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) {
                parport_put_port(pp);
                return NULL;
        }
-       memset(gc, 0, sizeof(struct gc));
+
+       init_MUTEX(&gc->sem);
 
        gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
 
index ad13f09a4e71068fe6baa36054c7346f798eab06..7d969420066c75c0140eed3ba2d88bc9cf7fedf5 100644 (file)
@@ -329,7 +329,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
 
        for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
                gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
-                         gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
+                         gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
                gf2k->dev.absmin[gf2k_abs[i]] = 32;
                gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
                gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
index 42e5005d621f2e8ae34d0a12d2750c30e41ff399..0da7bd133ccf39f03e948d60e2bfa19e18b742ea 100644 (file)
@@ -171,7 +171,7 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa
        *packet = 0;
        raw_data = gameport_read(gameport);
        if (raw_data & 1)
-               return IO_RETRY;
+               return IO_RETRY;
 
        for (i = 0; i < 64; i++) {
                raw_data = gameport_read(gameport);
index 028f3513629ad84d4f08503c7bba0d1e9fab9afc..e31b7b93fde200400460543f2edec229e6a7a40d 100644 (file)
@@ -78,6 +78,7 @@ static struct iforce_device iforce_device[] = {
        { 0x061c, 0xc0a4, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce }, //?
        { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",       btn_wheel, abs_wheel, ff_iforce }, //?
        { 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel",      btn_wheel, abs_wheel, ff_iforce }, //?
+       { 0x06f8, 0x0004, "Gullemot Jet Leader 3D",                     btn_joystick, abs_joystick, ff_iforce }, //?
        { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]",         btn_joystick, abs_joystick, ff_iforce }
 };
 
index 617c0b0e5a395f81ca585218d98f0a4788b848cf..6369a24684fe35eb1d25ed98a384c902197ad76b 100644 (file)
@@ -229,6 +229,7 @@ static struct usb_device_id iforce_usb_ids [] = {
        { USB_DEVICE(0x061c, 0xc0a4) },         /* ACT LABS Force RS */
        { USB_DEVICE(0x06f8, 0x0001) },         /* Guillemot Race Leader Force Feedback */
        { USB_DEVICE(0x06f8, 0x0004) },         /* Guillemot Force Feedback Racing Wheel */
+       { USB_DEVICE(0x06f8, 0xa302) },         /* Guillemot Jet Leader 3D */
        { }                                     /* Terminating entry */
 };
 
index ec0a2a64d49c44df0c6c710c74fb5b4dc488463d..a436f22208562c1647bc4c345b6ceecef4c76153 100644 (file)
@@ -4,8 +4,8 @@
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  Based on the work of:
- *     David Thompson
- *     Joseph Krahn
+ *     David Thompson
+ *     Joseph Krahn
  */
 
 /*
index 874367bfab0860c4f389544f3039481c5875c82d..01fd2e4791aeb2145c938d8ae33852dee9b359d3 100644 (file)
@@ -4,7 +4,7 @@
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  Based on the work of:
- *     David Thompson
+ *     David Thompson
  */
 
 /*
index aaee52ceb920ad8ced4edcb1d04a7b239186d7b1..9eb9954cac6e2584e70ef4c9a9d6646c494e348d 100644 (file)
@@ -79,7 +79,7 @@ static short tmdc_btn_pad[TMDC_BTN] =
        { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
 static short tmdc_btn_joy[TMDC_BTN] =
        { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
-         BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
+         BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
 static short tmdc_btn_fm[TMDC_BTN] =
         { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
 static short tmdc_btn_at[TMDC_BTN] =
index dd88b9cb49fa0e50e08c14d21b278dddf2d04df5..28100d461cb751c1c1d8b34f4fb5001b970e1b2c 100644 (file)
@@ -84,6 +84,7 @@ static struct tgfx {
        char phys[7][32];
        int sticks;
        int used;
+       struct semaphore sem;
 } *tgfx_base[3];
 
 /*
@@ -99,7 +100,7 @@ static void tgfx_timer(unsigned long private)
        for (i = 0; i < 7; i++)
                if (tgfx->sticks & (1 << i)) {
 
-                       dev = tgfx->dev + i;
+                       dev = tgfx->dev + i;
 
                        parport_write_data(tgfx->pd->port, ~(1 << i));
                        data1 = parport_read_status(tgfx->pd->port) ^ 0x7f;
@@ -122,23 +123,34 @@ static void tgfx_timer(unsigned long private)
 
 static int tgfx_open(struct input_dev *dev)
 {
-        struct tgfx *tgfx = dev->private;
-        if (!tgfx->used++) {
+       struct tgfx *tgfx = dev->private;
+       int err;
+
+       err = down_interruptible(&tgfx->sem);
+       if (err)
+               return err;
+
+       if (!tgfx->used++) {
                parport_claim(tgfx->pd);
                parport_write_control(tgfx->pd->port, 0x04);
-                mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
+               mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
        }
-        return 0;
+
+       up(&tgfx->sem);
+       return 0;
 }
 
 static void tgfx_close(struct input_dev *dev)
 {
-        struct tgfx *tgfx = dev->private;
-        if (!--tgfx->used) {
-                del_timer(&tgfx->timer);
+       struct tgfx *tgfx = dev->private;
+
+       down(&tgfx->sem);
+       if (!--tgfx->used) {
+               del_timer_sync(&tgfx->timer);
                parport_write_control(tgfx->pd->port, 0x00);
-               parport_release(tgfx->pd);
+               parport_release(tgfx->pd);
        }
+       up(&tgfx->sem);
 }
 
 /*
@@ -166,11 +178,12 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs)
                return NULL;
        }
 
-       if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) {
+       if (!(tgfx = kcalloc(1, sizeof(struct tgfx), GFP_KERNEL))) {
                parport_put_port(pp);
                return NULL;
        }
-       memset(tgfx, 0, sizeof(struct tgfx));
+
+       init_MUTEX(&tgfx->sem);
 
        tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
 
index 82fad9a23ace398331950e9a0ca76432206e2bf1..4d4985b59abf182887349fedd73e758d9986102d 100644 (file)
@@ -227,7 +227,7 @@ static ssize_t atkbd_do_set_##_name(struct device *d, struct device_attribute *a
 {                                                                              \
        return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name);               \
 }                                                                              \
-static struct device_attribute atkbd_attr_##_name =                            \
+static struct device_attribute atkbd_attr_##_name =                            \
        __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
 
 ATKBD_DEFINE_ATTR(extra);
@@ -388,7 +388,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
                        value = atkbd->release ? 0 :
                                (1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
 
-                       switch (value) {        /* Workaround Toshiba laptop multiple keypress */
+                       switch (value) {        /* Workaround Toshiba laptop multiple keypress */
                                case 0:
                                        atkbd->last = 0;
                                        break;
@@ -894,7 +894,7 @@ static int atkbd_reconnect(struct serio *serio)
        if (atkbd->write) {
                param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0)
                         | (test_bit(LED_NUML,    atkbd->dev.led) ? 2 : 0)
-                        | (test_bit(LED_CAPSL,   atkbd->dev.led) ? 4 : 0);
+                        | (test_bit(LED_CAPSL,   atkbd->dev.led) ? 4 : 0);
 
                if (atkbd_probe(atkbd))
                        return -1;
index 0f1220a0ceb5d0386eb5d07bf2875b5f2c9fbd18..a8551711e8d60031ffaadbb1e7e632a32f162aed 100644 (file)
@@ -39,6 +39,7 @@
 #define CORGI_KEY_CALENDER     KEY_F1
 #define CORGI_KEY_ADDRESS      KEY_F2
 #define CORGI_KEY_FN           KEY_F3
+#define CORGI_KEY_CANCEL       KEY_F4
 #define CORGI_KEY_OFF          KEY_SUSPEND
 #define CORGI_KEY_EXOK         KEY_F5
 #define CORGI_KEY_EXCANCEL     KEY_F6
@@ -46,6 +47,7 @@
 #define CORGI_KEY_EXJOGUP      KEY_F8
 #define CORGI_KEY_JAP1         KEY_LEFTCTRL
 #define CORGI_KEY_JAP2         KEY_LEFTALT
+#define CORGI_KEY_MAIL         KEY_F10
 #define CORGI_KEY_OK           KEY_F11
 #define CORGI_KEY_MENU         KEY_F12
 #define CORGI_HINGE_0          KEY_KP0
@@ -59,8 +61,8 @@ static unsigned char corgikbd_keycode[NR_SCANCODES] = {
        KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0,                                 /* 33-48 */
        CORGI_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0,         /* 49-64 */
        CORGI_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0,     /* 65-80 */
-       KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0,            /* 81-96 */
-       KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0,  /* 97-112 */
+       CORGI_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0,            /* 81-96 */
+       KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, CORGI_KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0,  /* 97-112 */
        CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0,   /* 113-124 */
        CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2       /* 125-127 */
 };
index 2694ff2b5beb6d7a513f0cd12382a693b24f3021..098963c7cdd6ae44909b9ca781db735c15bae28e 100644 (file)
  * information given below, I will _not_ be liable!
  *
  * RJ10 pinout:                To DE9:         Or DB25:
- *     1 - RxD <---->  Pin 3 (TxD) <-> Pin 2 (TxD)
- *     2 - GND <---->  Pin 5 (GND) <-> Pin 7 (GND)
- *     4 - TxD <---->  Pin 2 (RxD) <-> Pin 3 (RxD)
- *     3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
+ *     1 - RxD <---->  Pin 3 (TxD) <-> Pin 2 (TxD)
+ *     2 - GND <---->  Pin 5 (GND) <-> Pin 7 (GND)
+ *     4 - TxD <---->  Pin 2 (RxD) <-> Pin 3 (RxD)
+ *     3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
  *
  * Pin numbers for DE9 and DB25 are noted on the plug (quite small:). For
  * RJ10, it's like this:
index d3e9dd6a13cdc8236010765c56e12b648c16fe31..8935290256b392ed25457b07f711d0329cab4a07 100644 (file)
@@ -42,7 +42,7 @@ MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
 MODULE_DESCRIPTION("LoCoMo keyboard driver");
 MODULE_LICENSE("GPL");
 
-#define LOCOMOKBD_NUMKEYS      128
+#define LOCOMOKBD_NUMKEYS      128
 
 #define KEY_ACTIVITY           KEY_F16
 #define KEY_CONTACT            KEY_F18
@@ -61,7 +61,7 @@ static unsigned char locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
        KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0,                           /* 90 - 99 */
        0, 0, KEY_DOT, 0, KEY_COMMA, KEY_N, KEY_B, KEY_C, KEY_Z, KEY_A,         /* 100 - 109 */
        KEY_LEFTSHIFT, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, 0, 0,              /* 110 - 119 */
-       KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0             /* 120 - 128 */
+       KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0             /* 120 - 128 */
 };
 
 #define KB_ROWS                        16
@@ -82,7 +82,7 @@ struct locomokbd {
        struct locomo_dev *ldev;
        unsigned long base;
        spinlock_t lock;
-       
+
        struct timer_list timer;
 };
 
@@ -95,7 +95,7 @@ static inline void locomokbd_charge_all(unsigned long membase)
 static inline void locomokbd_activate_all(unsigned long membase)
 {
        unsigned long r;
-       
+
        locomo_writel(0, membase + LOCOMO_KSC);
        r = locomo_readl(membase + LOCOMO_KIC);
        r &= 0xFEFF;
@@ -127,7 +127,7 @@ static inline void locomokbd_reset_col(unsigned long membase, int col)
  */
 
 /* Scan the hardware keyboard and push any changes up through the input layer */
-static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs) 
+static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs)
 {
        unsigned int row, col, rowd, scancode;
        unsigned long flags;
@@ -138,7 +138,7 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
 
        if (regs)
                input_regs(&locomokbd->input, regs);
-       
+
        locomokbd_charge_all(membase);
 
        num_pressed = 0;
@@ -146,9 +146,9 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
 
                locomokbd_activate_col(membase, col);
                udelay(KB_DELAY);
-                
+
                rowd = ~locomo_readl(membase + LOCOMO_KIB);
-               for (row = 0; row < KB_ROWS; row++ ) {
+               for (row = 0; row < KB_ROWS; row++) {
                        scancode = SCANCODE(col, row);
                        if (rowd & KB_ROWMASK(row)) {
                                num_pressed += 1;
@@ -170,7 +170,7 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
        spin_unlock_irqrestore(&locomokbd->lock, flags);
 }
 
-/* 
+/*
  * LoCoMo keyboard interrupt handler.
  */
 static irqreturn_t locomokbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -205,8 +205,8 @@ static int locomokbd_probe(struct locomo_dev *dev)
        memset(locomokbd, 0, sizeof(struct locomokbd));
 
        /* try and claim memory region */
-       if (!request_mem_region((unsigned long) dev->mapbase, 
-                               dev->length, 
+       if (!request_mem_region((unsigned long) dev->mapbase,
+                               dev->length,
                                LOCOMO_DRIVER_NAME(dev))) {
                ret = -EBUSY;
                printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n");
@@ -225,7 +225,7 @@ static int locomokbd_probe(struct locomo_dev *dev)
        locomokbd->timer.data = (unsigned long) locomokbd;
 
        locomokbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
-       
+
        init_input_dev(&locomokbd->input);
        locomokbd->input.keycode = locomokbd->keycode;
        locomokbd->input.keycodesize = sizeof(unsigned char);
@@ -271,11 +271,11 @@ free:
 static int locomokbd_remove(struct locomo_dev *dev)
 {
        struct locomokbd *locomokbd = locomo_get_drvdata(dev);
-       
+
        free_irq(dev->irq[0], locomokbd);
 
        del_timer_sync(&locomokbd->timer);
-       
+
        input_unregister_device(&locomokbd->input);
        locomo_set_drvdata(dev, NULL);
 
index 859ed771ee0aca63aeb25de8a4c9e1be103945c0..eecbde294f1f091266f57a5d1e97c80f7c14ebec 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *     $Id: maple_keyb.c,v 1.4 2004/03/22 01:18:15 lethal Exp $
- *     SEGA Dreamcast keyboard driver
+ *     SEGA Dreamcast keyboard driver
  *     Based on drivers/usb/usbkbd.c
  */
 
@@ -40,7 +40,6 @@ struct dc_kbd {
        struct input_dev dev;
        unsigned char new[8];
        unsigned char old[8];
-       int open;
 };
 
 
@@ -95,22 +94,6 @@ static void dc_kbd_callback(struct mapleq *mq)
        }
 }
 
-
-static int dc_kbd_open(struct input_dev *dev)
-{
-       struct dc_kbd *kbd = dev->private;
-       kbd->open++;
-       return 0;
-}
-
-
-static void dc_kbd_close(struct input_dev *dev)
-{
-       struct dc_kbd *kbd = dev->private;
-       kbd->open--;
-}
-
-
 static int dc_kbd_connect(struct maple_device *dev)
 {
        int i;
@@ -133,9 +116,6 @@ static int dc_kbd_connect(struct maple_device *dev)
        clear_bit(0, kbd->dev.keybit);
 
        kbd->dev.private = kbd;
-       kbd->dev.open = dc_kbd_open;
-       kbd->dev.close = dc_kbd_close;
-       kbd->dev.event = NULL;
 
        kbd->dev.name = dev->product_name;
        kbd->dev.id.bustype = BUS_MAPLE;
index 158c8e845ff988a690c79f3f921e6ea39250df25..98710997aaaa2c48f7cde8301ff8cc6b3b14f6a2 100644 (file)
@@ -298,9 +298,11 @@ static int uinput_alloc_device(struct file *file, const char __user *buffer, siz
        /* check if absmin/absmax/absfuzz/absflat are filled as
         * told in Documentation/input/input-programming.txt */
        if (test_bit(EV_ABS, dev->evbit)) {
-               retval = uinput_validate_absbits(dev);
-               if (retval < 0)
+               int err = uinput_validate_absbits(dev);
+               if (err < 0) {
+                       retval = err;
                        kfree(dev->name);
+               }
        }
 
 exit:
index a7864195806a61d2c5dc2200d86469e9df5b99fa..c4909b49337d23e708e4e4850c1e69ac1f1488b7 100644 (file)
@@ -15,4 +15,4 @@ obj-$(CONFIG_MOUSE_SERIAL)    += sermouse.o
 obj-$(CONFIG_MOUSE_HIL)                += hil_ptr.o
 obj-$(CONFIG_MOUSE_VSXXXAA)    += vsxxxaa.o
 
-psmouse-objs  := psmouse-base.o alps.o logips2pp.o synaptics.o
+psmouse-objs  := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o
index 7bf4be733e9a89f6646ccf979503d8e4797e4400..a12e98158a759f87a199fa271d295017f468810c 100644 (file)
 
 #define ALPS_DUALPOINT 0x01
 #define ALPS_WHEEL     0x02
-#define ALPS_FW_BK     0x04
+#define ALPS_FW_BK_1   0x04
 #define ALPS_4BTN      0x08
 #define ALPS_OLDPROTO  0x10
 #define ALPS_PASS      0x20
+#define ALPS_FW_BK_2   0x40
 
 static struct alps_model_info alps_model_data[] = {
        { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO },            /* UMAX-530T */
@@ -43,11 +44,11 @@ static struct alps_model_info alps_model_data[] = {
        { { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
        { { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, 0 },
        { { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL },               /* Toshiba Satellite S2400-103 */
-       { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK },               /* NEC Versa L320 */
+       { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 },             /* NEC Versa L320 */
        { { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 },
        { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS },                /* Dell Latitude D800 */
        { { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
-       { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
+       { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 },             /* Ahtec Laptop */
        { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
        { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
        { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
@@ -61,11 +62,11 @@ static struct alps_model_info alps_model_data[] = {
 
 /*
  * ALPS abolute Mode - new format
- * 
- * byte 0:  1    ?    ?    ?    1    ?    ?    ? 
+ *
+ * byte 0:  1    ?    ?    ?    1    ?    ?    ?
  * byte 1:  0   x6   x5   x4   x3   x2   x1   x0
  * byte 2:  0   x10  x9   x8   x7    ?  fin  ges
- * byte 3:  0   y9   y8   y7    1    M    R    L 
+ * byte 3:  0   y9   y8   y7    1    M    R    L
  * byte 4:  0   y6   y5   y4   y3   y2   y1   y0
  * byte 5:  0   z6   z5   z4   z3   z2   z1   z0
  *
@@ -81,11 +82,12 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
        struct input_dev *dev = &psmouse->dev;
        struct input_dev *dev2 = &priv->dev2;
        int x, y, z, ges, fin, left, right, middle;
+       int back = 0, forward = 0;
 
        input_regs(dev, regs);
 
        if ((packet[0] & 0xc8) == 0x08) {   /* 3-byte PS/2 packet */
-               input_report_key(dev2, BTN_LEFT,   packet[0] & 1);    
+               input_report_key(dev2, BTN_LEFT,   packet[0] & 1);
                input_report_key(dev2, BTN_RIGHT,  packet[0] & 2);
                input_report_key(dev2, BTN_MIDDLE, packet[0] & 4);
                input_report_rel(dev2, REL_X,
@@ -112,6 +114,18 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
                z = packet[5];
        }
 
+       if (priv->i->flags & ALPS_FW_BK_1) {
+               back = packet[2] & 4;
+               forward = packet[0] & 0x10;
+       }
+
+       if (priv->i->flags & ALPS_FW_BK_2) {
+               back = packet[3] & 4;
+               forward = packet[2] & 4;
+               if ((middle = forward && back))
+                       forward = back = 0;
+       }
+
        ges = packet[2] & 1;
        fin = packet[2] & 2;
 
@@ -155,13 +169,12 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
        input_report_abs(dev, ABS_PRESSURE, z);
        input_report_key(dev, BTN_TOOL_FINGER, z > 0);
 
-
        if (priv->i->flags & ALPS_WHEEL)
                input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08));
 
-       if (priv->i->flags & ALPS_FW_BK) {
-               input_report_key(dev, BTN_FORWARD, packet[0] & 0x10);
-               input_report_key(dev, BTN_BACK, packet[2] & 0x04);
+       if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
+               input_report_key(dev, BTN_FORWARD, forward);
+               input_report_key(dev, BTN_BACK, back);
        }
 
        input_sync(dev);
@@ -257,7 +270,6 @@ static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *vers
 static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
 {
        struct ps2dev *ps2dev = &psmouse->ps2dev;
-       unsigned char param[3];
        int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
 
        if (ps2_command(ps2dev, NULL, cmd) ||
@@ -267,7 +279,7 @@ static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
                return -1;
 
        /* we may get 3 more bytes, just ignore them */
-       ps2_command(ps2dev, param, 0x0300);
+       ps2_drain(ps2dev, 3, 100);
 
        return 0;
 }
@@ -425,7 +437,7 @@ int alps_init(struct psmouse *psmouse)
                psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL);
        }
 
-       if (priv->i->flags & ALPS_FW_BK) {
+       if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
                psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
                psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
        }
@@ -436,8 +448,8 @@ int alps_init(struct psmouse *psmouse)
        priv->dev2.id.bustype = BUS_I8042;
        priv->dev2.id.vendor = 0x0002;
        priv->dev2.id.product = PSMOUSE_ALPS;
-       priv->dev2.id.version = 0x0000; 
-       
+       priv->dev2.id.version = 0x0000;
+
        priv->dev2.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
        priv->dev2.relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y);
        priv->dev2.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
@@ -461,17 +473,15 @@ init_fail:
 int alps_detect(struct psmouse *psmouse, int set_properties)
 {
        int version;
-       struct alps_model_info *model; 
+       struct alps_model_info *model;
 
        if (!(model = alps_get_model(psmouse, &version)))
                return -1;
 
        if (set_properties) {
                psmouse->vendor = "ALPS";
-               if (model->flags & ALPS_DUALPOINT) 
-                       psmouse->name = "DualPoint TouchPad";
-               else
-                       psmouse->name = "GlidePoint";
+               psmouse->name = model->flags & ALPS_DUALPOINT ?
+                               "DualPoint TouchPad" : "GlidePoint";
                psmouse->model = version;
        }
        return 0;
index 7baa09cca7c5341a5422a84fbceca005657bf2b3..e994849efb8fca3d6e69604caffeee7f5ec7db6a 100644 (file)
@@ -33,7 +33,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Amiga mouse driver");
 MODULE_LICENSE("GPL");
 
-static int amimouse_used = 0;
 static int amimouse_lastx, amimouse_lasty;
 static struct input_dev amimouse_dev;
 
@@ -81,16 +80,12 @@ static int amimouse_open(struct input_dev *dev)
 {
        unsigned short joy0dat;
 
-        if (amimouse_used++)
-                return 0;
-
        joy0dat = custom.joy0dat;
 
        amimouse_lastx = joy0dat & 0xff;
        amimouse_lasty = joy0dat >> 8;
 
        if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
-                amimouse_used--;
                 printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
                 return -EBUSY;
         }
@@ -100,8 +95,7 @@ static int amimouse_open(struct input_dev *dev)
 
 static void amimouse_close(struct input_dev *dev)
 {
-        if (!--amimouse_used)
-               free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
+       free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
 }
 
 static int __init amimouse_init(void)
index ca4e9688662729bd1fbb377d8b2c9b5c18196d2f..1f62c013401067fcb51d6d07485dee727e9338d7 100644 (file)
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -87,29 +87,23 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)");
 
 __obsolete_setup("inport_irq=");
 
-static int inport_used;
-
 static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
 static int inport_open(struct input_dev *dev)
 {
-       if (!inport_used++) {
-               if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
-                       return -EBUSY;
-               outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
-               outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
-       }
+       if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
+               return -EBUSY;
+       outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+       outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
 
        return 0;
 }
 
 static void inport_close(struct input_dev *dev)
 {
-       if (!--inport_used) {
-               outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
-               outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
-               free_irq(inport_irq, NULL);
-       }
+       outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+       outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
+       free_irq(inport_irq, NULL);
 }
 
 static struct input_dev inport_dev = {
@@ -120,11 +114,11 @@ static struct input_dev inport_dev = {
        .close  = inport_close,
        .name   = INPORT_NAME,
        .phys   = "isa023c/input0",
-       .id = { 
-               .bustype = BUS_ISA,
-               .vendor  = INPORT_VENDOR,
-               .product = 0x0001,
-               .version = 0x0100,
+       .id = {
+               .bustype = BUS_ISA,
+               .vendor  = INPORT_VENDOR,
+               .product = 0x0001,
+               .version = 0x0100,
        },
 };
 
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
new file mode 100644 (file)
index 0000000..bd9df9b
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Fujitsu B-series Lifebook PS/2 TouchScreen driver
+ *
+ * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Kenan Esau <kenan.esau@conan.de>
+ *
+ * TouchScreen detection, absolute mode setting and packet layout is taken from
+ * Harald Hoyer's description of the device.
+ *
+ * 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/input.h>
+#include <linux/serio.h>
+#include <linux/libps2.h>
+#include <linux/dmi.h>
+
+#include "psmouse.h"
+#include "lifebook.h"
+
+static struct dmi_system_id lifebook_dmi_table[] = {
+       {
+               .ident = "Lifebook B",
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
+               },
+       },
+       { }
+};
+
+
+static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+       unsigned char *packet = psmouse->packet;
+       struct input_dev *dev = &psmouse->dev;
+
+       if (psmouse->pktcnt != 3)
+               return PSMOUSE_GOOD_DATA;
+
+       input_regs(dev, regs);
+
+       /* calculate X and Y */
+       if ((packet[0] & 0x08) == 0x00) {
+               input_report_abs(dev, ABS_X,
+                                (packet[1] | ((packet[0] & 0x30) << 4)));
+               input_report_abs(dev, ABS_Y,
+                                1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
+       } else {
+               input_report_rel(dev, REL_X,
+                               ((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
+               input_report_rel(dev, REL_Y,
+                                -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
+       }
+
+       input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+       input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+       input_report_key(dev, BTN_TOUCH, packet[0] & 0x04);
+
+       input_sync(dev);
+
+       return PSMOUSE_FULL_PACKET;
+}
+
+static int lifebook_absolute_mode(struct psmouse *psmouse)
+{
+       struct ps2dev *ps2dev = &psmouse->ps2dev;
+       unsigned char param;
+
+       if (psmouse_reset(psmouse))
+               return -1;
+
+       /*
+          Enable absolute output -- ps2_command fails always but if
+          you leave this call out the touchsreen will never send
+          absolute coordinates
+       */
+       param = 0x07;
+       ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
+
+       return 0;
+}
+
+static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+{
+       unsigned char params[] = { 0, 1, 2, 2, 3 };
+
+       if (resolution == 0 || resolution > 400)
+               resolution = 400;
+
+       ps2_command(&psmouse->ps2dev, &params[resolution / 100], PSMOUSE_CMD_SETRES);
+       psmouse->resolution = 50 << params[resolution / 100];
+}
+
+static void lifebook_disconnect(struct psmouse *psmouse)
+{
+       psmouse_reset(psmouse);
+}
+
+int lifebook_detect(struct psmouse *psmouse, int set_properties)
+{
+        if (!dmi_check_system(lifebook_dmi_table))
+                return -1;
+
+       if (set_properties) {
+               psmouse->vendor = "Fujitsu";
+               psmouse->name = "Lifebook TouchScreen";
+       }
+
+        return 0;
+}
+
+int lifebook_init(struct psmouse *psmouse)
+{
+       if (lifebook_absolute_mode(psmouse))
+               return -1;
+
+       psmouse->dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
+       psmouse->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+       psmouse->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+       psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+       input_set_abs_params(&psmouse->dev, ABS_X, 0, 1024, 0, 0);
+       input_set_abs_params(&psmouse->dev, ABS_Y, 0, 1024, 0, 0);
+
+       psmouse->protocol_handler = lifebook_process_byte;
+       psmouse->set_resolution = lifebook_set_resolution;
+       psmouse->disconnect = lifebook_disconnect;
+       psmouse->reconnect  = lifebook_absolute_mode;
+       psmouse->pktsize = 3;
+
+       return 0;
+}
+
diff --git a/drivers/input/mouse/lifebook.h b/drivers/input/mouse/lifebook.h
new file mode 100644 (file)
index 0000000..be1c094
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Fujitsu B-series Lifebook PS/2 TouchScreen driver
+ *
+ * Copyright (c) 2005 Vojtech Pavlik
+ *
+ * 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 _LIFEBOOK_H
+#define _LIFEBOOK_H
+
+int lifebook_detect(struct psmouse *psmouse, int set_properties);
+int lifebook_init(struct psmouse *psmouse);
+
+#endif
index 77eb83e87f61cb03963f57a5580ec62bbe49ace7..8b5243167227ba364315cedc9f5d4e06696d682a 100644 (file)
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -77,16 +77,11 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)");
 
 __obsolete_setup("logibm_irq=");
 
-static int logibm_used = 0;
-
 static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
 static int logibm_open(struct input_dev *dev)
 {
-       if (logibm_used++)
-               return 0;
        if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) {
-               logibm_used--;
                printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
                return -EBUSY;
        }
@@ -96,8 +91,6 @@ static int logibm_open(struct input_dev *dev)
 
 static void logibm_close(struct input_dev *dev)
 {
-       if (--logibm_used)
-               return;
        outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
        free_irq(logibm_irq, NULL);
 }
@@ -167,7 +160,7 @@ static int __init logibm_init(void)
        outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
 
        input_register_device(&logibm_dev);
-       
+
        printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq);
 
        return 0;
index 12dc0ef5020fa3a3f00a7bd6b6403ce2413cf0c1..e90c60cbbf05a00459f56359c9d52e9a11eddec1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *     $Id: maplemouse.c,v 1.2 2004/03/22 01:18:15 lethal Exp $
- *     SEGA Dreamcast mouse driver
+ *     SEGA Dreamcast mouse driver
  *     Based on drivers/usb/usbmouse.c
  */
 
 MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
 MODULE_DESCRIPTION("SEGA Dreamcast mouse driver");
 
-struct dc_mouse {
-       struct input_dev dev;
-       int open;
-};
-
-
 static void dc_mouse_callback(struct mapleq *mq)
 {
        int buttons, relx, rely, relz;
        struct maple_device *mapledev = mq->dev;
-       struct dc_mouse *mouse = mapledev->private_data;
-       struct input_dev *dev = &mouse->dev;
+       struct input_dev *dev = mapledev->private_data;
        unsigned char *res = mq->recvbuf;
 
        buttons = ~res[8];
-       relx=*(unsigned short *)(res+12)-512;
-       rely=*(unsigned short *)(res+14)-512;
-       relz=*(unsigned short *)(res+16)-512;
+       relx = *(unsigned short *)(res + 12) - 512;
+       rely = *(unsigned short *)(res + 14) - 512;
+       relz = *(unsigned short *)(res + 16) - 512;
 
-       input_report_key(dev, BTN_LEFT,   buttons&4);
-       input_report_key(dev, BTN_MIDDLE, buttons&9);
-       input_report_key(dev, BTN_RIGHT,  buttons&2);
+       input_report_key(dev, BTN_LEFT,   buttons & 4);
+       input_report_key(dev, BTN_MIDDLE, buttons & 9);
+       input_report_key(dev, BTN_RIGHT,  buttons & 2);
        input_report_rel(dev, REL_X,      relx);
        input_report_rel(dev, REL_Y,      rely);
        input_report_rel(dev, REL_WHEEL,  relz);
        input_sync(dev);
 }
 
-
-static int dc_mouse_open(struct input_dev *dev)
-{
-       struct dc_mouse *mouse = dev->private;
-       mouse->open++;
-       return 0;
-}
-
-
-static void dc_mouse_close(struct input_dev *dev)
-{
-       struct dc_mouse *mouse = dev->private;
-       mouse->open--;
-}
-
-
 static int dc_mouse_connect(struct maple_device *dev)
 {
        unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
-       struct dc_mouse *mouse;
+       struct input_dev *input_dev;
 
-       if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL)))
+       if (!(input_dev = kmalloc(sizeof(struct input_dev), GFP_KERNEL)))
                return -1;
-       memset(mouse, 0, sizeof(struct dc_mouse));
-
-       dev->private_data = mouse;
 
-       mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
-       mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
-       mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
+       dev->private_data = input_dev;
 
-       init_input_dev(&mouse->dev);
+       memset(input_dev, 0, sizeof(struct dc_mouse));
+       init_input_dev(input_dev);
+       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+       input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
 
-       mouse->dev.private = mouse;
-       mouse->dev.open = dc_mouse_open;
-       mouse->dev.close = dc_mouse_close;
-       mouse->dev.event = NULL;
+       input_dev->name = dev->product_name;
+       input_dev->id.bustype = BUS_MAPLE;
 
-       mouse->dev.name = dev->product_name;
-       mouse->dev.id.bustype = BUS_MAPLE;
-       
-       input_register_device(&mouse->dev);
+       input_register_device(input_dev);
 
        maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE);
 
-       printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, mouse->dev.name);
+       printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, input_dev->name);
 
        return 0;
 }
@@ -96,10 +67,10 @@ static int dc_mouse_connect(struct maple_device *dev)
 
 static void dc_mouse_disconnect(struct maple_device *dev)
 {
-       struct dc_mouse *mouse = dev->private_data;
+       struct input_dev *input_dev = dev->private_data;
 
-       input_unregister_device(&mouse->dev);
-       kfree(mouse);
+       input_unregister_device(input_dev);
+       kfree(input_dev);
 }
 
 
index 0c74918fe2543ca23bfa922065948e93e9b4a121..93393d5c007800b6cd57963903c56eb1e85daf3c 100644 (file)
@@ -4,7 +4,7 @@
  *  Copyright (c) 2000-2001 Vojtech Pavlik
  *
  *  Based on the work of:
- *     Alan Cox        Robin O'Leary   
+ *     Alan Cox        Robin O'Leary
  */
 
 /*
@@ -56,7 +56,6 @@ static int pc110pad_io = 0x15e0;
 static struct input_dev pc110pad_dev;
 static int pc110pad_data[3];
 static int pc110pad_count;
-static int pc110pad_used;
 
 static char *pc110pad_name = "IBM PC110 TouchPad";
 static char *pc110pad_phys = "isa15e0/input0";
@@ -74,7 +73,7 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
 
        if (pc110pad_count < 3)
                return IRQ_HANDLED;
-       
+
        input_regs(&pc110pad_dev, regs);
        input_report_key(&pc110pad_dev, BTN_TOUCH,
                pc110pad_data[0] & 0x01);
@@ -90,15 +89,11 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
 
 static void pc110pad_close(struct input_dev *dev)
 {
-       if (!--pc110pad_used)
-               outb(PC110PAD_OFF, pc110pad_io + 2);
+       outb(PC110PAD_OFF, pc110pad_io + 2);
 }
 
 static int pc110pad_open(struct input_dev *dev)
 {
-       if (pc110pad_used++)
-               return 0;
-
        pc110pad_interrupt(0,NULL,NULL);
        pc110pad_interrupt(0,NULL,NULL);
        pc110pad_interrupt(0,NULL,NULL);
@@ -145,7 +140,7 @@ static int __init pc110pad_init(void)
 
        pc110pad_dev.absmax[ABS_X] = 0x1ff;
        pc110pad_dev.absmax[ABS_Y] = 0x0ff;
-        
+
        pc110pad_dev.open = pc110pad_open;
         pc110pad_dev.close = pc110pad_close;
 
@@ -156,17 +151,17 @@ static int __init pc110pad_init(void)
        pc110pad_dev.id.product = 0x0001;
        pc110pad_dev.id.version = 0x0100;
 
-       input_register_device(&pc110pad_dev);   
+       input_register_device(&pc110pad_dev);
 
        printk(KERN_INFO "input: %s at %#x irq %d\n",
                pc110pad_name, pc110pad_io, pc110pad_irq);
-       
+
        return 0;
 }
+
 static void __exit pc110pad_exit(void)
 {
-       input_unregister_device(&pc110pad_dev); 
+       input_unregister_device(&pc110pad_dev);
 
        outb(PC110PAD_OFF, pc110pad_io + 2);
 
index 019034b21a0bc91d3f0f941b05e7e495b6b69a08..19785a6c5abd790fdfba408ef84c6b477d9e64d6 100644 (file)
@@ -24,6 +24,7 @@
 #include "synaptics.h"
 #include "logips2pp.h"
 #include "alps.h"
+#include "lifebook.h"
 
 #define DRIVER_DESC    "PS/2 mouse driver"
 
@@ -31,10 +32,9 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-static unsigned int psmouse_max_proto = -1U;
+static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
 static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
 static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
-static char *psmouse_proto_abbrev[] = { NULL, "bare", NULL, NULL, NULL, "imps", "exps", NULL, NULL, NULL };
 #define param_check_proto_abbrev(name, p)      __param_check(name, p, unsigned int)
 #define param_set_proto_abbrev                 psmouse_set_maxproto
 #define param_get_proto_abbrev                 psmouse_get_maxproto
@@ -57,6 +57,7 @@ static unsigned int psmouse_resetafter;
 module_param_named(resetafter, psmouse_resetafter, uint, 0644);
 MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
 
+PSMOUSE_DEFINE_ATTR(protocol);
 PSMOUSE_DEFINE_ATTR(rate);
 PSMOUSE_DEFINE_ATTR(resolution);
 PSMOUSE_DEFINE_ATTR(resetafter);
@@ -67,7 +68,23 @@ __obsolete_setup("psmouse_smartscroll=");
 __obsolete_setup("psmouse_resetafter=");
 __obsolete_setup("psmouse_rate=");
 
-static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" };
+/*
+ * psmouse_sem protects all operations changing state of mouse
+ * (connecting, disconnecting, changing rate or resolution via
+ * sysfs). We could use a per-device semaphore but since there
+ * rarely more than one PS/2 mouse connected and since semaphore
+ * is taken in "slow" paths it is not worth it.
+ */
+static DECLARE_MUTEX(psmouse_sem);
+
+struct psmouse_protocol {
+       enum psmouse_type type;
+       char *name;
+       char *alias;
+       int maxproto;
+       int (*detect)(struct psmouse *, int);
+       int (*init)(struct psmouse *);
+};
 
 /*
  * psmouse_process_byte() analyzes the PS/2 data stream and reports
@@ -407,12 +424,15 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
  */
 static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
 {
-       if (!psmouse->vendor) psmouse->vendor = "Generic";
-       if (!psmouse->name) psmouse->name = "Mouse";
+       if (set_properties) {
+               if (!psmouse->vendor) psmouse->vendor = "Generic";
+               if (!psmouse->name) psmouse->name = "Mouse";
+       }
 
        return 0;
 }
 
+
 /*
  * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
  * the mouse may have.
@@ -423,6 +443,17 @@ static int psmouse_extensions(struct psmouse *psmouse,
 {
        int synaptics_hardware = 0;
 
+/*
+ * We always check for lifebook because it does not disturb mouse
+ * (it only checks DMI information).
+ */
+       if (lifebook_detect(psmouse, set_properties) == 0) {
+               if (max_proto > PSMOUSE_IMEX) {
+                       if (!set_properties || lifebook_init(psmouse) == 0)
+                               return PSMOUSE_LIFEBOOK;
+               }
+       }
+
 /*
  * Try Kensington ThinkingMouse (we try first, because synaptics probe
  * upsets the thinkingmouse).
@@ -506,6 +537,103 @@ static int psmouse_extensions(struct psmouse *psmouse,
        return PSMOUSE_PS2;
 }
 
+static struct psmouse_protocol psmouse_protocols[] = {
+       {
+               .type           = PSMOUSE_PS2,
+               .name           = "PS/2",
+               .alias          = "bare",
+               .maxproto       = 1,
+               .detect         = ps2bare_detect,
+       },
+       {
+               .type           = PSMOUSE_PS2PP,
+               .name           = "PS2++",
+               .alias          = "logitech",
+               .detect         = ps2pp_init,
+       },
+       {
+               .type           = PSMOUSE_THINKPS,
+               .name           = "ThinkPS/2",
+               .alias          = "thinkps",
+               .detect         = thinking_detect,
+       },
+       {
+               .type           = PSMOUSE_GENPS,
+               .name           = "GenPS/2",
+               .alias          = "genius",
+               .detect         = genius_detect,
+       },
+       {
+               .type           = PSMOUSE_IMPS,
+               .name           = "ImPS/2",
+               .alias          = "imps",
+               .maxproto       = 1,
+               .detect         = intellimouse_detect,
+       },
+       {
+               .type           = PSMOUSE_IMEX,
+               .name           = "ImExPS/2",
+               .alias          = "exps",
+               .maxproto       = 1,
+               .detect         = im_explorer_detect,
+       },
+       {
+               .type           = PSMOUSE_SYNAPTICS,
+               .name           = "SynPS/2",
+               .alias          = "synaptics",
+               .detect         = synaptics_detect,
+               .init           = synaptics_init,
+       },
+       {
+               .type           = PSMOUSE_ALPS,
+               .name           = "AlpsPS/2",
+               .alias          = "alps",
+               .detect         = alps_detect,
+               .init           = alps_init,
+       },
+       {
+               .type           = PSMOUSE_LIFEBOOK,
+               .name           = "LBPS/2",
+               .alias          = "lifebook",
+               .init           = lifebook_init,
+       },
+       {
+               .type           = PSMOUSE_AUTO,
+               .name           = "auto",
+               .alias          = "any",
+               .maxproto       = 1,
+       },
+};
+
+static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++)
+               if (psmouse_protocols[i].type == type)
+                       return &psmouse_protocols[i];
+
+       WARN_ON(1);
+       return &psmouse_protocols[0];
+}
+
+static struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len)
+{
+       struct psmouse_protocol *p;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) {
+               p = &psmouse_protocols[i];
+
+               if ((strlen(p->name) == len && !strncmp(p->name, name, len)) ||
+                   (strlen(p->alias) == len && !strncmp(p->alias, name, len)))
+                       return &psmouse_protocols[i];
+       }
+
+       return NULL;
+}
+
+
 /*
  * psmouse_probe() probes for a PS/2 mouse.
  */
@@ -653,30 +781,84 @@ static void psmouse_cleanup(struct serio *serio)
 
 static void psmouse_disconnect(struct serio *serio)
 {
-       struct psmouse *psmouse, *parent;
+       struct psmouse *psmouse, *parent = NULL;
 
+       psmouse = serio_get_drvdata(serio);
+
+       device_remove_file(&serio->dev, &psmouse_attr_protocol);
        device_remove_file(&serio->dev, &psmouse_attr_rate);
        device_remove_file(&serio->dev, &psmouse_attr_resolution);
        device_remove_file(&serio->dev, &psmouse_attr_resetafter);
 
-       psmouse = serio_get_drvdata(serio);
+       down(&psmouse_sem);
+
        psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 
        if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
                parent = serio_get_drvdata(serio->parent);
-               if (parent->pt_deactivate)
-                       parent->pt_deactivate(parent);
+               psmouse_deactivate(parent);
        }
 
        if (psmouse->disconnect)
                psmouse->disconnect(psmouse);
 
+       if (parent && parent->pt_deactivate)
+               parent->pt_deactivate(parent);
+
        psmouse_set_state(psmouse, PSMOUSE_IGNORE);
 
        input_unregister_device(&psmouse->dev);
        serio_close(serio);
        serio_set_drvdata(serio, NULL);
        kfree(psmouse);
+
+       if (parent)
+               psmouse_activate(parent);
+
+       up(&psmouse_sem);
+}
+
+static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto)
+{
+       memset(&psmouse->dev, 0, sizeof(struct input_dev));
+
+       init_input_dev(&psmouse->dev);
+
+       psmouse->dev.private = psmouse;
+       psmouse->dev.dev = &psmouse->ps2dev.serio->dev;
+
+       psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+       psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+
+       psmouse->set_rate = psmouse_set_rate;
+       psmouse->set_resolution = psmouse_set_resolution;
+       psmouse->protocol_handler = psmouse_process_byte;
+       psmouse->pktsize = 3;
+
+       if (proto && (proto->detect || proto->init)) {
+               if (proto->detect && proto->detect(psmouse, 1) < 0)
+                       return -1;
+
+               if (proto->init && proto->init(psmouse) < 0)
+                       return -1;
+
+               psmouse->type = proto->type;
+       }
+       else
+               psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
+
+       sprintf(psmouse->devname, "%s %s %s",
+               psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
+
+       psmouse->dev.name = psmouse->devname;
+       psmouse->dev.phys = psmouse->phys;
+       psmouse->dev.id.bustype = BUS_I8042;
+       psmouse->dev.id.vendor = 0x0002;
+       psmouse->dev.id.product = psmouse->type;
+       psmouse->dev.id.version = psmouse->model;
+
+       return 0;
 }
 
 /*
@@ -688,6 +870,8 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
        struct psmouse *psmouse, *parent = NULL;
        int retval;
 
+       down(&psmouse_sem);
+
        /*
         * If this is a pass-through port deactivate parent so the device
         * connected to this port can be successfully identified
@@ -697,20 +881,14 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
                psmouse_deactivate(parent);
        }
 
-       if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) {
+       if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) {
                retval = -ENOMEM;
                goto out;
        }
 
-       memset(psmouse, 0, sizeof(struct psmouse));
-
        ps2_init(&psmouse->ps2dev, serio);
        sprintf(psmouse->phys, "%s/input0", serio->phys);
-       psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
-       psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
-       psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
-       psmouse->dev.private = psmouse;
-       psmouse->dev.dev = &serio->dev;
+
        psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 
        serio_set_drvdata(serio, psmouse);
@@ -734,25 +912,10 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
        psmouse->resolution = psmouse_resolution;
        psmouse->resetafter = psmouse_resetafter;
        psmouse->smartscroll = psmouse_smartscroll;
-       psmouse->set_rate = psmouse_set_rate;
-       psmouse->set_resolution = psmouse_set_resolution;
-       psmouse->protocol_handler = psmouse_process_byte;
-       psmouse->pktsize = 3;
 
-       psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
-
-       sprintf(psmouse->devname, "%s %s %s",
-               psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
-
-       psmouse->dev.name = psmouse->devname;
-       psmouse->dev.phys = psmouse->phys;
-       psmouse->dev.id.bustype = BUS_I8042;
-       psmouse->dev.id.vendor = 0x0002;
-       psmouse->dev.id.product = psmouse->type;
-       psmouse->dev.id.version = psmouse->model;
+       psmouse_switch_protocol(psmouse, NULL);
 
        input_register_device(&psmouse->dev);
-
        printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
 
        psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
@@ -762,6 +925,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
        if (parent && parent->pt_activate)
                parent->pt_activate(parent);
 
+       device_create_file(&serio->dev, &psmouse_attr_protocol);
        device_create_file(&serio->dev, &psmouse_attr_rate);
        device_create_file(&serio->dev, &psmouse_attr_resolution);
        device_create_file(&serio->dev, &psmouse_attr_resetafter);
@@ -771,10 +935,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
        retval = 0;
 
 out:
-       /* If this is a pass-through port the parent awaits to be activated */
+       /* If this is a pass-through port the parent needs to be re-activated */
        if (parent)
                psmouse_activate(parent);
 
+       up(&psmouse_sem);
        return retval;
 }
 
@@ -791,6 +956,8 @@ static int psmouse_reconnect(struct serio *serio)
                return -1;
        }
 
+       down(&psmouse_sem);
+
        if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
                parent = serio_get_drvdata(serio->parent);
                psmouse_deactivate(parent);
@@ -823,6 +990,7 @@ out:
        if (parent)
                psmouse_activate(parent);
 
+       up(&psmouse_sem);
        return rc;
 }
 
@@ -893,26 +1061,109 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
 
        if (serio->drv != &psmouse_drv) {
                retval = -ENODEV;
-               goto out;
+               goto out_unpin;
+       }
+
+       retval = down_interruptible(&psmouse_sem);
+       if (retval)
+               goto out_unpin;
+
+       if (psmouse->state == PSMOUSE_IGNORE) {
+               retval = -ENODEV;
+               goto out_up;
        }
 
        if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
                parent = serio_get_drvdata(serio->parent);
                psmouse_deactivate(parent);
        }
+
        psmouse_deactivate(psmouse);
 
        retval = handler(psmouse, buf, count);
 
-       psmouse_activate(psmouse);
+       if (retval != -ENODEV)
+               psmouse_activate(psmouse);
+
        if (parent)
                psmouse_activate(parent);
 
-out:
+ out_up:
+       up(&psmouse_sem);
+ out_unpin:
        serio_unpin_driver(serio);
        return retval;
 }
 
+static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, char *buf)
+{
+       return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name);
+}
+
+static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *buf, size_t count)
+{
+       struct serio *serio = psmouse->ps2dev.serio;
+       struct psmouse *parent = NULL;
+       struct psmouse_protocol *proto;
+       int retry = 0;
+
+       if (!(proto = psmouse_protocol_by_name(buf, count)))
+               return -EINVAL;
+
+       if (psmouse->type == proto->type)
+               return count;
+
+       while (serio->child) {
+               if (++retry > 3) {
+                       printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n");
+                       return -EIO;
+               }
+
+               up(&psmouse_sem);
+               serio_unpin_driver(serio);
+               serio_unregister_child_port(serio);
+               serio_pin_driver_uninterruptible(serio);
+               down(&psmouse_sem);
+
+               if (serio->drv != &psmouse_drv)
+                       return -ENODEV;
+
+               if (psmouse->type == proto->type)
+                       return count; /* switched by other thread */
+       }
+
+       if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+               parent = serio_get_drvdata(serio->parent);
+               if (parent->pt_deactivate)
+                       parent->pt_deactivate(parent);
+       }
+
+       if (psmouse->disconnect)
+               psmouse->disconnect(psmouse);
+
+       psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+       input_unregister_device(&psmouse->dev);
+
+       psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
+
+       if (psmouse_switch_protocol(psmouse, proto) < 0) {
+               psmouse_reset(psmouse);
+               /* default to PSMOUSE_PS2 */
+               psmouse_switch_protocol(psmouse, &psmouse_protocols[0]);
+       }
+
+       psmouse_initialize(psmouse);
+       psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+
+       input_register_device(&psmouse->dev);
+       printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
+
+       if (parent && parent->pt_activate)
+               parent->pt_activate(parent);
+
+       return count;
+}
+
 static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf)
 {
        return sprintf(buf, "%d\n", psmouse->rate);
@@ -969,34 +1220,26 @@ static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char *
 
 static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
 {
-       int i;
+       struct psmouse_protocol *proto;
 
        if (!val)
                return -EINVAL;
 
-       if (!strncmp(val, "any", 3)) {
-               *((unsigned int *)kp->arg) = -1U;
-               return 0;
-       }
+       proto = psmouse_protocol_by_name(val, strlen(val));
 
-       for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) {
-               if (!psmouse_proto_abbrev[i])
-                       continue;
+       if (!proto || !proto->maxproto)
+               return -EINVAL;
 
-               if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) {
-                       *((unsigned int *)kp->arg) = i;
-                       return 0;
-               }
-       }
+       *((unsigned int *)kp->arg) = proto->type;
 
-       return -EINVAL;                                 \
+       return 0;                                       \
 }
 
 static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
 {
-       return sprintf(buffer, "%s\n",
-                       psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ?
-                               psmouse_proto_abbrev[psmouse_max_proto] : "any");
+       int type = *((unsigned int *)kp->arg);
+
+       return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
 }
 
 static int __init psmouse_init(void)
index 79e17a0c4664b7180b9ba19217ce754967a0cfa2..86691cf43433f182e9c2d7ac0d3f925dab5bb5bb 100644 (file)
@@ -77,6 +77,8 @@ enum psmouse_type {
        PSMOUSE_IMEX,
        PSMOUSE_SYNAPTICS,
        PSMOUSE_ALPS,
+       PSMOUSE_LIFEBOOK,
+       PSMOUSE_AUTO            /* This one should always be last */
 };
 
 int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
@@ -99,7 +101,7 @@ static ssize_t psmouse_do_set_##_name(struct device *d, struct device_attribute
 {                                                                              \
        return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name);      \
 }                                                                              \
-static struct device_attribute psmouse_attr_##_name =                          \
+static struct device_attribute psmouse_attr_##_name =                          \
        __ATTR(_name, S_IWUSR | S_IRUGO,                                        \
                psmouse_do_show_##_name, psmouse_do_set_##_name);
 
index 7280f68afcee2a7dcf30bc098d1da05e2fbf6d78..8fe1212b8fd73ff3a3d619e4c4d903600a07cbb6 100644 (file)
@@ -59,7 +59,7 @@ static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
        b = (short) (__raw_readl(0xe0310000) ^ 0x70);
 
        dx = x - rpcmouse_lastx;
-       dy = y - rpcmouse_lasty; 
+       dy = y - rpcmouse_lasty;
 
        rpcmouse_lastx = x;
        rpcmouse_lasty = y;
index b2cb101c8110ba2e1a0aec959f99c5ae49fc2489..f024be9b44d2f1b25d86b44589c0209ac19afd89 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for  DEC VSXXX-AA mouse (hockey-puck mouse, ball or two rollers)
- *             DEC VSXXX-GA mouse (rectangular mouse, with ball)
- *             DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
+ *             DEC VSXXX-GA mouse (rectangular mouse, with ball)
+ *             DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
  *
  * Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
  *
index 062848ac7e6b50f1a35f4c91b96fbe4a3d387487..c6194a9dd174be5d1a534cc7b962543b112d9f60 100644 (file)
@@ -220,6 +220,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
        struct mousedev_list *list;
        struct mousedev_motion *p;
        unsigned long flags;
+       int wake_readers = 0;
 
        list_for_each_entry(list, &mousedev->list, node) {
                spin_lock_irqsave(&list->packet_lock, flags);
@@ -255,11 +256,14 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
 
                spin_unlock_irqrestore(&list->packet_lock, flags);
 
-               if (list->ready)
+               if (list->ready) {
                        kill_fasync(&list->fasync, SIGIO, POLL_IN);
+                       wake_readers = 1;
+               }
        }
 
-       wake_up_interruptible(&mousedev->wait);
+       if (wake_readers)
+               wake_up_interruptible(&mousedev->wait);
 }
 
 static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
index 5900de3c3f4f04b0936d2788edf5461681dc075e..a9bf549c8dc5b0e8f637f691938d7fd2bd9de2e5 100644 (file)
@@ -396,7 +396,7 @@ static void i8042_stop(struct serio *serio)
        struct i8042_port *port = serio->port_data;
 
        port->exists = 0;
-       synchronize_kernel();
+       synchronize_sched();
        port->serio = NULL;
 }
 
index c978657068c55b6ade7644b65e9089ae272810bc..d4c990f7c85e9a1f64c2f03340ad01e625eaf29c 100644 (file)
@@ -29,6 +29,7 @@ MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(ps2_init);
 EXPORT_SYMBOL(ps2_sendbyte);
+EXPORT_SYMBOL(ps2_drain);
 EXPORT_SYMBOL(ps2_command);
 EXPORT_SYMBOL(ps2_schedule_command);
 EXPORT_SYMBOL(ps2_handle_ack);
@@ -45,11 +46,11 @@ struct ps2work {
 
 
 /*
- * ps2_sendbyte() sends a byte to the mouse, and waits for acknowledge.
- * It doesn't handle retransmission, though it could - because when there would
- * be need for retransmissions, the mouse has to be replaced anyway.
+ * ps2_sendbyte() sends a byte to the device and waits for acknowledge.
+ * It doesn't handle retransmission, though it could - because if there
+ * is a need for retransmissions device has to be replaced anyway.
  *
- * ps2_sendbyte() can only be called from a process context
+ * ps2_sendbyte() can only be called from a process context.
  */
 
 int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
@@ -71,6 +72,91 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
        return -ps2dev->nak;
 }
 
+/*
+ * ps2_drain() waits for device to transmit requested number of bytes
+ * and discards them.
+ */
+
+void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
+{
+       if (maxbytes > sizeof(ps2dev->cmdbuf)) {
+               WARN_ON(1);
+               maxbytes = sizeof(ps2dev->cmdbuf);
+       }
+
+       down(&ps2dev->cmd_sem);
+
+       serio_pause_rx(ps2dev->serio);
+       ps2dev->flags = PS2_FLAG_CMD;
+       ps2dev->cmdcnt = maxbytes;
+       serio_continue_rx(ps2dev->serio);
+
+       wait_event_timeout(ps2dev->wait,
+                          !(ps2dev->flags & PS2_FLAG_CMD),
+                          msecs_to_jiffies(timeout));
+       up(&ps2dev->cmd_sem);
+}
+
+/*
+ * ps2_is_keyboard_id() checks received ID byte against the list of
+ * known keyboard IDs.
+ */
+
+static inline int ps2_is_keyboard_id(char id_byte)
+{
+       static char keyboard_ids[] = {
+               0xab,   /* Regular keyboards            */
+               0xac,   /* NCD Sun keyboard             */
+               0x2b,   /* Trust keyboard, translated   */
+               0x5d,   /* Trust keyboard               */
+               0x60,   /* NMB SGI keyboard, translated */
+               0x47,   /* NMB SGI keyboard             */
+       };
+
+       return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL;
+}
+
+/*
+ * ps2_adjust_timeout() is called after receiving 1st byte of command
+ * response and tries to reduce remaining timeout to speed up command
+ * completion.
+ */
+
+static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
+{
+       switch (command) {
+               case PS2_CMD_RESET_BAT:
+                       /*
+                        * Device has sent the first response byte after
+                        * reset command, reset is thus done, so we can
+                        * shorten the timeout.
+                        * The next byte will come soon (keyboard) or not
+                        * at all (mouse).
+                        */
+                       if (timeout > msecs_to_jiffies(100))
+                               timeout = msecs_to_jiffies(100);
+                       break;
+
+               case PS2_CMD_GETID:
+                       /*
+                        * If device behind the port is not a keyboard there
+                        * won't be 2nd byte of ID response.
+                        */
+                       if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
+                               serio_pause_rx(ps2dev->serio);
+                               ps2dev->flags = ps2dev->cmdcnt = 0;
+                               serio_continue_rx(ps2dev->serio);
+                               timeout = 0;
+                       }
+                       break;
+
+               default:
+                       break;
+       }
+
+       return timeout;
+}
+
 /*
  * ps2_command() sends a command and its parameters to the mouse,
  * then waits for the response and puts it in the param array.
@@ -86,6 +172,11 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
        int rc = -1;
        int i;
 
+       if (receive > sizeof(ps2dev->cmdbuf)) {
+               WARN_ON(1);
+               return -1;
+       }
+
        down(&ps2dev->cmd_sem);
 
        serio_pause_rx(ps2dev->serio);
@@ -101,10 +192,9 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
         * ACKing the reset command, and so it can take a long
         * time before the ACK arrrives.
         */
-       if (command & 0xff)
-               if (ps2_sendbyte(ps2dev, command & 0xff,
-                       command == PS2_CMD_RESET_BAT ? 1000 : 200))
-                       goto out;
+       if (ps2_sendbyte(ps2dev, command & 0xff,
+                        command == PS2_CMD_RESET_BAT ? 1000 : 200))
+               goto out;
 
        for (i = 0; i < send; i++)
                if (ps2_sendbyte(ps2dev, param[i], 200))
@@ -120,33 +210,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
 
        if (ps2dev->cmdcnt && timeout > 0) {
 
-               if (command == PS2_CMD_RESET_BAT && timeout > msecs_to_jiffies(100)) {
-                       /*
-                        * Device has sent the first response byte
-                        * after a reset command, reset is thus done,
-                        * shorten the timeout. The next byte will come
-                        * soon (keyboard) or not at all (mouse).
-                        */
-                       timeout = msecs_to_jiffies(100);
-               }
-
-               if (command == PS2_CMD_GETID &&
-                   ps2dev->cmdbuf[receive - 1] != 0xab && /* Regular keyboards */
-                   ps2dev->cmdbuf[receive - 1] != 0xac && /* NCD Sun keyboard */
-                   ps2dev->cmdbuf[receive - 1] != 0x2b && /* Trust keyboard, translated */
-                   ps2dev->cmdbuf[receive - 1] != 0x5d && /* Trust keyboard */
-                   ps2dev->cmdbuf[receive - 1] != 0x60 && /* NMB SGI keyboard, translated */
-                   ps2dev->cmdbuf[receive - 1] != 0x47) { /* NMB SGI keyboard */
-                       /*
-                        * Device behind the port is not a keyboard
-                        * so we don't need to wait for the 2nd byte
-                        * of ID response.
-                        */
-                       serio_pause_rx(ps2dev->serio);
-                       ps2dev->flags = ps2dev->cmdcnt = 0;
-                       serio_continue_rx(ps2dev->serio);
-               }
-
+               timeout = ps2_adjust_timeout(ps2dev, command, timeout);
                wait_event_timeout(ps2dev->wait,
                                   !(ps2dev->flags & PS2_FLAG_CMD), timeout);
        }
@@ -160,7 +224,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
 
        rc = 0;
 
-out:
+ out:
        serio_pause_rx(ps2dev->serio);
        ps2dev->flags = 0;
        serio_continue_rx(ps2dev->serio);
index feab4970406e39423711da9e9b9f55180abea9d7..f367695e69b5c78e35a66ca731369f3e67b0550f 100644 (file)
 #include <linux/serio.h>
 #include <linux/errno.h>
 #include <linux/wait.h>
-#include <linux/completion.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
+#include <linux/kthread.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Serio abstraction core");
@@ -43,6 +42,7 @@ MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(serio_interrupt);
 EXPORT_SYMBOL(__serio_register_port);
 EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_unregister_child_port);
 EXPORT_SYMBOL(__serio_unregister_port_delayed);
 EXPORT_SYMBOL(__serio_register_driver);
 EXPORT_SYMBOL(serio_unregister_driver);
@@ -68,6 +68,37 @@ static void serio_destroy_port(struct serio *serio);
 static void serio_reconnect_port(struct serio *serio);
 static void serio_disconnect_port(struct serio *serio);
 
+static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
+{
+       int retval;
+
+       down(&serio->drv_sem);
+       retval = drv->connect(serio, drv);
+       up(&serio->drv_sem);
+
+       return retval;
+}
+
+static int serio_reconnect_driver(struct serio *serio)
+{
+       int retval = -1;
+
+       down(&serio->drv_sem);
+       if (serio->drv && serio->drv->reconnect)
+               retval = serio->drv->reconnect(serio);
+       up(&serio->drv_sem);
+
+       return retval;
+}
+
+static void serio_disconnect_driver(struct serio *serio)
+{
+       down(&serio->drv_sem);
+       if (serio->drv)
+               serio->drv->disconnect(serio);
+       up(&serio->drv_sem);
+}
+
 static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
 {
        while (ids->type || ids->proto) {
@@ -91,7 +122,7 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
 
        if (serio_match_port(drv->id_table, serio)) {
                serio->dev.driver = &drv->driver;
-               if (drv->connect(serio, drv)) {
+               if (serio_connect_driver(serio, drv)) {
                        serio->dev.driver = NULL;
                        goto out;
                }
@@ -138,8 +169,7 @@ struct serio_event {
 static DEFINE_SPINLOCK(serio_event_lock);      /* protects serio_event_list */
 static LIST_HEAD(serio_event_list);
 static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
-static DECLARE_COMPLETION(serio_exited);
-static int serio_pid;
+static struct task_struct *serio_task;
 
 static void serio_queue_event(void *object, struct module *owner,
                              enum serio_event_type event_type)
@@ -150,12 +180,12 @@ static void serio_queue_event(void *object, struct module *owner,
        spin_lock_irqsave(&serio_event_lock, flags);
 
        /*
-        * Scan event list for the other events for the same serio port,
+        * Scan event list for the other events for the same serio port,
         * starting with the most recent one. If event is the same we
         * do not need add new one. If event is of different type we
         * need to add this event and should not look further because
         * we need to preseve sequence of distinct events.
-        */
+        */
        list_for_each_entry_reverse(event, &serio_event_list, node) {
                if (event->object == object) {
                        if (event->type == event_type)
@@ -337,20 +367,15 @@ static struct serio *serio_get_pending_child(struct serio *parent)
 
 static int serio_thread(void *nothing)
 {
-       lock_kernel();
-       daemonize("kseriod");
-       allow_signal(SIGTERM);
-
        do {
                serio_handle_events();
-               wait_event_interruptible(serio_wait, !list_empty(&serio_event_list));
-               try_to_freeze(PF_FREEZE);
-       } while (!signal_pending(current));
+               wait_event_interruptible(serio_wait,
+                       kthread_should_stop() || !list_empty(&serio_event_list));
+               try_to_freeze();
+       } while (!kthread_should_stop());
 
        printk(KERN_DEBUG "serio: kseriod exiting\n");
-
-       unlock_kernel();
-       complete_and_exit(&serio_exited, 0);
+       return 0;
 }
 
 
@@ -557,7 +582,7 @@ static void serio_destroy_port(struct serio *serio)
 static void serio_reconnect_port(struct serio *serio)
 {
        do {
-               if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+               if (serio_reconnect_driver(serio)) {
                        serio_disconnect_port(serio);
                        serio_find_driver(serio);
                        /* Ok, old children are now gone, we are done */
@@ -629,6 +654,19 @@ void serio_unregister_port(struct serio *serio)
        up(&serio_sem);
 }
 
+/*
+ * Safely unregisters child port if one is present.
+ */
+void serio_unregister_child_port(struct serio *serio)
+{
+       down(&serio_sem);
+       if (serio->child) {
+               serio_disconnect_port(serio->child);
+               serio_destroy_port(serio->child);
+       }
+       up(&serio_sem);
+}
+
 /*
  * Submits register request to kseriod for subsequent execution.
  * Can be used when it is not obvious whether the serio_sem is
@@ -686,15 +724,14 @@ static int serio_driver_probe(struct device *dev)
        struct serio *serio = to_serio_port(dev);
        struct serio_driver *drv = to_serio_driver(dev->driver);
 
-       return drv->connect(serio, drv);
+       return serio_connect_driver(serio, drv);
 }
 
 static int serio_driver_remove(struct device *dev)
 {
        struct serio *serio = to_serio_port(dev);
-       struct serio_driver *drv = to_serio_driver(dev->driver);
 
-       drv->disconnect(serio);
+       serio_disconnect_driver(serio);
        return 0;
 }
 
@@ -730,11 +767,9 @@ start_over:
 
 static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
 {
-       down(&serio->drv_sem);
        serio_pause_rx(serio);
        serio->drv = drv;
        serio_continue_rx(serio);
-       up(&serio->drv_sem);
 }
 
 static int serio_bus_match(struct device *dev, struct device_driver *drv)
@@ -794,7 +829,7 @@ static int serio_resume(struct device *dev)
 {
        struct serio *serio = to_serio_port(dev);
 
-       if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+       if (serio_reconnect_driver(serio)) {
                /*
                 * Driver re-probing can take a while, so better let kseriod
                 * deal with it.
@@ -848,9 +883,10 @@ irqreturn_t serio_interrupt(struct serio *serio,
 
 static int __init serio_init(void)
 {
-       if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) {
+       serio_task = kthread_run(serio_thread, NULL, "kseriod");
+       if (IS_ERR(serio_task)) {
                printk(KERN_ERR "serio: Failed to start kseriod\n");
-               return -1;
+               return PTR_ERR(serio_task);
        }
 
        serio_bus.dev_attrs = serio_device_attrs;
@@ -866,8 +902,7 @@ static int __init serio_init(void)
 static void __exit serio_exit(void)
 {
        bus_unregister(&serio_bus);
-       kill_proc(serio_pid, SIGTERM, 1);
-       wait_for_completion(&serio_exited);
+       kthread_stop(serio_task);
 }
 
 module_init(serio_init);
index 546ce599334e0b305bc7efbdd5d759de2b99ade1..3cdc9cab688d84362ee1a53e32b6ae9899fdc7ea 100644 (file)
@@ -226,7 +226,7 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
                        input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0);
                        input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 255, 0, 0);
                        break;
-               
+
                case 1: /* 6-byte protocol */
                        input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 15, 0, 0);
 
index acb9137a02263be9f209778d0f5dff3b3fcf1b7f..bcfa1e36f957f47b03ce6e08bc5b49bf0803874e 100644 (file)
@@ -89,9 +89,9 @@ MODULE_LICENSE("GPL");
 #define H3600_SCANCODE_Q       4        /* 4 -> Q button */
 #define        H3600_SCANCODE_START    5        /* 5 -> start menu */
 #define        H3600_SCANCODE_UP       6        /* 6 -> up */
-#define H3600_SCANCODE_RIGHT   7        /* 7 -> right */
-#define H3600_SCANCODE_LEFT    8        /* 8 -> left */
-#define H3600_SCANCODE_DOWN    9        /* 9 -> down */
+#define H3600_SCANCODE_RIGHT   7        /* 7 -> right */
+#define H3600_SCANCODE_LEFT    8        /* 8 -> left */
+#define H3600_SCANCODE_DOWN    9        /* 9 -> down */
 
 static char *h3600_name = "H3600 TouchScreen";
 
@@ -113,7 +113,7 @@ struct h3600_dev {
 
 static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
-        int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
+       int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
        struct input_dev *dev = (struct input_dev *) dev_id;
 
        input_regs(dev, regs);
@@ -125,7 +125,7 @@ static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *
 
 static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
-        int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
+       int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
        struct input_dev *dev = (struct input_dev *) dev_id;
 
        /*
@@ -145,8 +145,8 @@ static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *
 static int flite_brightness = 25;
 
 enum flite_pwr {
-        FLITE_PWR_OFF = 0,
-        FLITE_PWR_ON = 1
+       FLITE_PWR_OFF = 0,
+       FLITE_PWR_ON = 1
 };
 
 /*
@@ -157,9 +157,9 @@ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
        struct h3600_dev *ts = dev->private;
 
        /* Must be in this order */
-               ts->serio->write(ts->serio, 1);
+       ts->serio->write(ts->serio, 1);
        ts->serio->write(ts->serio, pwr);
-       ts->serio->write(ts->serio, brightness);
+       ts->serio->write(ts->serio, brightness);
        return 0;
 }
 
@@ -169,26 +169,26 @@ static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,
 {
        struct input_dev *dev = (struct input_dev *) data;
 
-        switch (req) {
-        case PM_SUSPEND: /* enter D1-D3 */
-                suspended = 1;
-                h3600_flite_power(dev, FLITE_PWR_OFF);
-                break;
-        case PM_BLANK:
-                if (!suspended)
-                        h3600_flite_power(dev, FLITE_PWR_OFF);
-                break;
-        case PM_RESUME:  /* enter D0 */
-                /* same as unblank */
-        case PM_UNBLANK:
-                if (suspended) {
-                        //initSerial();
-                        suspended = 0;
-                }
-                h3600_flite_power(dev, FLITE_PWR_ON);
-                break;
-        }
-        return 0;
+       switch (req) {
+       case PM_SUSPEND: /* enter D1-D3 */
+               suspended = 1;
+               h3600_flite_power(dev, FLITE_PWR_OFF);
+               break;
+       case PM_BLANK:
+               if (!suspended)
+                       h3600_flite_power(dev, FLITE_PWR_OFF);
+               break;
+       case PM_RESUME:  /* enter D0 */
+               /* same as unblank */
+       case PM_UNBLANK:
+               if (suspended) {
+                       //initSerial();
+                       suspended = 0;
+               }
+               h3600_flite_power(dev, FLITE_PWR_ON);
+               break;
+       }
+       return 0;
 }
 #endif
 
@@ -199,25 +199,25 @@ static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,
  */
 static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
 {
-        struct input_dev *dev = &ts->dev;
+       struct input_dev *dev = &ts->dev;
        static int touched = 0;
        int key, down = 0;
 
        input_regs(dev, regs);
 
-        switch (ts->event) {
-                /*
-                   Buttons - returned as a single byte
-                        7 6 5 4 3 2 1 0
-                        S x x x N N N N
+       switch (ts->event) {
+               /*
+                  Buttons - returned as a single byte
+                       7 6 5 4 3 2 1 0
+                       S x x x N N N N
 
-                   S       switch state ( 0=pressed 1=released)
-                   x       Unused.
-                   NNNN    switch number 0-15
+                  S       switch state ( 0=pressed 1=released)
+                  x       Unused.
+                  NNNN    switch number 0-15
 
-                Note: This is true for non interrupt generated key events.
-                */
-                case KEYBD_ID:
+                  Note: This is true for non interrupt generated key events.
+               */
+               case KEYBD_ID:
                        down = (ts->buf[0] & 0x80) ? 0 : 1;
 
                        switch (ts->buf[0] & 0x7f) {
@@ -229,40 +229,40 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
                                         break;
                                case H3600_SCANCODE_CONTACTS:
                                        key = KEY_PROG2;
-                                        break;
+                                       break;
                                case H3600_SCANCODE_Q:
                                        key = KEY_Q;
-                                        break;
+                                       break;
                                case H3600_SCANCODE_START:
                                        key = KEY_PROG3;
-                                        break;
+                                       break;
                                case H3600_SCANCODE_UP:
                                        key = KEY_UP;
-                                        break;
+                                       break;
                                case H3600_SCANCODE_RIGHT:
                                        key = KEY_RIGHT;
-                                        break;
+                                       break;
                                case H3600_SCANCODE_LEFT:
                                        key = KEY_LEFT;
-                                        break;
+                                       break;
                                case H3600_SCANCODE_DOWN:
                                        key = KEY_DOWN;
-                                        break;
+                                       break;
                                default:
                                        key = 0;
                        }
-                        if (key)
-                               input_report_key(dev, key, down);
-                        break;
-                /*
-                 * Native touchscreen event data is formatted as shown below:-
-                 *
-                 *      +-------+-------+-------+-------+
-                 *      | Xmsb  | Xlsb  | Ymsb  | Ylsb  |
-                 *      +-------+-------+-------+-------+
-                 *       byte 0    1       2       3
-                 */
-                case TOUCHS_ID:
+                       if (key)
+                               input_report_key(dev, key, down);
+                       break;
+               /*
+                * Native touchscreen event data is formatted as shown below:-
+                *
+                *      +-------+-------+-------+-------+
+                *      | Xmsb  | Xlsb  | Ymsb  | Ylsb  |
+                *      +-------+-------+-------+-------+
+                *       byte 0    1       2       3
+                */
+               case TOUCHS_ID:
                        if (!touched) {
                                input_report_key(dev, BTN_TOUCH, 1);
                                touched = 1;
@@ -272,19 +272,19 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
                                unsigned short x, y;
 
                                x = ts->buf[0]; x <<= 8; x += ts->buf[1];
-                                y = ts->buf[2]; y <<= 8; y += ts->buf[3];
+                               y = ts->buf[2]; y <<= 8; y += ts->buf[3];
 
-                                       input_report_abs(dev, ABS_X, x);
-                                       input_report_abs(dev, ABS_Y, y);
+                               input_report_abs(dev, ABS_X, x);
+                               input_report_abs(dev, ABS_Y, y);
                        } else {
-                               input_report_key(dev, BTN_TOUCH, 0);
+                               input_report_key(dev, BTN_TOUCH, 0);
                                touched = 0;
                        }
-                        break;
+                       break;
                default:
                        /* Send a non input event elsewhere */
                        break;
-        }
+       }
 
        input_sync(dev);
 }
@@ -293,7 +293,7 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
  * h3600ts_event() handles events from the input module.
  */
 static int h3600ts_event(struct input_dev *dev, unsigned int type,
-                        unsigned int code, int value)
+                        unsigned int code, int value)
 {
        struct h3600_dev *ts = dev->private;
 
@@ -332,41 +332,41 @@ static int state;
 static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
                                      unsigned int flags, struct pt_regs *regs)
 {
-        struct h3600_dev *ts = serio_get_drvdata(serio);
+       struct h3600_dev *ts = serio_get_drvdata(serio);
 
        /*
-         * We have a new frame coming in.
-         */
+        * We have a new frame coming in.
+        */
        switch (state) {
                case STATE_SOF:
-                       if (data == CHAR_SOF)
-                               state = STATE_ID;
+                       if (data == CHAR_SOF)
+                               state = STATE_ID;
                        break;
-               case STATE_ID:
+               case STATE_ID:
                        ts->event = (data & 0xf0) >> 4;
                        ts->len = (data & 0xf);
                        ts->idx = 0;
                        if (ts->event >= MAX_ID) {
                                state = STATE_SOF;
-                               break;
+                               break;
                        }
                        ts->chksum = data;
-                       state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
+                       state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
                        break;
                case STATE_DATA:
                        ts->chksum += data;
                        ts->buf[ts->idx]= data;
-                       if(++ts->idx == ts->len)
-                               state = STATE_EOF;
+                       if (++ts->idx == ts->len)
+                               state = STATE_EOF;
                        break;
                case STATE_EOF:
-                       state = STATE_SOF;
-                       if (data == CHAR_EOF || data == ts->chksum)
+                       state = STATE_SOF;
+                       if (data == CHAR_EOF || data == ts->chksum)
                                h3600ts_process_packet(ts, regs);
-                       break;
-               default:
-                       printk("Error3\n");
-                       break;
+                       break;
+               default:
+                       printk("Error3\n");
+                       break;
        }
 
        return IRQ_HANDLED;
@@ -390,10 +390,10 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
        init_input_dev(&ts->dev);
 
        /* Device specific stuff */
-        set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
-        set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
+       set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
+       set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
 
-        if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
+       if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
                        SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
                        "h3600_action", &ts->dev)) {
                printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
@@ -401,7 +401,7 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
                return -EBUSY;
        }
 
-        if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
+       if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
                        SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
                        "h3600_suspend", &ts->dev)) {
                free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
@@ -433,7 +433,7 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
 
        sprintf(ts->phys, "%s/input0", serio->phys);
 
-               ts->dev.event = h3600ts_event;
+       ts->dev.event = h3600ts_event;
        ts->dev.private = ts;
        ts->dev.name = h3600_name;
        ts->dev.phys = ts->phys;
@@ -446,8 +446,8 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
 
        err = serio_open(serio, drv);
        if (err) {
-               free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
-               free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
+               free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
+               free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
                serio_set_drvdata(serio, NULL);
                kfree(ts);
                return err;
index 2d14a57a05e5d5030d54e2a6913d2129add0ea04..afaaebe5225bee37ab9486abe17226872143dbeb 100644 (file)
@@ -17,7 +17,7 @@
  * found in Gateway AOL Connected Touchpad computers.
  *
  * Documentation for ICS MK712 can be found at:
- *     http://www.icst.com/pdf/mk712.pdf
+ *     http://www.icst.com/pdf/mk712.pdf
  */
 
 /*
@@ -77,7 +77,6 @@ MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
 #define MK712_READ_ONE_POINT                   0x20
 #define MK712_POWERUP                          0x40
 
-static int mk712_used = 0;
 static struct input_dev mk712_dev;
 static DEFINE_SPINLOCK(mk712_lock);
 
@@ -130,17 +129,14 @@ static int mk712_open(struct input_dev *dev)
 
        spin_lock_irqsave(&mk712_lock, flags);
 
-       if (!mk712_used++) {
+       outb(0, mk712_io + MK712_CONTROL); /* Reset */
 
-               outb(0, mk712_io + MK712_CONTROL); /* Reset */
+       outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
+               MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
+               MK712_ENABLE_PERIODIC_CONVERSIONS |
+               MK712_POWERUP, mk712_io + MK712_CONTROL);
 
-               outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
-                       MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
-                       MK712_ENABLE_PERIODIC_CONVERSIONS |
-                       MK712_POWERUP, mk712_io + MK712_CONTROL);
-
-               outb(10, mk712_io + MK712_RATE); /* 187 points per second */
-       }
+       outb(10, mk712_io + MK712_RATE); /* 187 points per second */
 
        spin_unlock_irqrestore(&mk712_lock, flags);
 
@@ -153,8 +149,7 @@ static void mk712_close(struct input_dev *dev)
 
        spin_lock_irqsave(&mk712_lock, flags);
 
-       if (!--mk712_used)
-               outb(0, mk712_io + MK712_CONTROL);
+       outb(0, mk712_io + MK712_CONTROL);
 
        spin_unlock_irqrestore(&mk712_lock, flags);
 }
index 40395f567231570a10afa5040e09643b108016c0..afa46681f9833c576e3afd7b54f9a74debdac2bc 100644 (file)
@@ -224,6 +224,7 @@ actcapi_manufacturer_req_net(act2000_card *card)
 /*
  * Switch V.42 on or off
  */
+#if 0
 int
 actcapi_manufacturer_req_v42(act2000_card *card, ulong arg)
 {
@@ -242,6 +243,7 @@ actcapi_manufacturer_req_v42(act2000_card *card, ulong arg)
        ACTCAPI_QUEUE_TX;
         return 0;
 }
+#endif  /*  0  */
 
 /*
  * Set error-handler
index 04d2bcdd37a724aac183b1f49de8e4552fb2af33..f6d5f530b86be8e3d434ca17244ff2b9591b2623 100644 (file)
@@ -350,7 +350,6 @@ actcapi_nextsmsg(act2000_card *card)
 extern int actcapi_chkhdr(act2000_card *, actcapi_msghdr *);
 extern int actcapi_listen_req(act2000_card *);
 extern int actcapi_manufacturer_req_net(act2000_card *);
-extern int actcapi_manufacturer_req_v42(act2000_card *, ulong);
 extern int actcapi_manufacturer_req_errh(act2000_card *);
 extern int actcapi_manufacturer_req_msn(act2000_card *);
 extern int actcapi_connect_req(act2000_card *, act2000_chan *, char *, char, int, int);
index dc00c85e3e354ba970be2a71964fa4ab82e1bc80..ee750e9456dd4908a3f48487f1c148a18f1ca118 100644 (file)
@@ -486,6 +486,14 @@ static int avmcs_event(event_t event, int priority,
     return 0;
 } /* avmcs_event */
 
+static struct pcmcia_device_id avmcs_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
+       PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),
+       PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, avmcs_ids);
+
 static struct pcmcia_driver avmcs_driver = {
        .owner  = THIS_MODULE,
        .drv    = {
@@ -493,6 +501,7 @@ static struct pcmcia_driver avmcs_driver = {
        },
        .attach = avmcs_attach,
        .detach = avmcs_detach,
+       .id_table = avmcs_ids,
 };
 
 static int __init avmcs_init(void)
index 55bed00ca86557ec9d8bf91a69e85cb8aca4cb4a..91dd0551fc7ceacc3e83fe09cdae5dcb9ba867b6 100644 (file)
@@ -955,7 +955,7 @@ EXPORT_SYMBOL(b1dma_release_appl);
 EXPORT_SYMBOL(b1dma_send_message);
 EXPORT_SYMBOL(b1dmactl_read_proc);
 
-int b1dma_init(void)
+static int __init b1dma_init(void)
 {
        char *p;
        char rev[32];
@@ -972,7 +972,7 @@ int b1dma_init(void)
        return 0;
 }
 
-void b1dma_exit(void)
+static void __exit b1dma_exit(void)
 {
 }
 
index fa6b93b1a42d676e12576b6d49ffc50f7b556e6b..724aac2c1ccaf1669de1fb73f04b087d20959d03 100644 (file)
@@ -885,7 +885,7 @@ static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
 }
 
 
-void c4_reset_ctr(struct capi_ctr *ctrl)
+static void c4_reset_ctr(struct capi_ctr *ctrl)
 {
        avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card;
        avmctrl_info *cinfo;
@@ -933,7 +933,7 @@ static void c4_remove(struct pci_dev *pdev)
 /* ------------------------------------------------------------- */
 
 
-void c4_register_appl(struct capi_ctr *ctrl,
+static void c4_register_appl(struct capi_ctr *ctrl,
                                u16 appl,
                                capi_register_params *rp)
 {
@@ -978,7 +978,7 @@ void c4_register_appl(struct capi_ctr *ctrl,
 
 /* ------------------------------------------------------------- */
 
-void c4_release_appl(struct capi_ctr *ctrl, u16 appl)
+static void c4_release_appl(struct capi_ctr *ctrl, u16 appl)
 {
        avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
        avmcard *card = cinfo->card;
index cb9d9cee2a648f2ef3793102f74363fbbd8fc865..3b701d97bdf1e150b281badea07301aa57ba323e 100644 (file)
@@ -328,7 +328,7 @@ static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
        return 0;
 }
 
-void t1isa_reset_ctr(struct capi_ctr *ctrl)
+static void t1isa_reset_ctr(struct capi_ctr *ctrl)
 {
        avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
        avmcard *card = cinfo->card;
index 6e548a222ef12c3ce9fdfa80fc410e0d1e02841c..89497890158d9fad084828551a0d3b1db57b8b90 100644 (file)
@@ -44,7 +44,7 @@ static didd_adapter_change_notification_t\
   Array to held adapter information
    -------------------------------------------------------------------------- */
 static DESCRIPTOR  HandleTable[NEW_MAX_DESCRIPTORS];
-dword Adapters = 0; /* Number of adapters */
+static dword Adapters = 0; /* Number of adapters */
 /* --------------------------------------------------------------------------
   Shadow IDI_DIMAINT
   and 'shadow' debug stuff
index 8d6bb56754b8c08a5b0d8d392cc2f35996783a8a..293e27789d54caf983ec2b6d0b53b80548e89e64 100644 (file)
@@ -23,7 +23,7 @@ endif
 # Multipart objects.
 
 hisax_st5481-y                                 := st5481_init.o st5481_usb.o st5481_d.o \
-                                          st5481_b.o st5481_hdlc.o
+                                          st5481_b.o
 
 hisax-y                                        := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
                                           lmgr.o q931.o callc.o fsm.o
index c4f861a5db25791f3bd9b5fb867cc5dec4ddbae8..8ae08c41c853ef8f65b8010688a658ad9f79957e 100644 (file)
@@ -97,7 +97,7 @@ static WORD initAMD[] = {
 };
 
 
-void /* macro wWordAMD */
+static void /* macro wWordAMD */
 WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
 {
         wByteAMD(cs, 0x00, reg);
@@ -105,7 +105,7 @@ WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
         wByteAMD(cs, 0x01, HIBYTE(val));
 }
 
-WORD /* macro rWordAMD */
+static WORD /* macro rWordAMD */
 ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg)
 {
         WORD res;
@@ -665,7 +665,7 @@ Amd7930_l1hw(struct PStack *st, int pr, void *arg)
        }
 }
 
-void
+static void
 setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
 {
 
@@ -676,7 +676,7 @@ setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
 }
 
 
-void
+static void
 DC_Close_Amd7930(struct IsdnCardState *cs) {
         if (cs->debug & L1_DEB_ISAC)
                debugl1(cs, "Amd7930: DC_Close called");
index 7546e2e4a94ea766b09140a874aef6f1cc93e5fc..a98c5e38bbbc527ac512028887f3f4a645ee509b 100644 (file)
@@ -22,7 +22,7 @@
 
 extern const char *CardType[];
 
-const char *Asuscom_revision = "$Revision: 1.14.2.4 $";
+static const char *Asuscom_revision = "$Revision: 1.14.2.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -239,7 +239,7 @@ Start_IPAC:
        return IRQ_HANDLED;
 }
 
-void
+static void
 release_io_asuscom(struct IsdnCardState *cs)
 {
        int bytecnt = 8;
index 6fcb2cf7b0b69f97b1532c9728dc49785401d4cc..625799ab0d14d5292c96d3c41e01c90148e55567 100644 (file)
@@ -172,7 +172,7 @@ struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel)
                return(NULL);
 }
 
-void
+static void
 write_ctrl(struct BCState *bcs, int which) {
 
        if (bcs->cs->debug & L1_DEB_HSCX)
@@ -193,7 +193,7 @@ write_ctrl(struct BCState *bcs, int which) {
        }
 }
 
-void
+static void
 modehdlc(struct BCState *bcs, int mode, int bc)
 {
        struct IsdnCardState *cs = bcs->cs;
@@ -451,7 +451,7 @@ HDLC_irq(struct BCState *bcs, u_int stat) {
        }
 }
 
-inline void
+static inline void
 HDLC_irq_main(struct IsdnCardState *cs)
 {
        u_int stat;
@@ -487,7 +487,7 @@ HDLC_irq_main(struct IsdnCardState *cs)
        }
 }
 
-void
+static void
 hdlc_l2l1(struct PStack *st, int pr, void *arg)
 {
        struct BCState *bcs = st->l1.bcs;
@@ -547,7 +547,7 @@ hdlc_l2l1(struct PStack *st, int pr, void *arg)
        }
 }
 
-void
+static void
 close_hdlcstate(struct BCState *bcs)
 {
        modehdlc(bcs, 0, 0);
@@ -570,7 +570,7 @@ close_hdlcstate(struct BCState *bcs)
        }
 }
 
-int
+static int
 open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs)
 {
        if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
@@ -598,7 +598,7 @@ open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs)
        return (0);
 }
 
-int
+static int
 setstack_hdlc(struct PStack *st, struct BCState *bcs)
 {
        bcs->channel = st->l1.bc;
@@ -612,6 +612,7 @@ setstack_hdlc(struct PStack *st, struct BCState *bcs)
        return (0);
 }
 
+#if 0
 void __init
 clear_pending_hdlc_ints(struct IsdnCardState *cs)
 {
@@ -641,8 +642,9 @@ clear_pending_hdlc_ints(struct IsdnCardState *cs)
                debugl1(cs, "HDLC 2 VIN %x", val);
        }
 }
+#endif  /*  0  */
 
-void __init
+static void __init
 inithdlc(struct IsdnCardState *cs)
 {
        cs->bcs[0].BC_SetStack = setstack_hdlc;
index 663a0bf703b707b6fcc2c6ebfa2de1cbbd409605..67c60e04a37bdb38f6e5108164b0c8c5a9ab30ee 100644 (file)
@@ -501,6 +501,13 @@ static int avma1cs_event(event_t event, int priority,
     return 0;
 } /* avma1cs_event */
 
+static struct pcmcia_device_id avma1cs_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
+       PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
+
 static struct pcmcia_driver avma1cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -508,6 +515,7 @@ static struct pcmcia_driver avma1cs_driver = {
        },
        .attach         = avma1cs_attach,
        .detach         = avma1cs_detach,
+       .id_table       = avma1cs_ids,
 };
  
 /*====================================================================*/
index f410f628a3e20202b72d942e78e7b8c6093e2669..dcb308aeb50cccdac293e64aae89a7ee7631fd9d 100644 (file)
@@ -23,7 +23,7 @@
 
 extern const char *CardType[];
 
-const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $";
+static const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $";
 
 
 static inline u_char
@@ -167,7 +167,7 @@ bkm_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        }
 }
 
-void
+static void
 release_io_bkm(struct IsdnCardState *cs)
 {
        if (cs->hw.ax.base) {
index 94bb83ce7fd82a28fc9ebb4ad89bf3c2cd20710b..5f21b82c8c8dcba3699b3ee89d112c3439313357 100644 (file)
@@ -27,7 +27,7 @@
 
 extern const char *CardType[];
 
-const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $";
+static const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $";
 
 static const char *sct_quadro_subtypes[] =
 {
@@ -193,7 +193,7 @@ bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-void
+static void
 release_io_sct_quadro(struct IsdnCardState *cs)
 {
        release_region(cs->hw.ax.base & 0xffffffc0, 128);
@@ -261,7 +261,7 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-int __init
+static int __init
 sct_alloc_io(u_int adr, u_int len)
 {
        if (!request_region(adr, len, "scitel")) {
index 04065ab2610f9f228754b2837ecc99d8753cdeb9..7c56c44f0fd16955be1e7c488bfc862e709f24a1 100644 (file)
@@ -874,7 +874,7 @@ release_b_st(struct Channel *chanp)
        } 
 }
 
-struct Channel
+static struct Channel
 *selectfreechannel(struct PStack *st, int bch)
 {
        struct IsdnCardState *cs = st->l1.hardware;
@@ -1429,7 +1429,7 @@ capi_debug(struct Channel *chanp, capi_msg *cm)
        HiSax_putstatus(chanp->cs, "Ch", "%d CAPIMSG %s", chanp->chan, tmpbuf);
 }
 
-void
+static void
 lli_got_fac_req(struct Channel *chanp, capi_msg *cm) {
        if ((cm->para[0] != 3) || (cm->para[1] != 0))
                return;
@@ -1454,7 +1454,7 @@ lli_got_fac_req(struct Channel *chanp, capi_msg *cm) {
        }
 }
 
-void
+static void
 lli_got_manufacturer(struct Channel *chanp, struct IsdnCardState *cs, capi_msg *cm) {
        if ((cs->typ == ISDN_CTYPE_ELSA) || (cs->typ == ISDN_CTYPE_ELSA_PNP) ||
                (cs->typ == ISDN_CTYPE_ELSA_PCI)) {
index 1663ee69d41d22a3afc0e2312359a69892855393..c542e6fb2bde736f4c8a1e5efeda10e6c2bb46f0 100644 (file)
@@ -332,7 +332,7 @@ struct IsdnCard cards[HISAX_MAX_CARDS] = {
 #define HISAX_IDSIZE (HISAX_MAX_CARDS*8)
 static char HiSaxID[HISAX_IDSIZE] = { 0, };
 
-char *HiSax_id = HiSaxID;
+static char *HiSax_id = HiSaxID;
 #ifdef MODULE
 /* Variables for insmod */
 static int type[HISAX_MAX_CARDS] = { 0, };
@@ -391,7 +391,7 @@ char *HiSax_getrev(const char *revision)
        return rev;
 }
 
-void __init HiSaxVersion(void)
+static void __init HiSaxVersion(void)
 {
        char tmp[64];
 
@@ -608,6 +608,7 @@ static inline struct IsdnCardState *hisax_findcard(int driverid)
 /*
  * Find card with given card number
  */
+#if 0
 struct IsdnCardState *hisax_get_card(int cardnr)
 {
        if ((cardnr <= nrcards) && (cardnr > 0))
@@ -615,8 +616,9 @@ struct IsdnCardState *hisax_get_card(int cardnr)
                        return cards[cardnr - 1].cs;
        return NULL;
 }
+#endif  /*  0  */
 
-int HiSax_readstatus(u_char __user *buf, int len, int id, int channel)
+static int HiSax_readstatus(u_char __user *buf, int len, int id, int channel)
 {
        int count, cnt;
        u_char __user *p = buf;
@@ -768,7 +770,7 @@ int ll_run(struct IsdnCardState *cs, int addfeatures)
        return 0;
 }
 
-void ll_stop(struct IsdnCardState *cs)
+static void ll_stop(struct IsdnCardState *cs)
 {
        isdn_ctrl ic;
 
@@ -1184,7 +1186,7 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow
        return ret;
 }
 
-void HiSax_shiftcards(int idx)
+static void HiSax_shiftcards(int idx)
 {
        int i;
 
@@ -1192,7 +1194,7 @@ void HiSax_shiftcards(int idx)
                memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
 }
 
-int HiSax_inithardware(int *busy_flag)
+static int HiSax_inithardware(int *busy_flag)
 {
        int foundcards = 0;
        int i = 0;
index 394d481e093fde584c61ce5e13545b66bdd8f6a6..b62d6b30b72b861711090ef5d7fd2b591b615828 100644 (file)
@@ -28,7 +28,7 @@
 
 extern const char *CardType[];
 
-const char *Diva_revision = "$Revision: 1.33.2.6 $";
+static const char *Diva_revision = "$Revision: 1.33.2.6 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -706,7 +706,7 @@ diva_irq_ipacx_pci(int intno, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-void
+static void
 release_io_diva(struct IsdnCardState *cs)
 {
        int bytecnt;
index 4d7a0250d7e20b8c59de10799f9f526e4379f8be..110e9fd669c53a98b36b271a4771d7034a4c8549 100644 (file)
 
 extern const char *CardType[];
 
-const char *Elsa_revision = "$Revision: 2.32.2.4 $";
-const char *Elsa_Types[] =
+static const char *Elsa_revision = "$Revision: 2.32.2.4 $";
+static const char *Elsa_Types[] =
 {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
  "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", 
  "PCMCIA-IPAC" };
 
-const char *ITACVer[] =
+static const char *ITACVer[] =
 {"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2",
  "B1", "A1"};
 
@@ -425,7 +425,7 @@ Start_IPAC:
        return IRQ_HANDLED;
 }
 
-void
+static void
 release_io_elsa(struct IsdnCardState *cs)
 {
        int bytecnt = 8;
index bfc013225f46d9d35317e602ce048c06e173a3fd..9146be547044a071fd3d6ebc6cb6eb32eff22ae4 100644 (file)
@@ -508,6 +508,13 @@ static int elsa_cs_event(event_t event, int priority,
     return 0;
 } /* elsa_cs_event */
 
+static struct pcmcia_device_id elsa_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
+       PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
+
 static struct pcmcia_driver elsa_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -515,6 +522,7 @@ static struct pcmcia_driver elsa_cs_driver = {
        },
        .attach         = elsa_cs_attach,
        .detach         = elsa_cs_detach,
+       .id_table       = elsa_ids,
 };
 
 static int __init init_elsa_cs(void)
index 689c83395693a9d2ccc3ba124f302a4597244b86..898ec0916195a9b788a4679fad5bbd3b8fe50015 100644 (file)
@@ -237,7 +237,7 @@ static void mshutdown(struct IsdnCardState *cs)
 #endif
 }
 
-inline int
+static inline int
 write_modem(struct BCState *bcs) {
        int ret=0;
        struct IsdnCardState *cs = bcs->cs;
@@ -275,7 +275,7 @@ write_modem(struct BCState *bcs) {
        return(ret);
 }
 
-inline void
+static inline void
 modem_fill(struct BCState *bcs) {
                
        if (bcs->tx_skb) {
@@ -422,7 +422,7 @@ extern int open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs);
 extern void modehscx(struct BCState *bcs, int mode, int bc);
 extern void hscx_l2l1(struct PStack *st, int pr, void *arg);
 
-void
+static void
 close_elsastate(struct BCState *bcs)
 {
        modehscx(bcs, 0, bcs->channel);
@@ -442,7 +442,7 @@ close_elsastate(struct BCState *bcs)
        }
 }
 
-void
+static void
 modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) {
        int count, fp;
        u_char *msg = buf;
@@ -472,7 +472,7 @@ modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) {
        }
 }
 
-void
+static void
 modem_set_init(struct IsdnCardState *cs) {
        int timeout;
 
@@ -521,7 +521,7 @@ modem_set_init(struct IsdnCardState *cs) {
        udelay(RCV_DELAY);
 }
 
-void
+static void
 modem_set_dial(struct IsdnCardState *cs, int outgoing) {
        int timeout;
 #define RCV_DELAY 20000        
@@ -543,7 +543,7 @@ modem_set_dial(struct IsdnCardState *cs, int outgoing) {
        udelay(RCV_DELAY);
 }
 
-void
+static void
 modem_l2l1(struct PStack *st, int pr, void *arg)
 {
        struct BCState *bcs = st->l1.bcs;
@@ -579,7 +579,7 @@ modem_l2l1(struct PStack *st, int pr, void *arg)
        }
 }
 
-int
+static int
 setstack_elsa(struct PStack *st, struct BCState *bcs)
 {
 
@@ -614,7 +614,7 @@ setstack_elsa(struct PStack *st, struct BCState *bcs)
        return (0);
 }
 
-void
+static void
 init_modem(struct IsdnCardState *cs) {
 
        cs->bcs[0].BC_SetStack = setstack_elsa;
@@ -641,7 +641,7 @@ init_modem(struct IsdnCardState *cs) {
        modem_set_init(cs);
 }
 
-void
+static void
 release_modem(struct IsdnCardState *cs) {
 
        cs->hw.elsa.MFlag = 0;
diff --git a/drivers/isdn/hisax/enternow.h b/drivers/isdn/hisax/enternow.h
deleted file mode 100644 (file)
index ed2eec5..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* 2001/10/02
- *
- * enternow.h   Header-file included by
- *              enternow_pci.c
- *
- * Author       Christoph Ersfeld <info@formula-n.de>
- *              Formula-n Europe AG (www.formula-n.com)
- *              previously Gerdes AG
- *
- *
- *              This file is (c) under GNU PUBLIC LICENSE
- */
-
-
-/* ***************************************************************************************** *
- * ****************************** datatypes and macros ************************************* *
- * ***************************************************************************************** */
-
-#define BYTE                                                   unsigned char
-#define WORD                                                   unsigned int
-#define HIBYTE(w)                                              ((unsigned char)((w & 0xff00) / 256))
-#define LOBYTE(w)                                              ((unsigned char)(w & 0x00ff))
-#define InByte(addr)                                           inb(addr)
-#define OutByte(addr,val)                                      outb(val,addr)
-
-
-
-/* ***************************************************************************************** *
- * *********************************** card-specific *************************************** *
- * ***************************************************************************************** */
-
-/* für PowerISDN PCI */
-#define TJ_AMD_IRQ                                             0x20
-#define TJ_LED1                                                0x40
-#define TJ_LED2                                                0x80
-
-
-/* Das Fenster zum AMD...
- * Ab Adresse hw.njet.base + TJ_AMD_PORT werden vom AMD jeweils 8 Bit in
- * den TigerJet i/o-Raum gemappt
- * -> 0x01 des AMD bei hw.njet.base + 0C4 */
-#define TJ_AMD_PORT                                            0xC0
-
-
-
-/* ***************************************************************************************** *
- * *************************************** Prototypen ************************************** *
- * ***************************************************************************************** */
-
-BYTE ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset);
-void WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value);
index 1cc4d11e007a00786d10b4411a6e6622aef425fa..3341cf1555312ee7e7672269373b7bdb42b55531 100644 (file)
@@ -65,7 +65,6 @@
 #include "isac.h"
 #include "isdnl1.h"
 #include "amd7930_fn.h"
-#include "enternow.h"
 #include <linux/interrupt.h>
 #include <linux/ppp_defs.h>
 #include <linux/pci.h>
 
 
 
-const char *enternow_pci_rev = "$Revision: 1.1.4.5 $";
+static const char *enternow_pci_rev = "$Revision: 1.1.4.5 $";
+
+
+/* für PowerISDN PCI */
+#define TJ_AMD_IRQ                                              0x20
+#define TJ_LED1                                                 0x40
+#define TJ_LED2                                                 0x80
+
+
+/* Das Fenster zum AMD...
+ * Ab Adresse hw.njet.base + TJ_AMD_PORT werden vom AMD jeweils 8 Bit in
+ * den TigerJet i/o-Raum gemappt
+ * -> 0x01 des AMD bei hw.njet.base + 0C4 */
+#define TJ_AMD_PORT                                             0xC0
+
 
 
 /* *************************** I/O-Interface functions ************************************* */
 
 
 /* cs->readisac, macro rByteAMD */
-BYTE
-ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset)
+static unsigned char
+ReadByteAmd7930(struct IsdnCardState *cs, unsigned char offset)
 {
        /* direktes Register */
        if(offset < 8)
-               return (InByte(cs->hw.njet.isac + 4*offset));
+               return (inb(cs->hw.njet.isac + 4*offset));
 
        /* indirektes Register */
        else {
-               OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
-               return(InByte(cs->hw.njet.isac + 4*AMD_DR));
+               outb(offset, cs->hw.njet.isac + 4*AMD_CR);
+               return(inb(cs->hw.njet.isac + 4*AMD_DR));
        }
 }
 
 /* cs->writeisac, macro wByteAMD */
-void
-WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value)
+static void
+WriteByteAmd7930(struct IsdnCardState *cs, unsigned char offset, unsigned char value)
 {
        /* direktes Register */
        if(offset < 8)
-               OutByte(cs->hw.njet.isac + 4*offset, value);
+               outb(value, cs->hw.njet.isac + 4*offset);
 
        /* indirektes Register */
        else {
-               OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
-               OutByte(cs->hw.njet.isac + 4*AMD_DR, value);
+               outb(offset, cs->hw.njet.isac + 4*AMD_CR);
+               outb(value, cs->hw.njet.isac + 4*AMD_DR);
        }
 }
 
 
-void
-enpci_setIrqMask(struct IsdnCardState *cs, BYTE val) {
+static void
+enpci_setIrqMask(struct IsdnCardState *cs, unsigned char val) {
         if (!val)
-               OutByte(cs->hw.njet.base+NETJET_IRQMASK1, 0x00);
+               outb(0x00, cs->hw.njet.base+NETJET_IRQMASK1);
         else
-               OutByte(cs->hw.njet.base+NETJET_IRQMASK1, TJ_AMD_IRQ);
+               outb(TJ_AMD_IRQ, cs->hw.njet.base+NETJET_IRQMASK1);
 }
 
 
-static BYTE dummyrr(struct IsdnCardState *cs, int chan, BYTE off)
+static unsigned char dummyrr(struct IsdnCardState *cs, int chan, unsigned char off)
 {
         return(5);
 }
 
-static void dummywr(struct IsdnCardState *cs, int chan, BYTE off, BYTE value)
+static void dummywr(struct IsdnCardState *cs, int chan, unsigned char off, unsigned char value)
 {
 
 }
@@ -142,18 +155,18 @@ reset_enpci(struct IsdnCardState *cs)
 
        /* Reset on, (also for AMD) */
        cs->hw.njet.ctrl_reg = 0x07;
-       OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+       outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
        mdelay(20);
        /* Reset off */
        cs->hw.njet.ctrl_reg = 0x30;
-       OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+       outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
        /* 20ms delay */
        mdelay(20);
        cs->hw.njet.auxd = 0;  // LED-status
        cs->hw.njet.dmactrl = 0;
-       OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
-       OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
-       OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); // LED off
+       outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL);
+       outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
+       outb(cs->hw.njet.auxd, cs->hw.njet.auxa); // LED off
 }
 
 
@@ -161,7 +174,7 @@ static int
 enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
        u_long flags;
-        BYTE *chan;
+        unsigned char *chan;
 
        if (cs->debug & L1_DEB_ISAC)
                debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt);
@@ -187,16 +200,16 @@ enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                 case MDL_ASSIGN:
                         /* TEI assigned, LED1 on */
                         cs->hw.njet.auxd = TJ_AMD_IRQ << 1;
-                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                        outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
                         break;
                 case MDL_REMOVE:
                         /* TEI removed, LEDs off */
                        cs->hw.njet.auxd = 0;
-                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, 0x00);
+                        outb(0x00, cs->hw.njet.base + NETJET_AUXDATA);
                         break;
                 case MDL_BC_ASSIGN:
                         /* activate B-channel */
-                        chan = (BYTE *)arg;
+                        chan = (unsigned char *)arg;
 
                         if (cs->debug & L1_DEB_ISAC)
                                debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan);
@@ -204,11 +217,11 @@ enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                         cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN");
                         /* at least one b-channel in use, LED 2 on */
                         cs->hw.njet.auxd |= TJ_AMD_IRQ << 2;
-                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                        outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
                         break;
                 case MDL_BC_RELEASE:
                         /* deactivate B-channel */
-                        chan = (BYTE *)arg;
+                        chan = (unsigned char *)arg;
 
                         if (cs->debug & L1_DEB_ISAC)
                                debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan);
@@ -217,7 +230,7 @@ enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                         /* no b-channel active -> LED2 off */
                         if (!(cs->dc.amd7930.lmr1 & 3)) {
                                 cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2);
-                                OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                                outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
                         }
                         break;
                 default:
@@ -231,11 +244,11 @@ static irqreturn_t
 enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
        struct IsdnCardState *cs = dev_id;
-       BYTE s0val, s1val, ir;
+       unsigned char s0val, s1val, ir;
        u_long flags;
 
        spin_lock_irqsave(&cs->lock, flags);
-       s1val = InByte(cs->hw.njet.base + NETJET_IRQSTAT1);
+       s1val = inb(cs->hw.njet.base + NETJET_IRQSTAT1);
 
         /* AMD threw an interrupt */
        if (!(s1val & TJ_AMD_IRQ)) {
@@ -245,13 +258,13 @@ enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
                s1val = 1;
        } else
                s1val = 0;
-       s0val = InByte(cs->hw.njet.base + NETJET_IRQSTAT0);
+       s0val = inb(cs->hw.njet.base + NETJET_IRQSTAT0);
        if ((s0val | s1val)==0) { // shared IRQ
                spin_unlock_irqrestore(&cs->lock, flags);
                return IRQ_NONE;
        } 
        if (s0val)
-               OutByte(cs->hw.njet.base + NETJET_IRQSTAT0, s0val);
+               outb(s0val, cs->hw.njet.base + NETJET_IRQSTAT0);
 
        /* DMA-Interrupt: B-channel-stuff */
        /* set bits in sval to indicate which page is free */
@@ -342,20 +355,20 @@ setup_enternow_pci(struct IsdnCard *card)
 
                /* Reset an */
                cs->hw.njet.ctrl_reg = 0x07;  // geändert von 0xff
-               OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+               outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
                /* 20 ms Pause */
                mdelay(20);
 
                cs->hw.njet.ctrl_reg = 0x30;  /* Reset Off and status read clear */
-               OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+               outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
                mdelay(10);
 
                cs->hw.njet.auxd = 0x00; // war 0xc0
                cs->hw.njet.dmactrl = 0;
 
-               OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
-               OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
-               OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd);
+               outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL);
+               outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
+               outb(cs->hw.njet.auxd, cs->hw.njet.auxa);
 
                break;
        }
index 24a05a43f33e35ca78d142cb1ead3bdab60cd8fe..352b45ac5347239c0911c445da6da7f66767b249 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/pci.h>
 
 extern const char *CardType[];
-const char *gazel_revision = "$Revision: 2.19.2.4 $";
+static const char *gazel_revision = "$Revision: 2.19.2.4 $";
 
 #define R647      1
 #define R685      2
@@ -317,7 +317,8 @@ gazel_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
        spin_unlock_irqrestore(&cs->lock, flags);
        return IRQ_HANDLED;
 }
-void
+
+static void
 release_io_gazel(struct IsdnCardState *cs)
 {
        unsigned int i;
index ba1d028343ecd8e869a39d971d6a5d27e74b94e5..7333377ab31de0cc9e7d866626c9c9dd8cd9de88 100644 (file)
@@ -312,7 +312,7 @@ wait_busy(hfc4s8s_hw * a)
 /* function to read critical counter registers that   */
 /* may be udpated by the chip during read             */
 /******************************************************/
-static volatile u_char
+static u_char
 Read_hfc8_stable(hfc4s8s_hw * hw, int reg)
 {
        u_char ref8;
@@ -324,7 +324,7 @@ Read_hfc8_stable(hfc4s8s_hw * hw, int reg)
        return in8;
 }
 
-static volatile int
+static int
 Read_hfc16_stable(hfc4s8s_hw * hw, int reg)
 {
        int ref16;
@@ -1358,7 +1358,7 @@ chipreset(hfc4s8s_hw * hw)
 /********************************************/
 /* disable/enable hardware in nt or te mode */
 /********************************************/
-void
+static void
 hfc_hardware_enable(hfc4s8s_hw * hw, int enable, int nt_mode)
 {
        u_long flags;
@@ -1465,7 +1465,7 @@ hfc_hardware_enable(hfc4s8s_hw * hw, int enable, int nt_mode)
 /******************************************/
 /* disable memory mapped ports / io ports */
 /******************************************/
-void
+static void
 release_pci_ports(hfc4s8s_hw * hw)
 {
        pci_write_config_word(hw->pdev, PCI_COMMAND, 0);
@@ -1481,7 +1481,7 @@ release_pci_ports(hfc4s8s_hw * hw)
 /*****************************************/
 /* enable memory mapped ports / io ports */
 /*****************************************/
-void
+static void
 enable_pci_ports(hfc4s8s_hw * hw)
 {
 #ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
index ebea3feef003ad0e9f4008573fc67ca6ad6fc1ec..7cf87793e7907d5bdf4d354a1fc4011cce151ad6 100644 (file)
@@ -345,7 +345,7 @@ hfc_send_data(struct BCState *bcs)
                debugl1(cs,"send_data %d blocked", bcs->channel);
 }
 
-void
+static void
 main_rec_2bds0(struct BCState *bcs)
 {
        struct IsdnCardState *cs = bcs->cs;
@@ -399,7 +399,7 @@ main_rec_2bds0(struct BCState *bcs)
        return;
 }
 
-void
+static void
 mode_2bs0(struct BCState *bcs, int mode, int bc)
 {
        struct IsdnCardState *cs = bcs->cs;
@@ -505,7 +505,7 @@ hfc_l2l1(struct PStack *st, int pr, void *arg)
        }
 }
 
-void
+static void
 close_2bs0(struct BCState *bcs)
 {
        mode_2bs0(bcs, 0, bcs->channel);
@@ -534,7 +534,7 @@ open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs)
        return (0);
 }
 
-int
+static int
 setstack_2b(struct PStack *st, struct BCState *bcs)
 {
        bcs->channel = st->l1.bc;
@@ -1004,7 +1004,7 @@ HFCD_l1hw(struct PStack *st, int pr, void *arg)
        }
 }
 
-void
+static void
 setstack_hfcd(struct PStack *st, struct IsdnCardState *cs)
 {
        st->l1.l1hw = HFCD_l1hw;
@@ -1015,7 +1015,7 @@ hfc_dbusy_timer(struct IsdnCardState *cs)
 {
 }
 
-unsigned int __init
+static unsigned int __init
 *init_send_hfcd(int cnt)
 {
        int i, *send;
index bb376f39ac89d9b06e3c0d76828a8c5aa6f1565a..f978a5af866292489ceb58b267219c5a3b86b32e 100644 (file)
@@ -52,7 +52,7 @@ WaitNoBusy(struct IsdnCardState *cs)
                return (to);
 }
 
-int
+static int
 GetFreeFifoBytes(struct BCState *bcs)
 {
        int s;
@@ -66,7 +66,7 @@ GetFreeFifoBytes(struct BCState *bcs)
        return (s);
 }
 
-int
+static int
 ReadZReg(struct BCState *bcs, u_char reg)
 {
        int val;
@@ -394,7 +394,7 @@ main_irq_hfc(struct BCState *bcs)
        return;
 }
 
-void
+static void
 mode_hfc(struct BCState *bcs, int mode, int bc)
 {
        struct IsdnCardState *cs = bcs->cs;
@@ -507,7 +507,7 @@ hfc_l2l1(struct PStack *st, int pr, void *arg)
 }
 
 
-void
+static void
 close_hfcstate(struct BCState *bcs)
 {
        mode_hfc(bcs, 0, bcs->channel);
@@ -537,7 +537,7 @@ open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs)
        return (0);
 }
 
-int
+static int
 setstack_hfc(struct PStack *st, struct BCState *bcs)
 {
        bcs->channel = st->l1.bc;
@@ -551,7 +551,7 @@ setstack_hfc(struct PStack *st, struct BCState *bcs)
        return (0);
 }
 
-void __init
+static void __init
 init_send(struct BCState *bcs)
 {
        int i;
index c2db52696a86bb2350261556116877aa1fe8e06c..8337b0f26cc40183e0846c683bbd43797f4a97bf 100644 (file)
@@ -70,7 +70,7 @@ static const PCI_ENTRY id_list[] =
 /******************************************/
 /* free hardware resources used by driver */
 /******************************************/
-void
+static void
 release_io_hfcpci(struct IsdnCardState *cs)
 {
        printk(KERN_INFO "HiSax: release hfcpci at %p\n",
@@ -394,7 +394,7 @@ receive_dmsg(struct IsdnCardState *cs)
 /*******************************************************************************/
 /* check for transparent receive data and read max one threshold size if avail */
 /*******************************************************************************/
-int
+static int
 hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u_char * bdata)
 {
        unsigned short *z1r, *z2r;
@@ -446,7 +446,7 @@ hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u_char * bdata)
 /**********************************/
 /* B-channel main receive routine */
 /**********************************/
-void
+static void
 main_rec_hfcpci(struct BCState *bcs)
 {
        struct IsdnCardState *cs = bcs->cs;
@@ -1244,7 +1244,7 @@ HFCPCI_l1hw(struct PStack *st, int pr, void *arg)
 /***********************************************/
 /* called during init setting l1 stack pointer */
 /***********************************************/
-void
+static void
 setstack_hfcpci(struct PStack *st, struct IsdnCardState *cs)
 {
        st->l1.l1hw = HFCPCI_l1hw;
@@ -1268,7 +1268,7 @@ hfcpci_send_data(struct BCState *bcs)
 /***************************************************************/
 /* activate/deactivate hardware for selected channels and mode */
 /***************************************************************/
-void
+static void
 mode_hfcpci(struct BCState *bcs, int mode, int bc)
 {
        struct IsdnCardState *cs = bcs->cs;
@@ -1579,7 +1579,7 @@ hfcpci_bh(struct IsdnCardState *cs)
 /********************************/
 /* called for card init message */
 /********************************/
-void __init
+static void __init
 inithfcpci(struct IsdnCardState *cs)
 {
        cs->bcs[0].BC_SetStack = setstack_2b;
index 4df036ed1af0aa9d5816574d94ef2c0385c429d2..9ef2981e404ed5ba96f87080295eacf3bf46857a 100644 (file)
@@ -232,5 +232,4 @@ typedef union {
 #define Read_hfc(a,b) (*(((u_char *)a->hw.hfcpci.pci_io)+b))
 
 extern void main_irq_hcpci(struct BCState *bcs);
-extern void inithfcpci(struct IsdnCardState *cs);
 extern void releasehfcpci(struct IsdnCardState *cs);
index a307fcb6c6349304dbd163ca300b736bd15ea72c..f27c1608a3a706ba482d4163b0f67c2393e9dedd 100644 (file)
@@ -308,7 +308,7 @@ read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max)
 /******************************************/
 /* free hardware resources used by driver */
 /******************************************/
-void
+static void
 release_io_hfcsx(struct IsdnCardState *cs)
 {
        cs->hw.hfcsx.int_m2 = 0;        /* interrupt output off ! */
@@ -472,7 +472,7 @@ receive_dmsg(struct IsdnCardState *cs)
 /**********************************/
 /* B-channel main receive routine */
 /**********************************/
-void
+static void
 main_rec_hfcsx(struct BCState *bcs)
 {
        struct IsdnCardState *cs = bcs->cs;
@@ -1003,7 +1003,7 @@ HFCSX_l1hw(struct PStack *st, int pr, void *arg)
 /***********************************************/
 /* called during init setting l1 stack pointer */
 /***********************************************/
-void
+static void
 setstack_hfcsx(struct PStack *st, struct IsdnCardState *cs)
 {
        st->l1.l1hw = HFCSX_l1hw;
@@ -1027,7 +1027,7 @@ hfcsx_send_data(struct BCState *bcs)
 /***************************************************************/
 /* activate/deactivate hardware for selected channels and mode */
 /***************************************************************/
-void
+static void
 mode_hfcsx(struct BCState *bcs, int mode, int bc)
 {
        struct IsdnCardState *cs = bcs->cs;
@@ -1328,7 +1328,7 @@ hfcsx_bh(struct IsdnCardState *cs)
 /********************************/
 /* called for card init message */
 /********************************/
-void __devinit
+static void __devinit
 inithfcsx(struct IsdnCardState *cs)
 {
        cs->setstack_d = setstack_hfcsx;
index 12f54159344aa3ad7970052b89177462250e58f1..6792f13dc22011f3b57a3da96b793f280e8a9bbc 100644 (file)
@@ -193,5 +193,4 @@ struct hfcsx_extra {
 };
 
 extern void main_irq_hfcsx(struct BCState *bcs);
-extern void inithfcsx(struct IsdnCardState *cs);
 extern void releasehfcsx(struct IsdnCardState *cs);
index ffd74b84f502e0f999b2c40725de5aabf8331320..e2c3af49d72b9af938d47fd109924d74e7c84949 100644 (file)
@@ -60,7 +60,7 @@ static const char *hfcusb_revision =
 #include "hisax_debug.h"
 static u_int debug;
 module_param(debug, uint, 0);
-int hfc_debug;
+static int hfc_debug;
 #endif
 
 
@@ -85,7 +85,7 @@ static struct usb_device_id hfc_usb_idtab[] = {
 *   VendorID, ProductID, Devicename, LED_SCHEME,
 *   LED's BitMask in HFCUSB_P_DATA Register : LED_USB, LED_S0, LED_B1, LED_B2
 */
-vendor_data vdata[] = {
+static vendor_data vdata[] = {
        /* CologneChip Eval TA */
        {0x0959, 0x2bd0, "ISDN USB TA (Cologne Chip HFC-S USB based)",
         LED_OFF, {4, 0, 2, 1}
@@ -1137,7 +1137,7 @@ set_hfcmode(hfcusb_data * hfc, int channel, int mode)
        }
 }
 
-void
+static void
 hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
 {
        usb_fifo *fifo = my_hisax_if->priv;
index b171600cf641273b039aeefe0d505a15e66039fc..280dd29b30d6fbd0efaaf0f715a15637ab759b49 100644 (file)
@@ -168,7 +168,7 @@ static struct hfcusb_symbolic_list urb_errlist[] = {
 * 3 entries are the configuration number, the minimum interval for
 * Interrupt endpoints & boolean if E-channel logging possible
 */
-int validconf[][19] = {
+static int validconf[][19] = {
        // INT in, ISO out config
        {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT,
         EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
@@ -187,7 +187,7 @@ int validconf[][19] = {
 };
 
 // string description of chosen config
-char *conf_str[] = {
+static char *conf_str[] = {
        "4 Interrupt IN + 3 Isochron OUT",
        "3 Interrupt IN + 3 Isochron OUT",
        "4 Isochron IN + 3 Isochron OUT",
index 6fc55fea17029bb70428d8231a4e66662b1f931c..86ab1c13f6b15e7ab56f11aed977247809fd2f85 100644 (file)
@@ -52,7 +52,7 @@ hfcs_Timer(struct IsdnCardState *cs)
 */
 }
 
-void
+static void
 release_io_hfcs(struct IsdnCardState *cs)
 {
        release2bds0(cs);
index dc5791728d537f8311b7ba69cffc6bc4934aea6d..17cf7663c58233fda3610b9890d2e663254ba643 100644 (file)
@@ -1271,7 +1271,6 @@ extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf,
 void init_bcstate(struct IsdnCardState *cs, int bc);
 
 void setstack_HiSax(struct PStack *st, struct IsdnCardState *cs);
-unsigned int random_ri(void);
 void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st);
 void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st);
 
@@ -1315,15 +1314,11 @@ int QuickHex(char *txt, u_char * p, int cnt);
 void LogFrame(struct IsdnCardState *cs, u_char * p, int size);
 void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir);
 void iecpy(u_char * dest, u_char * iestart, int ieoffset);
-#ifdef ISDN_CHIP_ISAC
-void setstack_isac(struct PStack *st, struct IsdnCardState *cs);
-#endif /* ISDN_CHIP_ISAC */
 #endif /* __KERNEL__ */
 
 #define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);}
 
 int ll_run(struct IsdnCardState *cs, int addfeatures);
-void ll_stop(struct IsdnCardState *cs);
 int CallcNew(void);
 void CallcFree(void);
 int CallcNewChan(struct IsdnCardState *cs);
index 5bbbe3e951250708dbf6acd62fe2057101a27434..66dbaee77bfbd005ecd5db41b32e4cd459bec8c3 100644 (file)
@@ -151,7 +151,7 @@ hscx_l2l1(struct PStack *st, int pr, void *arg)
        }
 }
 
-void
+static void
 close_hscxstate(struct BCState *bcs)
 {
        modehscx(bcs, 0, bcs->channel);
@@ -203,7 +203,7 @@ open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs)
        return (0);
 }
 
-int
+static int
 setstack_hscx(struct PStack *st, struct BCState *bcs)
 {
        bcs->channel = st->l1.bc;
index dcf31f83c6000da39c2bd84cd888ad12b6bcb942..b4ca5859b1777cb1e99f88f7fb95714644a845ee 100644 (file)
@@ -108,7 +108,7 @@ icc_bh(struct IsdnCardState *cs)
 #endif
 }
 
-void
+static void
 icc_empty_fifo(struct IsdnCardState *cs, int count)
 {
        u_char *ptr;
@@ -563,13 +563,13 @@ ICC_l1hw(struct PStack *st, int pr, void *arg)
        }
 }
 
-void
+static void
 setstack_icc(struct PStack *st, struct IsdnCardState *cs)
 {
        st->l1.l1hw = ICC_l1hw;
 }
 
-void 
+static void
 DC_Close_icc(struct IsdnCardState *cs) {
        if (cs->dc.icc.mon_rx) {
                kfree(cs->dc.icc.mon_rx);
index 6485e232d86936f728ebb70be5957f929f654cdb..efba2f44801797f726f30c6033b14dfc3d65611a 100644 (file)
@@ -36,8 +36,6 @@ static void ph_command(struct IsdnCardState *cs, unsigned int command);
 static inline void cic_int(struct IsdnCardState *cs);
 static void dch_l2l1(struct PStack *st, int pr, void *arg);
 static void dbusy_timer_handler(struct IsdnCardState *cs);
-static void ipacx_new_ph(struct IsdnCardState *cs);
-static void dch_bh(struct IsdnCardState *cs);
 static void dch_empty_fifo(struct IsdnCardState *cs, int count);
 static void dch_fill_fifo(struct IsdnCardState *cs);
 static inline void dch_int(struct IsdnCardState *cs);
@@ -231,81 +229,6 @@ dbusy_timer_handler(struct IsdnCardState *cs)
        }
 }
 
-//----------------------------------------------------------
-// L1 state machine intermediate layer to isdnl1 module
-//----------------------------------------------------------
-static void
-ipacx_new_ph(struct IsdnCardState *cs)
-{
-       switch (cs->dc.isac.ph_state) {
-               case (IPACX_IND_RES):
-                       ph_command(cs, IPACX_CMD_DI);
-                       l1_msg(cs, HW_RESET | INDICATION, NULL);
-                       break;
-      
-               case (IPACX_IND_DC):
-                       l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
-                       break;
-      
-               case (IPACX_IND_DR):
-                       l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
-                       break;
-      
-               case (IPACX_IND_PU):
-                       l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
-                       break;
-
-               case (IPACX_IND_RSY):
-                       l1_msg(cs, HW_RSYNC | INDICATION, NULL);
-                       break;
-
-               case (IPACX_IND_AR):
-                       l1_msg(cs, HW_INFO2 | INDICATION, NULL);
-                       break;
-      
-               case (IPACX_IND_AI8):
-                       l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
-                       break;
-      
-               case (IPACX_IND_AI10):
-                       l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
-                       break;
-      
-               default:
-                       break;
-       }
-}
-
-//----------------------------------------------------------
-// bottom half handler for D channel
-//----------------------------------------------------------
-static void
-dch_bh(struct IsdnCardState *cs)
-{
-       struct PStack *st;
-       
-       if (!cs) return;
-  
-       if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
-               if (cs->debug) debugl1(cs, "D-Channel Busy cleared");
-               for (st = cs->stlist; st; st = st->next) {
-                       st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL);
-               }
-       }
-  
-       if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
-               DChannel_proc_rcv(cs);
-  }  
-  
-       if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
-               DChannel_proc_xmt(cs);
-  }  
-  
-       if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
-    ipacx_new_ph(cs);
-  }  
-}
-
 //----------------------------------------------------------
 // Fill buffer from receive FIFO
 //----------------------------------------------------------
@@ -991,14 +914,5 @@ init_ipacx(struct IsdnCardState *cs, int part)
        }
 }
 
-
-void __devinit
-setup_ipacx(struct IsdnCardState *cs)
-{
-       INIT_WORK(&cs->tqueue, (void *)(void *) dch_bh, cs);
-       cs->dbusytimer.function = (void *) dbusy_timer_handler;
-       cs->dbusytimer.data = (long) cs;
-       init_timer(&cs->dbusytimer);
-}
 //----------------- end of file -----------------------
 
index 20b9499529528c6d8cfa37ca7c1eda643ab613e0..85e063a08d23e3410215e8c519a729b59a5352de 100644 (file)
@@ -112,7 +112,7 @@ isac_bh(struct IsdnCardState *cs)
 #endif
 }
 
-void
+static void
 isac_empty_fifo(struct IsdnCardState *cs, int count)
 {
        u_char *ptr;
@@ -563,13 +563,13 @@ ISAC_l1hw(struct PStack *st, int pr, void *arg)
        }
 }
 
-void
+static void
 setstack_isac(struct PStack *st, struct IsdnCardState *cs)
 {
        st->l1.l1hw = ISAC_l1hw;
 }
 
-void 
+static void
 DC_Close_isac(struct IsdnCardState *cs) {
        if (cs->dc.isac.mon_rx) {
                kfree(cs->dc.isac.mon_rx);
index ee081321efb25e6e9741ded87490ac0bc6dab641..642a87c51295c70055509678fa71a370a766f9f2 100644 (file)
 #define ETX    0x03
 
 #define FAXMODCNT      13
-const  u_char  faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146};
+static const   u_char  faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146};
 static u_int   modmask = 0x1fff;
 static int     frm_extra_delay = 2;
 static int     para_TOA = 6;
-const   u_char  *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL" };
+static const   u_char  *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL" };
 
-void isar_setup(struct IsdnCardState *cs);
+static void isar_setup(struct IsdnCardState *cs);
 static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para);
 static void ll_deliver_faxstat(struct BCState *bcs, u_char status);
 
@@ -45,7 +45,7 @@ waitforHIA(struct IsdnCardState *cs, int timeout)
 }
 
 
-int
+static int
 sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len,
        u_char *msg)
 {
@@ -85,7 +85,7 @@ sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len,
 }
 
 /* Call only with IRQ disabled !!! */
-inline void
+static inline void
 rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg)
 {
        int i;
@@ -114,7 +114,7 @@ rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg)
 }
 
 /* Call only with IRQ disabled !!! */
-inline void
+static inline void
 get_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg)
 {
        ireg->iis = cs->BC_Read_Reg(cs, 1, ISAR_IIS);
@@ -127,7 +127,7 @@ get_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg)
 #endif
 }
 
-int
+static int
 waitrecmsg(struct IsdnCardState *cs, u_char *len,
        u_char *msg, int maxdelay)
 {
@@ -185,7 +185,7 @@ ISARVersion(struct IsdnCardState *cs, char *s)
        return(ver);
 }
 
-int
+static int
 isar_load_firmware(struct IsdnCardState *cs, u_char __user *buf)
 {
        int ret, size, cnt, debug;
@@ -739,7 +739,7 @@ isar_fill_fifo(struct BCState *bcs)
        }
 }
 
-inline
+static inline
 struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath)
 {
        if ((!dpath) || (dpath == 3))
@@ -751,7 +751,7 @@ struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath)
        return(NULL);
 }
 
-void
+static void
 send_frames(struct BCState *bcs)
 {
        if (bcs->tx_skb) {
@@ -806,7 +806,7 @@ send_frames(struct BCState *bcs)
        }
 }
 
-inline void
+static inline void
 check_send(struct IsdnCardState *cs, u_char rdm)
 {
        struct BCState *bcs;
@@ -828,11 +828,13 @@ check_send(struct IsdnCardState *cs, u_char rdm)
        
 }
 
-const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4",
-                       "300", "600", "1200", "2400", "4800", "7200",
-                       "9600nt", "9600t", "12000", "14400", "WRONG"};
-const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21",
-                       "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"};
+static const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200",
+                               "NODEF4", "300", "600", "1200", "2400",
+                               "4800", "7200", "9600nt", "9600t", "12000",
+                               "14400", "WRONG"};
+static const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21",
+                               "Bell103", "V23", "Bell202", "V17", "V29",
+                               "V27ter"};
 
 static void
 isar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) {
@@ -1388,7 +1390,7 @@ setup_iom2(struct BCState *bcs) {
        udelay(1000);
 }
 
-int
+static int
 modeisar(struct BCState *bcs, int mode, int bc)
 {
        struct IsdnCardState *cs = bcs->cs;
@@ -1562,7 +1564,7 @@ isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para)
                sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
 }
 
-void
+static void
 isar_setup(struct IsdnCardState *cs)
 {
        u_char msg;
@@ -1582,7 +1584,7 @@ isar_setup(struct IsdnCardState *cs)
        }
 }
 
-void
+static void
 isar_l2l1(struct PStack *st, int pr, void *arg)
 {
        struct BCState *bcs = st->l1.bcs;
@@ -1681,7 +1683,7 @@ isar_l2l1(struct PStack *st, int pr, void *arg)
        }
 }
 
-void
+static void
 close_isarstate(struct BCState *bcs)
 {
        modeisar(bcs, 0, bcs->channel);
@@ -1703,7 +1705,7 @@ close_isarstate(struct BCState *bcs)
        del_timer(&bcs->hw.isar.ftimer);
 }
 
-int
+static int
 open_isarstate(struct IsdnCardState *cs, struct BCState *bcs)
 {
        if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
@@ -1725,7 +1727,7 @@ open_isarstate(struct IsdnCardState *cs, struct BCState *bcs)
        return (0);
 }
 
-int
+static int
 setstack_isar(struct PStack *st, struct BCState *bcs)
 {
        bcs->channel = st->l1.bc;
index 4d08d27f14995bf20a0c9da4261d7b479421fcb4..ac899503a74f1ee49b117de3b0d12d670a5a7ab0 100644 (file)
@@ -151,7 +151,7 @@ l1m_debug(struct FsmInst *fi, char *fmt, ...)
        va_end(args);
 }
 
-void
+static void
 L1activated(struct IsdnCardState *cs)
 {
        struct PStack *st;
@@ -166,7 +166,7 @@ L1activated(struct IsdnCardState *cs)
        }
 }
 
-void
+static void
 L1deactivated(struct IsdnCardState *cs)
 {
        struct PStack *st;
@@ -370,7 +370,7 @@ init_bcstate(struct IsdnCardState *cs, int bc)
 
 #ifdef L2FRAME_DEBUG           /* psa */
 
-char *
+static char *
 l2cmd(u_char cmd)
 {
        switch (cmd & ~0x10) {
@@ -404,7 +404,7 @@ l2cmd(u_char cmd)
 
 static char tmpdeb[32];
 
-char *
+static char *
 l2frames(u_char * ptr)
 {
        switch (ptr[2] & ~0x10) {
index d311b5fbf895014f1b529e0f4cb67fc309918609..9022583fd6a06e97b76a6c44dddcc0b7d7eacf8b 100644 (file)
@@ -142,7 +142,7 @@ freewin1(struct Layer2 *l2)
        return cnt;
 }
 
-inline void
+static inline void
 freewin(struct PStack *st)
 {
        freewin1(&st->l2);
@@ -157,7 +157,7 @@ ReleaseWin(struct Layer2 *l2)
                printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt);
 }
 
-inline unsigned int
+static inline unsigned int
 cansend(struct PStack *st)
 {
        unsigned int p1;
@@ -169,7 +169,7 @@ cansend(struct PStack *st)
        return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag));
 }
 
-inline void
+static inline void
 clear_exception(struct Layer2 *l2)
 {
        test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
@@ -178,7 +178,7 @@ clear_exception(struct Layer2 *l2)
        clear_peer_busy(l2);
 }
 
-inline int
+static inline int
 l2headersize(struct Layer2 *l2, int ui)
 {
        return (((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) +
@@ -223,40 +223,31 @@ enqueue_super(struct PStack *st,
 
 #define enqueue_ui(a, b) enqueue_super(a, b)
 
-inline int
+static inline int
 IsUI(u_char * data)
 {
        return ((data[0] & 0xef) == UI);
 }
 
-inline int
+static inline int
 IsUA(u_char * data)
 {
        return ((data[0] & 0xef) == UA);
 }
 
-inline int
+static inline int
 IsDM(u_char * data)
 {
        return ((data[0] & 0xef) == DM);
 }
 
-inline int
+static inline int
 IsDISC(u_char * data)
 {
        return ((data[0] & 0xef) == DISC);
 }
 
-inline int
-IsRR(u_char * data, struct PStack *st)
-{
-       if (test_bit(FLG_MOD128, &st->l2.flag))
-               return (data[0] == RR);
-       else
-               return ((data[0] & 0xf) == 1);
-}
-
-inline int
+static inline int
 IsSFrame(u_char * data, struct PStack *st)
 {
        register u_char d = *data;
@@ -266,7 +257,7 @@ IsSFrame(u_char * data, struct PStack *st)
        return(((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c));
 }
 
-inline int
+static inline int
 IsSABME(u_char * data, struct PStack *st)
 {
        u_char d = data[0] & ~0x10;
@@ -274,25 +265,25 @@ IsSABME(u_char * data, struct PStack *st)
        return (test_bit(FLG_MOD128, &st->l2.flag) ? d == SABME : d == SABM);
 }
 
-inline int
+static inline int
 IsREJ(u_char * data, struct PStack *st)
 {
        return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == REJ : (data[0] & 0xf) == REJ);
 }
 
-inline int
+static inline int
 IsFRMR(u_char * data)
 {
        return ((data[0] & 0xef) == FRMR);
 }
 
-inline int
+static inline int
 IsRNR(u_char * data, struct PStack *st)
 {
        return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == RNR : (data[0] & 0xf) == RNR);
 }
 
-int
+static int
 iframe_error(struct PStack *st, struct sk_buff *skb)
 {
        int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1);
@@ -315,7 +306,7 @@ iframe_error(struct PStack *st, struct sk_buff *skb)
        return 0;
 }
 
-int
+static int
 super_error(struct PStack *st, struct sk_buff *skb)
 {
        if (skb->len != l2addrsize(&st->l2) +
@@ -325,7 +316,7 @@ super_error(struct PStack *st, struct sk_buff *skb)
        return 0;
 }
 
-int
+static int
 unnum_error(struct PStack *st, struct sk_buff *skb, int wantrsp)
 {
        int rsp = (*skb->data & 0x2) >> 1;
@@ -341,7 +332,7 @@ unnum_error(struct PStack *st, struct sk_buff *skb, int wantrsp)
        return 0;
 }
 
-int
+static int
 UI_error(struct PStack *st, struct sk_buff *skb)
 {
        int rsp = *skb->data & 0x2;
@@ -357,7 +348,7 @@ UI_error(struct PStack *st, struct sk_buff *skb)
        return 0;
 }
 
-int
+static int
 FRMR_error(struct PStack *st, struct sk_buff *skb)
 {
        int headers = l2addrsize(&st->l2) + 1;
@@ -444,51 +435,44 @@ send_uframe(struct PStack *st, u_char cmd, u_char cr)
        enqueue_super(st, skb);
 }
 
-inline u_char
+static inline u_char
 get_PollFlag(struct PStack * st, struct sk_buff * skb)
 {
        return (skb->data[l2addrsize(&(st->l2))] & 0x10);
 }
 
-inline void
-FreeSkb(struct sk_buff *skb)
-{
-       dev_kfree_skb(skb);
-}
-
-
-inline u_char
+static inline u_char
 get_PollFlagFree(struct PStack *st, struct sk_buff *skb)
 {
        u_char PF;
 
        PF = get_PollFlag(st, skb);
-       FreeSkb(skb);
+       dev_kfree_skb(skb);
        return (PF);
 }
 
-inline void
+static inline void
 start_t200(struct PStack *st, int i)
 {
        FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i);
        test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
 }
 
-inline void
+static inline void
 restart_t200(struct PStack *st, int i)
 {
        FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i);
        test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
 }
 
-inline void
+static inline void
 stop_t200(struct PStack *st, int i)
 {
        if(test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
                FsmDelTimer(&st->l2.t200, i);
 }
 
-inline void
+static inline void
 st5_dl_release_l2l3(struct PStack *st)
 {
                int pr;
@@ -501,7 +485,7 @@ st5_dl_release_l2l3(struct PStack *st)
                st->l2.l2l3(st, pr, NULL);
 }
 
-inline void
+static inline void
 lapb_dl_release_l2l3(struct PStack *st, int f)
 {
                if (test_bit(FLG_LAPB, &st->l2.flag))
@@ -802,7 +786,7 @@ l2_connected(struct FsmInst *fi, int event, void *arg)
                l2_mdl_error_ua(fi, event, arg);
                return;
        }
-       FreeSkb(skb);
+       dev_kfree_skb(skb);
 
        if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag))
                l2_disconnect(fi, event, arg);
@@ -840,7 +824,7 @@ l2_released(struct FsmInst *fi, int event, void *arg)
                l2_mdl_error_ua(fi, event, arg);
                return;
        }
-       FreeSkb(skb);
+       dev_kfree_skb(skb);
 
        stop_t200(st, 6);
        lapb_dl_release_l2l3(st, CONFIRM);
@@ -889,7 +873,7 @@ l2_st6_dm_release(struct FsmInst *fi, int event, void *arg)
        }
 }
 
-inline void
+static inline void
 enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf)
 {
        struct sk_buff *skb;
@@ -912,7 +896,7 @@ enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf)
        enqueue_super(st, skb);
 }
 
-inline void
+static inline void
 enquiry_response(struct PStack *st)
 {
        if (test_bit(FLG_OWN_BUSY, &st->l2.flag))
@@ -922,7 +906,7 @@ enquiry_response(struct PStack *st)
        test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
 }
 
-inline void
+static inline void
 transmit_enquiry(struct PStack *st)
 {
        if (test_bit(FLG_OWN_BUSY, &st->l2.flag))
@@ -1004,7 +988,7 @@ l2_st7_got_super(struct FsmInst *fi, int event, void *arg)
                PollFlag = (skb->data[0] & 0x10);
                nr = (skb->data[0] >> 5) & 0x7;
        }
-       FreeSkb(skb);
+       dev_kfree_skb(skb);
 
        if (PollFlag) {
                if (rsp)
@@ -1047,7 +1031,7 @@ l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg)
        if (!test_bit(FLG_L3_INIT, &st->l2.flag))
                skb_queue_tail(&st->l2.i_queue, skb);
        else
-               FreeSkb(skb);
+               dev_kfree_skb(skb);
 }
 
 static void
@@ -1093,7 +1077,7 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
                nr = (skb->data[i] >> 5) & 0x7;
        }
        if (test_bit(FLG_OWN_BUSY, &l2->flag)) {
-               FreeSkb(skb);
+               dev_kfree_skb(skb);
                if(PollFlag) enquiry_response(st);
        } else if (l2->vr == ns) {
                (l2->vr)++;
@@ -1111,7 +1095,7 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
                st->l2.l2l3(st, DL_DATA | INDICATION, skb);
        } else {
                /* n(s)!=v(r) */
-               FreeSkb(skb);
+               dev_kfree_skb(skb);
                if (test_and_set_bit(FLG_REJEXC, &l2->flag)) {
                        if (PollFlag)
                                enquiry_response(st);
@@ -1309,7 +1293,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
                skb = alloc_skb(oskb->len + i, GFP_ATOMIC);
                memcpy(skb_put(skb, i), header, i);
                memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len);
-               FreeSkb(oskb);
+               dev_kfree_skb(oskb);
        }
        st->l2.l2l1(st, PH_PULL | INDICATION, skb);
        test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
@@ -1349,7 +1333,7 @@ l2_st8_got_super(struct FsmInst *fi, int event, void *arg)
                PollFlag = (skb->data[0] & 0x10);
                nr = (skb->data[0] >> 5) & 0x7;
        }
-       FreeSkb(skb);
+       dev_kfree_skb(skb);
 
        if (rsp && PollFlag) {
                if (legalnr(st, nr)) {
@@ -1391,7 +1375,7 @@ l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
                establishlink(fi);
                test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
        }
-       FreeSkb(skb);
+       dev_kfree_skb(skb);
 }
 
 static void
@@ -1655,7 +1639,7 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg)
                                datap += len;
                        else {
                                FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'N');
-                               FreeSkb(skb);
+                               dev_kfree_skb(skb);
                                return;
                        }
                        if (!(*datap & 1)) {    /* I-Frame */
@@ -1684,16 +1668,16 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg)
                                        ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb);
                        } else {
                                FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'L');
-                               FreeSkb(skb);
+                               dev_kfree_skb(skb);
                                ret = 0;
                        }
                        if(c) {
-                               FreeSkb(skb);
+                               dev_kfree_skb(skb);
                                FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *)(long)c);
                                ret = 0;
                        }
                        if (ret)
-                               FreeSkb(skb);
+                               dev_kfree_skb(skb);
                        break;
                case (PH_PULL | CONFIRM):
                        FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
index f571b5d18e91f4136c34862bd01fd2608b914274..abcc9530eb347b007b74ea1f5a774c361e2c9902 100644 (file)
@@ -390,7 +390,7 @@ setstack_l3dc(struct PStack *st, struct Channel *chanp)
        }
 }
 
-void
+static void
 isdnl3_trans(struct PStack *st, int pr, void *arg) {
        st->l3.l3l2(st, pr, arg);
 }
index af5171da734572dcc934f391d3de6333f2d4e784..33747afc984db717dbb1601031f06dd1ffc69bae 100644 (file)
@@ -122,7 +122,7 @@ isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-void
+static void
 release_io_isurf(struct IsdnCardState *cs)
 {
        release_region(cs->hw.isurf.reset, 1);
index b843b7509ae2d4d484158048f084b17aabdc3826..908a7e14442179dba17794a886949edc22ff044a 100644 (file)
@@ -25,7 +25,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *ix1_revision = "$Revision: 2.12.2.4 $";
+static const char *ix1_revision = "$Revision: 2.12.2.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -162,7 +162,7 @@ ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-void
+static void
 release_io_ix1micro(struct IsdnCardState *cs)
 {
        if (cs->hw.ix1.cfg_reg)
index f05d52757557133d9533474abfa10a449c1162d9..363ae3179bbde9a255148c56c5e90a5e6d0eaf81 100644 (file)
@@ -74,7 +74,7 @@ jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value)
 
 
 
-void
+static void
 modejade(struct BCState *bcs, int mode, int bc)
 {
     struct IsdnCardState *cs = bcs->cs;
@@ -190,7 +190,7 @@ jade_l2l1(struct PStack *st, int pr, void *arg)
     }
 }
 
-void
+static void
 close_jadestate(struct BCState *bcs)
 {
     modejade(bcs, 0, bcs->channel);
@@ -243,7 +243,7 @@ open_jadestate(struct IsdnCardState *cs, struct BCState *bcs)
 }
 
 
-int
+static int
 setstack_jade(struct PStack *st, struct BCState *bcs)
 {
        bcs->channel = st->l1.bc;
index fa29444859941325f40311ea202c0edb4464e451..29055e1ee38169889731c5097f2fd464c217c9f6 100644 (file)
 #define        jade_TXAUDIOCH2CFG                              0x1A
 
 extern int JadeVersion(struct IsdnCardState *cs, char *s);
-extern void modejade(struct BCState *bcs, int mode, int bc);
 extern void clear_pending_jade_ints(struct IsdnCardState *cs);
 extern void initjade(struct IsdnCardState *cs);
 
index d6c1c8f8329d8672f260945b23033bcabb2997ea..c5c36eeff26111ee962b4e62b4548596b53a9304 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $";
+static const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $";
 
 #define MsgHead(ptr, cref, mty, dis) \
        *ptr++ = dis; \
index ec92308c1efc75138b22646be00ea4dc811f948c..a6d2abdb478aeab5c018c0e635d4bc5a5d7c70ee 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/config.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.32.2.3 $";
+static const char *dss1_revision = "$Revision: 2.32.2.3 $";
 
 #define EXT_BEARER_CAPS 1
 
index 3ab3a54daac1b90522d1df55bb4b4a7d5b9b4907..f7041d5ba64e3c08b1ea6ca733b4e22cecdfb66a 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *ni1_revision = "$Revision: 2.8.2.3 $";
+static const char *ni1_revision = "$Revision: 2.8.2.3 $";
 
 #define EXT_BEARER_CAPS 1
 
@@ -2665,7 +2665,7 @@ static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg )
        l3ni1_SendSpid( pc, pr, arg, 20 );
 }
 
-void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg )
+static void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg )
 {
        struct sk_buff *skb = arg;
 
index 3ac4484a4886bf1757c51993f843d536f7f898d4..fe11f226b28539b5a0c4c40920ce8ee8f4e98821 100644 (file)
@@ -18,7 +18,7 @@
 
 extern const char *CardType[];
 
-const char *mic_revision = "$Revision: 1.12.2.4 $";
+static const char *mic_revision = "$Revision: 1.12.2.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -157,7 +157,7 @@ mic_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-void
+static void
 release_io_mic(struct IsdnCardState *cs)
 {
        int bytecnt = 8;
index fe61d26365d390ee2e7d6a08982a7272d562f3ca..94da03c30c51507c1af9c74d449e04930a4a3c52 100644 (file)
@@ -25,8 +25,6 @@
 #include <asm/io.h>
 #include "netjet.h"
 
-const char *NETjet_revision = "$Revision: 1.29.2.4 $";
-
 /* Interface functions */
 
 u_char
@@ -66,7 +64,7 @@ NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size)
        outsb(cs->hw.njet.isac, data, size);
 }
 
-void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill)
+static void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill)
 {
        u_int mask=0x000000ff, val = 0, *p=pos;
        u_int i;
@@ -85,7 +83,7 @@ void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill)
        }
 }
 
-void
+static void
 mode_tiger(struct BCState *bcs, int mode, int bc)
 {
        struct IsdnCardState *cs = bcs->cs;
@@ -852,7 +850,7 @@ tiger_l2l1(struct PStack *st, int pr, void *arg)
 }
 
 
-void
+static void
 close_tigerstate(struct BCState *bcs)
 {
        mode_tiger(bcs, 0, bcs->channel);
@@ -900,7 +898,7 @@ open_tigerstate(struct IsdnCardState *cs, struct BCState *bcs)
        return (0);
 }
 
-int
+static int
 setstack_tiger(struct PStack *st, struct BCState *bcs)
 {
        bcs->channel = st->l1.bc;
@@ -966,7 +964,7 @@ inittiger(struct IsdnCardState *cs)
        cs->bcs[1].BC_Close = close_tigerstate;
 }
 
-void
+static void
 releasetiger(struct IsdnCardState *cs)
 {
        if (cs->bcs[0].hw.tiger.send) {
index cf77d8360975dd07b999375ac0773ab050548ada..68a2159cbd1109ffd9d06d3de6ec83bcc4e53ea9 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/isapnp.h>
 
 extern const char *CardType[];
-const char *niccy_revision = "$Revision: 1.21.2.4 $";
+static const char *niccy_revision = "$Revision: 1.21.2.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -178,7 +178,7 @@ niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-void
+static void
 release_io_niccy(struct IsdnCardState *cs)
 {
        if (cs->subtyp == NICCY_PCI) {
index fd664697f821bf8d10cbe3948130e04dd3268345..a7d3cd3f36fdabf7b4fb2f6f25366ddb7aa28ba9 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/ppp_defs.h>
 #include "netjet.h"
 
-const char *NETjet_S_revision = "$Revision: 2.13.2.4 $";
+static const char *NETjet_S_revision = "$Revision: 2.13.2.4 $";
 
 static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
 {
index 3d6441e9633c670dc912d93efda3b4866165a527..1ae7cac98a877724957349f52e9c3d7066e5623b 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/ppp_defs.h>
 #include "netjet.h"
 
-const char *NETjet_U_revision = "$Revision: 2.14.2.3 $";
+static const char *NETjet_U_revision = "$Revision: 2.14.2.3 $";
 
 static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
 {
index 170fcd4a39845cbc9e4b8fbe9756d07986287fa9..abecabf8c271326d201dc2b3e1c78bcd369af6fd 100644 (file)
@@ -516,7 +516,7 @@ struct MessageType cause_1tr6[] =
        {CAUSE_UserInfoDiscarded, "User Info Discarded"}
 };
 
-int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
+static int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
 
 static int
 prcause_1tr6(char *dest, u_char * p)
@@ -935,7 +935,7 @@ display(char *dest, u_char * p)
        return (dp - dest);
 }
 
-int
+static int
 prfacility(char *dest, u_char * p)
 {
        char *dp = dest;
index f3c481384a4ea8d93d3536c6aca4cd768ac4b649..7b63085ea6e51107c939e8011d86f03607f4f8f9 100644 (file)
@@ -17,7 +17,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *s0box_revision = "$Revision: 2.6.2.4 $";
+static const char *s0box_revision = "$Revision: 2.6.2.4 $";
 
 static inline void
 writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
@@ -183,7 +183,7 @@ s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-void
+static void
 release_io_s0box(struct IsdnCardState *cs)
 {
        release_region(cs->hw.teles3.cfg_reg, 8);
index 9e6d3d686cce58937b9f2895686f6af8cc95e8ae..821776e1561acb63ad9b5ad1c062c97bce6298de 100644 (file)
@@ -171,7 +171,7 @@ SaphirWatchDog(struct IsdnCardState *cs)
        mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
 }
 
-void
+static void
 release_io_saphir(struct IsdnCardState *cs)
 {
        byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff);
index 8390f16068534e4c2962fbaec73c8921eca85bd7..8c044a6a7fe3b1e6567a5926f99d71932dee4494 100644 (file)
@@ -51,9 +51,9 @@
 
 extern const char *CardType[];
 
-const char *Sedlbauer_revision = "$Revision: 1.34.2.6 $";
+static const char *Sedlbauer_revision = "$Revision: 1.34.2.6 $";
 
-const char *Sedlbauer_Types[] =
+static const char *Sedlbauer_Types[] =
        {"None", "speed card/win", "speed star", "speed fax+",
        "speed win II / ISDN PC/104", "speed star II", "speed pci",
        "speed fax+ pyramid", "speed fax+ pci", "HST Saphir III"};
@@ -394,7 +394,7 @@ sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-void
+static void
 release_io_sedlbauer(struct IsdnCardState *cs)
 {
        int bytecnt = 8;
index 449651241477da025b9497f122026796390ad566..058147a6957624fbe434735541386cfa8f50a1cc 100644 (file)
@@ -616,6 +616,18 @@ static int sedlbauer_event(event_t event, int priority,
     return 0;
 } /* sedlbauer_event */
 
+static struct pcmcia_device_id sedlbauer_ids[] = {
+       PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", "speed star II", "V 3.1", "(c) 93 - 98 cb ", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a, 0x50d4149c),
+       PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90),
+       PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce),
+       PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (C) 93-94 VK", 0x81fb79f5, 0xe4e9bc12, 0x8db143fe),
+       PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (c) 93-95 VK", 0x81fb79f5, 0xe4e9bc12, 0xb391ab4c),
+       PCMCIA_DEVICE_PROD_ID12("HST High Soft Tech GmbH", "Saphir II B", 0xd79e0b84, 0x21d083ae),
+/*     PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", 0x81fb79f5), */ /* too generic*/
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, sedlbauer_ids);
+
 static struct pcmcia_driver sedlbauer_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -623,6 +635,7 @@ static struct pcmcia_driver sedlbauer_driver = {
        },
        .attach         = sedlbauer_attach,
        .detach         = sedlbauer_detach,
+       .id_table       = sedlbauer_ids,
 };
 
 static int __init init_sedlbauer_cs(void)
index 132840b750cea71c2170bc9bf0a9aef23572b3fb..cdf35dc564c41d90c910abb53a1fa5923b43005c 100644 (file)
@@ -19,7 +19,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *sportster_revision = "$Revision: 1.16.2.4 $";
+static const char *sportster_revision = "$Revision: 1.16.2.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -132,7 +132,7 @@ sportster_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-void
+static void
 release_io_sportster(struct IsdnCardState *cs)
 {
        int i, adr;
@@ -144,7 +144,7 @@ release_io_sportster(struct IsdnCardState *cs)
        }
 }
 
-void
+static void
 reset_sportster(struct IsdnCardState *cs)
 {
        cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */
index e8177b017b1d7184f998177efd4706db7d91b6b0..0fda5c89429b4a73180a7c1bfbcfaa79a779e8ee 100644 (file)
@@ -450,12 +450,8 @@ int st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev,
                           usb_complete_t complete, void *context);
 void st5481_release_isocpipes(struct urb* urb[2]);
 
-int  st5481_isoc_flatten(struct urb *urb);
 void st5481_usb_pipe_reset(struct st5481_adapter *adapter,
                    u_char pipe, ctrl_complete_t complete, void *context);
-void st5481_usb_ctrl_msg(struct st5481_adapter *adapter,
-                 u8 request, u8 requesttype, u16 value, u16 index,
-                 ctrl_complete_t complete, void *context);
 void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter,
                         u8 request, u16 value,
                         ctrl_complete_t complete, void *context);
diff --git a/drivers/isdn/hisax/st5481_hdlc.c b/drivers/isdn/hisax/st5481_hdlc.c
deleted file mode 100644 (file)
index 680f42e..0000000
+++ /dev/null
@@ -1,580 +0,0 @@
-/*
- * Driver for ST5481 USB ISDN modem
- *
- * Author       Frode Isaksen
- * Copyright    2001 by Frode Isaksen      <fisaksen@bewan.com>
- *              2001 by Kai Germaschewski  <kai.germaschewski@gmx.de>
- * 
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/crc-ccitt.h>
-#include "st5481_hdlc.h"
-
-
-enum {
-       HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
-       HDLC_GET_DATA,HDLC_FAST_FLAG
-};
-
-enum {
-       HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG,
-       HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG,
-       HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0,
-       HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED
-};
-
-void 
-hdlc_rcv_init(struct hdlc_vars *hdlc, int do_adapt56)
-{
-       hdlc->bit_shift = 0;
-       hdlc->hdlc_bits1 = 0;
-       hdlc->data_bits = 0;
-       hdlc->ffbit_shift = 0;
-       hdlc->data_received = 0;
-       hdlc->state = HDLC_GET_DATA;
-       hdlc->do_adapt56 = do_adapt56;
-       hdlc->dchannel = 0;
-       hdlc->crc = 0;
-       hdlc->cbin = 0;
-       hdlc->shift_reg = 0;
-       hdlc->ffvalue = 0;
-       hdlc->dstpos = 0;
-}
-
-void 
-hdlc_out_init(struct hdlc_vars *hdlc, int is_d_channel, int do_adapt56)
-{
-       hdlc->bit_shift = 0;
-       hdlc->hdlc_bits1 = 0;
-       hdlc->data_bits = 0;
-       hdlc->ffbit_shift = 0;
-       hdlc->data_received = 0;
-       hdlc->do_closing = 0;
-       hdlc->ffvalue = 0;
-       if (is_d_channel) {
-               hdlc->dchannel = 1;
-               hdlc->state = HDLC_SEND_FIRST_FLAG;
-       } else {
-               hdlc->dchannel = 0;
-               hdlc->state = HDLC_SEND_FAST_FLAG;
-               hdlc->ffvalue = 0x7e;
-       } 
-       hdlc->cbin = 0x7e;
-       hdlc->bit_shift = 0;
-       if(do_adapt56){
-               hdlc->do_adapt56 = 1;           
-               hdlc->data_bits = 0;
-               hdlc->state = HDLC_SENDFLAG_B0;
-       } else {
-               hdlc->do_adapt56 = 0;           
-               hdlc->data_bits = 8;
-       }
-       hdlc->shift_reg = 0;
-}
-
-/*
-  hdlc_decode - decodes HDLC frames from a transparent bit stream.
-
-  The source buffer is scanned for valid HDLC frames looking for
-  flags (01111110) to indicate the start of a frame. If the start of
-  the frame is found, the bit stuffing is removed (0 after 5 1's).
-  When a new flag is found, the complete frame has been received
-  and the CRC is checked.
-  If a valid frame is found, the function returns the frame length 
-  excluding the CRC with the bit HDLC_END_OF_FRAME set.
-  If the beginning of a valid frame is found, the function returns
-  the length. 
-  If a framing error is found (too many 1s and not a flag) the function 
-  returns the length with the bit HDLC_FRAMING_ERROR set.
-  If a CRC error is found the function returns the length with the
-  bit HDLC_CRC_ERROR set.
-  If the frame length exceeds the destination buffer size, the function
-  returns the length with the bit HDLC_LENGTH_ERROR set.
-
-  src - source buffer
-  slen - source buffer length
-  count - number of bytes removed (decoded) from the source buffer
-  dst _ destination buffer
-  dsize - destination buffer size
-  returns - number of decoded bytes in the destination buffer and status
-  flag.
- */
-int hdlc_decode(struct hdlc_vars *hdlc, const unsigned char *src,
-               int slen, int *count, unsigned char *dst, int dsize)
-{
-       int status=0;
-
-       static const unsigned char fast_flag[]={
-               0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
-       };
-
-       static const unsigned char fast_flag_value[]={
-               0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
-       };
-
-       static const unsigned char fast_abort[]={
-               0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
-       };
-
-       *count = slen;
-
-       while(slen > 0){
-               if(hdlc->bit_shift==0){
-                       hdlc->cbin = *src++;
-                       slen--;
-                       hdlc->bit_shift = 8;
-                       if(hdlc->do_adapt56){
-                               hdlc->bit_shift --;
-                       }
-               }
-
-               switch(hdlc->state){
-               case STOPPED:
-                       return 0;
-               case HDLC_FAST_IDLE:
-                       if(hdlc->cbin == 0xff){
-                               hdlc->bit_shift = 0;
-                               break;
-                       }
-                       hdlc->state = HDLC_GET_FLAG_B0;
-                       hdlc->hdlc_bits1 = 0;
-                       hdlc->bit_shift = 8;
-                       break;
-               case HDLC_GET_FLAG_B0:
-                       if(!(hdlc->cbin & 0x80)) {
-                               hdlc->state = HDLC_GETFLAG_B1A6;
-                               hdlc->hdlc_bits1 = 0;
-                       } else {
-                               if(!hdlc->do_adapt56){
-                                       if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1)
-                                               hdlc->state = HDLC_FAST_IDLE;
-                               }
-                       }
-                       hdlc->cbin<<=1;
-                       hdlc->bit_shift --;
-                       break;
-               case HDLC_GETFLAG_B1A6:
-                       if(hdlc->cbin & 0x80){
-                               hdlc->hdlc_bits1++;
-                               if(hdlc->hdlc_bits1==6){
-                                       hdlc->state = HDLC_GETFLAG_B7;
-                               }
-                       } else {
-                               hdlc->hdlc_bits1 = 0;
-                       }
-                       hdlc->cbin<<=1;
-                       hdlc->bit_shift --;
-                       break;
-               case HDLC_GETFLAG_B7:
-                       if(hdlc->cbin & 0x80) {
-                               hdlc->state = HDLC_GET_FLAG_B0;
-                       } else {
-                               hdlc->state = HDLC_GET_DATA;
-                               hdlc->crc = 0xffff;
-                               hdlc->shift_reg = 0;
-                               hdlc->hdlc_bits1 = 0;
-                               hdlc->data_bits = 0;
-                               hdlc->data_received = 0;
-                       }
-                       hdlc->cbin<<=1;
-                       hdlc->bit_shift --;
-                       break;
-               case HDLC_GET_DATA:
-                       if(hdlc->cbin & 0x80){
-                               hdlc->hdlc_bits1++;
-                               switch(hdlc->hdlc_bits1){
-                               case 6:
-                                       break;
-                               case 7:
-                                       if(hdlc->data_received) {
-                                               // bad frame
-                                               status = -HDLC_FRAMING_ERROR;
-                                       }
-                                       if(!hdlc->do_adapt56){
-                                               if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){
-                                                       hdlc->state = HDLC_FAST_IDLE;
-                                                       hdlc->bit_shift=1;
-                                                       break;
-                                               }
-                                       } else {
-                                               hdlc->state = HDLC_GET_FLAG_B0;
-                                       }
-                                       break;
-                               default:
-                                       hdlc->shift_reg>>=1;
-                                       hdlc->shift_reg |= 0x80;
-                                       hdlc->data_bits++;
-                                       break;
-                               }
-                       } else {
-                               switch(hdlc->hdlc_bits1){
-                               case 5:
-                                       break;
-                               case 6:
-                                       if(hdlc->data_received){
-                                               if (hdlc->dstpos < 2) {
-                                                       status = -HDLC_FRAMING_ERROR;
-                                               } else if (hdlc->crc != 0xf0b8){
-                                                       // crc error
-                                                       status = -HDLC_CRC_ERROR;
-                                               } else {
-                                                       // remove CRC
-                                                       hdlc->dstpos -= 2;
-                                                       // good frame
-                                                       status = hdlc->dstpos;
-                                               }
-                                       }
-                                       hdlc->crc = 0xffff;
-                                       hdlc->shift_reg = 0;
-                                       hdlc->data_bits = 0;
-                                       if(!hdlc->do_adapt56){
-                                               if(hdlc->cbin==fast_flag[hdlc->bit_shift]){
-                                                       hdlc->ffvalue = fast_flag_value[hdlc->bit_shift];
-                                                       hdlc->state = HDLC_FAST_FLAG;
-                                                       hdlc->ffbit_shift = hdlc->bit_shift;
-                                                       hdlc->bit_shift = 1;
-                                               } else {
-                                                       hdlc->state = HDLC_GET_DATA;
-                                                       hdlc->data_received = 0;
-                                               }
-                                       } else {
-                                               hdlc->state = HDLC_GET_DATA;
-                                               hdlc->data_received = 0;
-                                       }
-                                       break;
-                               default:
-                                       hdlc->shift_reg>>=1;
-                                       hdlc->data_bits++;
-                                       break;
-                               }
-                               hdlc->hdlc_bits1 = 0;
-                       }
-                       if (status) {
-                               hdlc->dstpos = 0;
-                               *count -= slen;
-                               hdlc->cbin <<= 1;
-                               hdlc->bit_shift--;
-                               return status;
-                       }
-                       if(hdlc->data_bits==8){
-                               hdlc->data_bits = 0;
-                               hdlc->data_received = 1;
-                               hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
-
-                               // good byte received
-                               if (dsize--) {
-                                       dst[hdlc->dstpos++] = hdlc->shift_reg;
-                               } else {
-                                       // frame too long
-                                       status = -HDLC_LENGTH_ERROR;
-                                       hdlc->dstpos = 0;
-                               }
-                       }
-                       hdlc->cbin <<= 1;
-                       hdlc->bit_shift--;
-                       break;
-               case HDLC_FAST_FLAG:
-                       if(hdlc->cbin==hdlc->ffvalue){
-                               hdlc->bit_shift = 0;
-                               break;
-                       } else {
-                               if(hdlc->cbin == 0xff){
-                                       hdlc->state = HDLC_FAST_IDLE;
-                                       hdlc->bit_shift=0;
-                               } else if(hdlc->ffbit_shift==8){
-                                       hdlc->state = HDLC_GETFLAG_B7;
-                                       break;
-                               } else {
-                                       hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1];
-                                       hdlc->hdlc_bits1 = hdlc->ffbit_shift-2;
-                                       if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0;
-                                       hdlc->data_bits = hdlc->ffbit_shift-1;
-                                       hdlc->state = HDLC_GET_DATA;
-                                       hdlc->data_received = 0;
-                               }
-                       }
-                       break;
-               default:
-                       break;
-               }
-       }
-       *count -= slen;
-       return 0;
-}
-
-/*
-  hdlc_encode - encodes HDLC frames to a transparent bit stream.
-
-  The bit stream starts with a beginning flag (01111110). After
-  that each byte is added to the bit stream with bit stuffing added
-  (0 after 5 1's).
-  When the last byte has been removed from the source buffer, the
-  CRC (2 bytes is added) and the frame terminates with the ending flag.
-  For the dchannel, the idle character (all 1's) is also added at the end.
-  If this function is called with empty source buffer (slen=0), flags or
-  idle character will be generated.
-  src - source buffer
-  slen - source buffer length
-  count - number of bytes removed (encoded) from source buffer
-  dst _ destination buffer
-  dsize - destination buffer size
-  returns - number of encoded bytes in the destination buffer
-*/
-int hdlc_encode(struct hdlc_vars *hdlc, const unsigned char *src, 
-               unsigned short slen, int *count,
-               unsigned char *dst, int dsize)
-{
-       static const unsigned char xfast_flag_value[] = {
-               0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
-       };
-
-       int len = 0;
-
-       *count = slen;
-
-       while (dsize > 0) {
-               if(hdlc->bit_shift==0){ 
-                       if(slen && !hdlc->do_closing){
-                               hdlc->shift_reg = *src++;
-                               slen--;
-                               if (slen == 0) 
-                                       hdlc->do_closing = 1;  /* closing sequence, CRC + flag(s) */
-                               hdlc->bit_shift = 8;
-                       } else {
-                               if(hdlc->state == HDLC_SEND_DATA){
-                                       if(hdlc->data_received){
-                                               hdlc->state = HDLC_SEND_CRC1;
-                                               hdlc->crc ^= 0xffff;
-                                               hdlc->bit_shift = 8;
-                                               hdlc->shift_reg = hdlc->crc & 0xff;
-                                       } else if(!hdlc->do_adapt56){
-                                               hdlc->state = HDLC_SEND_FAST_FLAG;
-                                       } else {
-                                               hdlc->state = HDLC_SENDFLAG_B0;
-                                       }
-                               }
-                         
-                       }
-               }
-
-               switch(hdlc->state){
-               case STOPPED:
-                       while (dsize--)
-                               *dst++ = 0xff;
-                 
-                       return dsize;
-               case HDLC_SEND_FAST_FLAG:
-                       hdlc->do_closing = 0;
-                       if(slen == 0){
-                               *dst++ = hdlc->ffvalue;
-                               len++;
-                               dsize--;
-                               break;
-                       }
-                       if(hdlc->bit_shift==8){
-                               hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits);
-                               hdlc->state = HDLC_SEND_DATA;
-                               hdlc->crc = 0xffff;
-                               hdlc->hdlc_bits1 = 0;
-                               hdlc->data_received = 1;
-                       }
-                       break;
-               case HDLC_SENDFLAG_B0:
-                       hdlc->do_closing = 0;
-                       hdlc->cbin <<= 1;
-                       hdlc->data_bits++;
-                       hdlc->hdlc_bits1 = 0;
-                       hdlc->state = HDLC_SENDFLAG_B1A6;
-                       break;
-               case HDLC_SENDFLAG_B1A6:
-                       hdlc->cbin <<= 1;
-                       hdlc->data_bits++;
-                       hdlc->cbin++;
-                       if(++hdlc->hdlc_bits1 == 6)
-                               hdlc->state = HDLC_SENDFLAG_B7;
-                       break;
-               case HDLC_SENDFLAG_B7:
-                       hdlc->cbin <<= 1;
-                       hdlc->data_bits++;
-                       if(slen == 0){
-                               hdlc->state = HDLC_SENDFLAG_B0;
-                               break;
-                       }
-                       if(hdlc->bit_shift==8){
-                               hdlc->state = HDLC_SEND_DATA;
-                               hdlc->crc = 0xffff;
-                               hdlc->hdlc_bits1 = 0;
-                               hdlc->data_received = 1;
-                       }
-                       break;
-               case HDLC_SEND_FIRST_FLAG:
-                       hdlc->data_received = 1;
-                       if(hdlc->data_bits==8){
-                               hdlc->state = HDLC_SEND_DATA;
-                               hdlc->crc = 0xffff;
-                               hdlc->hdlc_bits1 = 0;
-                               break;
-                       }
-                       hdlc->cbin <<= 1;
-                       hdlc->data_bits++;
-                       if(hdlc->shift_reg & 0x01)
-                               hdlc->cbin++;
-                       hdlc->shift_reg >>= 1;
-                       hdlc->bit_shift--;
-                       if(hdlc->bit_shift==0){
-                               hdlc->state = HDLC_SEND_DATA;
-                               hdlc->crc = 0xffff;
-                               hdlc->hdlc_bits1 = 0;
-                       }
-                       break;
-               case HDLC_SEND_DATA:
-                       hdlc->cbin <<= 1;
-                       hdlc->data_bits++;
-                       if(hdlc->hdlc_bits1 == 5){
-                               hdlc->hdlc_bits1 = 0;
-                               break;
-                       }
-                       if(hdlc->bit_shift==8){
-                               hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
-                       }
-                       if(hdlc->shift_reg & 0x01){
-                               hdlc->hdlc_bits1++;
-                               hdlc->cbin++;
-                               hdlc->shift_reg >>= 1;
-                               hdlc->bit_shift--;
-                       } else {
-                               hdlc->hdlc_bits1 = 0;
-                               hdlc->shift_reg >>= 1;
-                               hdlc->bit_shift--;
-                       }
-                       break;
-               case HDLC_SEND_CRC1:
-                       hdlc->cbin <<= 1;
-                       hdlc->data_bits++;
-                       if(hdlc->hdlc_bits1 == 5){
-                               hdlc->hdlc_bits1 = 0;
-                               break;
-                       }
-                       if(hdlc->shift_reg & 0x01){
-                               hdlc->hdlc_bits1++;
-                               hdlc->cbin++;
-                               hdlc->shift_reg >>= 1;
-                               hdlc->bit_shift--;
-                       } else {
-                               hdlc->hdlc_bits1 = 0;
-                               hdlc->shift_reg >>= 1;
-                               hdlc->bit_shift--;
-                       }
-                       if(hdlc->bit_shift==0){
-                               hdlc->shift_reg = (hdlc->crc >> 8);
-                               hdlc->state = HDLC_SEND_CRC2;
-                               hdlc->bit_shift = 8;
-                       }
-                       break;
-               case HDLC_SEND_CRC2:
-                       hdlc->cbin <<= 1;
-                       hdlc->data_bits++;
-                       if(hdlc->hdlc_bits1 == 5){
-                               hdlc->hdlc_bits1 = 0;
-                               break;
-                       }
-                       if(hdlc->shift_reg & 0x01){
-                               hdlc->hdlc_bits1++;
-                               hdlc->cbin++;
-                               hdlc->shift_reg >>= 1;
-                               hdlc->bit_shift--;
-                       } else {
-                               hdlc->hdlc_bits1 = 0;
-                               hdlc->shift_reg >>= 1;
-                               hdlc->bit_shift--;
-                       }
-                       if(hdlc->bit_shift==0){
-                               hdlc->shift_reg = 0x7e;
-                               hdlc->state = HDLC_SEND_CLOSING_FLAG;
-                               hdlc->bit_shift = 8;
-                       }
-                       break;
-               case HDLC_SEND_CLOSING_FLAG:
-                       hdlc->cbin <<= 1;
-                       hdlc->data_bits++;
-                       if(hdlc->hdlc_bits1 == 5){
-                               hdlc->hdlc_bits1 = 0;
-                               break;
-                       }
-                       if(hdlc->shift_reg & 0x01){
-                               hdlc->cbin++;
-                       }
-                       hdlc->shift_reg >>= 1;
-                       hdlc->bit_shift--;
-                       if(hdlc->bit_shift==0){
-                               hdlc->ffvalue = xfast_flag_value[hdlc->data_bits];
-                               if(hdlc->dchannel){
-                                       hdlc->ffvalue = 0x7e;
-                                       hdlc->state = HDLC_SEND_IDLE1;
-                                       hdlc->bit_shift = 8-hdlc->data_bits;
-                                       if(hdlc->bit_shift==0)
-                                               hdlc->state = HDLC_SEND_FAST_IDLE;
-                               } else {
-                                       if(!hdlc->do_adapt56){
-                                               hdlc->state = HDLC_SEND_FAST_FLAG;
-                                               hdlc->data_received = 0;
-                                       } else {
-                                               hdlc->state = HDLC_SENDFLAG_B0;
-                                               hdlc->data_received = 0;
-                                       }
-                                       // Finished with this frame, send flags
-                                       if (dsize > 1) dsize = 1; 
-                               }
-                       }
-                       break;
-               case HDLC_SEND_IDLE1:
-                       hdlc->do_closing = 0;
-                       hdlc->cbin <<= 1;
-                       hdlc->cbin++;
-                       hdlc->data_bits++;
-                       hdlc->bit_shift--;
-                       if(hdlc->bit_shift==0){
-                               hdlc->state = HDLC_SEND_FAST_IDLE;
-                               hdlc->bit_shift = 0;
-                       }
-                       break;
-               case HDLC_SEND_FAST_IDLE:
-                       hdlc->do_closing = 0;
-                       hdlc->cbin = 0xff;
-                       hdlc->data_bits = 8;
-                       if(hdlc->bit_shift == 8){
-                               hdlc->cbin = 0x7e;
-                               hdlc->state = HDLC_SEND_FIRST_FLAG;
-                       } else {
-                               *dst++ = hdlc->cbin;
-                               hdlc->bit_shift = hdlc->data_bits = 0;
-                               len++;
-                               dsize = 0;
-                       }
-                       break;
-               default:
-                       break;
-               }
-               if(hdlc->do_adapt56){
-                       if(hdlc->data_bits==7){
-                               hdlc->cbin <<= 1;
-                               hdlc->cbin++;
-                               hdlc->data_bits++;
-                       }
-               }
-               if(hdlc->data_bits==8){
-                       *dst++ = hdlc->cbin;
-                       hdlc->data_bits = 0;
-                       len++;
-                       dsize--;
-               }
-       }
-       *count -= slen;
-
-       return len;
-}
-
diff --git a/drivers/isdn/hisax/st5481_hdlc.h b/drivers/isdn/hisax/st5481_hdlc.h
deleted file mode 100644 (file)
index 495432f..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Driver for ST5481 USB ISDN modem
- *
- * Author       Frode Isaksen
- * Copyright    2001 by Frode Isaksen      <fisaksen@bewan.com>
- *              2001 by Kai Germaschewski  <kai.germaschewski@gmx.de>
- * 
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef __ST5481_HDLC_H__
-#define __ST5481_HDLC_H__
-
-struct hdlc_vars {
-       int bit_shift; 
-       int hdlc_bits1;
-       int data_bits;
-       int ffbit_shift; // encoding only
-       int state;
-       int dstpos;
-
-       int data_received:1; // set if transferring data
-       int dchannel:1; // set if D channel (send idle instead of flags)
-       int do_adapt56:1; // set if 56K adaptation
-        int do_closing:1; // set if in closing phase (need to send CRC + flag
-
-       unsigned short crc;
-
-       unsigned char cbin; 
-       unsigned char shift_reg;
-       unsigned char ffvalue;
-       
-};
-
-
-/*
-  The return value from hdlc_decode is
-  the frame length, 0 if no complete frame was decoded,
-  or a negative error number
-*/
-
-#define HDLC_FRAMING_ERROR     1
-#define HDLC_CRC_ERROR         2
-#define HDLC_LENGTH_ERROR      3
-
-void 
-hdlc_rcv_init(struct hdlc_vars *hdlc, int do_adapt56);
-
-int
-hdlc_decode(struct hdlc_vars *hdlc, const unsigned char *src, int slen,int *count, 
-           unsigned char *dst, int dsize);
-
-void 
-hdlc_out_init(struct hdlc_vars *hdlc,int is_d_channel,int do_adapt56);
-
-int 
-hdlc_encode(struct hdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count,
-           unsigned char *dst,int dsize);
-
-#endif
index 2369180b1cb1f685a1d732f5ae38ae2d96993b37..ab62223297a56d8cdd2a097341ccd49ade474f42 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/slab.h>
 #include "st5481.h"
 
+static int st5481_isoc_flatten(struct urb *urb);
+
 /* ======================================================================
  * control pipe
  */
@@ -55,9 +57,9 @@ static void usb_next_ctrl_msg(struct urb *urb,
  * Asynchronous endpoint 0 request (async version of usb_control_msg).
  * The request will be queued up in a FIFO if the endpoint is busy.
  */
-void usb_ctrl_msg(struct st5481_adapter *adapter,
-                 u8 request, u8 requesttype, u16 value, u16 index,
-                 ctrl_complete_t complete, void *context)
+static void usb_ctrl_msg(struct st5481_adapter *adapter,
+                        u8 request, u8 requesttype, u16 value, u16 index,
+                        ctrl_complete_t complete, void *context)
 {
        struct st5481_ctrl *ctrl = &adapter->ctrl;
        int w_index;
@@ -571,7 +573,7 @@ void st5481_release_in(struct st5481_in *in)
  * Make the transfer_buffer contiguous by
  * copying from the iso descriptors if necessary. 
  */
-int st5481_isoc_flatten(struct urb *urb)
+static int st5481_isoc_flatten(struct urb *urb)
 {
        struct usb_iso_packet_descriptor *pipd,*pend;
        unsigned char *src,*dst;
index 082726db39855c7231bf6ec3b7e3dfbbe76b324c..ceb0df92fd3e4e98aa856ac23824f336b715588a 100644 (file)
@@ -74,7 +74,7 @@ static char *strTeiEvent[] =
        "EV_T202",
 };
 
-unsigned int
+static unsigned int
 random_ri(void)
 {
        unsigned int x;
index ef8984c5f1f7aa142553d36480ce6ac0a1e4b77f..a2b1816af37a8b67b4dfb1832a36e4a0a802fc42 100644 (file)
@@ -18,7 +18,7 @@
 
 extern const char *CardType[];
 
-const char *TeleInt_revision = "$Revision: 1.16.2.5 $";
+static const char *TeleInt_revision = "$Revision: 1.16.2.5 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -203,7 +203,7 @@ TeleInt_Timer(struct IsdnCardState *cs)
        add_timer(&cs->hw.hfc.timer);
 }
 
-void
+static void
 release_io_TeleInt(struct IsdnCardState *cs)
 {
        del_timer(&cs->hw.hfc.timer);
index 5ec5ec3e1eabda2189473130f91adca70d3779af..2b7df8f9823327acd590b3fd138ab45daeb507ff 100644 (file)
@@ -23,7 +23,7 @@
 
 extern const char *CardType[];
 
-const char *teles0_revision = "$Revision: 2.15.2.4 $";
+static const char *teles0_revision = "$Revision: 2.15.2.4 $";
 
 #define TELES_IOMEM_SIZE       0x400
 #define byteout(addr,val) outb(val,addr)
@@ -183,7 +183,7 @@ teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-void
+static void
 release_io_teles0(struct IsdnCardState *cs)
 {
        if (cs->hw.teles0.cfg_reg)
index c5b1f65f7275a87d1cac654a472f232a4b1f6b72..adeaad62d35c3d01353a5706a17b3ecb458daf45 100644 (file)
@@ -21,7 +21,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *teles3_revision = "$Revision: 2.19.2.4 $";
+static const char *teles3_revision = "$Revision: 2.19.2.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -154,7 +154,7 @@ release_ioregs(struct IsdnCardState *cs, int mask)
                release_region(cs->hw.teles3.hscx[1] + 32, 32);
 }
 
-void
+static void
 release_io_teles3(struct IsdnCardState *cs)
 {
        if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
index 63e8e20c17a833c769e2a7da6fed0ebf20a0ac60..107376ff5b9b53a61683cc0a5d116740e35fb8a3 100644 (file)
@@ -489,6 +489,12 @@ static int teles_cs_event(event_t event, int priority,
     return 0;
 } /* teles_cs_event */
 
+static struct pcmcia_device_id teles_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, teles_ids);
+
 static struct pcmcia_driver teles_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -496,6 +502,7 @@ static struct pcmcia_driver teles_cs_driver = {
        },
        .attach         = teles_attach,
        .detach         = teles_detach,
+       .id_table       = teles_ids,
 };
 
 static int __init init_teles_cs(void)
index 0661c6c31ad0629b3ae07792f05136718ca31f68..e2bb4fd8e25e7602e9c69fd0151edb739a119daa 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/pci.h>
 
 extern const char *CardType[];
-const char *telespci_revision = "$Revision: 2.23.2.3 $";
+static const char *telespci_revision = "$Revision: 2.23.2.3 $";
 
 #define ZORAN_PO_RQ_PEN        0x02000000
 #define ZORAN_PO_WR    0x00800000
@@ -257,7 +257,7 @@ telespci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-void
+static void
 release_io_telespci(struct IsdnCardState *cs)
 {
        iounmap(cs->hw.teles0.membase);
index d2b6b8e72980dcd2172d56313685228748c712b1..7baf8e4884716080266b3eb3df37a7d41152da41 100644 (file)
@@ -41,7 +41,7 @@ static const PCI_ENTRY id_list[] =
 
 extern const char *CardType[];
 
-const char *w6692_revision = "$Revision: 1.18.2.4 $";
+static const char *w6692_revision = "$Revision: 1.18.2.4 $";
 
 #define DBUSY_TIMER_VALUE 80
 
@@ -880,7 +880,7 @@ setstack_w6692(struct PStack *st, struct BCState *bcs)
        return (0);
 }
 
-void resetW6692(struct IsdnCardState *cs)
+static void resetW6692(struct IsdnCardState *cs)
 {
        cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST);
        mdelay(10);
@@ -902,7 +902,7 @@ void resetW6692(struct IsdnCardState *cs)
        }
 }
 
-void __init initW6692(struct IsdnCardState *cs, int part)
+static void __init initW6692(struct IsdnCardState *cs, int part)
 {
        if (part & 1) {
                cs->setstack_d = setstack_W6692;
index 8ee25b2ccce1b8fb354d1f99088a577d866ed32f..1fd3d4e5f2849b5e9eb699c75cdb6374654d203a 100644 (file)
@@ -42,6 +42,8 @@ typedef struct _hycapi_appl {
 
 static hycapi_appl hycapi_applications[CAPI_MAXAPPL];
 
+static u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
+
 static inline int _hycapi_appCheck(int app_id, int ctrl_no)
 {
        if((ctrl_no <= 0) || (ctrl_no > CAPI_MAXCONTR) || (app_id <= 0) ||
@@ -57,7 +59,7 @@ static inline int _hycapi_appCheck(int app_id, int ctrl_no)
 Kernel-Capi callback reset_ctr
 ******************************/     
 
-void 
+static void
 hycapi_reset_ctr(struct capi_ctr *ctrl)
 {
        hycapictrl_info *cinfo = ctrl->driverdata;
@@ -73,7 +75,7 @@ hycapi_reset_ctr(struct capi_ctr *ctrl)
 Kernel-Capi callback remove_ctr
 ******************************/     
 
-void 
+static void
 hycapi_remove_ctr(struct capi_ctr *ctrl)
 {
        int i;
@@ -215,7 +217,7 @@ Error-checking is done for CAPI-compliance.
 The application is recorded in the internal list.
 *************************************************************/
 
-void 
+static void
 hycapi_register_appl(struct capi_ctr *ctrl, __u16 appl, 
                     capi_register_params *rp)
 {
@@ -291,7 +293,7 @@ Release the application from the internal list an remove it's
 registration at controller-level
 ******************************************************************/
 
-void 
+static void
 hycapi_release_appl(struct capi_ctr *ctrl, __u16 appl)
 {
        int chk;
@@ -364,7 +366,7 @@ firmware-releases that do not check the MsgLen-Indication!
 
 ***************************************************************/
 
-u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
+static u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
 {
        __u16 appl_id;
        int _len, _len2;
@@ -437,8 +439,8 @@ Informations provided in the /proc/capi-entries.
 
 *********************************************************************/
 
-int hycapi_read_proc(char *page, char **start, off_t off,
-                    int count, int *eof, struct capi_ctr *ctrl)
+static int hycapi_read_proc(char *page, char **start, off_t off,
+                           int count, int *eof, struct capi_ctr *ctrl)
 {
        hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
        hysdn_card *card = cinfo->card;
@@ -485,7 +487,7 @@ on capi-interface registration.
 
 **************************************************************/
 
-int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+static int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
 {
 #ifdef HYCAPI_PRINTFNAMES
        printk(KERN_NOTICE "hycapi_load_firmware\n");    
@@ -494,7 +496,7 @@ int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
 }
 
 
-char *hycapi_procinfo(struct capi_ctr *ctrl)
+static char *hycapi_procinfo(struct capi_ctr *ctrl)
 {
        hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
 #ifdef HYCAPI_PRINTFNAMES
index 6c04281e57b850a4432bc2b4e4cc841f9e8b5a9c..7bfba196f3155a9db17137fcab48e5195f3e9bdc 100644 (file)
@@ -53,7 +53,7 @@ struct boot_data {
 /*  to be called at start of POF file reading,       */
 /*  before starting any decryption on any POF record. */
 /*****************************************************/
-void
+static void
 StartDecryption(struct boot_data *boot)
 {
        boot->Cryptor = CRYPT_STARTTERM;
@@ -66,7 +66,7 @@ StartDecryption(struct boot_data *boot)
 /*       to HI and LO boot loader and (all) seq tags, because  */
 /*       global Cryptor is started for whole POF.              */
 /***************************************************************/
-void
+static void
 DecryptBuf(struct boot_data *boot, int cnt)
 {
        uchar *bufp = boot->buf.BootBuf;
index 4cee26e558eedad031f528451ae9414f954d28a9..432f6f99089e5dd5109bcb6b828a8336301eeaf1 100644 (file)
@@ -227,7 +227,6 @@ typedef struct hycapictrl_info hycapictrl_info;
 /*****************/
 /* exported vars */
 /*****************/
-extern int cardmax;            /* number of found cards */
 extern hysdn_card *card_root;  /* pointer to first card */
 
 
@@ -244,7 +243,6 @@ extern void hysdn_procconf_release(void);   /* deinit proc config filesys */
 /* hysdn_proclog.c */
 extern int hysdn_proclog_init(hysdn_card *);   /* init proc log entry */
 extern void hysdn_proclog_release(hysdn_card *);       /* deinit proc log entry */
-extern void put_log_buffer(hysdn_card *, char *);      /* output log data */
 extern void hysdn_addlog(hysdn_card *, char *,...);    /* output data to log */
 extern void hysdn_card_errlog(hysdn_card *, tErrLogEntry *, int);      /* output card log */
 
@@ -278,16 +276,6 @@ extern unsigned int hycapi_enable;
 extern int hycapi_capi_create(hysdn_card *);   /* create a new capi device */
 extern int hycapi_capi_release(hysdn_card *);  /* delete the device */
 extern int hycapi_capi_stop(hysdn_card *card);   /* suspend */
-extern int hycapi_load_firmware(struct capi_ctr *, capiloaddata *);
-extern void hycapi_reset_ctr(struct capi_ctr *);
-extern void hycapi_remove_ctr(struct capi_ctr *);
-extern void hycapi_register_appl(struct capi_ctr *, __u16 appl,
-                                capi_register_params *);
-extern void hycapi_release_appl(struct capi_ctr *, __u16 appl);
-extern u16  hycapi_send_message(struct capi_ctr *, struct sk_buff *skb);
-extern char *hycapi_procinfo(struct capi_ctr *);
-extern int hycapi_read_proc(char *page, char **start, off_t off,
-                           int count, int *eof, struct capi_ctr *card);
 extern void hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len);
 extern void hycapi_tx_capiack(hysdn_card * card);
 extern struct sk_buff *hycapi_tx_capiget(hysdn_card *card);
index 5cac2bf5f4b06f98030455666e6a018afb2f3f7d..12c8137b5161427eef3c8c85305d584da00de24c 100644 (file)
@@ -34,7 +34,7 @@ MODULE_AUTHOR("Werner Cornelius");
 MODULE_LICENSE("GPL");
 
 static char *hysdn_init_revision = "$Revision: 1.6.6.6 $";
-int cardmax;                   /* number of found cards */
+static int cardmax;            /* number of found cards */
 hysdn_card *card_root = NULL;  /* pointer to first card */
 
 /**********************************************/
index 8ef2b7c952a67d5e7d2195024f739e52bdab0223..4d57011c5737646025e5844820065acce465a364 100644 (file)
@@ -22,6 +22,8 @@
 /* the proc subdir for the interface is defined in the procconf module */
 extern struct proc_dir_entry *hysdn_proc_entry;
 
+static void put_log_buffer(hysdn_card * card, char *cp);
+
 /*************************************************/
 /* structure keeping ascii log for device output */
 /*************************************************/
@@ -93,7 +95,7 @@ hysdn_addlog(hysdn_card * card, char *fmt,...)
 /* opened for read got the contents.        */
 /* Flushes buffers not longer in use.       */
 /********************************************/
-void
+static void
 put_log_buffer(hysdn_card * card, char *cp)
 {
        struct log_data *ib;
index 5350836a4f987ee3fc428800090008032c5bcad9..2cc56d6a9fae76758e5a2e5f71a84bd4a25dffcf 100644 (file)
@@ -391,16 +391,6 @@ isdn_audio_adpcm2xlaw(adpcm_state * s, int fmt, unsigned char *in,
        return olen;
 }
 
-int
-isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out)
-{
-       int olen = 0;
-
-       if (s->nleft)
-               isdn_audio_put_bits(0, 8 - s->nleft, s, &out, &olen);
-       return olen;
-}
-
 int
 isdn_audio_xlaw2adpcm(adpcm_state * s, int fmt, unsigned char *in,
                      unsigned char *out, int len)
index 5a977b21dcfa906a2fc8a1825499b9e1e128b3b9..013c3582e0d19f3f813fb8712d3f47d1ef345374 100644 (file)
@@ -35,7 +35,6 @@ extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long);
 extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int);
 extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int);
 extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int);
-extern int isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out);
 extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int);
 extern void isdn_audio_eval_dtmf(modem_info *);
 dtmf_state *isdn_audio_dtmf_init(dtmf_state *);
index c406df6f268a5f630c051bea40c5a45351203de0..eebcb0b97f0e9b6f05d0df1bfa12633285dd9f37 100644 (file)
@@ -67,7 +67,7 @@ static isdn_divert_if *divert_if; /* = NULL */
 static int isdn_writebuf_stub(int, int, const u_char __user *, int);
 static void set_global_features(void);
 static int isdn_wildmat(char *s, char *p);
-
+static int isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding);
 
 static inline void
 isdn_lock_driver(isdn_driver_t *drv)
@@ -388,7 +388,7 @@ isdn_all_eaz(int di, int ch)
  */
 #include <linux/isdn/capicmd.h>
 
-int
+static int
 isdn_capi_rec_hl_msg(capi_msg *cm) {
        
        int di;
@@ -1923,7 +1923,7 @@ isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
        return ret;
 }
 
-int
+static int
 isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding)
 {
        int j, k, m;
index 808135c427ad74737156f516dced2cbce010d84f..e27e9c3a81ed6622641bf853d9e99411c6759183 100644 (file)
@@ -41,7 +41,6 @@ extern int  isdn_get_free_channel(int, int, int, int, int, char *);
 extern int  isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
 extern int  register_isdn(isdn_if * i);
 extern int  isdn_msncmp( const char *,  const char *);
-extern int  isdn_add_channels(isdn_driver_t *, int, int, int);
 #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
 extern void isdn_dumppkt(char *, u_char *, int, int);
 #endif
index 83a4f5382bc2c5b932b65cd9d434417c1e1113b4..0193b6f7c70ca705142fe0d7731dd242b4eacbb6 100644 (file)
@@ -39,7 +39,7 @@
    */
 
 
-int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
+static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
 {
        struct net_device *ndev = concap -> net_dev;
        isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev;
@@ -58,7 +58,7 @@ int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
 }
 
 
-int isdn_concap_dl_connect_req(struct concap_proto *concap)
+static int isdn_concap_dl_connect_req(struct concap_proto *concap)
 {
        struct net_device *ndev = concap -> net_dev;
        isdn_net_local *lp = (isdn_net_local *) ndev->priv;
@@ -71,7 +71,7 @@ int isdn_concap_dl_connect_req(struct concap_proto *concap)
        return ret;
 }
 
-int isdn_concap_dl_disconn_req(struct concap_proto *concap)
+static int isdn_concap_dl_disconn_req(struct concap_proto *concap)
 {
        IX25DEBUG( "isdn_concap_dl_disconn_req: %s \n", concap -> net_dev -> name);
 
@@ -85,15 +85,6 @@ struct concap_device_ops isdn_concap_reliable_dl_dops = {
        &isdn_concap_dl_disconn_req
 };
 
-struct concap_device_ops isdn_concap_demand_dial_dops = {
-       NULL, /* set this first entry to something like &isdn_net_start_xmit,
-                but the entry part of the current isdn_net_start_xmit must be
-                separated first. */
-       /* no connection control for demand dial semantics */
-       NULL,
-       NULL,
-};
-
 /* The following should better go into a dedicated source file such that
    this sourcefile does not need to include any protocol specific header
    files. For now:
index 306eb180438ff2af2663b9d1ee01786fe90ddca8..6ac7e0445ea5e594383a4db71a80ed06e1c3551a 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 extern struct concap_device_ops isdn_concap_reliable_dl_dops;
-extern struct concap_device_ops isdn_concap_demand_dial_dops;
 extern struct concap_proto * isdn_concap_new( int );
 
 
index e2b790e34510840b3587b0357d7e1f6cb97bcc89..f30e8e63ae0dedf9802a044d5d3c6eedd3679721 100644 (file)
@@ -176,7 +176,7 @@ static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
 
 /* Prototypes */
 
-int isdn_net_force_dial_lp(isdn_net_local *);
+static int isdn_net_force_dial_lp(isdn_net_local *);
 static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
 
 static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
@@ -312,7 +312,7 @@ isdn_net_unbind_channel(isdn_net_local * lp)
  * Since this function is called every second, simply reset the
  * byte-counter of the interface after copying it to the cps-variable.
  */
-unsigned long last_jiffies = -HZ;
+static unsigned long last_jiffies = -HZ;
 
 void
 isdn_net_autohup(void)
@@ -1131,7 +1131,7 @@ isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
 }
 
 
-void isdn_net_tx_timeout(struct net_device * ndev)
+static void isdn_net_tx_timeout(struct net_device * ndev)
 {
        isdn_net_local *lp = (isdn_net_local *) ndev->priv;
 
@@ -1424,7 +1424,7 @@ isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
 }
 
 /* cisco hdlck device private ioctls */
-int
+static int
 isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        isdn_net_local *lp = (isdn_net_local *) dev->priv;
@@ -2461,7 +2461,7 @@ isdn_net_findif(char *name)
  * This is called from the userlevel-routine below or
  * from isdn_net_start_xmit().
  */
-int
+static int
 isdn_net_force_dial_lp(isdn_net_local * lp)
 {
        if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) {
index e21007eca0f08ff10b996eebd51f7cfce3897d6a..ad5aa38fb5a6eb6001b4b97d1f8154037f3836e3 100644 (file)
@@ -273,7 +273,7 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
        return 1;
 }
 
-void
+static void
 isdn_tty_cleanup_xmit(modem_info * info)
 {
        skb_queue_purge(&info->xmit_queue);
@@ -560,7 +560,7 @@ isdn_tty_modem_ncarrier(modem_info * info)
 /*
  * return the usage calculated by si and layer 2 protocol
  */
-int
+static int
 isdn_calc_usage(int si, int l2)
 {
        int usg = ISDN_USAGE_MODEM;
index 2423a7ff0cc32ce9541248aff4e93eb2296ff433..9f0fa9501f4d40287fbf980c55a8ec0be9b5926f 100644 (file)
@@ -109,7 +109,6 @@ extern int  isdn_tty_modem_init(void);
 extern void isdn_tty_exit(void);
 extern void isdn_tty_readmodem(void);
 extern int  isdn_tty_find_icall(int, int, setup_parm *);
-extern void isdn_tty_cleanup_xmit(modem_info *);
 extern int  isdn_tty_stat_callback(int, isdn_ctrl *);
 extern int  isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
 extern int  isdn_tty_capi_facility(capi_msg *cm); 
index ce2c3ef92e4661d9050985d442df4cf2017e1cd6..a943d078bacc2991bdd52e8680b4648c3aafb866 100644 (file)
@@ -148,7 +148,7 @@ isdn_tty_fax_modem_result(int code, modem_info * info)
        }
 }
 
-int
+static int
 isdn_tty_fax_command1(modem_info * info, isdn_ctrl * c)
 {
        static char *msg[] =
@@ -316,7 +316,7 @@ isdn_tty_fax_bitorder(modem_info * info, struct sk_buff *skb)
  * Parse AT+F.. FAX class 1 commands
  */
 
-int
+static int
 isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
 {
        static char *cmd[] =
@@ -408,7 +408,7 @@ isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
  * Parse AT+F.. FAX class 2 commands
  */
 
-int
+static int
 isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
 {
        atemu *m = &info->emu;
index 4ab7600cf9c1bb34194580dd05073a4bf9d09424..edf14a2aa3c80a89571770c7ad174572f265b317 100644 (file)
@@ -40,15 +40,15 @@ typedef struct isdn_x25iface_proto_data {
 
 
 /* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */
-void isdn_x25iface_proto_del( struct concap_proto * );
-int isdn_x25iface_proto_close( struct concap_proto * );
-int isdn_x25iface_proto_restart( struct concap_proto *,
-                                struct net_device *,
-                                struct concap_device_ops *);
-int isdn_x25iface_xmit( struct concap_proto *, struct sk_buff * );
-int isdn_x25iface_receive( struct concap_proto *, struct sk_buff * );
-int isdn_x25iface_connect_ind( struct concap_proto * );
-int isdn_x25iface_disconn_ind( struct concap_proto * );
+static void isdn_x25iface_proto_del( struct concap_proto * );
+static int isdn_x25iface_proto_close( struct concap_proto * );
+static int isdn_x25iface_proto_restart( struct concap_proto *,
+                                       struct net_device *,
+                                       struct concap_device_ops *);
+static int isdn_x25iface_xmit( struct concap_proto *, struct sk_buff * );
+static int isdn_x25iface_receive( struct concap_proto *, struct sk_buff * );
+static int isdn_x25iface_connect_ind( struct concap_proto * );
+static int isdn_x25iface_disconn_ind( struct concap_proto * );
 
 
 static struct concap_proto_ops ix25_pops = {
@@ -102,7 +102,7 @@ struct concap_proto * isdn_x25iface_proto_new(void)
 
 /* close the x25iface encapsulation protocol 
  */
-int isdn_x25iface_proto_close(struct concap_proto *cprot){
+static int isdn_x25iface_proto_close(struct concap_proto *cprot){
 
        ix25_pdata_t *tmp;
         int ret = 0;
@@ -129,7 +129,7 @@ int isdn_x25iface_proto_close(struct concap_proto *cprot){
 
 /* Delete the x25iface encapsulation protocol instance
  */
-void isdn_x25iface_proto_del(struct concap_proto *cprot){
+static void isdn_x25iface_proto_del(struct concap_proto *cprot){
 
        ix25_pdata_t * tmp;
  
@@ -158,9 +158,9 @@ void isdn_x25iface_proto_del(struct concap_proto *cprot){
 
 /* (re-)initialize the data structures for x25iface encapsulation
  */
-int isdn_x25iface_proto_restart(struct concap_proto *cprot,
-                               struct net_device *ndev, 
-                               struct concap_device_ops *dops)
+static int isdn_x25iface_proto_restart(struct concap_proto *cprot,
+                                       struct net_device *ndev,
+                                       struct concap_device_ops *dops)
 {
        ix25_pdata_t * pda = cprot -> proto_data ;
        ulong flags;
@@ -187,7 +187,7 @@ int isdn_x25iface_proto_restart(struct concap_proto *cprot,
 
 /* deliver a dl_data frame received from i4l HL driver to the network layer 
  */
-int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
+static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
 {
        IX25DEBUG( "isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev) );
        if ( ( (ix25_pdata_t*) (cprot->proto_data) ) 
@@ -206,7 +206,7 @@ int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
 
 /* a connection set up is indicated by lower layer 
  */
-int isdn_x25iface_connect_ind(struct concap_proto *cprot)
+static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
 {
        struct sk_buff * skb = dev_alloc_skb(1);
        enum wan_states *state_p 
@@ -235,7 +235,7 @@ int isdn_x25iface_connect_ind(struct concap_proto *cprot)
        
 /* a disconnect is indicated by lower layer 
  */
-int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
+static int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
 {
        struct sk_buff *skb;
        enum wan_states *state_p 
@@ -264,7 +264,7 @@ int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
 /* process a frame handed over to us from linux network layer. First byte
    semantics as defined in Documentation/networking/x25-iface.txt
    */
-int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
+static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
 {
        unsigned char firstbyte = skb->data[0];
        enum wan_states *state = &((ix25_pdata_t*)cprot->proto_data)->state;
index 692ec72d1ee8b8626c209b9cabc6f0799c2f55a2..f151f36c8255d4995efccdf53cd2097ddda406e9 100644 (file)
@@ -124,23 +124,6 @@ void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
 }
 
 
-/*
- * Disconnect received (actually RELEASE COMPLETE) 
- * This means we were not able to establish connection with remote
- * Inform the big boss above
- */
-void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
-             struct callb_data *data) 
-{
-        isdn_ctrl ictl;
-
-        ictl.command = ISDN_STAT_DHUP;
-        ictl.driver=dev->id;
-        ictl.arg=chan->id;
-        dev->dev_if->statcallb(&ictl);
-}
-
-
 /*
  * Incoming call received
  * inform user
index f510dc56b57eadb94f14bd15b9652bcaca205e93..17aa0f54bfc3ce7d8c4c9935ebf2ab0f740f4fdb 100644 (file)
@@ -19,9 +19,6 @@ extern void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
 extern void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan, 
                     struct callb_data *data);
 
-extern void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan, 
-                    struct callb_data *data);
-
 extern void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan, 
                    struct callb_data *data);
 extern void cb_in_2(struct pcbit_dev * dev, struct pcbit_chan* chan, 
index 29eb03a8c29d093ab0ec32e0f568317253a7f9f6..bef321d0e51d5a2775ef47fd6ddbcd6b6507bffc 100644 (file)
@@ -627,16 +627,6 @@ int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb)
         return 0;
 }
 
-int capi_decode_disc_conf(struct pcbit_chan *chan, struct sk_buff *skb)
-{
-        ushort errcode;
-
-        errcode = *((ushort*) skb->data);
-        skb_pull(skb, 2);
-
-        return errcode;                
-}
-
 #ifdef DEBUG
 int capi_decode_debug_188(u_char *hdr, ushort hdrlen)
 {
index 18e6aa360a8f9c249576bae3295de938bdd4e462..df8e73c04d7fc2052cc0b86ad6d9eed8a789967a 100644 (file)
@@ -54,7 +54,6 @@ extern int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb);
 
 /* Connection Termination */
 extern int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause);
-extern int capi_decode_disc_conf(struct pcbit_chan *chan, struct sk_buff *skb);
 
 extern int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb);
 extern int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb);
index e98f9c48c18461a9a56cc5bf6395cf4a1f73b357..5de861f4081605ec66d0c375291dda166c8bae80 100644 (file)
@@ -56,10 +56,10 @@ static char* pcbit_devname[MAX_PCBIT_CARDS] = {
  * prototypes
  */
 
-int pcbit_command(isdn_ctrl* ctl);
-int pcbit_stat(u_char __user * buf, int len, int, int);
-int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb);
-int pcbit_writecmd(const u_char __user *, int, int, int);
+static int pcbit_command(isdn_ctrl* ctl);
+static int pcbit_stat(u_char __user * buf, int len, int, int);
+static int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb);
+static int pcbit_writecmd(const u_char __user *, int, int, int);
 
 static int set_protocol_running(struct pcbit_dev * dev);
 
@@ -238,7 +238,7 @@ void pcbit_terminate(int board)
 }
 #endif
 
-int pcbit_command(isdn_ctrl* ctl)
+static int pcbit_command(isdn_ctrl* ctl)
 {
        struct pcbit_dev  *dev;
        struct pcbit_chan *chan;
@@ -330,7 +330,7 @@ static void pcbit_block_timer(unsigned long data)
 }
 #endif
 
-int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb)
+static int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb)
 {
        ushort hdrlen;
        int refnum, len;
@@ -389,7 +389,7 @@ int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb)
        return len;
 }
 
-int pcbit_writecmd(const u_char __user *buf, int len, int driver, int channel)
+static int pcbit_writecmd(const u_char __user *buf, int len, int driver, int channel)
 {
        struct pcbit_dev * dev;
        int i, j;
@@ -713,7 +713,7 @@ static char statbuf[STATBUF_LEN];
 static int stat_st = 0;
 static int stat_end = 0;
 
-int pcbit_stat(u_char __user *buf, int len, int driver, int channel)
+static int pcbit_stat(u_char __user *buf, int len, int driver, int channel)
 {
        int stat_count;
        stat_count = stat_end - stat_st;
index 9cc474cd0c44c5bc7401a41d78599e6b62c82c49..0f2b7d602ac031ebd6750702648d1e44934014e4 100644 (file)
@@ -6,5 +6,5 @@ obj-$(CONFIG_ISDN_DRV_SC)       += sc.o
 
 # Multipart objects.
 
-sc-y                           := shmem.o init.o debug.o packet.o command.o event.o \
+sc-y                           := shmem.o init.o packet.o command.o event.o \
                                   ioctl.o interrupt.o message.o timer.o        
index b2c4eac7cef536ad42403837aedac5a4d3cd8a74..19f2fcf0ae4a2f579eabac0e9b5720eec8b9f209 100644 (file)
 #include "card.h"
 #include "scioc.h"
 
-int dial(int card, unsigned long channel, setup_parm setup);
-int hangup(int card, unsigned long channel);
-int answer(int card, unsigned long channel);
-int clreaz(int card, unsigned long channel);
-int seteaz(int card, unsigned long channel, char *);
-int setl2(int card, unsigned long arg);
-int setl3(int card, unsigned long arg);
-int acceptb(int card, unsigned long channel);
+static int dial(int card, unsigned long channel, setup_parm setup);
+static int hangup(int card, unsigned long channel);
+static int answer(int card, unsigned long channel);
+static int clreaz(int card, unsigned long channel);
+static int seteaz(int card, unsigned long channel, char *);
+static int setl2(int card, unsigned long arg);
+static int setl3(int card, unsigned long arg);
+static int acceptb(int card, unsigned long channel);
 
 extern int cinst;
 extern board *sc_adapter[];
@@ -147,56 +147,6 @@ int command(isdn_ctrl *cmd)
        return 0;
 }
 
-/*
- * Confirm our ability to communicate with the board.  This test assumes no
- * other message activity is present
- */
-int loopback(int card) 
-{
-
-       int status;
-       static char testmsg[] = "Test Message";
-       RspMessage rspmsg;
-
-       if(!IS_VALID_CARD(card)) {
-               pr_debug("Invalid param: %d is not a valid card id\n", card);
-               return -ENODEV;
-       }
-
-       pr_debug("%s: Sending loopback message\n",
-               sc_adapter[card]->devicename);
-
-       /*
-        * Send the loopback message to confirm that memory transfer is
-        * operational
-        */
-       status = send_and_receive(card, CMPID, cmReqType1,
-                                 cmReqClass0,
-                                 cmReqMsgLpbk,
-                                 0,
-                                 (unsigned char) strlen(testmsg),
-                                 (unsigned char *)testmsg,
-                                 &rspmsg, SAR_TIMEOUT);
-
-
-       if (!status) {
-               pr_debug("%s: Loopback message successfully sent\n",
-                       sc_adapter[card]->devicename);
-               if(strcmp(rspmsg.msg_data.byte_array, testmsg)) {
-                       pr_debug("%s: Loopback return != sent\n",
-                               sc_adapter[card]->devicename);
-                       return -EIO;
-               }
-               return 0;
-       }
-       else {
-               pr_debug("%s: Send loopback message failed\n",
-                       sc_adapter[card]->devicename);
-               return -EIO;
-       }
-
-}
-
 /*
  * start the onboard firmware
  */
@@ -222,16 +172,10 @@ int startproc(int card)
 }
 
 
-int loadproc(int card, char *data) 
-{
-       return -1;
-}
-
-
 /*
  * Dials the number passed in 
  */
-int dial(int card, unsigned long channel, setup_parm setup) 
+static int dial(int card, unsigned long channel, setup_parm setup)
 {
        int status;
        char Phone[48];
@@ -261,7 +205,7 @@ int dial(int card, unsigned long channel, setup_parm setup)
 /*
  * Answer an incoming call 
  */
-int answer(int card, unsigned long channel) 
+static int answer(int card, unsigned long channel)
 {
        if(!IS_VALID_CARD(card)) {
                pr_debug("Invalid param: %d is not a valid card id\n", card);
@@ -282,7 +226,7 @@ int answer(int card, unsigned long channel)
 /*
  * Hangup up the call on specified channel
  */
-int hangup(int card, unsigned long channel) 
+static int hangup(int card, unsigned long channel)
 {
        int status;
 
@@ -305,7 +249,7 @@ int hangup(int card, unsigned long channel)
 /*
  * Set the layer 2 protocol (X.25, HDLC, Raw)
  */
-int setl2(int card, unsigned long arg) 
+static int setl2(int card, unsigned long arg)
 {
        int status =0;
        int protocol,channel;
@@ -340,7 +284,7 @@ int setl2(int card, unsigned long arg)
 /*
  * Set the layer 3 protocol
  */
-int setl3(int card, unsigned long channel) 
+static int setl3(int card, unsigned long channel)
 {
        int protocol = channel >> 8;
 
@@ -355,7 +299,7 @@ int setl3(int card, unsigned long channel)
        return 0;
 }
 
-int acceptb(int card, unsigned long channel)
+static int acceptb(int card, unsigned long channel)
 {
        if(!IS_VALID_CARD(card)) {
                pr_debug("Invalid param: %d is not a valid card id\n", card);
@@ -374,7 +318,7 @@ int acceptb(int card, unsigned long channel)
        return 0;
 }
 
-int clreaz(int card, unsigned long arg)
+static int clreaz(int card, unsigned long arg)
 {
        if(!IS_VALID_CARD(card)) {
                pr_debug("Invalid param: %d is not a valid card id\n", card);
@@ -388,7 +332,7 @@ int clreaz(int card, unsigned long arg)
        return 0;
 }
 
-int seteaz(int card, unsigned long arg, char *num)
+static int seteaz(int card, unsigned long arg, char *num)
 {
        if(!IS_VALID_CARD(card)) {
                pr_debug("Invalid param: %d is not a valid card id\n", card);
diff --git a/drivers/isdn/sc/debug.c b/drivers/isdn/sc/debug.c
deleted file mode 100644 (file)
index 1a992a7..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/* $Id: debug.c,v 1.5.6.1 2001/09/23 22:24:59 kai Exp $
- *
- * Copyright (C) 1996  SpellCaster Telecommunications Inc.
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For more information, please contact gpl-info@spellcast.com or write:
- *
- *     SpellCaster Telecommunications Inc.
- *     5621 Finch Avenue East, Unit #3
- *     Scarborough, Ontario  Canada
- *     M1B 2T9
- *     +1 (416) 297-8565
- *     +1 (416) 297-6433 Facsimile
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-int dbg_level = 0;
-static char dbg_funcname[255];
-
-void dbg_endfunc(void)
-{
-       if (dbg_level) {
-               printk("<-- Leaving function %s\n", dbg_funcname);
-               strcpy(dbg_funcname, "");
-       }
-}
-
-void dbg_func(char *func)
-{
-       strcpy(dbg_funcname, func);
-       if(dbg_level)
-               printk("--> Entering function %s\n", dbg_funcname);
-}
-
-inline void pullphone(char *dn, char *str)
-{
-       int i = 0;
-
-       while(dn[i] != ',')
-               str[i] = dn[i], i++;
-       str[i] = 0x0;
-}
index efefedea37b9a8dddf085fcb7c287c9014c3497a..40b0df04ed9f1620e2d36e8336bb243fda21ce88 100644 (file)
@@ -20,9 +20,9 @@ board *sc_adapter[MAX_CARDS];
 int cinst;
 
 static char devname[] = "scX";
-const char version[] = "2.0b1";
+static const char version[] = "2.0b1";
 
-const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" };
+static const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" };
 
 /* insmod set parameters */
 static unsigned int io[] = {0,0,0,0};
@@ -35,26 +35,13 @@ module_param_array(irq, int, NULL, 0);
 module_param_array(ram, int, NULL, 0);
 module_param(do_reset, bool, 0);
 
-static int sup_irq[] = { 11, 10, 9, 5, 12, 14, 7, 3, 4, 6 };
-#define MAX_IRQS       10
-
 extern irqreturn_t interrupt_handler(int, void *, struct pt_regs *);
 extern int sndpkt(int, int, int, struct sk_buff *);
 extern int command(isdn_ctrl *);
 extern int indicate_status(int, int, ulong, char*);
 extern int reset(int);
 
-int identify_board(unsigned long, unsigned int);
-
-int irq_supported(int irq_x)
-{
-       int i;
-       for(i=0 ; i < MAX_IRQS ; i++) {
-               if(sup_irq[i] == irq_x)
-                       return 1;
-       }
-       return 0;
-}
+static int identify_board(unsigned long, unsigned int);
 
 static int __init sc_init(void)
 {
@@ -454,7 +441,7 @@ static void __exit sc_exit(void)
        pr_info("SpellCaster ISA ISDN Adapter Driver Unloaded.\n");
 }
 
-int identify_board(unsigned long rambase, unsigned int iobase) 
+static int identify_board(unsigned long rambase, unsigned int iobase)
 {
        unsigned int pgport;
        unsigned long sig;
index e5e164aca7faf7d46aa9f05291e715da334adbe6..8631d338d69ab550084ad4e3d0eaaebacd206b6c 100644 (file)
@@ -31,7 +31,7 @@ extern void rcvpkt(int, RspMessage *);
 extern int cinst;
 extern board *sc_adapter[];
 
-int get_card_from_irq(int irq)
+static int get_card_from_irq(int irq)
 {
        int i;
 
index 1371a990416a4fcc8d95f42a947cf74c6e070044..3314a5a19854239f2bf335102c4e6f1c6dabfa97 100644 (file)
@@ -14,7 +14,6 @@
 
 extern int indicate_status(int, int, unsigned long, char *);
 extern int startproc(int);
-extern int loadproc(int, char *record);
 extern int reset(int);
 extern int send_and_receive(int, unsigned int, unsigned char,unsigned char,
                unsigned char,unsigned char, 
@@ -23,7 +22,7 @@ extern int send_and_receive(int, unsigned int, unsigned char,unsigned char,
 extern board *sc_adapter[];
 
 
-int GetStatus(int card, boardInfo *);
+static int GetStatus(int card, boardInfo *);
 
 /*
  * Process private IOCTL messages (typically from scctrl)
@@ -428,7 +427,7 @@ int sc_ioctl(int card, scs_ioctl *data)
        return 0;
 }
 
-int GetStatus(int card, boardInfo *bi)
+static int GetStatus(int card, boardInfo *bi)
 {
        RspMessage rcvmsg;
        int i, status;
index 8e3fac3ba1a19672e65ce3f5e8ccfe6192566458..f50defc38ae5b47baac92c6117b39d9a3bab1b04 100644 (file)
@@ -213,19 +213,3 @@ int setup_buffers(int card, int c)
        return 0;
 }
 
-int print_skb(int card,char *skb_p, int len){
-       int i,data;
-       pr_debug("%s: data at 0x%x len: 0x%x\n", sc_adapter[card]->devicename,
-                       skb_p,len);
-       for(i=1;i<=len;i++,skb_p++){
-               data = (int) (0xff & (*skb_p));
-               pr_debug("%s: data =  0x%x", sc_adapter[card]->devicename,data);
-               if(!(i%4))
-                       pr_debug(" ");
-               if(!(i%32))
-                       pr_debug("\n");
-       }
-       pr_debug("\n");
-       return 0;
-}              
-
index 7bc2dfad0775f2cbdf66fd0bbdeb94eaab079f8b..24854826ca4599842fd7165f4de12f548f1f9b45 100644 (file)
@@ -108,6 +108,7 @@ void memcpy_fromshmem(int card, void *dest, const void *src, size_t n)
                sc_adapter[card]->rambase + ((unsigned long) src %0x4000), (unsigned long) dest); */
 }
 
+#if 0
 void memset_shmem(int card, void *dest, int c, size_t n)
 {
        unsigned long flags;
@@ -141,3 +142,4 @@ void memset_shmem(int card, void *dest, int c, size_t n)
                ((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
        spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
 }
+#endif  /*  0  */
index 710d0f47ca35ccd2bdce256cc806b425bde3e8da..aced19aac5a2e5011d81cb4f03ef6805836e5d62 100644 (file)
@@ -32,7 +32,7 @@ extern int  sendmessage(int, unsigned int, unsigned int, unsigned int,
 /*
  * Write the proper values into the I/O ports following a reset
  */
-void setup_ports(int card)
+static void setup_ports(int card)
 {
 
        outb((sc_adapter[card]->rambase >> 12), sc_adapter[card]->ioport[EXP_BASE]);
@@ -129,19 +129,3 @@ void check_phystat(unsigned long data)
                ceReqPhyStatus,0,0,NULL);
 }
 
-/*
- * When in trace mode, this callback is used to swap the working shared
- * RAM page to the trace page(s) and process all received messages. It
- * must be called often enough to get all of the messages out of RAM before
- * it loops around.
- * Trace messages are \n terminated strings.
- * We output the messages in 64 byte chunks through readstat. Each chunk
- * is scanned for a \n followed by a time stamp. If the timerstamp is older
- * than the current time, scanning stops and the page and offset are recorded
- * as the starting point the next time the trace timer is called. The final
- * step is to restore the working page and reset the timer.
- */
-void trace_timer(unsigned long data)
-{
-       /* not implemented */
-}
index 8a7117a08cf09a44b712eff882ab175150ecd537..91691a6c004e4dd33d2bb3e9eed8896ee8f3c2a6 100644 (file)
@@ -86,33 +86,18 @@ config PMAC_SMU
          on the "SMU" system control chip which replaces the old PMU.
          If you don't know, say Y.
 
-config PMAC_PBOOK
-       bool "Power management support for PowerBooks"
-       depends on ADB_PMU
-       ---help---
-         This provides support for putting a PowerBook to sleep; it also
-         enables media bay support.  Power management works on the
-         PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3 and
-         the Titanium Powerbook G4, as well as the iBooks.  You should get
-         the power management daemon, pmud, to make it work and you must have
-         the /dev/pmu device (see the pmud README).
-
-         Get pmud from <ftp://ftp.samba.org/pub/ppclinux/pmud/>.
-
-         If you have a PowerBook, you should say Y here.
-
-         You may also want to compile the dma sound driver as a module and
-         have it autoloaded. The act of removing the module shuts down the
-         sound hardware for more power savings.
-
-config PM
-       bool
-       depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
-       default y
-
 config PMAC_APM_EMU
        tristate "APM emulation"
-       depends on PMAC_PBOOK
+       depends on PPC_PMAC && PPC32 && PM
+
+config PMAC_MEDIABAY
+       bool "Support PowerBook hotswap media bay"
+       depends on PPC_PMAC && PPC32
+       help
+         This option adds support for older PowerBook's hotswap media bay
+         that can contains batteries, floppy drives, or IDE devices. PCI
+         devices are not fully supported in the bay as I never had one to
+         try with
 
 # made a separate option since backlight may end up beeing used
 # on non-powerbook machines (but only on PMU based ones AFAIK)
@@ -126,13 +111,6 @@ config PMAC_BACKLIGHT
          events; also, the PowerBook button device will be enabled so you can
          change the screen brightness.
 
-config MAC_SERIAL
-       tristate "Support for PowerMac serial ports (OBSOLETE DRIVER)"
-       depends on PPC_PMAC && BROKEN
-       help
-         This driver is obsolete. Use CONFIG_SERIAL_PMACZILOG in
-         "Character devices --> Serial drivers --> PowerMac z85c30" option.
-
 config ADB_MACIO
        bool "Include MacIO (CHRP) ADB driver"
        depends on ADB && PPC_CHRP && !PPC_PMAC64
index c3a4705a82953a7391c0010698c45487938023fc..f5ae171dbfef3b537ce98139dd7fe3e78ddad249 100644 (file)
@@ -6,8 +6,7 @@
 
 obj-$(CONFIG_PPC_PMAC)         += macio_asic.o
 
-obj-$(CONFIG_PMAC_PBOOK)       += mediabay.o
-obj-$(CONFIG_MAC_SERIAL)       += macserial.o
+obj-$(CONFIG_PMAC_MEDIABAY)    += mediabay.o
 obj-$(CONFIG_MAC_EMUMOUSEBTN)  += mac_hid.o
 obj-$(CONFIG_INPUT_ADBHID)     += adbhid.o
 obj-$(CONFIG_ANSLCD)           += ans-lcd.o
index 493e2afa191cec0d56e92a62dfe2d13a301cbb4e..c0dc1e3fa58bfa1f28074f136de8bcfa8d269cca 100644 (file)
@@ -90,7 +90,7 @@ static int sleepy_trackpad;
 static int autopoll_devs;
 int __adb_probe_sync;
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
 static struct pmu_sleep_notifier adb_sleep_notifier = {
        adb_notify_sleep,
@@ -320,9 +320,9 @@ int __init adb_init(void)
                printk(KERN_WARNING "Warning: no ADB interface detected\n");
                adb_controller = NULL;
        } else {
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
                pmu_register_sleep_notifier(&adb_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 #ifdef CONFIG_PPC
                if (machine_is_compatible("AAPL,PowerBook1998") ||
                        machine_is_compatible("PowerBook1,1"))
@@ -337,7 +337,7 @@ int __init adb_init(void)
 
 __initcall(adb_init);
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 /*
  * notify clients before sleep and reset bus afterwards
  */
@@ -378,7 +378,7 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
        }
        return PBOOK_SLEEP_OK;
 }
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
 static int
 do_adb_reset_bus(void)
diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c
deleted file mode 100644 (file)
index 0be3ac6..0000000
+++ /dev/null
@@ -1,3036 +0,0 @@
-/*
- * macserial.c: Serial port driver for Power Macintoshes.
- *
- * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *
- * Receive DMA code by Takashi Oe <toe@unlserve.unl.edu>.
- *
- * $Id: macserial.c,v 1.24.2.4 1999/10/19 04:36:42 paulus Exp $
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#ifdef CONFIG_SERIAL_CONSOLE
-#include <linux/console.h>
-#endif
-#include <linux/slab.h>
-#include <linux/bitops.h>
-
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/prom.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-#endif
-#include <asm/dbdma.h>
-
-#include "macserial.h"
-
-#ifdef CONFIG_PMAC_PBOOK
-static int serial_notify_sleep(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier serial_sleep_notifier = {
-       serial_notify_sleep,
-       SLEEP_LEVEL_MISC,
-};
-#endif
-
-#define SUPPORT_SERIAL_DMA
-#define MACSERIAL_VERSION      "2.0"
-
-/*
- * It would be nice to dynamically allocate everything that
- * depends on NUM_SERIAL, so we could support any number of
- * Z8530s, but for now...
- */
-#define NUM_SERIAL     2               /* Max number of ZS chips supported */
-#define NUM_CHANNELS   (NUM_SERIAL * 2)        /* 2 channels per chip */
-
-/* On PowerMacs, the hardware takes care of the SCC recovery time,
-   but we need the eieio to make sure that the accesses occur
-   in the order we want. */
-#define RECOVERY_DELAY eieio()
-
-static struct tty_driver *serial_driver;
-
-struct mac_zschannel zs_channels[NUM_CHANNELS];
-
-struct mac_serial zs_soft[NUM_CHANNELS];
-int zs_channels_found;
-struct mac_serial *zs_chain;   /* list of all channels */
-
-struct tty_struct zs_ttys[NUM_CHANNELS];
-
-static int is_powerbook;
-
-#ifdef CONFIG_SERIAL_CONSOLE
-static struct console sercons;
-#endif
-
-#ifdef CONFIG_KGDB
-struct mac_zschannel *zs_kgdbchan;
-static unsigned char scc_inittab[] = {
-       9,  0x80,       /* reset A side (CHRA) */
-       13, 0,          /* set baud rate divisor */
-       12, 1,
-       14, 1,          /* baud rate gen enable, src=rtxc (BRENABL) */
-       11, 0x50,       /* clocks = br gen (RCBR | TCBR) */
-       5,  0x6a,       /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
-       4,  0x44,       /* x16 clock, 1 stop (SB1 | X16CLK)*/
-       3,  0xc1,       /* rx enable, 8 bits (RxENABLE | Rx8)*/
-};
-#endif
-#define ZS_CLOCK         3686400       /* Z8530 RTxC input clock rate */
-
-/* serial subtype definitions */
-#define SERIAL_TYPE_NORMAL     1
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/*
- * Debugging.
- */
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_POWER
-#undef SERIAL_DEBUG_THROTTLE
-#undef SERIAL_DEBUG_STOP
-#undef SERIAL_DEBUG_BAUDS
-
-#define RS_STROBE_TIME 10
-#define RS_ISR_PASS_LIMIT 256
-
-#define _INLINE_ inline
-
-#ifdef SERIAL_DEBUG_OPEN
-#define OPNDBG(fmt, arg...)    printk(KERN_DEBUG fmt , ## arg)
-#else
-#define OPNDBG(fmt, arg...)    do { } while (0)
-#endif
-#ifdef SERIAL_DEBUG_POWER
-#define PWRDBG(fmt, arg...)    printk(KERN_DEBUG fmt , ## arg)
-#else
-#define PWRDBG(fmt, arg...)    do { } while (0)
-#endif
-#ifdef SERIAL_DEBUG_BAUDS
-#define BAUDBG(fmt, arg...)    printk(fmt , ## arg)
-#else
-#define BAUDBG(fmt, arg...)    do { } while (0)
-#endif
-
-static void probe_sccs(void);
-static void change_speed(struct mac_serial *info, struct termios *old);
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-static int set_scc_power(struct mac_serial * info, int state);
-static int setup_scc(struct mac_serial * info);
-static void dbdma_reset(volatile struct dbdma_regs *dma);
-static void dbdma_flush(volatile struct dbdma_regs *dma);
-static irqreturn_t rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs);
-static void dma_init(struct mac_serial * info);
-static void rxdma_start(struct mac_serial * info, int curr);
-static void rxdma_to_tty(struct mac_serial * info);
-
-/*
- * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
-
-
-static inline int __pmac
-serial_paranoia_check(struct mac_serial *info,
-                     char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-       static const char badmagic[] = KERN_WARNING
-               "Warning: bad magic number for serial struct %s in %s\n";
-       static const char badinfo[] = KERN_WARNING
-               "Warning: null mac_serial for %s in %s\n";
-
-       if (!info) {
-               printk(badinfo, name, routine);
-               return 1;
-       }
-       if (info->magic != SERIAL_MAGIC) {
-               printk(badmagic, name, routine);
-               return 1;
-       }
-#endif
-       return 0;
-}
-
-/* 
- * Reading and writing Z8530 registers.
- */
-static inline unsigned char __pmac read_zsreg(struct mac_zschannel *channel,
-                                             unsigned char reg)
-{
-       unsigned char retval;
-       unsigned long flags;
-
-       /*
-        * We have to make this atomic.
-        */
-       spin_lock_irqsave(&channel->lock, flags);
-       if (reg != 0) {
-               *channel->control = reg;
-               RECOVERY_DELAY;
-       }
-       retval = *channel->control;
-       RECOVERY_DELAY;
-       spin_unlock_irqrestore(&channel->lock, flags);
-       return retval;
-}
-
-static inline void __pmac write_zsreg(struct mac_zschannel *channel,
-                                     unsigned char reg, unsigned char value)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&channel->lock, flags);
-       if (reg != 0) {
-               *channel->control = reg;
-               RECOVERY_DELAY;
-       }
-       *channel->control = value;
-       RECOVERY_DELAY;
-       spin_unlock_irqrestore(&channel->lock, flags);
-       return;
-}
-
-static inline unsigned char __pmac read_zsdata(struct mac_zschannel *channel)
-{
-       unsigned char retval;
-
-       retval = *channel->data;
-       RECOVERY_DELAY;
-       return retval;
-}
-
-static inline void write_zsdata(struct mac_zschannel *channel,
-                               unsigned char value)
-{
-       *channel->data = value;
-       RECOVERY_DELAY;
-       return;
-}
-
-static inline void load_zsregs(struct mac_zschannel *channel,
-                              unsigned char *regs)
-{
-       ZS_CLEARERR(channel);
-       ZS_CLEARFIFO(channel);
-       /* Load 'em up */
-       write_zsreg(channel, R4, regs[R4]);
-       write_zsreg(channel, R10, regs[R10]);
-       write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
-       write_zsreg(channel, R5, regs[R5] & ~TxENAB);
-       write_zsreg(channel, R1, regs[R1]);
-       write_zsreg(channel, R9, regs[R9]);
-       write_zsreg(channel, R11, regs[R11]);
-       write_zsreg(channel, R12, regs[R12]);
-       write_zsreg(channel, R13, regs[R13]);
-       write_zsreg(channel, R14, regs[R14]);
-       write_zsreg(channel, R15, regs[R15]);
-       write_zsreg(channel, R3, regs[R3]);
-       write_zsreg(channel, R5, regs[R5]);
-       return;
-}
-
-/* Sets or clears DTR/RTS on the requested line */
-static inline void zs_rtsdtr(struct mac_serial *ss, int set)
-{
-       if (set)
-               ss->curregs[5] |= (RTS | DTR);
-       else
-               ss->curregs[5] &= ~(RTS | DTR);
-       write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
-       return;
-}
-
-/* Utility routines for the Zilog */
-static inline int get_zsbaud(struct mac_serial *ss)
-{
-       struct mac_zschannel *channel = ss->zs_channel;
-       int brg;
-
-       if ((ss->curregs[R11] & TCBR) == 0) {
-               /* higher rates don't use the baud rate generator */
-               return (ss->curregs[R4] & X32CLK)? ZS_CLOCK/32: ZS_CLOCK/16;
-       }
-       /* The baud rate is split up between two 8-bit registers in
-        * what is termed 'BRG time constant' format in my docs for
-        * the chip, it is a function of the clk rate the chip is
-        * receiving which happens to be constant.
-        */
-       brg = (read_zsreg(channel, 13) << 8);
-       brg |= read_zsreg(channel, 12);
-       return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
-}
-
-/* On receive, this clears errors and the receiver interrupts */
-static inline void rs_recv_clear(struct mac_zschannel *zsc)
-{
-       write_zsreg(zsc, 0, ERR_RES);
-       write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
-}
-
-/*
- * Reset a Descriptor-Based DMA channel.
- */
-static void dbdma_reset(volatile struct dbdma_regs *dma)
-{
-       int i;
-
-       out_le32(&dma->control, (WAKE|FLUSH|PAUSE|RUN) << 16);
-
-       /*
-        * Yes this looks peculiar, but apparently it needs to be this
-        * way on some machines.  (We need to make sure the DBDMA
-        * engine has actually got the write above and responded
-        * to it. - paulus)
-        */
-       for (i = 200; i > 0; --i)
-               if (ld_le32(&dma->status) & RUN)
-                       udelay(1);
-}
-
-/*
- * Tells a DBDMA channel to stop and write any buffered data
- * it might have to memory.
- */
-static _INLINE_ void dbdma_flush(volatile struct dbdma_regs *dma)
-{
-       int i = 0;
-
-       out_le32(&dma->control, (FLUSH << 16) | FLUSH);
-       while (((in_le32(&dma->status) & FLUSH) != 0) && (i++ < 100))
-               udelay(1);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt().  They were separated out for readability's sake.
- *
- *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static _INLINE_ void rs_sched_event(struct mac_serial *info,
-                                 int event)
-{
-       info->event |= 1 << event;
-       schedule_work(&info->tqueue);
-}
-
-/* Work out the flag value for a z8530 status value. */
-static _INLINE_ int stat_to_flag(int stat)
-{
-       int flag;
-
-       if (stat & Rx_OVR) {
-               flag = TTY_OVERRUN;
-       } else if (stat & FRM_ERR) {
-               flag = TTY_FRAME;
-       } else if (stat & PAR_ERR) {
-               flag = TTY_PARITY;
-       } else
-               flag = 0;
-       return flag;
-}
-
-static _INLINE_ void receive_chars(struct mac_serial *info,
-                                  struct pt_regs *regs)
-{
-       struct tty_struct *tty = info->tty;
-       unsigned char ch, stat, flag;
-
-       while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) != 0) {
-
-               stat = read_zsreg(info->zs_channel, R1);
-               ch = read_zsdata(info->zs_channel);
-
-#ifdef CONFIG_KGDB
-               if (info->kgdb_channel) {
-                       if (ch == 0x03 || ch == '$')
-                               breakpoint();
-                       if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
-                               write_zsreg(info->zs_channel, 0, ERR_RES);
-                       return;
-               }
-#endif
-               if (!tty)
-                       continue;
-               if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-                       tty_flip_buffer_push(tty);
-
-               if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                       static int flip_buf_ovf;
-                       if (++flip_buf_ovf <= 1)
-                               printk(KERN_WARNING "FB. overflow: %d\n",
-                                                   flip_buf_ovf);
-                       break;
-               }
-               tty->flip.count++;
-               {
-                       static int flip_max_cnt;
-                       if (flip_max_cnt < tty->flip.count)
-                               flip_max_cnt = tty->flip.count;
-               }
-               flag = stat_to_flag(stat);
-               if (flag)
-                       /* reset the error indication */
-                       write_zsreg(info->zs_channel, 0, ERR_RES);
-               *tty->flip.flag_buf_ptr++ = flag;
-               *tty->flip.char_buf_ptr++ = ch;
-       }
-       if (tty)
-               tty_flip_buffer_push(tty);
-}
-
-static void transmit_chars(struct mac_serial *info)
-{
-       if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0)
-               return;
-       info->tx_active = 0;
-
-       if (info->x_char && !info->power_wait) {
-               /* Send next char */
-               write_zsdata(info->zs_channel, info->x_char);
-               info->x_char = 0;
-               info->tx_active = 1;
-               return;
-       }
-
-       if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped
-           || info->power_wait) {
-               write_zsreg(info->zs_channel, 0, RES_Tx_P);
-               return;
-       }
-
-       /* Send char */
-       write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
-       info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-       info->xmit_cnt--;
-       info->tx_active = 1;
-
-       if (info->xmit_cnt < WAKEUP_CHARS)
-               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-}
-
-static void powerup_done(unsigned long data)
-{
-       struct mac_serial *info = (struct mac_serial *) data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&info->lock, flags);
-       info->power_wait = 0;
-       transmit_chars(info);
-       spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static _INLINE_ void status_handle(struct mac_serial *info)
-{
-       unsigned char status;
-
-       /* Get status from Read Register 0 */
-       status = read_zsreg(info->zs_channel, 0);
-
-       /* Check for DCD transitions */
-       if (((status ^ info->read_reg_zero) & DCD) != 0
-           && info->tty && !C_CLOCAL(info->tty)) {
-               if (status & DCD) {
-                       wake_up_interruptible(&info->open_wait);
-               } else {
-                       if (info->tty)
-                               tty_hangup(info->tty);
-               }
-       }
-
-       /* Check for CTS transitions */
-       if (info->tty && C_CRTSCTS(info->tty)) {
-               /*
-                * For some reason, on the Power Macintosh,
-                * it seems that the CTS bit is 1 when CTS is
-                * *negated* and 0 when it is asserted.
-                * The DCD bit doesn't seem to be inverted
-                * like this.
-                */
-               if ((status & CTS) == 0) {
-                       if (info->tx_stopped) {
-#ifdef SERIAL_DEBUG_FLOW
-                               printk(KERN_DEBUG "CTS up\n");
-#endif
-                               info->tx_stopped = 0;
-                               if (!info->tx_active)
-                                       transmit_chars(info);
-                       }
-               } else {
-#ifdef SERIAL_DEBUG_FLOW
-                       printk(KERN_DEBUG "CTS down\n");
-#endif
-                       info->tx_stopped = 1;
-               }
-       }
-
-       /* Clear status condition... */
-       write_zsreg(info->zs_channel, 0, RES_EXT_INT);
-       info->read_reg_zero = status;
-}
-
-static _INLINE_ void receive_special_dma(struct mac_serial *info)
-{
-       unsigned char stat, flag;
-       volatile struct dbdma_regs *rd = &info->rx->dma;
-       int where = RX_BUF_SIZE;
-
-       spin_lock(&info->rx_dma_lock);
-       if ((ld_le32(&rd->status) & ACTIVE) != 0)
-               dbdma_flush(rd);
-       if (in_le32(&rd->cmdptr)
-           == virt_to_bus(info->rx_cmds[info->rx_cbuf] + 1))
-               where -= in_le16(&info->rx->res_count);
-       where--;
-
-       stat = read_zsreg(info->zs_channel, R1);
-
-       flag = stat_to_flag(stat);
-       if (flag) {
-               info->rx_flag_buf[info->rx_cbuf][where] = flag;
-               /* reset the error indication */
-               write_zsreg(info->zs_channel, 0, ERR_RES);
-       }
-
-       spin_unlock(&info->rx_dma_lock);
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-static irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-       struct mac_serial *info = (struct mac_serial *) dev_id;
-       unsigned char zs_intreg;
-       int shift;
-       unsigned long flags;
-       int handled = 0;
-
-       if (!(info->flags & ZILOG_INITIALIZED)) {
-               printk(KERN_WARNING "rs_interrupt: irq %d, port not "
-                                   "initialized\n", irq);
-               disable_irq(irq);
-               return IRQ_NONE;
-       }
-
-       /* NOTE: The read register 3, which holds the irq status,
-        *       does so for both channels on each chip.  Although
-        *       the status value itself must be read from the A
-        *       channel and is only valid when read from channel A.
-        *       Yes... broken hardware...
-        */
-#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
-
-       if (info->zs_chan_a == info->zs_channel)
-               shift = 3;      /* Channel A */
-       else
-               shift = 0;      /* Channel B */
-
-       spin_lock_irqsave(&info->lock, flags);
-       for (;;) {
-               zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
-#ifdef SERIAL_DEBUG_INTR
-               printk(KERN_DEBUG "rs_interrupt: irq %d, zs_intreg 0x%x\n",
-                      irq, (int)zs_intreg);
-#endif
-
-               if ((zs_intreg & CHAN_IRQMASK) == 0)
-                       break;
-               handled = 1;
-
-               if (zs_intreg & CHBRxIP) {
-                       /* If we are doing DMA, we only ask for interrupts
-                          on characters with errors or special conditions. */
-                       if (info->dma_initted)
-                               receive_special_dma(info);
-                       else
-                               receive_chars(info, regs);
-               }
-               if (zs_intreg & CHBTxIP)
-                       transmit_chars(info);
-               if (zs_intreg & CHBEXT)
-                       status_handle(info);
-       }
-       spin_unlock_irqrestore(&info->lock, flags);
-       return IRQ_RETVAL(handled);
-}
-
-/* Transmit DMA interrupt - not used at present */
-static irqreturn_t rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-       return IRQ_HANDLED;
-}
-
-/*
- * Receive DMA interrupt.
- */
-static irqreturn_t rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-       struct mac_serial *info = (struct mac_serial *) dev_id;
-       volatile struct dbdma_cmd *cd;
-
-       if (!info->dma_initted)
-               return IRQ_NONE;
-       spin_lock(&info->rx_dma_lock);
-       /* First, confirm that this interrupt is, indeed, coming */
-       /* from Rx DMA */
-       cd = info->rx_cmds[info->rx_cbuf] + 2;
-       if ((in_le16(&cd->xfer_status) & (RUN | ACTIVE)) != (RUN | ACTIVE)) {
-               spin_unlock(&info->rx_dma_lock);
-               return IRQ_NONE;
-       }
-       if (info->rx_fbuf != RX_NO_FBUF) {
-               info->rx_cbuf = info->rx_fbuf;
-               if (++info->rx_fbuf == info->rx_nbuf)
-                       info->rx_fbuf = 0;
-               if (info->rx_fbuf == info->rx_ubuf)
-                       info->rx_fbuf = RX_NO_FBUF;
-       }
-       spin_unlock(&info->rx_dma_lock);
-       return IRQ_HANDLED;
-}
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
-       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-
-#ifdef SERIAL_DEBUG_STOP
-       printk(KERN_DEBUG "rs_stop %ld....\n",
-              tty->ldisc.chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "rs_stop"))
-               return;
-
-#if 0
-       spin_lock_irqsave(&info->lock, flags);
-       if (info->curregs[5] & TxENAB) {
-               info->curregs[5] &= ~TxENAB;
-               info->pendregs[5] &= ~TxENAB;
-               write_zsreg(info->zs_channel, 5, info->curregs[5]);
-       }
-       spin_unlock_irqrestore(&info->lock, flags);
-#endif
-}
-
-static void rs_start(struct tty_struct *tty)
-{
-       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-       unsigned long flags;
-
-#ifdef SERIAL_DEBUG_STOP
-       printk(KERN_DEBUG "rs_start %ld....\n", 
-              tty->ldisc.chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "rs_start"))
-               return;
-
-       spin_lock_irqsave(&info->lock, flags);
-#if 0
-       if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
-               info->curregs[5] |= TxENAB;
-               info->pendregs[5] = info->curregs[5];
-               write_zsreg(info->zs_channel, 5, info->curregs[5]);
-       }
-#else
-       if (info->xmit_cnt && info->xmit_buf && !info->tx_active) {
-               transmit_chars(info);
-       }
-#endif
-       spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static void do_softint(void *private_)
-{
-       struct mac_serial       *info = (struct mac_serial *) private_;
-       struct tty_struct       *tty;
-
-       tty = info->tty;
-       if (!tty)
-               return;
-
-       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
-               tty_wakeup(tty);
-}
-
-static int startup(struct mac_serial * info)
-{
-       int delay;
-
-       OPNDBG("startup() (ttyS%d, irq %d)\n", info->line, info->irq);
-       if (info->flags & ZILOG_INITIALIZED) {
-               OPNDBG(" -> already inited\n");
-               return 0;
-       }
-
-       if (!info->xmit_buf) {
-               info->xmit_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
-               if (!info->xmit_buf)
-                       return -ENOMEM;
-       }
-
-       OPNDBG("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
-
-       delay = set_scc_power(info, 1);
-
-       setup_scc(info);
-
-       if (delay) {
-               unsigned long flags;
-
-               /* delay is in ms */
-               spin_lock_irqsave(&info->lock, flags);
-               info->power_wait = 1;
-               mod_timer(&info->powerup_timer,
-                         jiffies + (delay * HZ + 999) / 1000);
-               spin_unlock_irqrestore(&info->lock, flags);
-       }
-
-       OPNDBG("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq);
-
-       info->flags |= ZILOG_INITIALIZED;
-       enable_irq(info->irq);
-       if (info->dma_initted) {
-               enable_irq(info->rx_dma_irq);
-       }
-
-       return 0;
-}
-
-static _INLINE_ void rxdma_start(struct mac_serial * info, int curr)
-{
-       volatile struct dbdma_regs *rd = &info->rx->dma;
-       volatile struct dbdma_cmd *cd = info->rx_cmds[curr];
-
-//printk(KERN_DEBUG "SCC: rxdma_start\n");
-
-       st_le32(&rd->cmdptr, virt_to_bus(cd));
-       out_le32(&rd->control, (RUN << 16) | RUN);
-}
-
-static void rxdma_to_tty(struct mac_serial *info)
-{
-       struct tty_struct       *tty = info->tty;
-       volatile struct dbdma_regs *rd = &info->rx->dma;
-       unsigned long flags;
-       int residue, available, space, do_queue;
-
-       if (!tty)
-               return;
-
-       do_queue = 0;
-       spin_lock_irqsave(&info->rx_dma_lock, flags);
-more:
-       space = TTY_FLIPBUF_SIZE - tty->flip.count;
-       if (!space) {
-               do_queue++;
-               goto out;
-       }
-       residue = 0;
-       if (info->rx_ubuf == info->rx_cbuf) {
-               if ((ld_le32(&rd->status) & ACTIVE) != 0) {
-                       dbdma_flush(rd);
-                       if (in_le32(&rd->cmdptr)
-                           == virt_to_bus(info->rx_cmds[info->rx_cbuf]+1))
-                               residue = in_le16(&info->rx->res_count);
-               }
-       }
-       available = RX_BUF_SIZE - residue - info->rx_done_bytes;
-       if (available > space)
-               available = space;
-       if (available) {
-               memcpy(tty->flip.char_buf_ptr,
-                      info->rx_char_buf[info->rx_ubuf] + info->rx_done_bytes,
-                      available);
-               memcpy(tty->flip.flag_buf_ptr,
-                      info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
-                      available);
-               tty->flip.char_buf_ptr += available;
-               tty->flip.count += available;
-               tty->flip.flag_buf_ptr += available;
-               memset(info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
-                      0, available);
-               info->rx_done_bytes += available;
-               do_queue++;
-       }
-       if (info->rx_done_bytes == RX_BUF_SIZE) {
-               volatile struct dbdma_cmd *cd = info->rx_cmds[info->rx_ubuf];
-
-               if (info->rx_ubuf == info->rx_cbuf)
-                       goto out;
-               /* mark rx_char_buf[rx_ubuf] free */
-               st_le16(&cd->command, DBDMA_NOP);
-               cd++;
-               st_le32(&cd->cmd_dep, 0);
-               st_le32((unsigned int *)&cd->res_count, 0);
-               cd++;
-               st_le16(&cd->xfer_status, 0);
-
-               if (info->rx_fbuf == RX_NO_FBUF) {
-                       info->rx_fbuf = info->rx_ubuf;
-                       if (!(ld_le32(&rd->status) & ACTIVE)) {
-                               dbdma_reset(&info->rx->dma);
-                               rxdma_start(info, info->rx_ubuf);
-                               info->rx_cbuf = info->rx_ubuf;
-                       }
-               }
-               info->rx_done_bytes = 0;
-               if (++info->rx_ubuf == info->rx_nbuf)
-                       info->rx_ubuf = 0;
-               if (info->rx_fbuf == info->rx_ubuf)
-                       info->rx_fbuf = RX_NO_FBUF;
-               goto more;
-       }
-out:
-       spin_unlock_irqrestore(&info->rx_dma_lock, flags);
-       if (do_queue)
-               tty_flip_buffer_push(tty);
-}
-
-static void poll_rxdma(unsigned long private_)
-{
-       struct mac_serial       *info = (struct mac_serial *) private_;
-       unsigned long flags;
-
-       rxdma_to_tty(info);
-       spin_lock_irqsave(&info->rx_dma_lock, flags);
-       mod_timer(&info->poll_dma_timer, RX_DMA_TIMER);
-       spin_unlock_irqrestore(&info->rx_dma_lock, flags);
-}
-
-static void dma_init(struct mac_serial * info)
-{
-       int i, size;
-       volatile struct dbdma_cmd *cd;
-       unsigned char *p;
-
-       info->rx_nbuf = 8;
-
-       /* various mem set up */
-       size = sizeof(struct dbdma_cmd) * (3 * info->rx_nbuf + 2)
-               + (RX_BUF_SIZE * 2 + sizeof(*info->rx_cmds)
-                  + sizeof(*info->rx_char_buf) + sizeof(*info->rx_flag_buf))
-               * info->rx_nbuf;
-       info->dma_priv = kmalloc(size, GFP_KERNEL | GFP_DMA);
-       if (info->dma_priv == NULL)
-               return;
-       memset(info->dma_priv, 0, size);
-
-       info->rx_cmds = (volatile struct dbdma_cmd **)info->dma_priv;
-       info->rx_char_buf = (unsigned char **) (info->rx_cmds + info->rx_nbuf);
-       info->rx_flag_buf = info->rx_char_buf + info->rx_nbuf;
-       p = (unsigned char *) (info->rx_flag_buf + info->rx_nbuf);
-       for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
-               info->rx_char_buf[i] = p;
-       for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
-               info->rx_flag_buf[i] = p;
-
-       /* a bit of DMA programming */
-       cd = info->rx_cmds[0] = (volatile struct dbdma_cmd *) DBDMA_ALIGN(p);
-       st_le16(&cd->command, DBDMA_NOP);
-       cd++;
-       st_le16(&cd->req_count, RX_BUF_SIZE);
-       st_le16(&cd->command, INPUT_MORE);
-       st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[0]));
-       cd++;
-       st_le16(&cd->req_count, 4);
-       st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
-       st_le32(&cd->phy_addr, virt_to_bus(cd-2));
-       st_le32(&cd->cmd_dep, DBDMA_STOP);
-       for (i = 1; i < info->rx_nbuf; i++) {
-               info->rx_cmds[i] = ++cd;
-               st_le16(&cd->command, DBDMA_NOP);
-               cd++;
-               st_le16(&cd->req_count, RX_BUF_SIZE);
-               st_le16(&cd->command, INPUT_MORE);
-               st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[i]));
-               cd++;
-               st_le16(&cd->req_count, 4);
-               st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
-               st_le32(&cd->phy_addr, virt_to_bus(cd-2));
-               st_le32(&cd->cmd_dep, DBDMA_STOP);
-       }
-       cd++;
-       st_le16(&cd->command, DBDMA_NOP | BR_ALWAYS);
-       st_le32(&cd->cmd_dep, virt_to_bus(info->rx_cmds[0]));
-
-       /* setup DMA to our liking */
-       dbdma_reset(&info->rx->dma);
-       st_le32(&info->rx->dma.intr_sel, 0x10001);
-       st_le32(&info->rx->dma.br_sel, 0x10001);
-       out_le32(&info->rx->dma.wait_sel, 0x10001);
-
-       /* set various flags */
-       info->rx_ubuf = 0;
-       info->rx_cbuf = 0;
-       info->rx_fbuf = info->rx_ubuf + 1;
-       if (info->rx_fbuf == info->rx_nbuf)
-               info->rx_fbuf = RX_NO_FBUF;
-       info->rx_done_bytes = 0;
-
-       /* setup polling */
-       init_timer(&info->poll_dma_timer);
-       info->poll_dma_timer.function = (void *)&poll_rxdma;
-       info->poll_dma_timer.data = (unsigned long)info;
-
-       info->dma_initted = 1;
-}
-
-/*
- * FixZeroBug....Works around a bug in the SCC receving channel.
- * Taken from Darwin code, 15 Sept. 2000  -DanM
- *
- * The following sequence prevents a problem that is seen with O'Hare ASICs
- * (most versions -- also with some Heathrow and Hydra ASICs) where a zero
- * at the input to the receiver becomes 'stuck' and locks up the receiver.
- * This problem can occur as a result of a zero bit at the receiver input
- * coincident with any of the following events:
- *
- *     The SCC is initialized (hardware or software).
- *     A framing error is detected.
- *     The clocking option changes from synchronous or X1 asynchronous
- *             clocking to X16, X32, or X64 asynchronous clocking.
- *     The decoding mode is changed among NRZ, NRZI, FM0, or FM1.
- *
- * This workaround attempts to recover from the lockup condition by placing
- * the SCC in synchronous loopback mode with a fast clock before programming
- * any of the asynchronous modes.
- */
-static void fix_zero_bug_scc(struct mac_serial * info)
-{
-       write_zsreg(info->zs_channel, 9,
-                   (info->zs_channel == info->zs_chan_a? CHRA: CHRB));
-       udelay(10);
-       write_zsreg(info->zs_channel, 9,
-                   ((info->zs_channel == info->zs_chan_a? CHRA: CHRB) | NV));
-
-       write_zsreg(info->zs_channel, 4, (X1CLK | EXTSYNC));
-
-       /* I think this is wrong....but, I just copying code....
-       */
-       write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE));
-
-       write_zsreg(info->zs_channel, 5, (8 & ~TxENAB));
-       write_zsreg(info->zs_channel, 9, NV);   /* Didn't we already do this? */
-       write_zsreg(info->zs_channel, 11, (RCBR | TCBR));
-       write_zsreg(info->zs_channel, 12, 0);
-       write_zsreg(info->zs_channel, 13, 0);
-       write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR));
-       write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR | BRENABL));
-       write_zsreg(info->zs_channel, 3, (8 | RxENABLE));
-       write_zsreg(info->zs_channel, 0, RES_EXT_INT);
-       write_zsreg(info->zs_channel, 0, RES_EXT_INT);  /* to kill some time */
-
-       /* The channel should be OK now, but it is probably receiving
-        * loopback garbage.
-        * Switch to asynchronous mode, disable the receiver,
-        * and discard everything in the receive buffer.
-        */
-       write_zsreg(info->zs_channel, 9, NV);
-       write_zsreg(info->zs_channel, 4, PAR_ENA);
-       write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE));
-
-       while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV) {
-               (void)read_zsreg(info->zs_channel, 8);
-               write_zsreg(info->zs_channel, 0, RES_EXT_INT);
-               write_zsreg(info->zs_channel, 0, ERR_RES);
-       }
-}
-
-static int setup_scc(struct mac_serial * info)
-{
-       unsigned long flags;
-
-       OPNDBG("setting up ttyS%d SCC...\n", info->line);
-
-       spin_lock_irqsave(&info->lock, flags);
-
-       /* Nice buggy HW ... */
-       fix_zero_bug_scc(info);
-
-       /*
-        * Reset the chip.
-        */
-       write_zsreg(info->zs_channel, 9,
-                   (info->zs_channel == info->zs_chan_a? CHRA: CHRB));
-       udelay(10);
-       write_zsreg(info->zs_channel, 9, 0);
-
-       /*
-        * Clear the receive FIFO.
-        */
-       ZS_CLEARFIFO(info->zs_channel);
-       info->xmit_fifo_size = 1;
-
-       /*
-        * Reset DMAs
-        */
-       if (info->has_dma)
-               dma_init(info);
-
-       /*
-        * Clear the interrupt registers.
-        */
-       write_zsreg(info->zs_channel, 0, ERR_RES);
-       write_zsreg(info->zs_channel, 0, RES_H_IUS);
-
-       /*
-        * Turn on RTS and DTR.
-        */
-       if (!info->is_irda)
-               zs_rtsdtr(info, 1);
-
-       /*
-        * Finally, enable sequencing and interrupts
-        */
-       if (!info->dma_initted) {
-               /* interrupt on ext/status changes, all received chars,
-                  transmit ready */
-               info->curregs[1] = (info->curregs[1] & ~0x18)
-                               | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
-       } else {
-               /* interrupt on ext/status changes, W/Req pin is
-                  receive DMA request */
-               info->curregs[1] = (info->curregs[1] & ~(0x18 | TxINT_ENAB))
-                               | (EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN);
-               write_zsreg(info->zs_channel, 1, info->curregs[1]);
-               /* enable W/Req pin */
-               info->curregs[1] |= WT_RDY_ENAB;
-               write_zsreg(info->zs_channel, 1, info->curregs[1]);
-               /* enable interrupts on transmit ready and receive errors */
-               info->curregs[1] |= INT_ERR_Rx | TxINT_ENAB;
-       }
-       info->pendregs[1] = info->curregs[1];
-       info->curregs[3] |= (RxENABLE | Rx8);
-       info->pendregs[3] = info->curregs[3];
-       info->curregs[5] |= (TxENAB | Tx8);
-       info->pendregs[5] = info->curregs[5];
-       info->curregs[9] |= (NV | MIE);
-       info->pendregs[9] = info->curregs[9];
-       write_zsreg(info->zs_channel, 3, info->curregs[3]);
-       write_zsreg(info->zs_channel, 5, info->curregs[5]);
-       write_zsreg(info->zs_channel, 9, info->curregs[9]);
-
-       if (info->tty)
-               clear_bit(TTY_IO_ERROR, &info->tty->flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
-       spin_unlock_irqrestore(&info->lock, flags);
-
-       /*
-        * Set the speed of the serial port
-        */
-       change_speed(info, 0);
-
-       /* Save the current value of RR0 */
-       info->read_reg_zero = read_zsreg(info->zs_channel, 0);
-
-       if (info->dma_initted) {
-               spin_lock_irqsave(&info->rx_dma_lock, flags);
-               rxdma_start(info, 0);
-               info->poll_dma_timer.expires = RX_DMA_TIMER;
-               add_timer(&info->poll_dma_timer);
-               spin_unlock_irqrestore(&info->rx_dma_lock, flags);
-       }
-
-       return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct mac_serial * info)
-{
-       OPNDBG("Shutting down serial port %d (irq %d)....\n", info->line,
-              info->irq);
-
-       if (!(info->flags & ZILOG_INITIALIZED)) {
-               OPNDBG("(already shutdown)\n");
-               return;
-       }
-
-       if (info->has_dma) {
-               del_timer(&info->poll_dma_timer);
-               dbdma_reset(info->tx_dma);
-               dbdma_reset(&info->rx->dma);
-               disable_irq(info->tx_dma_irq);
-               disable_irq(info->rx_dma_irq);
-       }
-       disable_irq(info->irq);
-
-       info->pendregs[1] = info->curregs[1] = 0;
-       write_zsreg(info->zs_channel, 1, 0);    /* no interrupts */
-
-       info->curregs[3] &= ~RxENABLE;
-       info->pendregs[3] = info->curregs[3];
-       write_zsreg(info->zs_channel, 3, info->curregs[3]);
-
-       info->curregs[5] &= ~TxENAB;
-       if (!info->tty || C_HUPCL(info->tty))
-               info->curregs[5] &= ~DTR;
-       info->pendregs[5] = info->curregs[5];
-       write_zsreg(info->zs_channel, 5, info->curregs[5]);
-
-       if (info->tty)
-               set_bit(TTY_IO_ERROR, &info->tty->flags);
-
-       set_scc_power(info, 0);
-
-       if (info->xmit_buf) {
-               free_page((unsigned long) info->xmit_buf);
-               info->xmit_buf = 0;
-       }
-
-       if (info->has_dma && info->dma_priv) {
-               kfree(info->dma_priv);
-               info->dma_priv = NULL;
-               info->dma_initted = 0;
-       }
-
-       memset(info->curregs, 0, sizeof(info->curregs));
-       memset(info->pendregs, 0, sizeof(info->pendregs));
-
-       info->flags &= ~ZILOG_INITIALIZED;
-}
-
-/*
- * Turn power on or off to the SCC and associated stuff
- * (port drivers, modem, IR port, etc.)
- * Returns the number of milliseconds we should wait before
- * trying to use the port.
- */
-static int set_scc_power(struct mac_serial * info, int state)
-{
-       int delay = 0;
-
-       if (state) {
-               PWRDBG("ttyS%d: powering up hardware\n", info->line);
-               pmac_call_feature(
-                       PMAC_FTR_SCC_ENABLE,
-                       info->dev_node, info->port_type, 1);
-               if (info->is_internal_modem) {
-                       pmac_call_feature(
-                               PMAC_FTR_MODEM_ENABLE,
-                               info->dev_node, 0, 1);
-                       delay = 2500;   /* wait for 2.5s before using */
-               } else if (info->is_irda)
-                       mdelay(50);     /* Do better here once the problems
-                                        * with blocking have been ironed out
-                                        */
-       } else {
-               /* TODO: Make that depend on a timer, don't power down
-                * immediately
-                */
-               PWRDBG("ttyS%d: shutting down hardware\n", info->line);
-               if (info->is_internal_modem) {
-                       PWRDBG("ttyS%d: shutting down modem\n", info->line);
-                       pmac_call_feature(
-                               PMAC_FTR_MODEM_ENABLE,
-                               info->dev_node, 0, 0);
-               }
-               pmac_call_feature(
-                       PMAC_FTR_SCC_ENABLE,
-                       info->dev_node, info->port_type, 0);
-       }
-       return delay;
-}
-
-static void irda_rts_pulses(struct mac_serial *info, int w)
-{
-       udelay(w);
-       write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
-       udelay(2);
-       write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
-       udelay(8);
-       write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
-       udelay(4);
-       write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
-}
-
-/*
- * Set the irda codec on the imac to the specified baud rate.
- */
-static void irda_setup(struct mac_serial *info)
-{
-       int code, speed, t;
-
-       speed = info->tty->termios->c_cflag & CBAUD;
-       if (speed < B2400 || speed > B115200)
-               return;
-       code = 0x4d + B115200 - speed;
-
-       /* disable serial interrupts and receive DMA */
-       write_zsreg(info->zs_channel, 1, info->curregs[1] & ~0x9f);
-
-       /* wait for transmitter to drain */
-       t = 10000;
-       while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0
-              || (read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
-               if (--t <= 0) {
-                       printk(KERN_ERR "transmitter didn't drain\n");
-                       return;
-               }
-               udelay(10);
-       }
-       udelay(100);
-
-       /* set to 8 bits, no parity, 19200 baud, RTS on, DTR off */
-       write_zsreg(info->zs_channel, 4, X16CLK | SB1);
-       write_zsreg(info->zs_channel, 11, TCBR | RCBR);
-       t = BPS_TO_BRG(19200, ZS_CLOCK/16);
-       write_zsreg(info->zs_channel, 12, t);
-       write_zsreg(info->zs_channel, 13, t >> 8);
-       write_zsreg(info->zs_channel, 14, BRENABL);
-       write_zsreg(info->zs_channel, 3, Rx8 | RxENABLE);
-       write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
-
-       /* set TxD low for ~104us and pulse RTS */
-       udelay(1000);
-       write_zsdata(info->zs_channel, 0xfe);
-       irda_rts_pulses(info, 150);
-       irda_rts_pulses(info, 180);
-       irda_rts_pulses(info, 50);
-       udelay(100);
-
-       /* assert DTR, wait 30ms, talk to the chip */
-       write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS | DTR);
-       mdelay(30);
-       while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV)
-               read_zsdata(info->zs_channel);
-
-       write_zsdata(info->zs_channel, 1);
-       t = 1000;
-       while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {
-               if (--t <= 0) {
-                       printk(KERN_ERR "irda_setup timed out on 1st byte\n");
-                       goto out;
-               }
-               udelay(10);
-       }
-       t = read_zsdata(info->zs_channel);
-       if (t != 4)
-               printk(KERN_ERR "irda_setup 1st byte = %x\n", t);
-
-       write_zsdata(info->zs_channel, code);
-       t = 1000;
-       while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {
-               if (--t <= 0) {
-                       printk(KERN_ERR "irda_setup timed out on 2nd byte\n");
-                       goto out;
-               }
-               udelay(10);
-       }
-       t = read_zsdata(info->zs_channel);
-       if (t != code)
-               printk(KERN_ERR "irda_setup 2nd byte = %x (%x)\n", t, code);
-
-       /* Drop DTR again and do some more RTS pulses */
- out:
-       udelay(100);
-       write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
-       irda_rts_pulses(info, 80);
-
-       /* We should be right to go now.  We assume that load_zsregs
-          will get called soon to load up the correct baud rate etc. */
-       info->curregs[5] = (info->curregs[5] | RTS) & ~DTR;
-       info->pendregs[5] = info->curregs[5];
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct mac_serial *info, struct termios *old_termios)
-{
-       unsigned cflag;
-       int     bits;
-       int     brg, baud;
-       unsigned long flags;
-
-       if (!info->tty || !info->tty->termios)
-               return;
-
-       cflag = info->tty->termios->c_cflag;
-       baud = tty_get_baud_rate(info->tty);
-       if (baud == 0) {
-               if (old_termios) {
-                       info->tty->termios->c_cflag &= ~CBAUD;
-                       info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
-                       cflag = info->tty->termios->c_cflag;
-                       baud = tty_get_baud_rate(info->tty);
-               }
-               else
-                       baud = info->zs_baud;
-       }
-       if (baud > 230400)
-               baud = 230400;
-       else if (baud == 0)
-               baud = 38400;
-
-       spin_lock_irqsave(&info->lock, flags);
-       info->zs_baud = baud;
-       info->clk_divisor = 16;
-
-       BAUDBG(KERN_DEBUG "set speed to %d bds, ", baud);
-
-       switch (baud) {
-       case ZS_CLOCK/16:       /* 230400 */
-               info->curregs[4] = X16CLK;
-               info->curregs[11] = 0;
-               break;
-       case ZS_CLOCK/32:       /* 115200 */
-               info->curregs[4] = X32CLK;
-               info->curregs[11] = 0;
-               break;
-       default:
-               info->curregs[4] = X16CLK;
-               info->curregs[11] = TCBR | RCBR;
-               brg = BPS_TO_BRG(baud, ZS_CLOCK/info->clk_divisor);
-               info->curregs[12] = (brg & 255);
-               info->curregs[13] = ((brg >> 8) & 255);
-               info->curregs[14] = BRENABL;
-       }
-
-       /* byte size and parity */
-       info->curregs[3] &= ~RxNBITS_MASK;
-       info->curregs[5] &= ~TxNBITS_MASK;
-       switch (cflag & CSIZE) {
-       case CS5:
-               info->curregs[3] |= Rx5;
-               info->curregs[5] |= Tx5;
-               BAUDBG("5 bits, ");
-               bits = 7;
-               break;
-       case CS6:
-               info->curregs[3] |= Rx6;
-               info->curregs[5] |= Tx6;
-               BAUDBG("6 bits, ");
-               bits = 8;
-               break;
-       case CS7:
-               info->curregs[3] |= Rx7;
-               info->curregs[5] |= Tx7;
-               BAUDBG("7 bits, ");
-               bits = 9;
-               break;
-       case CS8:
-       default: /* defaults to 8 bits */
-               info->curregs[3] |= Rx8;
-               info->curregs[5] |= Tx8;
-               BAUDBG("8 bits, ");
-               bits = 10;
-               break;
-       }
-       info->pendregs[3] = info->curregs[3];
-       info->pendregs[5] = info->curregs[5];
-
-       info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
-       if (cflag & CSTOPB) {
-               info->curregs[4] |= SB2;
-               bits++;
-               BAUDBG("2 stop, ");
-       } else {
-               info->curregs[4] |= SB1;
-               BAUDBG("1 stop, ");
-       }
-       if (cflag & PARENB) {
-               bits++;
-               info->curregs[4] |= PAR_ENA;
-               BAUDBG("parity, ");
-       }
-       if (!(cflag & PARODD)) {
-               info->curregs[4] |= PAR_EVEN;
-       }
-       info->pendregs[4] = info->curregs[4];
-
-       if (!(cflag & CLOCAL)) {
-               if (!(info->curregs[15] & DCDIE))
-                       info->read_reg_zero = read_zsreg(info->zs_channel, 0);
-               info->curregs[15] |= DCDIE;
-       } else
-               info->curregs[15] &= ~DCDIE;
-       if (cflag & CRTSCTS) {
-               info->curregs[15] |= CTSIE;
-               if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
-                       info->tx_stopped = 1;
-       } else {
-               info->curregs[15] &= ~CTSIE;
-               info->tx_stopped = 0;
-       }
-       info->pendregs[15] = info->curregs[15];
-
-       /* Calc timeout value. This is pretty broken with high baud rates with HZ=100.
-          This code would love a larger HZ and a >1 fifo size, but this is not
-          a priority. The resulting value must be >HZ/2
-        */
-       info->timeout = ((info->xmit_fifo_size*HZ*bits) / baud);
-       info->timeout += HZ/50+1;       /* Add .02 seconds of slop */
-
-       BAUDBG("timeout=%d/%ds, base:%d\n", (int)info->timeout, (int)HZ,
-              (int)info->baud_base);
-
-       /* set the irda codec to the right rate */
-       if (info->is_irda)
-               irda_setup(info);
-
-       /* Load up the new values */
-       load_zsregs(info->zs_channel, info->curregs);
-
-       spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
-       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
-               return;
-
-       spin_lock_irqsave(&info->lock, flags);
-       if (!(info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||
-             !info->xmit_buf))
-               /* Enable transmitter */
-               transmit_chars(info);
-       spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static int rs_write(struct tty_struct * tty,
-                   const unsigned char *buf, int count)
-{
-       int     c, ret = 0;
-       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_write"))
-               return 0;
-
-       if (!tty || !info->xmit_buf || !tmp_buf)
-               return 0;
-
-       while (1) {
-               spin_lock_irqsave(&info->lock, flags);
-               c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                         SERIAL_XMIT_SIZE - info->xmit_head));
-               if (c <= 0) {
-                       spin_unlock_irqrestore(&info->lock, flags);
-                       break;
-               }
-               memcpy(info->xmit_buf + info->xmit_head, buf, c);
-               info->xmit_head = ((info->xmit_head + c) &
-                                  (SERIAL_XMIT_SIZE-1));
-               info->xmit_cnt += c;
-               spin_unlock_irqrestore(&info->lock, flags);
-               buf += c;
-               count -= c;
-               ret += c;
-       }
-       spin_lock_irqsave(&info->lock, flags);
-       if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
-           && !info->tx_active)
-               transmit_chars(info);
-       spin_unlock_irqrestore(&info->lock, flags);
-       return ret;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
-       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-       int     ret;
-
-       if (serial_paranoia_check(info, tty->name, "rs_write_room"))
-               return 0;
-       ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
-       if (ret < 0)
-               ret = 0;
-       return ret;
-}
-
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
-       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
-               return 0;
-       return info->xmit_cnt;
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
-       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
-               return;
-       spin_lock_irqsave(&info->lock, flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-       spin_unlock_irqrestore(&info->lock, flags);
-       tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- * 
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_throttle(struct tty_struct * tty)
-{
-       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-       unsigned long flags;
-#ifdef SERIAL_DEBUG_THROTTLE
-       printk(KERN_DEBUG "throttle %ld....\n",tty->ldisc.chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "rs_throttle"))
-               return;
-
-       if (I_IXOFF(tty)) {
-               spin_lock_irqsave(&info->lock, flags);
-               info->x_char = STOP_CHAR(tty);
-               if (!info->tx_active)
-                       transmit_chars(info);
-               spin_unlock_irqrestore(&info->lock, flags);
-       }
-
-       if (C_CRTSCTS(tty)) {
-               /*
-                * Here we want to turn off the RTS line.  On Macintoshes,
-                * the external serial ports using a DIN-8 or DIN-9
-                * connector only have the DTR line (which is usually
-                * wired to both RTS and DTR on an external modem in
-                * the cable).  RTS doesn't go out to the serial port
-                * socket, it acts as an output enable for the transmit
-                * data line.  So in this case we don't drop RTS.
-                *
-                * Macs with internal modems generally do have both RTS
-                * and DTR wired to the modem, so in that case we do
-                * drop RTS.
-                */
-               if (info->is_internal_modem) {
-                       spin_lock_irqsave(&info->lock, flags);
-                       info->curregs[5] &= ~RTS;
-                       info->pendregs[5] &= ~RTS;
-                       write_zsreg(info->zs_channel, 5, info->curregs[5]);
-                       spin_unlock_irqrestore(&info->lock, flags);
-               }
-       }
-       
-#ifdef CDTRCTS
-       if (tty->termios->c_cflag & CDTRCTS) {
-               spin_lock_irqsave(&info->lock, flags);
-               info->curregs[5] &= ~DTR;
-               info->pendregs[5] &= ~DTR;
-               write_zsreg(info->zs_channel, 5, info->curregs[5]);
-               spin_unlock_irqrestore(&info->lock, flags);
-       }
-#endif /* CDTRCTS */
-}
-
-static void rs_unthrottle(struct tty_struct * tty)
-{
-       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-       unsigned long flags;
-#ifdef SERIAL_DEBUG_THROTTLE
-       printk(KERN_DEBUG "unthrottle %s: %d....\n",
-                       tty->ldisc.chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
-               return;
-
-       if (I_IXOFF(tty)) {
-               spin_lock_irqsave(&info->lock, flags);
-               if (info->x_char)
-                       info->x_char = 0;
-               else {
-                       info->x_char = START_CHAR(tty);
-                       if (!info->tx_active)
-                               transmit_chars(info);
-               }
-               spin_unlock_irqrestore(&info->lock, flags);
-       }
-
-       if (C_CRTSCTS(tty) && info->is_internal_modem) {
-               /* Assert RTS line */
-               spin_lock_irqsave(&info->lock, flags);
-               info->curregs[5] |= RTS;
-               info->pendregs[5] |= RTS;
-               write_zsreg(info->zs_channel, 5, info->curregs[5]);
-               spin_unlock_irqrestore(&info->lock, flags);
-       }
-
-#ifdef CDTRCTS
-       if (tty->termios->c_cflag & CDTRCTS) {
-               /* Assert DTR line */
-               spin_lock_irqsave(&info->lock, flags);
-               info->curregs[5] |= DTR;
-               info->pendregs[5] |= DTR;
-               write_zsreg(info->zs_channel, 5, info->curregs[5]);
-               spin_unlock_irqrestore(&info->lock, flags);
-       }
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct mac_serial * info,
-                          struct serial_struct __user * retinfo)
-{
-       struct serial_struct tmp;
-  
-       if (!retinfo)
-               return -EFAULT;
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.type = info->type;
-       tmp.line = info->line;
-       tmp.port = info->port;
-       tmp.irq = info->irq;
-       tmp.flags = info->flags;
-       tmp.baud_base = info->baud_base;
-       tmp.close_delay = info->close_delay;
-       tmp.closing_wait = info->closing_wait;
-       tmp.custom_divisor = info->custom_divisor;
-       if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
-               return -EFAULT;
-       return 0;
-}
-
-static int set_serial_info(struct mac_serial * info,
-                          struct serial_struct __user * new_info)
-{
-       struct serial_struct new_serial;
-       struct mac_serial old_info;
-       int                     retval = 0;
-
-       if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
-               return -EFAULT;
-       old_info = *info;
-
-       if (!capable(CAP_SYS_ADMIN)) {
-               if ((new_serial.baud_base != info->baud_base) ||
-                   (new_serial.type != info->type) ||
-                   (new_serial.close_delay != info->close_delay) ||
-                   ((new_serial.flags & ~ZILOG_USR_MASK) !=
-                    (info->flags & ~ZILOG_USR_MASK)))
-                       return -EPERM;
-               info->flags = ((info->flags & ~ZILOG_USR_MASK) |
-                              (new_serial.flags & ZILOG_USR_MASK));
-               info->custom_divisor = new_serial.custom_divisor;
-               goto check_and_exit;
-       }
-
-       if (info->count > 1)
-               return -EBUSY;
-
-       /*
-        * OK, past this point, all the error checking has been done.
-        * At this point, we start making changes.....
-        */
-
-       info->baud_base = new_serial.baud_base;
-       info->flags = ((info->flags & ~ZILOG_FLAGS) |
-                       (new_serial.flags & ZILOG_FLAGS));
-       info->type = new_serial.type;
-       info->close_delay = new_serial.close_delay;
-       info->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
-       if (info->flags & ZILOG_INITIALIZED)
-               retval = setup_scc(info);
-       return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting. This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space. 
- */
-static int get_lsr_info(struct mac_serial * info, unsigned int *value)
-{
-       unsigned char status;
-       unsigned long flags;
-
-       spin_lock_irqsave(&info->lock, flags);
-       status = read_zsreg(info->zs_channel, 0);
-       spin_unlock_irqrestore(&info->lock, flags);
-       status = (status & Tx_BUF_EMP)? TIOCSER_TEMT: 0;
-       return put_user(status,value);
-}
-
-static int rs_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       struct mac_serial * info = (struct mac_serial *)tty->driver_data;
-       unsigned char control, status;
-       unsigned long flags;
-
-#ifdef CONFIG_KGDB
-       if (info->kgdb_channel)
-               return -ENODEV;
-#endif
-       if (serial_paranoia_check(info, tty->name, __FUNCTION__))
-               return -ENODEV;
-
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-
-       spin_lock_irqsave(&info->lock, flags);
-       control = info->curregs[5];
-       status = read_zsreg(info->zs_channel, 0);
-       spin_unlock_irqrestore(&info->lock, flags);
-       return    ((control & RTS) ? TIOCM_RTS: 0)
-               | ((control & DTR) ? TIOCM_DTR: 0)
-               | ((status  & DCD) ? TIOCM_CAR: 0)
-               | ((status  & CTS) ? 0: TIOCM_CTS);
-}
-
-static int rs_tiocmset(struct tty_struct *tty, struct file *file,
-                      unsigned int set, unsigned int clear)
-{
-       struct mac_serial * info = (struct mac_serial *)tty->driver_data;
-       unsigned int arg, bits;
-       unsigned long flags;
-
-#ifdef CONFIG_KGDB
-       if (info->kgdb_channel)
-               return -ENODEV;
-#endif
-       if (serial_paranoia_check(info, tty->name, __FUNCTION__))
-               return -ENODEV;
-
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-
-       spin_lock_irqsave(&info->lock, flags);
-       if (set & TIOCM_RTS)
-               info->curregs[5] |= RTS;
-       if (set & TIOCM_DTR)
-               info->curregs[5] |= DTR;
-       if (clear & TIOCM_RTS)
-               info->curregs[5] &= ~RTS;
-       if (clear & TIOCM_DTR)
-               info->curregs[5] &= ~DTR;
-
-       info->pendregs[5] = info->curregs[5];
-       write_zsreg(info->zs_channel, 5, info->curregs[5]);
-       spin_unlock_irqrestore(&info->lock, flags);
-       return 0;
-}
-
-/*
- * rs_break - turn transmit break condition on/off
- */
-static void rs_break(struct tty_struct *tty, int break_state)
-{
-       struct mac_serial *info = (struct mac_serial *) tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_break"))
-               return;
-
-       spin_lock_irqsave(&info->lock, flags);
-       if (break_state == -1)
-               info->curregs[5] |= SND_BRK;
-       else
-               info->curregs[5] &= ~SND_BRK;
-       write_zsreg(info->zs_channel, 5, info->curregs[5]);
-       spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static int rs_ioctl(struct tty_struct *tty, struct file * file,
-                   unsigned int cmd, unsigned long arg)
-{
-       struct mac_serial * info = (struct mac_serial *)tty->driver_data;
-
-#ifdef CONFIG_KGDB
-       if (info->kgdb_channel)
-               return -ENODEV;
-#endif
-       if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
-               return -ENODEV;
-
-       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
-                   return -EIO;
-       }
-
-       switch (cmd) {
-               case TIOCGSERIAL:
-                       return get_serial_info(info,
-                                       (struct serial_struct __user *) arg);
-               case TIOCSSERIAL:
-                       return set_serial_info(info,
-                                       (struct serial_struct __user *) arg);
-               case TIOCSERGETLSR: /* Get line status register */
-                       return get_lsr_info(info, (unsigned int *) arg);
-
-               case TIOCSERGSTRUCT:
-                       if (copy_to_user((struct mac_serial __user *) arg,
-                                        info, sizeof(struct mac_serial)))
-                               return -EFAULT;
-                       return 0;
-
-               default:
-                       return -ENOIOCTLCMD;
-               }
-       return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
-{
-       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-       int was_stopped;
-
-       if (tty->termios->c_cflag == old_termios->c_cflag)
-               return;
-       was_stopped = info->tx_stopped;
-
-       change_speed(info, old_termios);
-
-       if (was_stopped && !info->tx_stopped) {
-               tty->hw_stopped = 0;
-               rs_start(tty);
-       }
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- * 
- * This routine is called when the serial port gets closed.
- * Wait for the last remaining data to be sent.
- * ------------------------------------------------------------
- */
-static void rs_close(struct tty_struct *tty, struct file * filp)
-{
-       struct mac_serial * info = (struct mac_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
-               return;
-
-       spin_lock_irqsave(&info->lock, flags);
-
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&info->lock, flags);
-               return;
-       }
-
-       OPNDBG("rs_close ttyS%d, count = %d\n", info->line, info->count);
-       if ((tty->count == 1) && (info->count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  Info->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk(KERN_ERR "rs_close: bad serial port count; tty->count "
-                               "is 1, info->count is %d\n", info->count);
-               info->count = 1;
-       }
-       if (--info->count < 0) {
-               printk(KERN_ERR "rs_close: bad serial port count for "
-                               "ttyS%d: %d\n", info->line, info->count);
-               info->count = 0;
-       }
-       if (info->count) {
-               spin_unlock_irqrestore(&info->lock, flags);
-               return;
-       }
-       info->flags |= ZILOG_CLOSING;
-       /*
-        * Now we wait for the transmit buffer to clear; and we notify 
-        * the line discipline to only process XON/XOFF characters.
-        */
-       OPNDBG("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
-       tty->closing = 1;
-       if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) {
-               spin_unlock_irqrestore(&info->lock, flags);
-               tty_wait_until_sent(tty, info->closing_wait);
-               spin_lock_irqsave(&info->lock, flags);
-       }
-
-       /*
-        * At this point we stop accepting input.  To do this, we
-        * disable the receiver and receive interrupts.
-        */
-       info->curregs[3] &= ~RxENABLE;
-       info->pendregs[3] = info->curregs[3];
-       write_zsreg(info->zs_channel, 3, info->curregs[3]);
-       info->curregs[1] &= ~(0x18);    /* disable any rx ints */
-       info->pendregs[1] = info->curregs[1];
-       write_zsreg(info->zs_channel, 1, info->curregs[1]);
-       ZS_CLEARFIFO(info->zs_channel);
-       if (info->flags & ZILOG_INITIALIZED) {
-               /*
-                * Before we drop DTR, make sure the SCC transmitter
-                * has completely drained.
-                */
-               OPNDBG("waiting end of Rx...\n");
-               spin_unlock_irqrestore(&info->lock, flags);
-               rs_wait_until_sent(tty, info->timeout);
-               spin_lock_irqsave(&info->lock, flags);
-       }
-
-       shutdown(info);
-       /* restore flags now since shutdown() will have disabled this port's
-          specific irqs */
-       spin_unlock_irqrestore(&info->lock, flags);
-
-       if (tty->driver->flush_buffer)
-               tty->driver->flush_buffer(tty);
-       tty_ldisc_flush(tty);
-       tty->closing = 0;
-       info->event = 0;
-       info->tty = 0;
-
-       if (info->blocked_open) {
-               if (info->close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
-               }
-               wake_up_interruptible(&info->open_wait);
-       }
-       info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING);
-       wake_up_interruptible(&info->close_wait);
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       struct mac_serial *info = (struct mac_serial *) tty->driver_data;
-       unsigned long orig_jiffies, char_time;
-
-       if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
-               return;
-
-/*     printk("rs_wait_until_sent, timeout:%d, tty_stopped:%d, tx_stopped:%d\n",
-                       timeout, tty->stopped, info->tx_stopped);
-*/
-       orig_jiffies = jiffies;
-       /*
-        * Set the check interval to be 1/5 of the estimated time to
-        * send a single character, and make it at least 1.  The check
-        * interval should also be less than the timeout.
-        */
-       if (info->timeout <= HZ/50) {
-               printk(KERN_INFO "macserial: invalid info->timeout=%d\n",
-                                   info->timeout);
-               info->timeout = HZ/50+1;
-       }
-
-       char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
-       char_time = char_time / 5;
-       if (char_time > HZ) {
-               printk(KERN_WARNING "macserial: char_time %ld >HZ !!!\n",
-                                   char_time);
-               char_time = 1;
-       } else if (char_time == 0)
-               char_time = 1;
-       if (timeout)
-               char_time = min_t(unsigned long, char_time, timeout);
-       while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
-               msleep_interruptible(jiffies_to_msecs(char_time));
-               if (signal_pending(current))
-                       break;
-               if (timeout && time_after(jiffies, orig_jiffies + timeout))
-                       break;
-       }
-       current->state = TASK_RUNNING;
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void rs_hangup(struct tty_struct *tty)
-{
-       struct mac_serial * info = (struct mac_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "rs_hangup"))
-               return;
-
-       rs_flush_buffer(tty);
-       shutdown(info);
-       info->event = 0;
-       info->count = 0;
-       info->flags &= ~ZILOG_NORMAL_ACTIVE;
-       info->tty = 0;
-       wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-                          struct mac_serial *info)
-{
-       DECLARE_WAITQUEUE(wait,current);
-       int             retval;
-       int             do_clocal = 0;
-
-       /*
-        * If the device is in the middle of being closed, then block
-        * until it's done, and then try again.
-        */
-       if (info->flags & ZILOG_CLOSING) {
-               interruptible_sleep_on(&info->close_wait);
-               return -EAGAIN;
-       }
-
-       /*
-        * If non-blocking mode is set, or the port is not enabled,
-        * then make the check up front and then exit.
-        */
-       if ((filp->f_flags & O_NONBLOCK) ||
-           (tty->flags & (1 << TTY_IO_ERROR))) {
-               info->flags |= ZILOG_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (tty->termios->c_cflag & CLOCAL)
-               do_clocal = 1;
-
-       /*
-        * Block waiting for the carrier detect and the line to become
-        * free (i.e., not in use by the callout).  While we are in
-        * this loop, info->count is dropped by one, so that
-        * rs_close() knows when to free things.  We restore it upon
-        * exit, either normal or abnormal.
-        */
-       retval = 0;
-       add_wait_queue(&info->open_wait, &wait);
-       OPNDBG("block_til_ready before block: ttyS%d, count = %d\n",
-              info->line, info->count);
-       spin_lock_irq(&info->lock);
-       if (!tty_hung_up_p(filp)) 
-               info->count--;
-       spin_unlock_irq(&info->lock);
-       info->blocked_open++;
-       while (1) {
-               spin_lock_irq(&info->lock);
-               if ((tty->termios->c_cflag & CBAUD) &&
-                   !info->is_irda)
-                       zs_rtsdtr(info, 1);
-               spin_unlock_irq(&info->lock);
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) ||
-                   !(info->flags & ZILOG_INITIALIZED)) {
-                       retval = -EAGAIN;
-                       break;
-               }
-               if (!(info->flags & ZILOG_CLOSING) &&
-                   (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               OPNDBG("block_til_ready blocking: ttyS%d, count = %d\n",
-                      info->line, info->count);
-               schedule();
-       }
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&info->open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               info->count++;
-       info->blocked_open--;
-       OPNDBG("block_til_ready after blocking: ttyS%d, count = %d\n",
-              info->line, info->count);
-       if (retval)
-               return retval;
-       info->flags |= ZILOG_NORMAL_ACTIVE;
-       return 0;
-}
-
-/*
- * This routine is called whenever a serial port is opened.  It
- * enables interrupts for a serial port, linking in its ZILOG structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int rs_open(struct tty_struct *tty, struct file * filp)
-{
-       struct mac_serial       *info;
-       int                     retval, line;
-       unsigned long           page;
-
-       line = tty->index;
-       if ((line < 0) || (line >= zs_channels_found)) {
-               return -ENODEV;
-       }
-       info = zs_soft + line;
-
-#ifdef CONFIG_KGDB
-       if (info->kgdb_channel) {
-               return -ENODEV;
-       }
-#endif
-       if (serial_paranoia_check(info, tty->name, "rs_open"))
-               return -ENODEV;
-       OPNDBG("rs_open %s, count = %d, tty=%p\n", tty->name,
-              info->count, tty);
-
-       info->count++;
-       tty->driver_data = info;
-       info->tty = tty;
-
-       if (!tmp_buf) {
-               page = get_zeroed_page(GFP_KERNEL);
-               if (!page)
-                       return -ENOMEM;
-               if (tmp_buf)
-                       free_page(page);
-               else
-                       tmp_buf = (unsigned char *) page;
-       }
-
-       /*
-        * If the port is the middle of closing, bail out now
-        */
-       if (tty_hung_up_p(filp) ||
-           (info->flags & ZILOG_CLOSING)) {
-               if (info->flags & ZILOG_CLOSING)
-                       interruptible_sleep_on(&info->close_wait);
-               return -EAGAIN;
-       }
-
-       /*
-        * Start up serial port
-        */
-
-       retval = startup(info);
-       if (retval)
-               return retval;
-
-       retval = block_til_ready(tty, filp, info);
-       if (retval) {
-               OPNDBG("rs_open returning after block_til_ready with %d\n",
-                       retval);
-               return retval;
-       }
-
-#ifdef CONFIG_SERIAL_CONSOLE
-       if (sercons.cflag && sercons.index == line) {
-               tty->termios->c_cflag = sercons.cflag;
-               sercons.cflag = 0;
-               change_speed(info, 0);
-       }
-#endif
-
-       OPNDBG("rs_open %s successful...\n", tty->name);
-       return 0;
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
-       printk(KERN_INFO "PowerMac Z8530 serial driver version " MACSERIAL_VERSION "\n");
-}
-
-/*
- * Initialize one channel, both the mac_serial and mac_zschannel
- * structs.  We use the dev_node field of the mac_serial struct.
- */
-static int
-chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan,
-         struct mac_zschannel *zs_chan_a)
-{
-       struct device_node *ch = zss->dev_node;
-       char *conn;
-       int len;
-       struct slot_names_prop {
-               int     count;
-               char    name[1];
-       } *slots;
-
-       zss->irq = ch->intrs[0].line;
-       zss->has_dma = 0;
-#if !defined(CONFIG_KGDB) && defined(SUPPORT_SERIAL_DMA)
-       if (ch->n_addrs >= 3 && ch->n_intrs == 3)
-               zss->has_dma = 1;
-#endif
-       zss->dma_initted = 0;
-
-       zs_chan->control = (volatile unsigned char *)
-               ioremap(ch->addrs[0].address, 0x1000);
-       zs_chan->data = zs_chan->control + 0x10;
-       spin_lock_init(&zs_chan->lock);
-       zs_chan->parent = zss;
-       zss->zs_channel = zs_chan;
-       zss->zs_chan_a = zs_chan_a;
-
-       /* setup misc varariables */
-       zss->kgdb_channel = 0;
-
-       /* For now, we assume you either have a slot-names property
-        * with "Modem" in it, or your channel is compatible with
-        * "cobalt". Might need additional fixups
-        */
-       zss->is_internal_modem = device_is_compatible(ch, "cobalt");
-       conn = get_property(ch, "AAPL,connector", &len);
-       zss->is_irda = conn && (strcmp(conn, "infrared") == 0);
-       zss->port_type = PMAC_SCC_ASYNC;
-       /* 1999 Powerbook G3 has slot-names property instead */
-       slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len);
-       if (slots && slots->count > 0) {
-               if (strcmp(slots->name, "IrDA") == 0)
-                       zss->is_irda = 1;
-               else if (strcmp(slots->name, "Modem") == 0)
-                       zss->is_internal_modem = 1;
-       }
-       if (zss->is_irda)
-               zss->port_type = PMAC_SCC_IRDA;
-       if (zss->is_internal_modem) {
-               struct device_node* i2c_modem = find_devices("i2c-modem");
-               if (i2c_modem) {
-                       char* mid = get_property(i2c_modem, "modem-id", NULL);
-                       if (mid) switch(*mid) {
-                       case 0x04 :
-                       case 0x05 :
-                       case 0x07 :
-                       case 0x08 :
-                       case 0x0b :
-                       case 0x0c :
-                               zss->port_type = PMAC_SCC_I2S1;
-                       }
-                       printk(KERN_INFO "macserial: i2c-modem detected, id: %d\n",
-                               mid ? (*mid) : 0);
-               } else {
-                       printk(KERN_INFO "macserial: serial modem detected\n");
-               }
-       }
-
-       while (zss->has_dma) {
-               zss->dma_priv = NULL;
-               /* it seems that the last two addresses are the
-                  DMA controllers */
-               zss->tx_dma = (volatile struct dbdma_regs *)
-                       ioremap(ch->addrs[ch->n_addrs - 2].address, 0x100);
-               zss->rx = (volatile struct mac_dma *)
-                       ioremap(ch->addrs[ch->n_addrs - 1].address, 0x100);
-               zss->tx_dma_irq = ch->intrs[1].line;
-               zss->rx_dma_irq = ch->intrs[2].line;
-               spin_lock_init(&zss->rx_dma_lock);
-               break;
-       }
-
-       init_timer(&zss->powerup_timer);
-       zss->powerup_timer.function = powerup_done;
-       zss->powerup_timer.data = (unsigned long) zss;
-       return 0;
-}
-
-/*
- * /proc fs routines. TODO: Add status lines & error stats
- */
-static inline int
-line_info(char *buf, struct mac_serial *info)
-{
-       int             ret=0;
-       unsigned char* connector;
-       int lenp;
-
-       ret += sprintf(buf, "%d: port:0x%X irq:%d", info->line, info->port, info->irq);
-
-       connector = get_property(info->dev_node, "AAPL,connector", &lenp);
-       if (connector)
-               ret+=sprintf(buf+ret," con:%s ", connector);
-       if (info->is_internal_modem) {
-               if (!connector)
-                       ret+=sprintf(buf+ret," con:");
-               ret+=sprintf(buf+ret,"%s", " (internal modem)");
-       }
-       if (info->is_irda) {
-               if (!connector)
-                       ret+=sprintf(buf+ret," con:");
-               ret+=sprintf(buf+ret,"%s", " (IrDA)");
-       }
-       ret+=sprintf(buf+ret,"\n");
-
-       return ret;
-}
-
-int macserial_read_proc(char *page, char **start, off_t off, int count,
-                int *eof, void *data)
-{
-       int l, len = 0;
-       off_t   begin = 0;
-       struct mac_serial *info;
-
-       len += sprintf(page, "serinfo:1.0 driver:" MACSERIAL_VERSION "\n");
-       for (info = zs_chain; info && len < 4000; info = info->zs_next) {
-               l = line_info(page + len, info);
-               len += l;
-               if (len+begin > off+count)
-                       goto done;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
-               }
-       }
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (off-begin);
-       return ((count < begin+len-off) ? count : begin+len-off);
-}
-
-/* Ask the PROM how many Z8530s we have and initialize their zs_channels */
-static void
-probe_sccs(void)
-{
-       struct device_node *dev, *ch;
-       struct mac_serial **pp;
-       int n, chip, nchan;
-       struct mac_zschannel *zs_chan;
-       int chan_a_index;
-
-       n = 0;
-       pp = &zs_chain;
-       zs_chan = zs_channels;
-       for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
-               nchan = 0;
-               chip = n;
-               if (n >= NUM_CHANNELS) {
-                       printk(KERN_WARNING "Sorry, can't use %s: no more "
-                                           "channels\n", dev->full_name);
-                       continue;
-               }
-               chan_a_index = 0;
-               for (ch = dev->child; ch != 0; ch = ch->sibling) {
-                       if (nchan >= 2) {
-                               printk(KERN_WARNING "SCC: Only 2 channels per "
-                                       "chip are supported\n");
-                               break;
-                       }
-                       if (ch->n_addrs < 1 || (ch ->n_intrs < 1)) {
-                               printk("Can't use %s: %d addrs %d intrs\n",
-                                     ch->full_name, ch->n_addrs, ch->n_intrs);
-                               continue;
-                       }
-
-                       /* The channel with the higher address
-                          will be the A side. */
-                       if (nchan > 0 &&
-                           ch->addrs[0].address
-                           > zs_soft[n-1].dev_node->addrs[0].address)
-                               chan_a_index = 1;
-
-                       /* minimal initialization for now */
-                       zs_soft[n].dev_node = ch;
-                       *pp = &zs_soft[n];
-                       pp = &zs_soft[n].zs_next;
-                       ++nchan;
-                       ++n;
-               }
-               if (nchan == 0)
-                       continue;
-
-               /* set up A side */
-               if (chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan))
-                       continue;
-               ++zs_chan;
-
-               /* set up B side, if it exists */
-               if (nchan > 1)
-                       if (chan_init(&zs_soft[chip + 1 - chan_a_index],
-                                 zs_chan, zs_chan - 1))
-                               continue;
-               ++zs_chan;
-       }
-       *pp = 0;
-
-       zs_channels_found = n;
-#ifdef CONFIG_PMAC_PBOOK
-       if (n)
-               pmu_register_sleep_notifier(&serial_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-}
-
-static struct tty_operations serial_ops = {
-       .open = rs_open,
-       .close = rs_close,
-       .write = rs_write,
-       .flush_chars = rs_flush_chars,
-       .write_room = rs_write_room,
-       .chars_in_buffer = rs_chars_in_buffer,
-       .flush_buffer = rs_flush_buffer,
-       .ioctl = rs_ioctl,
-       .throttle = rs_throttle,
-       .unthrottle = rs_unthrottle,
-       .set_termios = rs_set_termios,
-       .stop = rs_stop,
-       .start = rs_start,
-       .hangup = rs_hangup,
-       .break_ctl = rs_break,
-       .wait_until_sent = rs_wait_until_sent,
-       .read_proc = macserial_read_proc,
-       .tiocmget = rs_tiocmget,
-       .tiocmset = rs_tiocmset,
-};
-
-static int macserial_init(void)
-{
-       int channel, i;
-       struct mac_serial *info;
-
-       /* Find out how many Z8530 SCCs we have */
-       if (zs_chain == 0)
-               probe_sccs();
-
-       serial_driver = alloc_tty_driver(zs_channels_found);
-       if (!serial_driver)
-               return -ENOMEM;
-
-       /* XXX assume it's a powerbook if we have a via-pmu
-        * 
-        * This is OK for core99 machines as well.
-        */
-       is_powerbook = find_devices("via-pmu") != 0;
-
-       /* Register the interrupt handler for each one
-        * We also request the OF resources here as probe_sccs()
-        * might be called too early for that
-        */
-       for (i = 0; i < zs_channels_found; ++i) {
-               struct device_node* ch = zs_soft[i].dev_node;
-               if (!request_OF_resource(ch, 0, NULL)) {
-                       printk(KERN_ERR "macserial: can't request IO resource !\n");
-                       put_tty_driver(serial_driver);
-                       return -ENODEV;
-               }
-               if (zs_soft[i].has_dma) {
-                       if (!request_OF_resource(ch, ch->n_addrs - 2, " (tx dma)")) {
-                               printk(KERN_ERR "macserial: can't request TX DMA resource !\n");
-                               zs_soft[i].has_dma = 0;
-                               goto no_dma;
-                       }
-                       if (!request_OF_resource(ch, ch->n_addrs - 1, " (rx dma)")) {
-                               release_OF_resource(ch, ch->n_addrs - 2);
-                               printk(KERN_ERR "macserial: can't request RX DMA resource !\n");
-                               zs_soft[i].has_dma = 0;
-                               goto no_dma;
-                       }
-                       if (request_irq(zs_soft[i].tx_dma_irq, rs_txdma_irq, 0,
-                                       "SCC-txdma", &zs_soft[i]))
-                               printk(KERN_ERR "macserial: can't get irq %d\n",
-                                      zs_soft[i].tx_dma_irq);
-                       disable_irq(zs_soft[i].tx_dma_irq);
-                       if (request_irq(zs_soft[i].rx_dma_irq, rs_rxdma_irq, 0,
-                                       "SCC-rxdma", &zs_soft[i]))
-                               printk(KERN_ERR "macserial: can't get irq %d\n",
-                                      zs_soft[i].rx_dma_irq);
-                       disable_irq(zs_soft[i].rx_dma_irq);
-               }
-no_dma:                
-               if (request_irq(zs_soft[i].irq, rs_interrupt, 0,
-                               "SCC", &zs_soft[i]))
-                       printk(KERN_ERR "macserial: can't get irq %d\n",
-                              zs_soft[i].irq);
-               disable_irq(zs_soft[i].irq);
-       }
-
-       show_serial_version();
-
-       /* Initialize the tty_driver structure */
-       /* Not all of this is exactly right for us. */
-
-       serial_driver->owner = THIS_MODULE;
-       serial_driver->driver_name = "macserial";
-       serial_driver->devfs_name = "tts/";
-       serial_driver->name = "ttyS";
-       serial_driver->major = TTY_MAJOR;
-       serial_driver->minor_start = 64;
-       serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
-       serial_driver->subtype = SERIAL_TYPE_NORMAL;
-       serial_driver->init_termios = tty_std_termios;
-       serial_driver->init_termios.c_cflag =
-               B38400 | CS8 | CREAD | HUPCL | CLOCAL;
-       serial_driver->flags = TTY_DRIVER_REAL_RAW;
-       tty_set_operations(serial_driver, &serial_ops);
-
-       if (tty_register_driver(serial_driver))
-               printk(KERN_ERR "Error: couldn't register serial driver\n");
-
-       for (channel = 0; channel < zs_channels_found; ++channel) {
-#ifdef CONFIG_KGDB
-               if (zs_soft[channel].kgdb_channel) {
-                       kgdb_interruptible(1);
-                       continue;
-               }
-#endif
-               zs_soft[channel].clk_divisor = 16;
-/* -- we are not sure the SCC is powered ON at this point
-               zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-*/
-               zs_soft[channel].zs_baud = 38400;
-
-               /* If console serial line, then enable interrupts. */
-               if (zs_soft[channel].is_cons) {
-                       printk(KERN_INFO "macserial: console line, enabling "
-                                       "interrupt %d\n", zs_soft[channel].irq);
-                       panic("macserial: console not supported yet !");
-                       write_zsreg(zs_soft[channel].zs_channel, R1,
-                                   (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
-                       write_zsreg(zs_soft[channel].zs_channel, R9,
-                                   (NV | MIE));
-               }
-       }
-
-       for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
-       {
-               unsigned char* connector;
-               int lenp;
-
-#ifdef CONFIG_KGDB
-               if (info->kgdb_channel) {
-                       continue;
-               }
-#endif
-               info->magic = SERIAL_MAGIC;
-               info->port = (int) info->zs_channel->control;
-               info->line = i;
-               info->tty = 0;
-               info->custom_divisor = 16;
-               info->timeout = 0;
-               info->close_delay = 50;
-               info->closing_wait = 3000;
-               info->x_char = 0;
-               info->event = 0;
-               info->count = 0;
-               info->blocked_open = 0;
-               INIT_WORK(&info->tqueue, do_softint, info);
-               spin_lock_init(&info->lock);
-               init_waitqueue_head(&info->open_wait);
-               init_waitqueue_head(&info->close_wait);
-               info->timeout = HZ;
-               printk(KERN_INFO "tty%02d at 0x%08x (irq = %d)", info->line, 
-                       info->port, info->irq);
-               printk(" is a Z8530 ESCC");
-               connector = get_property(info->dev_node, "AAPL,connector", &lenp);
-               if (connector)
-                       printk(", port = %s", connector);
-               if (info->is_internal_modem)
-                       printk(" (internal modem)");
-               if (info->is_irda)
-                       printk(" (IrDA)");
-               printk("\n");
-       }
-       tmp_buf = 0;
-
-       return 0;
-}
-
-void macserial_cleanup(void)
-{
-       int i;
-       unsigned long flags;
-       struct mac_serial *info;
-
-       for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
-               set_scc_power(info, 0);
-       spin_lock_irqsave(&info->lock, flags);
-       for (i = 0; i < zs_channels_found; ++i) {
-               free_irq(zs_soft[i].irq, &zs_soft[i]);
-               if (zs_soft[i].has_dma) {
-                       free_irq(zs_soft[i].tx_dma_irq, &zs_soft[i]);
-                       free_irq(zs_soft[i].rx_dma_irq, &zs_soft[i]);
-               }
-               release_OF_resource(zs_soft[i].dev_node, 0);
-               if (zs_soft[i].has_dma) {
-                       struct device_node* ch = zs_soft[i].dev_node;
-                       release_OF_resource(ch, ch->n_addrs - 2);
-                       release_OF_resource(ch, ch->n_addrs - 1);
-               }
-       }
-       spin_unlock_irqrestore(&info->lock, flags);
-       tty_unregister_driver(serial_driver);
-       put_tty_driver(serial_driver);
-
-       if (tmp_buf) {
-               free_page((unsigned long) tmp_buf);
-               tmp_buf = 0;
-       }
-
-#ifdef CONFIG_PMAC_PBOOK
-       if (zs_channels_found)
-               pmu_unregister_sleep_notifier(&serial_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-}
-
-module_init(macserial_init);
-module_exit(macserial_cleanup);
-MODULE_LICENSE("GPL");
-
-#if 0
-/*
- * register_serial and unregister_serial allows for serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-/* PowerMac: Unused at this time, just here to make things link. */
-int register_serial(struct serial_struct *req)
-{
-       return -1;
-}
-
-void unregister_serial(int line)
-{
-       return;
-}
-#endif
-
-/*
- * ------------------------------------------------------------
- * Serial console driver
- * ------------------------------------------------------------
- */
-#ifdef CONFIG_SERIAL_CONSOLE
-
-/*
- *     Print a string to the serial port trying not to disturb
- *     any possible real use of the port...
- */
-static void serial_console_write(struct console *co, const char *s,
-                                unsigned count)
-{
-       struct mac_serial *info = zs_soft + co->index;
-       int i;
-
-       /* Turn of interrupts and enable the transmitter. */
-       write_zsreg(info->zs_channel, R1, info->curregs[1] & ~TxINT_ENAB);
-       write_zsreg(info->zs_channel, R5, info->curregs[5] | TxENAB | RTS | DTR);
-
-       for (i=0; i<count; i++) {
-               /* Wait for the transmit buffer to empty. */
-               while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0) {
-                       eieio();
-               }
-
-               write_zsdata(info->zs_channel, s[i]);
-               if (s[i] == 10) {
-                       while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP)
-                                == 0)
-                               eieio();
-
-                       write_zsdata(info->zs_channel, 13);
-               }
-       }
-
-       /* Restore the values in the registers. */
-       write_zsreg(info->zs_channel, R1, info->curregs[1]);
-       /* Don't disable the transmitter. */
-}
-
-static struct tty_driver *serial_driver;
-
-static struct tty_driver *serial_console_device(struct console *c, int *index)
-{
-       *index = c->index;
-       return serial_driver;
-}
-
-/*
- *     Setup initial baud/bits/parity. We do two things here:
- *     - construct a cflag setting for the first rs_open()
- *     - initialize the serial port
- *     Return non-zero if we didn't find a serial port.
- */
-static int __init serial_console_setup(struct console *co, char *options)
-{
-       struct mac_serial *info;
-       int     baud = 38400;
-       int     bits = 8;
-       int     parity = 'n';
-       int     cflag = CREAD | HUPCL | CLOCAL;
-       int     brg;
-       char    *s;
-       long    flags;
-
-       /* Find out how many Z8530 SCCs we have */
-       if (zs_chain == 0)
-               probe_sccs();
-
-       if (zs_chain == 0)
-               return -1;
-
-       /* Do we have the device asked for? */
-       if (co->index >= zs_channels_found)
-               return -1;
-       info = zs_soft + co->index;
-
-       set_scc_power(info, 1);
-
-       /* Reset the channel */
-       write_zsreg(info->zs_channel, R9, CHRA);
-
-       if (options) {
-               baud = simple_strtoul(options, NULL, 10);
-               s = options;
-               while(*s >= '0' && *s <= '9')
-                       s++;
-               if (*s)
-                       parity = *s++;
-               if (*s)
-                       bits   = *s - '0';
-       }
-
-       /*
-        *      Now construct a cflag setting.
-        */
-       switch(baud) {
-       case 1200:
-               cflag |= B1200;
-               break;
-       case 2400:
-               cflag |= B2400;
-               break;
-       case 4800:
-               cflag |= B4800;
-               break;
-       case 9600:
-               cflag |= B9600;
-               break;
-       case 19200:
-               cflag |= B19200;
-               break;
-       case 57600:
-               cflag |= B57600;
-               break;
-       case 115200:
-               cflag |= B115200;
-               break;
-       case 38400:
-       default:
-               cflag |= B38400;
-               break;
-       }
-       switch(bits) {
-       case 7:
-               cflag |= CS7;
-               break;
-       default:
-       case 8:
-               cflag |= CS8;
-               break;
-       }
-       switch(parity) {
-       case 'o': case 'O':
-               cflag |= PARENB | PARODD;
-               break;
-       case 'e': case 'E':
-               cflag |= PARENB;
-               break;
-       }
-       co->cflag = cflag;
-
-       spin_lock_irqsave(&info->lock, flags);
-        memset(info->curregs, 0, sizeof(info->curregs));
-
-       info->zs_baud = baud;
-       info->clk_divisor = 16;
-       switch (info->zs_baud) {
-       case ZS_CLOCK/16:       /* 230400 */
-               info->curregs[4] = X16CLK;
-               info->curregs[11] = 0;
-               break;
-       case ZS_CLOCK/32:       /* 115200 */
-               info->curregs[4] = X32CLK;
-               info->curregs[11] = 0;
-               break;
-       default:
-               info->curregs[4] = X16CLK;
-               info->curregs[11] = TCBR | RCBR;
-               brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
-               info->curregs[12] = (brg & 255);
-               info->curregs[13] = ((brg >> 8) & 255);
-               info->curregs[14] = BRENABL;
-       }
-
-       /* byte size and parity */
-       info->curregs[3] &= ~RxNBITS_MASK;
-       info->curregs[5] &= ~TxNBITS_MASK;
-       switch (cflag & CSIZE) {
-       case CS5:
-               info->curregs[3] |= Rx5;
-               info->curregs[5] |= Tx5;
-               break;
-       case CS6:
-               info->curregs[3] |= Rx6;
-               info->curregs[5] |= Tx6;
-               break;
-       case CS7:
-               info->curregs[3] |= Rx7;
-               info->curregs[5] |= Tx7;
-               break;
-       case CS8:
-       default: /* defaults to 8 bits */
-               info->curregs[3] |= Rx8;
-               info->curregs[5] |= Tx8;
-               break;
-       }
-        info->curregs[5] |= TxENAB | RTS | DTR;
-       info->pendregs[3] = info->curregs[3];
-       info->pendregs[5] = info->curregs[5];
-
-       info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
-       if (cflag & CSTOPB) {
-               info->curregs[4] |= SB2;
-       } else {
-               info->curregs[4] |= SB1;
-       }
-       if (cflag & PARENB) {
-               info->curregs[4] |= PAR_ENA;
-               if (!(cflag & PARODD)) {
-                       info->curregs[4] |= PAR_EVEN;
-               }
-       }
-       info->pendregs[4] = info->curregs[4];
-
-       if (!(cflag & CLOCAL)) {
-               if (!(info->curregs[15] & DCDIE))
-                       info->read_reg_zero = read_zsreg(info->zs_channel, 0);
-               info->curregs[15] |= DCDIE;
-       } else
-               info->curregs[15] &= ~DCDIE;
-       if (cflag & CRTSCTS) {
-               info->curregs[15] |= CTSIE;
-               if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
-                       info->tx_stopped = 1;
-       } else {
-               info->curregs[15] &= ~CTSIE;
-               info->tx_stopped = 0;
-       }
-       info->pendregs[15] = info->curregs[15];
-
-       /* Load up the new values */
-       load_zsregs(info->zs_channel, info->curregs);
-
-       spin_unlock_irqrestore(&info->lock, flags);
-
-       return 0;
-}
-
-static struct console sercons = {
-       .name           = "ttyS",
-       .write          = serial_console_write,
-       .device         = serial_console_device,
-       .setup          = serial_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-
-/*
- *     Register console.
- */
-static void __init mac_scc_console_init(void)
-{
-       register_console(&sercons);
-}
-console_initcall(mac_scc_console_init);
-
-#endif /* ifdef CONFIG_SERIAL_CONSOLE */
-
-#ifdef CONFIG_KGDB
-/* These are for receiving and sending characters under the kgdb
- * source level kernel debugger.
- */
-void putDebugChar(char kgdb_char)
-{
-       struct mac_zschannel *chan = zs_kgdbchan;
-       while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
-               udelay(5);
-       write_zsdata(chan, kgdb_char);
-}
-
-char getDebugChar(void)
-{
-       struct mac_zschannel *chan = zs_kgdbchan;
-       while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
-               eieio(); /*barrier();*/
-       return read_zsdata(chan);
-}
-
-void kgdb_interruptible(int yes)
-{
-       struct mac_zschannel *chan = zs_kgdbchan;
-       int one, nine;
-       nine = read_zsreg(chan, 9);
-       if (yes == 1) {
-               one = EXT_INT_ENAB|INT_ALL_Rx;
-               nine |= MIE;
-               printk("turning serial ints on\n");
-       } else {
-               one = RxINT_DISAB;
-               nine &= ~MIE;
-               printk("turning serial ints off\n");
-       }
-       write_zsreg(chan, 1, one);
-       write_zsreg(chan, 9, nine);
-}
-
-/* This sets up the serial port we're using, and turns on
- * interrupts for that channel, so kgdb is usable once we're done.
- */
-static inline void kgdb_chaninit(struct mac_zschannel *ms, int intson, int bps)
-{
-       int brg;
-       int i, x;
-       volatile char *sccc = ms->control;
-       brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
-       printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
-       for (i = 20000; i != 0; --i) {
-               x = *sccc; eieio();
-       }
-       for (i = 0; i < sizeof(scc_inittab); ++i) {
-               write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]);
-               i++;
-       }
-}
-
-/* This is called at boot time to prime the kgdb serial debugging
- * serial line.  The 'tty_num' argument is 0 for /dev/ttya and 1
- * for /dev/ttyb which is determined in setup_arch() from the
- * boot command line flags.
- * XXX at the moment probably only channel A will work
- */
-void __init zs_kgdb_hook(int tty_num)
-{
-       /* Find out how many Z8530 SCCs we have */
-       if (zs_chain == 0)
-               probe_sccs();
-
-       set_scc_power(&zs_soft[tty_num], 1);
-
-       zs_kgdbchan = zs_soft[tty_num].zs_channel;
-       zs_soft[tty_num].change_needed = 0;
-       zs_soft[tty_num].clk_divisor = 16;
-       zs_soft[tty_num].zs_baud = 38400;
-       zs_soft[tty_num].kgdb_channel = 1;     /* This runs kgdb */
-
-       /* Turn on transmitter/receiver at 8-bits/char */
-        kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
-       printk("KGDB: on channel %d initialized\n", tty_num);
-       set_debug_traps(); /* init stub */
-}
-#endif /* ifdef CONFIG_KGDB */
-
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * notify clients before sleep and reset bus afterwards
- */
-int
-serial_notify_sleep(struct pmu_sleep_notifier *self, int when)
-{
-       int i;
-
-       switch (when) {
-       case PBOOK_SLEEP_REQUEST:
-       case PBOOK_SLEEP_REJECT:
-               break;
-
-       case PBOOK_SLEEP_NOW:
-               for (i=0; i<zs_channels_found; i++) {
-                       struct mac_serial *info = &zs_soft[i];
-                       if (info->flags & ZILOG_INITIALIZED) {
-                               shutdown(info);
-                               info->flags |= ZILOG_SLEEPING;
-                       }
-               }
-               break;
-       case PBOOK_WAKE:
-               for (i=0; i<zs_channels_found; i++) {
-                       struct mac_serial *info = &zs_soft[i];
-                       if (info->flags & ZILOG_SLEEPING) {
-                               info->flags &= ~ZILOG_SLEEPING;
-                               startup(info);
-                       }
-               }
-               break;
-       }
-       return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
diff --git a/drivers/macintosh/macserial.h b/drivers/macintosh/macserial.h
deleted file mode 100644 (file)
index bade11a..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * macserial.h: Definitions for the Macintosh Z8530 serial driver.
- *
- * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-#ifndef _MACSERIAL_H
-#define _MACSERIAL_H
-
-#include <linux/spinlock.h>
-
-#define NUM_ZSREGS    16
-
-struct serial_struct {
-       int     type;
-       int     line;
-       int     port;
-       int     irq;
-       int     flags;
-       int     xmit_fifo_size;
-       int     custom_divisor;
-       int     baud_base;
-       unsigned short  close_delay;
-       char    reserved_char[2];
-       int     hub6;
-       unsigned short  closing_wait; /* time to wait before closing */
-       unsigned short  closing_wait2; /* no longer used... */
-       int     reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output.  65535 means don't wait at all.
- */
-#define ZILOG_CLOSING_WAIT_INF 0
-#define ZILOG_CLOSING_WAIT_NONE        65535
-
-/*
- * Definitions for ZILOG_struct (and serial_struct) flags field
- */
-#define ZILOG_HUP_NOTIFY       0x0001  /* Notify getty on hangups and closes 
-                                        * on the callout port */
-#define ZILOG_FOURPORT                 0x0002  /* Set OU1, OUT2 per AST Fourport settings */
-#define ZILOG_SAK              0x0004  /* Secure Attention Key (Orange book) */
-#define ZILOG_SPLIT_TERMIOS    0x0008  /* Separate termios for dialin/callout */
-
-#define ZILOG_SPD_MASK         0x0030
-#define ZILOG_SPD_HI           0x0010  /* Use 56000 instead of 38400 bps */
-
-#define ZILOG_SPD_VHI          0x0020  /* Use 115200 instead of 38400 bps */
-#define ZILOG_SPD_CUST         0x0030  /* Use user-specified divisor */
-
-#define ZILOG_SKIP_TEST                0x0040  /* Skip UART test during autoconfiguration */
-#define ZILOG_AUTO_IRQ                 0x0080  /* Do automatic IRQ during autoconfiguration */
-#define ZILOG_SESSION_LOCKOUT  0x0100  /* Lock out cua opens based on session */
-#define ZILOG_PGRP_LOCKOUT     0x0200  /* Lock out cua opens based on pgrp */
-#define ZILOG_CALLOUT_NOHUP    0x0400  /* Don't do hangups for cua device */
-
-#define ZILOG_FLAGS            0x0FFF  /* Possible legal ZILOG flags */
-#define ZILOG_USR_MASK         0x0430  /* Legal flags that non-privileged
-                                        * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define ZILOG_INITIALIZED      0x80000000 /* Serial port was initialized */
-#define ZILOG_CALLOUT_ACTIVE   0x40000000 /* Call out device is active */
-#define ZILOG_NORMAL_ACTIVE    0x20000000 /* Normal device is active */
-#define ZILOG_BOOT_AUTOCONF    0x10000000 /* Autoconfigure port on bootup */
-#define ZILOG_CLOSING          0x08000000 /* Serial port is closing */
-#define ZILOG_CTS_FLOW         0x04000000 /* Do CTS flow control */
-#define ZILOG_CHECK_CD         0x02000000 /* i.e., CLOCAL */
-#define ZILOG_SLEEPING         0x01000000 /* have shut it down for sleep */
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-/*
- * This is our internal structure for each serial port's state.
- * 
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct mac_serial;
-
-struct mac_zschannel {
-       volatile unsigned char* control;
-       volatile unsigned char* data;
-       spinlock_t              lock;
-       /* Used for debugging */
-       struct mac_serial*      parent;
-};
-
-struct mac_dma {
-       volatile struct dbdma_regs      dma;
-       volatile unsigned short         res_count;
-       volatile unsigned short         command;
-       volatile unsigned int           buf_addr;
-};
-
-struct mac_serial {
-       struct mac_serial *zs_next;     /* For IRQ servicing chain */
-       struct mac_zschannel *zs_channel; /* Channel registers */
-       struct mac_zschannel *zs_chan_a;        /* A side registers */
-       unsigned char read_reg_zero;
-       struct device_node* dev_node;
-       spinlock_t lock;
-
-       char soft_carrier;  /* Use soft carrier on this channel */
-       char break_abort;   /* Is serial console in, so process brk/abrt */
-       char kgdb_channel;  /* Kgdb is running on this channel */
-       char is_cons;       /* Is this our console. */
-       char is_internal_modem; /* is connected to an internal modem */
-       char is_irda;           /* is connected to an IrDA codec */
-       int port_type;          /* Port type for pmac_feature */
-       unsigned char tx_active; /* character is being xmitted */
-       unsigned char tx_stopped; /* output is suspended */
-       unsigned char power_wait; /* waiting for power-up delay to expire */
-
-       /* We need to know the current clock divisor
-        * to read the bps rate the chip has currently
-        * loaded.
-        */
-       unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
-       int zs_baud;
-
-       /* Current write register values */
-       unsigned char curregs[NUM_ZSREGS];
-
-       /* Values we need to set next opportunity */
-       unsigned char pendregs[NUM_ZSREGS];
-
-       char change_needed;
-
-       int                     magic;
-       int                     baud_base;
-       int                     port;
-       int                     irq;
-       int                     flags;          /* defined in tty.h */
-       int                     type;           /* UART type */
-       struct tty_struct       *tty;
-       int                     read_status_mask;
-       int                     ignore_status_mask;
-       int                     timeout;
-       int                     xmit_fifo_size;
-       int                     custom_divisor;
-       int                     x_char; /* xon/xoff character */
-       int                     close_delay;
-       unsigned short          closing_wait;
-       unsigned short          closing_wait2;
-       unsigned long           event;
-       unsigned long           last_active;
-       int                     line;
-       int                     count;      /* # of fd on device */
-       int                     blocked_open; /* # of blocked opens */
-       unsigned char           *xmit_buf;
-       int                     xmit_head;
-       int                     xmit_tail;
-       int                     xmit_cnt;
-       struct work_struct      tqueue;
-       wait_queue_head_t       open_wait;
-       wait_queue_head_t       close_wait;
-
-       volatile struct dbdma_regs *tx_dma;
-       int                     tx_dma_irq;
-       volatile struct dbdma_cmd *tx_cmds;
-       volatile struct mac_dma *rx;
-       int                     rx_dma_irq;
-       volatile struct dbdma_cmd **rx_cmds;
-       unsigned char           **rx_char_buf;
-       unsigned char           **rx_flag_buf;
-#define        RX_BUF_SIZE     256
-       int                     rx_nbuf;
-       int                     rx_done_bytes;
-       int                     rx_ubuf;
-       int                     rx_fbuf;
-#define        RX_NO_FBUF      (-1)
-       int                     rx_cbuf;
-       spinlock_t              rx_dma_lock;
-       int                     has_dma;
-       int                     dma_initted;
-       void                    *dma_priv;
-       struct timer_list       poll_dma_timer;
-#define RX_DMA_TIMER   (jiffies + 10*HZ/1000)
-
-       struct timer_list       powerup_timer;
-};
-
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP  0
-
-#endif /* __KERNEL__ */
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/* The Zilog register set */
-
-#define        FLAG    0x7e
-
-/* Write Register 0 */
-#define        R0      0               /* Register selects */
-#define        R1      1
-#define        R2      2
-#define        R3      3
-#define        R4      4
-#define        R5      5
-#define        R6      6
-#define        R7      7
-#define        R8      8
-#define        R9      9
-#define        R10     10
-#define        R11     11
-#define        R12     12
-#define        R13     13
-#define        R14     14
-#define        R15     15
-
-#define        NULLCODE        0       /* Null Code */
-#define        POINT_HIGH      0x8     /* Select upper half of registers */
-#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
-#define        SEND_ABORT      0x18    /* HDLC Abort */
-#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
-#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
-#define        ERR_RES         0x30    /* Error Reset */
-#define        RES_H_IUS       0x38    /* Reset highest IUS */
-
-#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
-#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
-#define        RES_EOM_L       0xC0    /* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
-#define        TxINT_ENAB      0x2     /* Tx Int Enable */
-#define        PAR_SPEC        0x4     /* Parity is special condition */
-
-#define        RxINT_DISAB     0       /* Rx Int Disable */
-#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
-#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
-#define        INT_ERR_Rx      0x18    /* Int on error only */
-
-#define        WT_RDY_RT       0x20    /* W/Req reflects recv if 1, xmit if 0 */
-#define        WT_FN_RDYFN     0x40    /* W/Req pin is DMA request if 1, wait if 0 */
-#define        WT_RDY_ENAB     0x80    /* Enable W/Req pin */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define        RxENABLE        0x1     /* Rx Enable */
-#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
-#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
-#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
-#define        ENT_HM          0x10    /* Enter Hunt Mode */
-#define        AUTO_ENAB       0x20    /* Auto Enables */
-#define        Rx5             0x0     /* Rx 5 Bits/Character */
-#define        Rx7             0x40    /* Rx 7 Bits/Character */
-#define        Rx6             0x80    /* Rx 6 Bits/Character */
-#define        Rx8             0xc0    /* Rx 8 Bits/Character */
-#define RxNBITS_MASK   0xc0
-
-/* Write Register 4 */
-
-#define        PAR_ENA         0x1     /* Parity Enable */
-#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
-
-#define        SYNC_ENAB       0       /* Sync Modes Enable */
-#define        SB1             0x4     /* 1 stop bit/char */
-#define        SB15            0x8     /* 1.5 stop bits/char */
-#define        SB2             0xc     /* 2 stop bits/char */
-#define SB_MASK                0xc
-
-#define        MONSYNC         0       /* 8 Bit Sync character */
-#define        BISYNC          0x10    /* 16 bit sync character */
-#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
-#define        EXTSYNC         0x30    /* External Sync Mode */
-
-#define        X1CLK           0x0     /* x1 clock mode */
-#define        X16CLK          0x40    /* x16 clock mode */
-#define        X32CLK          0x80    /* x32 clock mode */
-#define        X64CLK          0xC0    /* x64 clock mode */
-#define XCLK_MASK      0xC0
-
-/* Write Register 5 */
-
-#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
-#define        RTS             0x2     /* RTS */
-#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
-#define        TxENAB          0x8     /* Tx Enable */
-#define        SND_BRK         0x10    /* Send Break */
-#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
-#define        Tx7             0x20    /* Tx 7 bits/character */
-#define        Tx6             0x40    /* Tx 6 bits/character */
-#define        Tx8             0x60    /* Tx 8 bits/character */
-#define TxNBITS_MASK   0x60
-#define        DTR             0x80    /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 7' (Some enhanced feature control) */
-#define        ENEXREAD        0x40    /* Enable read of some write registers */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define        VIS     1       /* Vector Includes Status */
-#define        NV      2       /* No Vector */
-#define        DLC     4       /* Disable Lower Chain */
-#define        MIE     8       /* Master Interrupt Enable */
-#define        STATHI  0x10    /* Status high */
-#define        NORESET 0       /* No reset on write to R9 */
-#define        CHRB    0x40    /* Reset channel B */
-#define        CHRA    0x80    /* Reset channel A */
-#define        FHWRES  0xc0    /* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define        BIT6    1       /* 6 bit/8bit sync */
-#define        LOOPMODE 2      /* SDLC Loop mode */
-#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
-#define        MARKIDLE 8      /* Mark/flag on idle */
-#define        GAOP    0x10    /* Go active on poll */
-#define        NRZ     0       /* NRZ mode */
-#define        NRZI    0x20    /* NRZI mode */
-#define        FM1     0x40    /* FM1 (transition = 1) */
-#define        FM0     0x60    /* FM0 (transition = 0) */
-#define        CRCPS   0x80    /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define        TRxCXT  0       /* TRxC = Xtal output */
-#define        TRxCTC  1       /* TRxC = Transmit clock */
-#define        TRxCBR  2       /* TRxC = BR Generator Output */
-#define        TRxCDP  3       /* TRxC = DPLL output */
-#define        TRxCOI  4       /* TRxC O/I */
-#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
-#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
-#define        TCBR    0x10    /* Transmit clock = BR Generator output */
-#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
-#define        RCRTxCP 0       /* Receive clock = RTxC pin */
-#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
-#define        RCBR    0x40    /* Receive clock = BR Generator output */
-#define        RCDPLL  0x60    /* Receive clock = DPLL output */
-#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define        BRENABL 1       /* Baud rate generator enable */
-#define        BRSRC   2       /* Baud rate generator source */
-#define        DTRREQ  4       /* DTR/Request function */
-#define        AUTOECHO 8      /* Auto Echo */
-#define        LOOPBAK 0x10    /* Local loopback */
-#define        SEARCH  0x20    /* Enter search mode */
-#define        RMC     0x40    /* Reset missing clock */
-#define        DISDPLL 0x60    /* Disable DPLL */
-#define        SSBR    0x80    /* Set DPLL source = BR generator */
-#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
-#define        SFMM    0xc0    /* Set FM mode */
-#define        SNRZI   0xe0    /* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define        EN85C30 1       /* Enable some 85c30-enhanced registers */
-#define        ZCIE    2       /* Zero count IE */
-#define        ENSTFIFO 4      /* Enable status FIFO (SDLC) */
-#define        DCDIE   8       /* DCD IE */
-#define        SYNCIE  0x10    /* Sync/hunt IE */
-#define        CTSIE   0x20    /* CTS IE */
-#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
-#define        BRKIE   0x80    /* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define        Rx_CH_AV        0x1     /* Rx Character Available */
-#define        ZCOUNT          0x2     /* Zero count */
-#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
-#define        DCD             0x8     /* DCD */
-#define        SYNC_HUNT       0x10    /* Sync/hunt */
-#define        CTS             0x20    /* CTS */
-#define        TxEOM           0x40    /* Tx underrun */
-#define        BRK_ABRT        0x80    /* Break/Abort */
-
-/* Read Register 1 */
-#define        ALL_SNT         0x1     /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define        RES3            0x8     /* 0/3 */
-#define        RES4            0x4     /* 0/4 */
-#define        RES5            0xc     /* 0/5 */
-#define        RES6            0x2     /* 0/6 */
-#define        RES7            0xa     /* 0/7 */
-#define        RES8            0x6     /* 0/8 */
-#define        RES18           0xe     /* 1/8 */
-#define        RES28           0x0     /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define        PAR_ERR         0x10    /* Parity error */
-#define        Rx_OVR          0x20    /* Rx Overrun Error */
-#define        FRM_ERR         0x40    /* CRC/Framing Error */
-#define        END_FR          0x80    /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-#define        CHB_Tx_EMPTY    0x00
-#define        CHB_EXT_STAT    0x02
-#define        CHB_Rx_AVAIL    0x04
-#define        CHB_SPECIAL     0x06
-#define        CHA_Tx_EMPTY    0x08
-#define        CHA_EXT_STAT    0x0a
-#define        CHA_Rx_AVAIL    0x0c
-#define        CHA_SPECIAL     0x0e
-#define        STATUS_MASK     0x06
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
-#define        CHBTxIP 0x2             /* Channel B Tx IP */
-#define        CHBRxIP 0x4             /* Channel B Rx IP */
-#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
-#define        CHATxIP 0x10            /* Channel A Tx IP */
-#define        CHARxIP 0x20            /* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10  (misc status bits) */
-#define        ONLOOP  2               /* On loop */
-#define        LOOPSEND 0x10           /* Loop sending */
-#define        CLK2MIS 0x40            /* Two clocks missing */
-#define        CLK1MIS 0x80            /* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(channel)    (write_zsreg(channel, 0, ERR_RES))
-#define ZS_CLEARFIFO(channel)   do { volatile unsigned char garbage; \
-                                    garbage = read_zsdata(channel); \
-                                    garbage = read_zsdata(channel); \
-                                    garbage = read_zsdata(channel); \
-                               } while(0)
-
-#endif /* !(_MACSERIAL_H) */
index 5ba190ce14a07dbc8a17607d5dce10bc919f8b29..c9ca1118e449207c2dca58a742b0ddd204a556d7 100644 (file)
@@ -328,9 +328,7 @@ static int monitor_task(void *arg)
        struct thermostat* th = arg;
 
        while(!kthread_should_stop()) {
-               if (current->flags & PF_FREEZE)
-                       refrigerator(PF_FREEZE);
-
+               try_to_freeze();
                msleep_interruptible(2000);
 
 #ifndef DEBUG
index b941ee220997adbc96b50b48862d0e47c687afda..4a0a0ad2d03c09e7bff0e9185c4355e274514264 100644 (file)
 #include <asm/backlight.h>
 #endif
 
+#ifdef CONFIG_PPC32
+#include <asm/open_pic.h>
+#endif
+
 /* Some compile options */
 #undef SUSPEND_USES_PMU
 #define DEBUG_SLEEP
@@ -151,10 +155,10 @@ static spinlock_t pmu_lock;
 static u8 pmu_intr_mask;
 static int pmu_version;
 static int drop_interrupts;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 static int option_lid_wakeup = 1;
 static int sleep_in_progress;
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 static unsigned long async_req_locks;
 static unsigned int pmu_irq_stats[11];
 
@@ -164,7 +168,6 @@ static struct proc_dir_entry *proc_pmu_irqstats;
 static struct proc_dir_entry *proc_pmu_options;
 static int option_server_mode;
 
-#ifdef CONFIG_PMAC_PBOOK
 int pmu_battery_count;
 int pmu_cur_battery;
 unsigned int pmu_power_flags;
@@ -172,7 +175,6 @@ struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
 static int query_batt_timer = BATTERY_POLLING_COUNT;
 static struct adb_request batt_req;
 static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];
-#endif /* CONFIG_PMAC_PBOOK */
 
 #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
 extern int disable_kernel_backlight;
@@ -206,11 +208,9 @@ static int proc_get_irqstats(char *page, char **start, off_t off,
 static int pmu_set_backlight_level(int level, void* data);
 static int pmu_set_backlight_enable(int on, int level, void* data);
 #endif /* CONFIG_PMAC_BACKLIGHT */
-#ifdef CONFIG_PMAC_PBOOK
 static void pmu_pass_intr(unsigned char *data, int len);
 static int proc_get_batt(char *page, char **start, off_t off,
                        int count, int *eof, void *data);
-#endif /* CONFIG_PMAC_PBOOK */
 static int proc_read_options(char *page, char **start, off_t off,
                        int count, int *eof, void *data);
 static int proc_write_options(struct file *file, const char __user *buffer,
@@ -403,8 +403,12 @@ static int __init via_pmu_start(void)
 
        bright_req_1.complete = 1;
        bright_req_2.complete = 1;
-#ifdef CONFIG_PMAC_PBOOK
        batt_req.complete = 1;
+
+#ifdef CONFIG_PPC32
+       if (pmu_kind == PMU_KEYLARGO_BASED)
+               openpic_set_irq_priority(vias->intrs[0].line,
+                                        OPENPIC_PRIORITY_DEFAULT + 1);
 #endif
 
        if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",
@@ -458,7 +462,7 @@ static int __init via_pmu_dev_init(void)
        register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PPC32
        if (machine_is_compatible("AAPL,3400/2400") ||
                machine_is_compatible("AAPL,3500")) {
                int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
@@ -486,20 +490,19 @@ static int __init via_pmu_dev_init(void)
                                pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
                }
        }
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PPC32 */
+
        /* Create /proc/pmu */
        proc_pmu_root = proc_mkdir("pmu", NULL);
        if (proc_pmu_root) {
-#ifdef CONFIG_PMAC_PBOOK
-               int i;
+               long i;
 
                for (i=0; i<pmu_battery_count; i++) {
                        char title[16];
-                       sprintf(title, "battery_%d", i);
+                       sprintf(title, "battery_%ld", i);
                        proc_pmu_batt[i] = create_proc_read_entry(title, 0, proc_pmu_root,
                                                proc_get_batt, (void *)i);
                }
-#endif /* CONFIG_PMAC_PBOOK */
 
                proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root,
                                        proc_get_info, NULL);
@@ -619,8 +622,6 @@ static void pmu_set_server_mode(int server_mode)
        pmu_wait_complete(&req);
 }
 
-#ifdef CONFIG_PMAC_PBOOK
-
 /* This new version of the code for 2400/3400/3500 powerbooks
  * is inspired from the implementation in gkrellm-pmu
  */
@@ -803,8 +804,6 @@ query_battery_state(void)
                        2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1);
 }
 
-#endif /* CONFIG_PMAC_PBOOK */
-
 static int __pmac
 proc_get_info(char *page, char **start, off_t off,
                int count, int *eof, void *data)
@@ -813,11 +812,9 @@ proc_get_info(char *page, char **start, off_t off,
 
        p += sprintf(p, "PMU driver version     : %d\n", PMU_DRIVER_VERSION);
        p += sprintf(p, "PMU firmware version   : %02x\n", pmu_version);
-#ifdef CONFIG_PMAC_PBOOK
        p += sprintf(p, "AC Power               : %d\n",
                ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0));
        p += sprintf(p, "Battery count          : %d\n", pmu_battery_count);
-#endif /* CONFIG_PMAC_PBOOK */
 
        return p - page;
 }
@@ -849,12 +846,11 @@ proc_get_irqstats(char *page, char **start, off_t off,
        return p - page;
 }
 
-#ifdef CONFIG_PMAC_PBOOK
 static int __pmac
 proc_get_batt(char *page, char **start, off_t off,
                int count, int *eof, void *data)
 {
-       int batnum = (int)data;
+       long batnum = (long)data;
        char *p = page;
        
        p += sprintf(p, "\n");
@@ -873,7 +869,6 @@ proc_get_batt(char *page, char **start, off_t off,
 
        return p - page;
 }
-#endif /* CONFIG_PMAC_PBOOK */
 
 static int __pmac
 proc_read_options(char *page, char **start, off_t off,
@@ -881,11 +876,11 @@ proc_read_options(char *page, char **start, off_t off,
 {
        char *p = page;
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
        if (pmu_kind == PMU_KEYLARGO_BASED &&
            pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
                p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif
        if (pmu_kind == PMU_KEYLARGO_BASED)
                p += sprintf(p, "server_mode=%d\n", option_server_mode);
 
@@ -922,12 +917,12 @@ proc_write_options(struct file *file, const char __user *buffer,
        *(val++) = 0;
        while(*val == ' ')
                val++;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
        if (pmu_kind == PMU_KEYLARGO_BASED &&
            pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
                if (!strcmp(label, "lid_wakeup"))
                        option_lid_wakeup = ((*val) == '1');
-#endif /* CONFIG_PMAC_PBOOK */
+#endif
        if (pmu_kind == PMU_KEYLARGO_BASED && !strcmp(label, "server_mode")) {
                int new_value;
                new_value = ((*val) == '1');
@@ -1422,7 +1417,6 @@ next:
        }
        /* Tick interrupt */
        else if ((1 << pirq) & PMU_INT_TICK) {
-#ifdef CONFIG_PMAC_PBOOK
                /* Environement or tick interrupt, query batteries */
                if (pmu_battery_count) {
                        if ((--query_batt_timer) == 0) {
@@ -1437,7 +1431,6 @@ next:
                pmu_pass_intr(data, len);
        } else {
               pmu_pass_intr(data, len);
-#endif /* CONFIG_PMAC_PBOOK */
        }
        goto next;
 }
@@ -2052,7 +2045,7 @@ pmu_i2c_simple_write(int bus, int addr,  u8* data, int len)
        return -1;
 }
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 
 static LIST_HEAD(sleep_notifiers);
 
@@ -2705,6 +2698,8 @@ powerbook_sleep_3400(void)
        return 0;
 }
 
+#endif /* CONFIG_PM */
+
 /*
  * Support for /dev/pmu device
  */
@@ -2884,11 +2879,11 @@ static int __pmac
 pmu_ioctl(struct inode * inode, struct file *filp,
                     u_int cmd, u_long arg)
 {
-       struct pmu_private *pp = filp->private_data;
        __u32 __user *argp = (__u32 __user *)arg;
-       int error;
+       int error = -EINVAL;
 
        switch (cmd) {
+#ifdef CONFIG_PM
        case PMU_IOC_SLEEP:
                if (!capable(CAP_SYS_ADMIN))
                        return -EACCES;
@@ -2910,12 +2905,13 @@ pmu_ioctl(struct inode * inode, struct file *filp,
                        error = -ENOSYS;
                }
                sleep_in_progress = 0;
-               return error;
+               break;
        case PMU_IOC_CAN_SLEEP:
                if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0)
                        return put_user(0, argp);
                else
                        return put_user(1, argp);
+#endif /* CONFIG_PM */
 
 #ifdef CONFIG_PMAC_BACKLIGHT
        /* Backlight should have its own device or go via
@@ -2936,11 +2932,13 @@ pmu_ioctl(struct inode * inode, struct file *filp,
                error = get_user(value, argp);
                if (!error)
                        error = set_backlight_level(value);
-               return error;
+               break;
        }
 #ifdef CONFIG_INPUT_ADBHID
        case PMU_IOC_GRAB_BACKLIGHT: {
+               struct pmu_private *pp = filp->private_data;
                unsigned long flags;
+
                if (pp->backlight_locker)
                        return 0;
                pp->backlight_locker = 1;
@@ -2956,7 +2954,7 @@ pmu_ioctl(struct inode * inode, struct file *filp,
        case PMU_IOC_HAS_ADB:
                return put_user(pmu_has_adb, argp);
        }
-       return -EINVAL;
+       return error;
 }
 
 static struct file_operations pmu_device_fops __pmacdata = {
@@ -2972,14 +2970,16 @@ static struct miscdevice pmu_device __pmacdata = {
        PMU_MINOR, "pmu", &pmu_device_fops
 };
 
-void pmu_device_init(void)
+static int pmu_device_init(void)
 {
        if (!via)
-               return;
+               return 0;
        if (misc_register(&pmu_device) < 0)
                printk(KERN_ERR "via-pmu: cannot register misc device.\n");
+       return 0;
 }
-#endif /* CONFIG_PMAC_PBOOK */
+device_initcall(pmu_device_init);
+
 
 #ifdef DEBUG_SLEEP
 static inline void  __pmac
@@ -3147,12 +3147,12 @@ EXPORT_SYMBOL(pmu_i2c_combined_read);
 EXPORT_SYMBOL(pmu_i2c_stdsub_write);
 EXPORT_SYMBOL(pmu_i2c_simple_read);
 EXPORT_SYMBOL(pmu_i2c_simple_write);
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 EXPORT_SYMBOL(pmu_register_sleep_notifier);
 EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
 EXPORT_SYMBOL(pmu_enable_irled);
 EXPORT_SYMBOL(pmu_battery_count);
 EXPORT_SYMBOL(pmu_batteries);
 EXPORT_SYMBOL(pmu_power_flags);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
index af56313ba0af9d6ed7b5ed6a23826d690b44fdbc..0c7bfa74c8efccc36502b1cc99c38a542956f6ba 100644 (file)
@@ -180,7 +180,6 @@ struct mca_device *mca_find_device_by_slot(int slot)
 
        return info.mca_dev;
 }
-EXPORT_SYMBOL(mca_find_device_by_slot);
 
 /**
  *     mca_read_stored_pos - read POS register from boot data
index 0c6b5b6baff60ded7fb24d2f71988711d723c604..4a0c57db2b67657b8c09cfbe67f5d2cfb487ed95 100644 (file)
@@ -338,6 +338,7 @@ static int super_written(struct bio *bio, unsigned int bytes_done, int error)
 
        if (atomic_dec_and_test(&rdev->mddev->pending_writes))
                wake_up(&rdev->mddev->sb_wait);
+       bio_put(bio);
        return 0;
 }
 
@@ -2976,8 +2977,7 @@ static int md_thread(void * arg)
                wait_event_interruptible_timeout(thread->wqueue,
                                                 test_bit(THREAD_WAKEUP, &thread->flags),
                                                 thread->timeout);
-               if (current->flags & PF_FREEZE)
-                       refrigerator(PF_FREEZE);
+               try_to_freeze();
 
                clear_bit(THREAD_WAKEUP, &thread->flags);
 
index 84a49d2ec919bd84a02ce14266967f16e9d255a8..4adb2843f8be14875a0e1bfa6586b0cb09d32054 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ir-common.c,v 1.8 2005/02/22 12:28:40 kraxel Exp $
+ * $Id: ir-common.c,v 1.10 2005/05/22 19:23:39 nsh Exp $
  *
  * some common structs and functions to handle infrared remotes via
  * input layer ...
@@ -131,10 +131,10 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
        [ 18 ] = KEY_KP0,
 
        [  0 ] = KEY_POWER,
-       [ 27 ] = KEY_LANGUAGE,  //MTS button
+//      [ 27 ] = MTS button
        [  2 ] = KEY_TUNER,     // TV/FM
        [ 30 ] = KEY_VIDEO,
-       [ 22 ] = KEY_INFO,      //display button
+//      [ 22 ] = display button
        [  4 ] = KEY_VOLUMEUP,
        [  8 ] = KEY_VOLUMEDOWN,
        [ 12 ] = KEY_CHANNELUP,
@@ -142,7 +142,7 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
        [  3 ] = KEY_ZOOM,      // fullscreen
        [ 31 ] = KEY_SUBTITLE,  // closed caption/teletext
        [ 32 ] = KEY_SLEEP,
-       [ 41 ] = KEY_SEARCH,    //boss key
+//      [ 41 ] = boss key
        [ 20 ] = KEY_MUTE,
        [ 43 ] = KEY_RED,
        [ 44 ] = KEY_GREEN,
@@ -150,17 +150,17 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
        [ 46 ] = KEY_BLUE,
        [ 24 ] = KEY_KPPLUS,    //fine tune +
        [ 25 ] = KEY_KPMINUS,   //fine tune -
-       [ 42 ] = KEY_ANGLE,     //picture in picture
-       [ 33 ] = KEY_KPDOT,
+//      [ 42 ] = picture in picture
+        [ 33 ] = KEY_KPDOT,
        [ 19 ] = KEY_KPENTER,
-       [ 17 ] = KEY_AGAIN,     //recall
+//      [ 17 ] = recall
        [ 34 ] = KEY_BACK,
        [ 35 ] = KEY_PLAYPAUSE,
        [ 36 ] = KEY_NEXT,
-       [ 37 ] = KEY_T,         //time shifting
+//      [ 37 ] = time shifting
        [ 38 ] = KEY_STOP,
-       [ 39 ] = KEY_RECORD,
-       [ 40 ] = KEY_SHUFFLE    //snapshot
+       [ 39 ] = KEY_RECORD
+//      [ 40 ] = snapshot
 };
 EXPORT_SYMBOL_GPL(ir_codes_winfast);
 
@@ -184,18 +184,30 @@ IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
        [ 0x07 ] = KEY_KP7,             // 7
        [ 0x08 ] = KEY_KP8,             // 8
        [ 0x09 ] = KEY_KP9,             // 9
+       [ 0x0a ] = KEY_TEXT,            // keypad asterisk as well
        [ 0x0b ] = KEY_RED,             // red button
-       [ 0x0c ] = KEY_OPTION,          // black key without text
+       [ 0x0c ] = KEY_RADIO,           // radio
        [ 0x0d ] = KEY_MENU,            // menu
+       [ 0x0e ] = KEY_SUBTITLE,        // also the # key
        [ 0x0f ] = KEY_MUTE,            // mute
        [ 0x10 ] = KEY_VOLUMEUP,        // volume +
        [ 0x11 ] = KEY_VOLUMEDOWN,      // volume -
-       [ 0x1e ] = KEY_NEXT,            // skip >|
+       [ 0x12 ] = KEY_PREVIOUS,        // previous channel
+       [ 0x14 ] = KEY_UP,              // up
+       [ 0x15 ] = KEY_DOWN,            // down
+       [ 0x16 ] = KEY_LEFT,            // left
+       [ 0x17 ] = KEY_RIGHT,           // right
+       [ 0x18 ] = KEY_VIDEO,           // Videos
+       [ 0x19 ] = KEY_AUDIO,           // Music
+       [ 0x1a ] = KEY_MHP,             // Pictures - presume this means "Multimedia Home Platform"- no "PICTURES" key in input.h
+       [ 0x1b ] = KEY_EPG,             // Guide
+       [ 0x1c ] = KEY_TV,              // TV
+       [ 0x1e ] = KEY_NEXTSONG,        // skip >|
        [ 0x1f ] = KEY_EXIT,            // back/exit
        [ 0x20 ] = KEY_CHANNELUP,       // channel / program +
        [ 0x21 ] = KEY_CHANNELDOWN,     // channel / program -
        [ 0x22 ] = KEY_CHANNEL,         // source (old black remote)
-       [ 0x24 ] = KEY_PREVIOUS,        // replay |<
+       [ 0x24 ] = KEY_PREVIOUSSONG,    // replay |<
        [ 0x25 ] = KEY_ENTER,           // OK
        [ 0x26 ] = KEY_SLEEP,           // minimize (old black remote)
        [ 0x29 ] = KEY_BLUE,            // blue key
@@ -213,6 +225,39 @@ IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
 };
 EXPORT_SYMBOL(ir_codes_hauppauge_new);
 
+IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = {
+       [  2 ] = KEY_KP0,
+       [  1 ] = KEY_KP1,
+       [ 11 ] = KEY_KP2,
+       [ 27 ] = KEY_KP3,
+       [  5 ] = KEY_KP4,
+       [  9 ] = KEY_KP5,
+       [ 21 ] = KEY_KP6,
+       [  6 ] = KEY_KP7,
+       [ 10 ] = KEY_KP8,
+       [ 18 ] = KEY_KP9,
+
+       [  3 ] = KEY_TUNER,       // TV/FM
+       [  7 ] = KEY_SEARCH,      // scan
+       [ 28 ] = KEY_ZOOM,        // full screen
+       [ 30 ] = KEY_POWER,
+       [ 23 ] = KEY_VOLUMEDOWN,
+       [ 31 ] = KEY_VOLUMEUP,
+       [ 20 ] = KEY_CHANNELDOWN,
+       [ 22 ] = KEY_CHANNELUP,
+       [ 24 ] = KEY_MUTE,
+
+       [  0 ] = KEY_LIST,        // source
+       [ 19 ] = KEY_INFO,        // loop
+       [ 16 ] = KEY_LAST,        // +100
+       [ 13 ] = KEY_CLEAR,       // reset
+       [ 12 ] = BTN_RIGHT,       // fun++
+       [  4 ] = BTN_LEFT,        // fun--
+       [ 14 ] = KEY_GOTO,        // function
+       [ 15 ] = KEY_STOP,         // freeze
+};
+EXPORT_SYMBOL(ir_codes_pixelview);
+
 /* -------------------------------------------------------------------------- */
 
 static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
@@ -379,3 +424,4 @@ EXPORT_SYMBOL_GPL(ir_decode_biphase);
  * c-basic-offset: 8
  * End:
  */
+
index cb826c9adfe7e60124547528f8da72154bbca548..c04fd11526e08432cc648403ecbdaef0e3aeeeb2 100644 (file)
@@ -403,7 +403,7 @@ static struct file_operations video_fops =
        .llseek         = no_llseek,
 };
 
-void vv_callback(struct saa7146_dev *dev, unsigned long status)
+static void vv_callback(struct saa7146_dev *dev, unsigned long status)
 {
        u32 isr = status;
        
index 4983e1b1bb1d2a7ac137f56d65365544c4fbb791..01387f883cdff2e1d1bbe774674ab42cd2ff352e 100644 (file)
@@ -27,9 +27,9 @@ source "drivers/media/dvb/ttpci/Kconfig"
 
 comment "Supported USB Adapters"
        depends on DVB_CORE && USB
+source "drivers/media/dvb/dvb-usb/Kconfig"
 source "drivers/media/dvb/ttusb-budget/Kconfig"
 source "drivers/media/dvb/ttusb-dec/Kconfig"
-source "drivers/media/dvb/dibusb/Kconfig"
 source "drivers/media/dvb/cinergyT2/Kconfig"
 
 comment "Supported FlexCopII (B2C2) Adapters"
index 520fc3902819a5e40b956fb07ee444b8f307f277..3c6ff16191033ab1943dafaac7b61f28870eacb7 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
-obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dibusb/ cinergyT2/
+obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/
index 99bd675df955ba49c61041ec35e379f75e907d76..fafd0ab3a28fc90f8828d24a8c51e546322f62ac 100644 (file)
@@ -6,6 +6,7 @@ config DVB_B2C2_FLEXCOP
        select DVB_MT312
        select DVB_NXT2002
        select DVB_STV0297
+       select DVB_BCM3510
        help
          Support for the digital TV receiver chip made by B2C2 Inc. included in
          Technisats PCI cards and USB boxes.
index 71be400e9aeb710316ae65bf1860bb66323f51e9..0410cc96a48e2cc3a90238ab92e4dd45904d4e2f 100644 (file)
@@ -10,6 +10,7 @@
 #include "stv0299.h"
 #include "mt352.h"
 #include "nxt2002.h"
+#include "bcm3510.h"
 #include "stv0297.h"
 #include "mt312.h"
 
@@ -285,21 +286,25 @@ static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_front
 }
 
 static struct mt352_config samsung_tdtc9251dh0_config = {
-
        .demod_address = 0x0f,
-       .demod_init = samsung_tdtc9251dh0_demod_init,
-       .pll_set = samsung_tdtc9251dh0_pll_set,
+       .demod_init    = samsung_tdtc9251dh0_demod_init,
+       .pll_set       = samsung_tdtc9251dh0_pll_set,
 };
 
-static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
 {
        struct flexcop_device *fc = fe->dvb->priv;
        return request_firmware(fw, name, fc->dev);
 }
 
 static struct nxt2002_config samsung_tbmv_config = {
-       .demod_address = 0x0a,
-       .request_firmware = nxt2002_request_firmware,
+       .demod_address    = 0x0a,
+       .request_firmware = flexcop_fe_request_firmware,
+};
+
+static struct bcm3510_config air2pc_atsc_first_gen_config = {
+       .demod_address    = 0x0f,
+       .request_firmware = flexcop_fe_request_firmware,
 };
 
 static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
@@ -354,11 +359,16 @@ int flexcop_frontend_init(struct flexcop_device *fc)
                fc->dev_type          = FC_AIR_DVB;
                info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
        } else
-       /* try the air atsc (nxt2002) */
+       /* try the air atsc 2nd generation (nxt2002) */
        if ((fc->fe = nxt2002_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
-               fc->dev_type          = FC_AIR_ATSC;
+               fc->dev_type          = FC_AIR_ATSC2;
                info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
        } else
+       /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
+       if ((fc->fe = bcm3510_attach(&air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
+               fc->dev_type          = FC_AIR_ATSC1;
+               info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address);
+       } else
        /* try the cable dvb (stv0297) */
        if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap, 0xf8)) != NULL) {
                fc->dev_type                        = FC_CABLE;
index 19e06da4677497c8628cc0744ebdceb309812d10..23082545651fd2e36d6d5424bf15954b97779675 100644 (file)
@@ -45,11 +45,12 @@ const char *flexcop_revision_names[] = {
 
 const char *flexcop_device_names[] = {
        "Unkown device",
-       "AirStar 2 DVB-T",
-       "AirStar 2 ATSC",
-       "SkyStar 2 DVB-S",
-       "SkyStar 2 DVB-S (old version)",
-       "CableStar 2 DVB-C",
+       "Air2PC/AirStar 2 DVB-T",
+       "Air2PC/AirStar 2 ATSC 1st generation",
+       "Air2PC/AirStar 2 ATSC 2nd generation",
+       "Sky2PC/SkyStar 2 DVB-S",
+       "Sky2PC/SkyStar 2 DVB-S (old version)",
+       "Cable2PC/CableStar 2 DVB-C",
 };
 
 const char *flexcop_bus_names[] = {
index 5e131be55cb3f342d3dfdb982fd909c159d791f9..75b50f21afe65eab15d11404d5f6bd0aca389dfd 100644 (file)
@@ -21,7 +21,8 @@ extern const char *flexcop_revision_names[];
 typedef enum {
        FC_UNK = 0,
        FC_AIR_DVB,
-       FC_AIR_ATSC,
+       FC_AIR_ATSC1,
+       FC_AIR_ATSC2,
        FC_SKY,
        FC_SKY_OLD,
        FC_CABLE,
diff --git a/drivers/media/dvb/dibusb/Kconfig b/drivers/media/dvb/dibusb/Kconfig
deleted file mode 100644 (file)
index 74dfc73..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-config DVB_DIBUSB
-       tristate "DiBcom USB DVB-T devices (see help for a complete device list)"
-       depends on DVB_CORE && USB
-       select FW_LOADER
-       select DVB_DIB3000MB
-       select DVB_DIB3000MC
-       select DVB_MT352
-       help
-         Support for USB 1.1 and 2.0 DVB-T devices based on reference designs made by
-         DiBcom (http://www.dibcom.fr) and C&E.
-
-         Devices supported by this driver:
-
-           TwinhanDTV USB-Ter (VP7041)
-               TwinhanDTV Magic Box (VP7041e)
-           KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
-           Hama DVB-T USB-Box
-           DiBcom reference devices (non-public)
-           Ultima Electronic/Artec T1 USB TVBOX
-           Compro Videomate DVB-U2000 - DVB-T USB
-           Grandtec DVB-T USB
-           Avermedia AverTV DVBT USB
-           Artec T1 USB1.1 and USB2.0 boxes
-           Yakumo/Typhoon DVB-T USB2.0
-           Hanftek UMT-010 USB2.0
-           Hauppauge WinTV NOVA-T USB2
-
-         The VP7041 seems to be identical to "CTS Portable" (Chinese
-         Television System).
-
-         These devices can be understood as budget ones, they "only" deliver
-         (a part of) the MPEG2 transport stream.
-
-         A firmware is needed to get the device working. See Documentation/dvb/README.dibusb
-         details.
-
-         Say Y if you own such a device and want to use it. You should build it as
-         a module.
-
-config DVB_DIBUSB_MISDESIGNED_DEVICES
-       bool "Enable support for some misdesigned (see help) devices, which identify with wrong IDs"
-       depends on DVB_DIBUSB
-       help
-         Somehow Artec/Ultima Electronic forgot to program the eeprom of some of their
-         USB1.1/USB2.0 devices.
-         So comes that they identify with the default Vendor and Product ID of the Cypress
-         CY7C64613 (AN2235) or Cypress FX2.
-
-         Affected device IDs:
-           0x0574:0x2235 (Artec T1 USB1.1, cold)
-           0x04b4:0x8613 (Artec T1 USB2.0, cold)
-           0x0574:0x1002 (Artec T1 USB2.0, warm)
-           0x0574:0x2131 (aged DiBcom USB1.1 test device)
-
-         Say Y if your device has one of the mentioned IDs.
-
-config DVB_DIBCOM_DEBUG
-       bool "Enable extended debug support for DiBcom USB device"
-       depends on DVB_DIBUSB
-       help
-         Say Y if you want to enable debuging. See modinfo dvb-dibusb for
-         debug levels.
diff --git a/drivers/media/dvb/dibusb/Makefile b/drivers/media/dvb/dibusb/Makefile
deleted file mode 100644 (file)
index e941c50..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-dvb-dibusb-objs = dvb-dibusb-core.o \
-       dvb-dibusb-dvb.o \
-       dvb-dibusb-fe-i2c.o \
-       dvb-dibusb-firmware.o \
-       dvb-dibusb-remote.o \
-       dvb-dibusb-usb.o \
-       dvb-fe-dtt200u.o
-
-obj-$(CONFIG_DVB_DIBUSB) += dvb-dibusb.o
-
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-core.c b/drivers/media/dvb/dibusb/dvb-dibusb-core.c
deleted file mode 100644 (file)
index 26235f9..0000000
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Driver for mobile USB Budget DVB-T devices based on reference 
- * design made by DiBcom (http://www.dibcom.fr/)
- * 
- * dvb-dibusb-core.c
- * 
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- * 
- * based on GPL code from DiBcom, which has
- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
- *
- * Remote control code added by David Matthews (dm@prolingua.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, version 2.
- *
- * Acknowledgements
- * 
- *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
- *  sources, on which this driver (and the dib3000mb/mc/p frontends) are based.
- * 
- * see Documentation/dvb/README.dibusb for more information
- */
-#include "dvb-dibusb.h"
-
-#include <linux/moduleparam.h>
-
-/* debug */
-int dvb_dibusb_debug;
-module_param_named(debug, dvb_dibusb_debug,  int, 0644);
-
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
-#define DBSTATUS ""
-#else
-#define DBSTATUS " (debugging is not enabled)"
-#endif
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=err,32=rc (|-able))." DBSTATUS);
-#undef DBSTATUS
-
-static int pid_parse;
-module_param(pid_parse, int, 0644);
-MODULE_PARM_DESC(pid_parse, "enable pid parsing (filtering) when running at USB2.0");
-
-static int rc_query_interval = 100;
-module_param(rc_query_interval, int, 0644);
-MODULE_PARM_DESC(rc_query_interval, "interval in msecs for remote control query (default: 100; min: 40)");
-
-static int rc_key_repeat_count = 2;
-module_param(rc_key_repeat_count, int, 0644);
-MODULE_PARM_DESC(rc_key_repeat_count, "how many key repeats will be dropped before passing the key event again (default: 2)");
-
-/* Vendor IDs */
-#define USB_VID_ADSTECH                                                0x06e1
-#define USB_VID_ANCHOR                                         0x0547
-#define USB_VID_AVERMEDIA                                      0x14aa
-#define USB_VID_COMPRO                                         0x185b
-#define USB_VID_COMPRO_UNK                                     0x145f
-#define USB_VID_CYPRESS                                                0x04b4
-#define USB_VID_DIBCOM                                         0x10b8
-#define USB_VID_EMPIA                                          0xeb1a
-#define USB_VID_GRANDTEC                                       0x5032
-#define USB_VID_HANFTEK                                                0x15f4
-#define USB_VID_HAUPPAUGE                                      0x2040
-#define USB_VID_HYPER_PALTEK                           0x1025
-#define USB_VID_IMC_NETWORKS                           0x13d3
-#define USB_VID_TWINHAN                                                0x1822
-#define USB_VID_ULTIMA_ELECTRONIC                      0x05d8
-
-/* Product IDs */
-#define USB_PID_ADSTECH_USB2_COLD                      0xa333
-#define USB_PID_ADSTECH_USB2_WARM                      0xa334
-#define USB_PID_AVERMEDIA_DVBT_USB_COLD                0x0001
-#define USB_PID_AVERMEDIA_DVBT_USB_WARM                0x0002
-#define USB_PID_COMPRO_DVBU2000_COLD           0xd000
-#define USB_PID_COMPRO_DVBU2000_WARM           0xd001
-#define USB_PID_COMPRO_DVBU2000_UNK_COLD       0x010c
-#define USB_PID_COMPRO_DVBU2000_UNK_WARM       0x010d
-#define USB_PID_DIBCOM_MOD3000_COLD                    0x0bb8
-#define USB_PID_DIBCOM_MOD3000_WARM                    0x0bb9
-#define USB_PID_DIBCOM_MOD3001_COLD                    0x0bc6
-#define USB_PID_DIBCOM_MOD3001_WARM                    0x0bc7
-#define USB_PID_DIBCOM_ANCHOR_2135_COLD                0x2131
-#define USB_PID_GRANDTEC_DVBT_USB_COLD         0x0fa0
-#define USB_PID_GRANDTEC_DVBT_USB_WARM         0x0fa1
-#define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
-#define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
-#define USB_PID_TWINHAN_VP7041_COLD                    0x3201
-#define USB_PID_TWINHAN_VP7041_WARM                    0x3202
-#define USB_PID_ULTIMA_TVBOX_COLD                      0x8105
-#define USB_PID_ULTIMA_TVBOX_WARM                      0x8106
-#define USB_PID_ULTIMA_TVBOX_AN2235_COLD       0x8107
-#define USB_PID_ULTIMA_TVBOX_AN2235_WARM       0x8108
-#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD       0x2235
-#define USB_PID_ULTIMA_TVBOX_USB2_COLD         0x8109
-#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD      0x8613
-#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM      0x1002
-#define USB_PID_UNK_HYPER_PALTEK_COLD          0x005e
-#define USB_PID_UNK_HYPER_PALTEK_WARM          0x005f
-#define USB_PID_HANFTEK_UMT_010_COLD           0x0001
-#define USB_PID_HANFTEK_UMT_010_WARM           0x0015
-#define USB_PID_YAKUMO_DTT200U_COLD                    0x0201
-#define USB_PID_YAKUMO_DTT200U_WARM                    0x0301
-#define USB_PID_WINTV_NOVA_T_USB2_COLD         0x9300
-#define USB_PID_WINTV_NOVA_T_USB2_WARM         0x9301
-
-/* USB Driver stuff
- * table of devices that this driver is working with
- *
- * ATTENTION: Never ever change the order of this table, the particular 
- * devices depend on this order 
- *
- * Each entry is used as a reference in the device_struct. Currently this is 
- * the only non-redundant way of assigning USB ids to actual devices I'm aware 
- * of, because there is only one place in the code where the assignment of 
- * vendor and product id is done, here.
- */
-static struct usb_device_id dib_table [] = {
-/* 00 */       { USB_DEVICE(USB_VID_AVERMEDIA,         USB_PID_AVERMEDIA_DVBT_USB_COLD)},
-/* 01 */       { USB_DEVICE(USB_VID_AVERMEDIA,         USB_PID_AVERMEDIA_DVBT_USB_WARM)},
-/* 02 */       { USB_DEVICE(USB_VID_AVERMEDIA,         USB_PID_YAKUMO_DTT200U_COLD) },
-/* 03 */       { USB_DEVICE(USB_VID_AVERMEDIA,         USB_PID_YAKUMO_DTT200U_WARM) },
-
-/* 04 */       { USB_DEVICE(USB_VID_COMPRO,            USB_PID_COMPRO_DVBU2000_COLD) },
-/* 05 */       { USB_DEVICE(USB_VID_COMPRO,            USB_PID_COMPRO_DVBU2000_WARM) },
-/* 06 */       { USB_DEVICE(USB_VID_COMPRO_UNK,        USB_PID_COMPRO_DVBU2000_UNK_COLD) },
-/* 07 */       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3000_COLD) },
-/* 08 */       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3000_WARM) },
-/* 09 */       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3001_COLD) },
-/* 10 */       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3001_WARM) },
-/* 11 */       { USB_DEVICE(USB_VID_EMPIA,                     USB_PID_KWORLD_VSTREAM_COLD) },
-/* 12 */       { USB_DEVICE(USB_VID_EMPIA,                     USB_PID_KWORLD_VSTREAM_WARM) },
-/* 13 */       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB_COLD) },
-/* 14 */       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB_WARM) },
-/* 15 */       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_DIBCOM_MOD3000_COLD) },
-/* 16 */       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_DIBCOM_MOD3000_WARM) },
-/* 17 */       { USB_DEVICE(USB_VID_HYPER_PALTEK,      USB_PID_UNK_HYPER_PALTEK_COLD) },
-/* 18 */       { USB_DEVICE(USB_VID_HYPER_PALTEK,      USB_PID_UNK_HYPER_PALTEK_WARM) },
-/* 19 */       { USB_DEVICE(USB_VID_IMC_NETWORKS,      USB_PID_TWINHAN_VP7041_COLD) },
-/* 20 */       { USB_DEVICE(USB_VID_IMC_NETWORKS,      USB_PID_TWINHAN_VP7041_WARM) },
-/* 21 */       { USB_DEVICE(USB_VID_TWINHAN,           USB_PID_TWINHAN_VP7041_COLD) },
-/* 22 */       { USB_DEVICE(USB_VID_TWINHAN,           USB_PID_TWINHAN_VP7041_WARM) },
-/* 23 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
-/* 24 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
-/* 25 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
-/* 26 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
-/* 27 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
-       
-/* 28 */       { USB_DEVICE(USB_VID_HANFTEK,           USB_PID_HANFTEK_UMT_010_COLD) },
-/* 29 */       { USB_DEVICE(USB_VID_HANFTEK,           USB_PID_HANFTEK_UMT_010_WARM) },
-
-/* 30 */       { USB_DEVICE(USB_VID_HAUPPAUGE,         USB_PID_WINTV_NOVA_T_USB2_COLD) },
-/* 31 */       { USB_DEVICE(USB_VID_HAUPPAUGE,         USB_PID_WINTV_NOVA_T_USB2_WARM) },
-/* 32 */       { USB_DEVICE(USB_VID_ADSTECH,           USB_PID_ADSTECH_USB2_COLD) },
-/* 33 */       { USB_DEVICE(USB_VID_ADSTECH,           USB_PID_ADSTECH_USB2_WARM) },
-/* 
- * activate the following define when you have one of the devices and want to 
- * build it from build-2.6 in dvb-kernel
- */
-// #define CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
-#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
-/* 34 */       { USB_DEVICE(USB_VID_ANCHOR,            USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
-/* 35 */       { USB_DEVICE(USB_VID_CYPRESS,           USB_PID_ULTIMA_TVBOX_USB2_FX_COLD) },
-/* 36 */       { USB_DEVICE(USB_VID_ANCHOR,            USB_PID_ULTIMA_TVBOX_USB2_FX_WARM) },
-/* 37 */       { USB_DEVICE(USB_VID_ANCHOR,            USB_PID_DIBCOM_ANCHOR_2135_COLD) },
-#endif
-                       { }             /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, dib_table);
-
-static struct dibusb_usb_controller dibusb_usb_ctrl[] = {
-       { .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 },
-       { .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 },
-       { .name = "Cypress FX2",    .cpu_cs_register = 0xe600 },
-};
-
-struct dibusb_tuner dibusb_tuner[] = {
-       { DIBUSB_TUNER_CABLE_THOMSON, 
-         0x61 
-       },
-       { DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5,
-         0x60 
-       },
-       { DIBUSB_TUNER_CABLE_LG_TDTP_E102P,
-         0x61
-       },
-       { DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5,
-         0x60
-       },
-};
-
-static struct dibusb_demod dibusb_demod[] = {
-       { DIBUSB_DIB3000MB,
-         16,
-         { 0x8, 0 },
-       },
-       { DIBUSB_DIB3000MC,
-         32,
-         { 0x9, 0xa, 0xb, 0xc }, 
-       },
-       { DIBUSB_MT352,
-         254,
-         { 0xf, 0 }, 
-       },
-       { DTT200U_FE,
-         8,
-         { 0xff,0 }, /* there is no i2c bus in this device */
-       }
-};
-
-static struct dibusb_device_class dibusb_device_classes[] = {
-       { .id = DIBUSB1_1, .usb_ctrl = &dibusb_usb_ctrl[0],
-         .firmware = "dvb-dibusb-5.0.0.11.fw",
-         .pipe_cmd = 0x01, .pipe_data = 0x02, 
-         .urb_count = 7, .urb_buffer_size = 4096,
-         DIBUSB_RC_NEC_PROTOCOL,
-         &dibusb_demod[DIBUSB_DIB3000MB],
-         &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
-       },
-       { DIBUSB1_1_AN2235, &dibusb_usb_ctrl[1],
-         "dvb-dibusb-an2235-1.fw",
-         0x01, 0x02, 
-         7, 4096,
-         DIBUSB_RC_NEC_PROTOCOL,
-         &dibusb_demod[DIBUSB_DIB3000MB],
-         &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
-       },
-       { DIBUSB2_0,&dibusb_usb_ctrl[2],
-         "dvb-dibusb-6.0.0.5.fw",
-         0x01, 0x06, 
-         7, 4096,
-         DIBUSB_RC_NEC_PROTOCOL,
-         &dibusb_demod[DIBUSB_DIB3000MC],
-         &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5],
-       },
-       { UMT2_0, &dibusb_usb_ctrl[2],
-         "dvb-dibusb-umt-2.fw",
-         0x01, 0x06,
-         20, 512,
-         DIBUSB_RC_NO,
-         &dibusb_demod[DIBUSB_MT352],
-         &dibusb_tuner[DIBUSB_TUNER_CABLE_LG_TDTP_E102P],
-       },
-       { DIBUSB2_0B,&dibusb_usb_ctrl[2],
-         "dvb-dibusb-adstech-usb2-1.fw",
-         0x01, 0x06,
-         7, 4096,
-         DIBUSB_RC_NEC_PROTOCOL,
-         &dibusb_demod[DIBUSB_DIB3000MB],
-         &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
-       },
-       { NOVAT_USB2,&dibusb_usb_ctrl[2],
-         "dvb-dibusb-nova-t-1.fw",
-         0x01, 0x06,
-         7, 4096,
-         DIBUSB_RC_HAUPPAUGE_PROTO,
-         &dibusb_demod[DIBUSB_DIB3000MC],
-         &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5],
-       },
-       { DTT200U,&dibusb_usb_ctrl[2],
-         "dvb-dtt200u-1.fw",
-         0x01, 0x02,
-         7, 4096,
-         DIBUSB_RC_NO,
-         &dibusb_demod[DTT200U_FE],
-         NULL, /* no explicit tuner/pll-programming necessary (it has the ENV57H1XD5) */
-       },
-};
-
-static struct dibusb_usb_device dibusb_devices[] = {
-       {       "TwinhanDTV USB1.1 / Magic Box / HAMA USB1.1 DVB-T device",
-               &dibusb_device_classes[DIBUSB1_1],
-               { &dib_table[19], &dib_table[21], NULL},
-               { &dib_table[20], &dib_table[22], NULL},
-       },
-       {       "KWorld V-Stream XPERT DTV - DVB-T USB1.1",
-               &dibusb_device_classes[DIBUSB1_1],
-               { &dib_table[11], NULL },
-               { &dib_table[12], NULL },
-       },
-       {       "Grandtec USB1.1 DVB-T",
-               &dibusb_device_classes[DIBUSB1_1],
-               { &dib_table[13], &dib_table[15], NULL },
-               { &dib_table[14], &dib_table[16], NULL },
-       },
-       {       "DiBcom USB1.1 DVB-T reference design (MOD3000)",
-               &dibusb_device_classes[DIBUSB1_1],
-               { &dib_table[7],  NULL },
-               { &dib_table[8],  NULL },
-       },
-       {       "Artec T1 USB1.1 TVBOX with AN2135",
-               &dibusb_device_classes[DIBUSB1_1],
-               { &dib_table[23], NULL },
-               { &dib_table[24], NULL },
-       },
-       {       "Artec T1 USB1.1 TVBOX with AN2235",
-               &dibusb_device_classes[DIBUSB1_1_AN2235],
-               { &dib_table[25], NULL },
-               { &dib_table[26], NULL },
-       },
-       {       "Avermedia AverTV DVBT USB1.1",
-               &dibusb_device_classes[DIBUSB1_1],
-               { &dib_table[0],  NULL },
-               { &dib_table[1],  NULL },
-       },
-       {       "Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)",
-               &dibusb_device_classes[DIBUSB1_1],
-               { &dib_table[4], &dib_table[6], NULL},
-               { &dib_table[5], NULL },
-       },
-       {       "Unkown USB1.1 DVB-T device ???? please report the name to the author",
-               &dibusb_device_classes[DIBUSB1_1],
-               { &dib_table[17], NULL },
-               { &dib_table[18], NULL },
-       },
-       {       "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
-               &dibusb_device_classes[DIBUSB2_0],
-               { &dib_table[9],  NULL },
-               { &dib_table[10], NULL },
-       },
-       {       "Artec T1 USB2.0 TVBOX (please report the warm ID)",
-               &dibusb_device_classes[DIBUSB2_0],
-               { &dib_table[27], NULL },
-               { NULL },
-       },
-       {       "Hauppauge WinTV NOVA-T USB2",
-               &dibusb_device_classes[NOVAT_USB2],
-               { &dib_table[30], NULL },
-               { &dib_table[31], NULL },
-       },
-       {       "DTT200U (Yakumo/Hama/Typhoon) DVB-T USB2.0",
-               &dibusb_device_classes[DTT200U],
-               { &dib_table[2], NULL },
-               { &dib_table[3], NULL },
-       },      
-       {       "Hanftek UMT-010 DVB-T USB2.0",
-               &dibusb_device_classes[UMT2_0],
-               { &dib_table[28], NULL },
-               { &dib_table[29], NULL },
-       },      
-       {       "KWorld/ADSTech Instant DVB-T USB 2.0",
-               &dibusb_device_classes[DIBUSB2_0B],
-               { &dib_table[32], NULL },
-               { &dib_table[33], NULL }, /* device ID with default DIBUSB2_0-firmware */
-       },
-#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
-       {       "Artec T1 USB1.1 TVBOX with AN2235 (misdesigned)",
-               &dibusb_device_classes[DIBUSB1_1_AN2235],
-               { &dib_table[34], NULL },
-               { NULL },
-       },
-       {       "Artec T1 USB2.0 TVBOX with FX2 IDs (misdesigned, please report the warm ID)",
-               &dibusb_device_classes[DTT200U],
-               { &dib_table[35], NULL },
-               { &dib_table[36], NULL }, /* undefined, it could be that the device will get another USB ID in warm state */
-       },
-       {       "DiBcom USB1.1 DVB-T reference design (MOD3000) with AN2135 default IDs",
-               &dibusb_device_classes[DIBUSB1_1],
-               { &dib_table[37], NULL },
-               { NULL },
-       },
-#endif
-};
-
-static int dibusb_exit(struct usb_dibusb *dib)
-{
-       deb_info("init_state before exiting everything: %x\n",dib->init_state);
-       dibusb_remote_exit(dib);
-       dibusb_fe_exit(dib);
-       dibusb_i2c_exit(dib);
-       dibusb_dvb_exit(dib);
-       dibusb_urb_exit(dib);
-       deb_info("init_state should be zero now: %x\n",dib->init_state);
-       dib->init_state = DIBUSB_STATE_INIT;
-       kfree(dib);
-       return 0;
-}
-
-static int dibusb_init(struct usb_dibusb *dib)
-{
-       int ret = 0;
-       sema_init(&dib->usb_sem, 1);
-       sema_init(&dib->i2c_sem, 1);
-
-       dib->init_state = DIBUSB_STATE_INIT;
-       
-       if ((ret = dibusb_urb_init(dib)) ||
-               (ret = dibusb_dvb_init(dib)) || 
-               (ret = dibusb_i2c_init(dib))) {
-               dibusb_exit(dib);
-               return ret;
-       }
-
-       if ((ret = dibusb_fe_init(dib)))
-               err("could not initialize a frontend.");
-       
-       if ((ret = dibusb_remote_init(dib)))
-               err("could not initialize remote control.");
-       
-       return 0;
-}
-
-static struct dibusb_usb_device * dibusb_device_class_quirk(struct usb_device *udev, struct dibusb_usb_device *dev)
-{
-       int i;
-
-       /* Quirk for the Kworld/ADSTech Instant USB2.0 device. It has the same USB
-        * IDs like the USB1.1 KWorld after loading the firmware. Which is a bad
-        * idea and make this quirk necessary.
-        */
-       if (dev->dev_cl->id == DIBUSB1_1 && udev->speed == USB_SPEED_HIGH) {
-               info("this seems to be the Kworld/ADSTech Instant USB2.0 device or equal.");
-               for (i = 0; i < sizeof(dibusb_devices)/sizeof(struct dibusb_usb_device); i++) {
-                       if (dibusb_devices[i].dev_cl->id == DIBUSB2_0B) {
-                               dev = &dibusb_devices[i];
-                               break;
-                       }
-               }
-       }
-
-       return dev;
-}
-
-static struct dibusb_usb_device * dibusb_find_device (struct usb_device *udev,int *cold)
-{
-       int i,j;
-       struct dibusb_usb_device *dev = NULL;
-       *cold = -1;
-
-       for (i = 0; i < sizeof(dibusb_devices)/sizeof(struct dibusb_usb_device); i++) {
-               for (j = 0; j < DIBUSB_ID_MAX_NUM && dibusb_devices[i].cold_ids[j] != NULL; j++) {
-                       deb_info("check for cold %x %x\n",dibusb_devices[i].cold_ids[j]->idVendor, dibusb_devices[i].cold_ids[j]->idProduct);
-                       if (dibusb_devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
-                               dibusb_devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
-                               *cold = 1;
-                               dev = &dibusb_devices[i];
-                               break;
-                       }
-               }
-
-               if (dev != NULL)
-                       break;
-
-               for (j = 0; j < DIBUSB_ID_MAX_NUM && dibusb_devices[i].warm_ids[j] != NULL; j++) {
-                       deb_info("check for warm %x %x\n",dibusb_devices[i].warm_ids[j]->idVendor, dibusb_devices[i].warm_ids[j]->idProduct);
-                       if (dibusb_devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
-                               dibusb_devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
-                               *cold = 0;
-                               dev = &dibusb_devices[i];
-                               break;
-                       }
-               }
-       }
-
-       if (dev != NULL)
-               dev = dibusb_device_class_quirk(udev,dev);
-
-       return dev;
-}
-
-/*
- * USB 
- */
-static int dibusb_probe(struct usb_interface *intf, 
-               const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct usb_dibusb *dib = NULL;
-       struct dibusb_usb_device *dibdev = NULL;
-       
-       int ret = -ENOMEM,cold=0;
-
-       if ((dibdev = dibusb_find_device(udev,&cold)) == NULL) {
-               err("something went very wrong, "
-                               "unknown product ID: %.4x",le16_to_cpu(udev->descriptor.idProduct));
-               return -ENODEV;
-       }
-       
-       if (cold == 1) {
-               info("found a '%s' in cold state, will try to load a firmware",dibdev->name);
-               ret = dibusb_loadfirmware(udev,dibdev);
-       } else {
-               info("found a '%s' in warm state.",dibdev->name);
-               dib = kmalloc(sizeof(struct usb_dibusb),GFP_KERNEL);
-               if (dib == NULL) {
-                       err("no memory");
-                       return ret;
-               }
-               memset(dib,0,sizeof(struct usb_dibusb));
-               
-               dib->udev = udev;
-               dib->dibdev = dibdev;
-
-               /* store parameters to structures */
-               dib->rc_query_interval = rc_query_interval;
-               dib->pid_parse = pid_parse;
-               dib->rc_key_repeat_count = rc_key_repeat_count;
-
-               usb_set_intfdata(intf, dib);
-               
-               ret = dibusb_init(dib);
-       }
-       
-       if (ret == 0)
-               info("%s successfully initialized and connected.",dibdev->name);
-       else 
-               info("%s error while loading driver (%d)",dibdev->name,ret);
-       return ret;
-}
-
-static void dibusb_disconnect(struct usb_interface *intf)
-{
-       struct usb_dibusb *dib = usb_get_intfdata(intf);
-       const char *name = DRIVER_DESC;
-       
-       usb_set_intfdata(intf,NULL);
-       if (dib != NULL && dib->dibdev != NULL) {
-               name = dib->dibdev->name;
-               dibusb_exit(dib);
-       }
-       info("%s successfully deinitialized and disconnected.",name);
-       
-}
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver dibusb_driver = {
-       .owner          = THIS_MODULE,
-       .name           = DRIVER_DESC,
-       .probe          = dibusb_probe,
-       .disconnect = dibusb_disconnect,
-       .id_table       = dib_table,
-};
-
-/* module stuff */
-static int __init usb_dibusb_init(void)
-{
-       int result;
-       if ((result = usb_register(&dibusb_driver))) {
-               err("usb_register failed. Error number %d",result);
-               return result;
-       }
-       
-       return 0;
-}
-
-static void __exit usb_dibusb_exit(void)
-{
-       /* deregister this driver from the USB subsystem */
-       usb_deregister(&dibusb_driver);
-}
-
-module_init (usb_dibusb_init);
-module_exit (usb_dibusb_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c b/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
deleted file mode 100644 (file)
index 400b439..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * dvb-dibusb-dvb.c is part of the driver for mobile USB Budget DVB-T devices 
- * based on reference design made by DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * see dvb-dibusb-core.c for more copyright details.
- *
- * This file contains functions for initializing and handling the 
- * linux-dvb API.
- */
-#include "dvb-dibusb.h"
-
-#include <linux/usb.h>
-#include <linux/version.h>
-
-static u32 urb_compl_count;
-
-/*
- * MPEG2 TS DVB stuff 
- */
-void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
-{
-       struct usb_dibusb *dib = urb->context;
-
-       deb_ts("urb complete feedcount: %d, status: %d, length: %d\n",dib->feedcount,urb->status,
-                       urb->actual_length);
-
-       urb_compl_count++;
-       if (urb_compl_count % 1000 == 0)
-               deb_info("%d urbs completed so far.\n",urb_compl_count);
-
-       switch (urb->status) {
-               case 0:         /* success */
-               case -ETIMEDOUT:    /* NAK */
-                       break;
-               case -ECONNRESET:   /* kill */
-               case -ENOENT:
-               case -ESHUTDOWN:
-                       return;
-               default:        /* error */
-                       deb_ts("urb completition error %d.", urb->status);
-                       break;
-       }
-
-       if (dib->feedcount > 0 && urb->actual_length > 0) {
-               if (dib->init_state & DIBUSB_STATE_DVB)
-                       dvb_dmx_swfilter(&dib->demux, (u8*) urb->transfer_buffer,urb->actual_length);
-       } else 
-               deb_ts("URB dropped because of feedcount.\n");
-
-       usb_submit_urb(urb,GFP_ATOMIC);
-}
-
-static int dibusb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) 
-{
-       struct usb_dibusb *dib = dvbdmxfeed->demux->priv;
-       int newfeedcount;
-       
-       if (dib == NULL)
-               return -ENODEV;
-
-       newfeedcount = dib->feedcount + (onoff ? 1 : -1);
-
-       /* 
-        * stop feed before setting a new pid if there will be no pid anymore 
-        */
-       if (newfeedcount == 0) {
-               deb_ts("stop feeding\n");
-               if (dib->xfer_ops.fifo_ctrl != NULL) {
-                       if (dib->xfer_ops.fifo_ctrl(dib->fe,0)) {
-                               err("error while inhibiting fifo.");
-                               return -ENODEV;
-                       }
-               }
-               dibusb_streaming(dib,0);
-       }
-       
-       dib->feedcount = newfeedcount;
-
-       /* activate the pid on the device specific pid_filter */
-       deb_ts("setting pid: %5d %04x at index %d '%s'\n",dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? "on" : "off");
-       if (dib->pid_parse && dib->xfer_ops.pid_ctrl != NULL)
-               dib->xfer_ops.pid_ctrl(dib->fe,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
-
-       /* 
-        * start the feed if this was the first pid to set and there is still a pid
-        * for reception.
-        */
-       if (dib->feedcount == onoff && dib->feedcount > 0) {
-
-               deb_ts("controlling pid parser\n");
-               if (dib->xfer_ops.pid_parse != NULL) {
-                       if (dib->xfer_ops.pid_parse(dib->fe,dib->pid_parse) < 0) {
-                               err("could not handle pid_parser");
-                       }
-               }
-               
-               deb_ts("start feeding\n");
-               if (dib->xfer_ops.fifo_ctrl != NULL) {
-                       if (dib->xfer_ops.fifo_ctrl(dib->fe,1)) {
-                               err("error while enabling fifo.");
-                               return -ENODEV;
-                       }
-               }
-               dibusb_streaming(dib,1);
-       }
-       return 0;
-}
-
-static int dibusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-       deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
-       return dibusb_ctrl_feed(dvbdmxfeed,1);
-}
-
-static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-       deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
-       return dibusb_ctrl_feed(dvbdmxfeed,0);
-}
-
-int dibusb_dvb_init(struct usb_dibusb *dib)
-{
-       int ret;
-
-       urb_compl_count = 0;
-
-       if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC,
-                       THIS_MODULE)) < 0) {
-               deb_info("dvb_register_adapter failed: error %d", ret);
-               goto err;
-       }
-       dib->adapter.priv = dib;
-       
-/* i2c is done in dibusb_i2c_init */
-       
-       dib->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
-
-       dib->demux.priv = (void *)dib;
-       /* get pidcount from demod */
-       dib->demux.feednum = dib->demux.filternum = 255;
-       dib->demux.start_feed = dibusb_start_feed;
-       dib->demux.stop_feed = dibusb_stop_feed;
-       dib->demux.write_to_decoder = NULL;
-       if ((ret = dvb_dmx_init(&dib->demux)) < 0) {
-               err("dvb_dmx_init failed: error %d",ret);
-               goto err_dmx;
-       }
-
-       dib->dmxdev.filternum = dib->demux.filternum;
-       dib->dmxdev.demux = &dib->demux.dmx;
-       dib->dmxdev.capabilities = 0;
-       if ((ret = dvb_dmxdev_init(&dib->dmxdev, &dib->adapter)) < 0) {
-               err("dvb_dmxdev_init failed: error %d",ret);
-               goto err_dmx_dev;
-       }
-
-       dvb_net_init(&dib->adapter, &dib->dvb_net, &dib->demux.dmx);
-
-       goto success;
-err_dmx_dev:
-       dvb_dmx_release(&dib->demux);
-err_dmx:
-       dvb_unregister_adapter(&dib->adapter);
-err:
-       return ret;
-success:
-       dib->init_state |= DIBUSB_STATE_DVB;
-       return 0;
-}
-
-int dibusb_dvb_exit(struct usb_dibusb *dib)
-{
-       if (dib->init_state & DIBUSB_STATE_DVB) {
-               dib->init_state &= ~DIBUSB_STATE_DVB;
-               deb_info("unregistering DVB part\n");
-               dvb_net_release(&dib->dvb_net);
-               dib->demux.dmx.close(&dib->demux.dmx);
-               dvb_dmxdev_release(&dib->dmxdev);
-               dvb_dmx_release(&dib->demux);
-               dvb_unregister_adapter(&dib->adapter);
-       }
-       return 0;
-}
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
deleted file mode 100644 (file)
index 5a71b88..0000000
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
- * dvb-dibusb-fe-i2c.c is part of the driver for mobile USB Budget DVB-T devices
- * based on reference design made by DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * see dvb-dibusb-core.c for more copyright details.
- *
- * This file contains functions for attaching, initializing of an appropriate
- * demodulator/frontend. I2C-stuff is also located here.
- *
- */
-#include "dvb-dibusb.h"
-
-#include <linux/usb.h>
-
-static int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr,
-                         u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
-{
-       u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
-       /* write only ? */
-       int wo = (rbuf == NULL || rlen == 0),
-               len = 2 + wlen + (wo ? 0 : 2);
-
-       sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
-       sndbuf[1] = (addr << 1) | (wo ? 0 : 1);
-
-       memcpy(&sndbuf[2],wbuf,wlen);
-
-       if (!wo) {
-               sndbuf[wlen+2] = (rlen >> 8) & 0xff;
-               sndbuf[wlen+3] = rlen & 0xff;
-       }
-
-       return dibusb_readwrite_usb(dib,sndbuf,len,rbuf,rlen);
-}
-
-/*
- * I2C master xfer function
- */
-static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num)
-{
-       struct usb_dibusb *dib = i2c_get_adapdata(adap);
-       int i;
-
-       if (down_interruptible(&dib->i2c_sem) < 0)
-               return -EAGAIN;
-
-       if (num > 2)
-               warn("more than 2 i2c messages at a time is not handled yet. TODO.");
-
-       for (i = 0; i < num; i++) {
-               /* write/read request */
-               if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
-                       if (dibusb_i2c_msg(dib, msg[i].addr, msg[i].buf,msg[i].len,
-                                               msg[i+1].buf,msg[i+1].len) < 0)
-                               break;
-                       i++;
-               } else
-                       if (dibusb_i2c_msg(dib, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
-                               break;
-       }
-
-       up(&dib->i2c_sem);
-       return i;
-}
-
-static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
-{
-       return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm dibusb_algo = {
-       .name                   = "DiBcom USB i2c algorithm",
-       .id                             = I2C_ALGO_BIT,
-       .master_xfer    = dibusb_i2c_xfer,
-       .functionality  = dibusb_i2c_func,
-};
-
-static int dibusb_general_demod_init(struct dvb_frontend *fe);
-static u8 dibusb_general_pll_addr(struct dvb_frontend *fe);
-static int dibusb_general_pll_init(struct dvb_frontend *fe, u8 pll_buf[5]);
-static int dibusb_general_pll_set(struct dvb_frontend *fe,
-               struct dvb_frontend_parameters* params, u8 pll_buf[5]);
-
-static struct mt352_config mt352_hanftek_umt_010_config = {
-       .demod_address = 0x1e,
-       .demod_init = dibusb_general_demod_init,
-       .pll_set = dibusb_general_pll_set,
-};
-
-static int dibusb_tuner_quirk(struct usb_dibusb *dib)
-{
-       switch (dib->dibdev->dev_cl->id) {
-               case DIBUSB1_1: /* some these device have the ENV77H11D5 and some the THOMSON CABLE */
-               case DIBUSB1_1_AN2235: { /* actually its this device, but in warm state they are indistinguishable */
-                       struct dibusb_tuner *t;
-                       u8 b[2] = { 0,0 } ,b2[1];
-                       struct i2c_msg msg[2] = {
-                               { .flags = 0, .buf = b, .len = 2 },
-                               { .flags = I2C_M_RD, .buf = b2, .len = 1},
-                       };
-
-                       t = &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5];
-
-                       msg[0].addr = msg[1].addr = t->pll_addr;
-
-                       if (dib->xfer_ops.tuner_pass_ctrl != NULL)
-                               dib->xfer_ops.tuner_pass_ctrl(dib->fe,1,t->pll_addr);
-                       dibusb_i2c_xfer(&dib->i2c_adap,msg,2);
-                       if (dib->xfer_ops.tuner_pass_ctrl != NULL)
-                               dib->xfer_ops.tuner_pass_ctrl(dib->fe,0,t->pll_addr);
-
-                       if (b2[0] == 0xfe)
-                               info("this device has the Thomson Cable onboard. Which is default.");
-                       else {
-                               dib->tuner = t;
-                               info("this device has the Panasonic ENV77H11D5 onboard.");
-                       }
-                       break;
-               }
-               default:
-                       break;
-       }
-       return 0;
-}
-
-int dibusb_fe_init(struct usb_dibusb* dib)
-{
-       struct dib3000_config demod_cfg;
-       int i;
-
-       if (dib->init_state & DIBUSB_STATE_I2C) {
-               for (i = 0; i < sizeof(dib->dibdev->dev_cl->demod->i2c_addrs) / sizeof(unsigned char) &&
-                               dib->dibdev->dev_cl->demod->i2c_addrs[i] != 0; i++) {
-
-                       demod_cfg.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i];
-                       demod_cfg.pll_addr = dibusb_general_pll_addr;
-                       demod_cfg.pll_set = dibusb_general_pll_set;
-                       demod_cfg.pll_init = dibusb_general_pll_init;
-
-                       deb_info("demod id: %d %d\n",dib->dibdev->dev_cl->demod->id,DTT200U_FE);
-
-                       switch (dib->dibdev->dev_cl->demod->id) {
-                               case DIBUSB_DIB3000MB:
-                                       dib->fe = dib3000mb_attach(&demod_cfg,&dib->i2c_adap,&dib->xfer_ops);
-                               break;
-                               case DIBUSB_DIB3000MC:
-                                       dib->fe = dib3000mc_attach(&demod_cfg,&dib->i2c_adap,&dib->xfer_ops);
-                               break;
-                               case DIBUSB_MT352:
-                                       mt352_hanftek_umt_010_config.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i];
-                                       dib->fe = mt352_attach(&mt352_hanftek_umt_010_config, &dib->i2c_adap);
-                               break;
-                               case DTT200U_FE:
-                                       dib->fe = dtt200u_fe_attach(dib,&dib->xfer_ops);
-                               break;
-                       }
-                       if (dib->fe != NULL) {
-                               info("found demodulator at i2c address 0x%x",dib->dibdev->dev_cl->demod->i2c_addrs[i]);
-                               break;
-                       }
-               }
-               /* if a frontend was found */
-               if (dib->fe != NULL) {
-                       if (dib->fe->ops->sleep != NULL)
-                               dib->fe_sleep = dib->fe->ops->sleep;
-                       dib->fe->ops->sleep = dibusb_hw_sleep;
-
-                       if (dib->fe->ops->init != NULL )
-                               dib->fe_init = dib->fe->ops->init;
-                       dib->fe->ops->init = dibusb_hw_wakeup;
-
-                       /* setting the default tuner */
-                       dib->tuner = dib->dibdev->dev_cl->tuner;
-
-                       /* check which tuner is mounted on this device, in case this is unsure */
-                       dibusb_tuner_quirk(dib);
-               }
-       }
-       if (dib->fe == NULL) {
-               err("A frontend driver was not found for device '%s'.",
-                      dib->dibdev->name);
-               return -ENODEV;
-       } else {
-               if (dvb_register_frontend(&dib->adapter, dib->fe)) {
-                       err("Frontend registration failed.");
-                       if (dib->fe->ops->release)
-                               dib->fe->ops->release(dib->fe);
-                       dib->fe = NULL;
-                       return -ENODEV;
-               }
-       }
-
-       return 0;
-}
-
-int dibusb_fe_exit(struct usb_dibusb *dib)
-{
-       if (dib->fe != NULL)
-               dvb_unregister_frontend(dib->fe);
-       return 0;
-}
-
-int dibusb_i2c_init(struct usb_dibusb *dib)
-{
-       int ret = 0;
-
-       dib->adapter.priv = dib;
-
-       strncpy(dib->i2c_adap.name,dib->dibdev->name,I2C_NAME_SIZE);
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
-       dib->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
-#else
-       dib->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
-#endif
-       dib->i2c_adap.algo              = &dibusb_algo;
-       dib->i2c_adap.algo_data = NULL;
-       dib->i2c_adap.id                = I2C_ALGO_BIT;
-
-       i2c_set_adapdata(&dib->i2c_adap, dib);
-
-       if ((ret = i2c_add_adapter(&dib->i2c_adap)) < 0)
-               err("could not add i2c adapter");
-
-       dib->init_state |= DIBUSB_STATE_I2C;
-
-       return ret;
-}
-
-int dibusb_i2c_exit(struct usb_dibusb *dib)
-{
-       if (dib->init_state & DIBUSB_STATE_I2C)
-               i2c_del_adapter(&dib->i2c_adap);
-       dib->init_state &= ~DIBUSB_STATE_I2C;
-       return 0;
-}
-
-
-/* pll stuff, maybe removed soon (thx to Gerd/Andrew in advance) */
-static int thomson_cable_eu_pll_set(struct dvb_frontend_parameters *fep, u8 pllbuf[4])
-{
-       u32 tfreq = (fep->frequency + 36125000) / 62500;
-       int vu,p0,p1,p2;
-
-       if (fep->frequency > 403250000)
-               vu = 1, p2 = 1, p1 = 0, p0 = 1;
-       else if (fep->frequency > 115750000)
-               vu = 0, p2 = 1, p1 = 1, p0 = 0;
-       else if (fep->frequency > 44250000)
-               vu = 0, p2 = 0, p1 = 1, p0 = 1;
-       else
-               return -EINVAL;
-
-       pllbuf[0] = (tfreq >> 8) & 0x7f;
-       pllbuf[1] = tfreq & 0xff;
-       pllbuf[2] = 0x8e;
-       pllbuf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0;
-       return 0;
-}
-
-static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend_parameters *fep, u8 pllbuf[4])
-{
-       u32 freq_khz = fep->frequency / 1000;
-       u32 tfreq = ((freq_khz + 36125)*6 + 500) / 1000;
-       u8 TA, T210, R210, ctrl1, cp210, p4321;
-       if (freq_khz > 858000) {
-               err("frequency cannot be larger than 858 MHz.");
-               return -EINVAL;
-       }
-
-       // contol data 1 : 1 | T/A=1 | T2,T1,T0 = 0,0,0 | R2,R1,R0 = 0,1,0
-       TA = 1;
-       T210 = 0;
-       R210 = 0x2;
-       ctrl1 = (1 << 7) | (TA << 6) | (T210 << 3) | R210;
-
-// ********    CHARGE PUMP CONFIG vs RF FREQUENCIES     *****************
-       if (freq_khz < 470000)
-               cp210 = 2;  // VHF Low and High band ch E12 to E4 to E12
-       else if (freq_khz < 526000)
-               cp210 = 4;  // UHF band Ch E21 to E27
-       else // if (freq < 862000000)
-               cp210 = 5;  // UHF band ch E28 to E69
-
-//*********************    BW select  *******************************
-       if (freq_khz < 153000)
-               p4321  = 1; // BW selected for VHF low
-       else if (freq_khz < 470000)
-               p4321  = 2; // BW selected for VHF high E5 to E12
-       else // if (freq < 862000000)
-               p4321  = 4; // BW selection for UHF E21 to E69
-
-       pllbuf[0] = (tfreq >> 8) & 0xff;
-       pllbuf[1] = (tfreq >> 0) & 0xff;
-       pllbuf[2] = 0xff & ctrl1;
-       pllbuf[3] =  (cp210 << 5) | (p4321);
-
-       return 0;
-}
-
-/*
- *                         7   6               5       4       3       2       1       0
- * Address Byte             1  1               0       0       0       MA1     MA0     R/~W=0
- *
- * Program divider byte 1   0  n14             n13     n12     n11     n10     n9      n8
- * Program divider byte 2      n7      n6              n5      n4      n3      n2      n1      n0
- *
- * Control byte 1           1  T/A=1   T2      T1      T0      R2      R1      R0
- *                          1  T/A=0   0       0       ATC     AL2     AL1     AL0
- *
- * Control byte 2           CP2        CP1             CP0     BS5     BS4     BS3     BS2     BS1
- *
- * MA0/1 = programmable address bits
- * R/~W  = read/write bit (0 for writing)
- * N14-0 = programmable LO frequency
- *
- * T/A   = test AGC bit (0 = next 6 bits AGC setting,
- *                       1 = next 6 bits test and reference divider ratio settings)
- * T2-0  = test bits
- * R2-0  = reference divider ratio and programmable frequency step
- * ATC   = AGC current setting and time constant
- *         ATC = 0: AGC current = 220nA, AGC time constant = 2s
- *         ATC = 1: AGC current = 9uA, AGC time constant = 50ms
- * AL2-0 = AGC take-over point bits
- * CP2-0 = charge pump current
- * BS5-1 = PMOS ports control bits;
- *             BSn = 0 corresponding port is off, high-impedance state (at power-on)
- *             BSn = 1 corresponding port is on
- */
-static int panasonic_cofdm_env77h11d5_tda6650_init(struct dvb_frontend *fe, u8 pllbuf[4])
-{
-       pllbuf[0] = 0x0b;
-       pllbuf[1] = 0xf5;
-       pllbuf[2] = 0x85;
-       pllbuf[3] = 0xab;
-       return 0;
-}
-
-static int panasonic_cofdm_env77h11d5_tda6650_set (struct dvb_frontend_parameters *fep,u8 pllbuf[4])
-{
-       int tuner_frequency = 0;
-       u8 band, cp, filter;
-
-       // determine charge pump
-       tuner_frequency = fep->frequency + 36166000;
-       if (tuner_frequency < 87000000)
-               return -EINVAL;
-       else if (tuner_frequency < 130000000)
-               cp = 3;
-       else if (tuner_frequency < 160000000)
-               cp = 5;
-       else if (tuner_frequency < 200000000)
-               cp = 6;
-       else if (tuner_frequency < 290000000)
-               cp = 3;
-       else if (tuner_frequency < 420000000)
-               cp = 5;
-       else if (tuner_frequency < 480000000)
-               cp = 6;
-       else if (tuner_frequency < 620000000)
-               cp = 3;
-       else if (tuner_frequency < 830000000)
-               cp = 5;
-       else if (tuner_frequency < 895000000)
-               cp = 7;
-       else
-               return -EINVAL;
-
-       // determine band
-       if (fep->frequency < 49000000)
-               return -EINVAL;
-       else if (fep->frequency < 161000000)
-               band = 1;
-       else if (fep->frequency < 444000000)
-               band = 2;
-       else if (fep->frequency < 861000000)
-               band = 4;
-       else
-               return -EINVAL;
-
-       // setup PLL filter
-       switch (fep->u.ofdm.bandwidth) {
-               case BANDWIDTH_6_MHZ:
-               case BANDWIDTH_7_MHZ:
-                       filter = 0;
-                       break;
-               case BANDWIDTH_8_MHZ:
-                       filter = 1;
-                       break;
-               default:
-                       return -EINVAL;
-       }
-
-       // calculate divisor
-       // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
-       tuner_frequency = (((fep->frequency / 1000) * 6) + 217496) / 1000;
-
-       // setup tuner buffer
-       pllbuf[0] = (tuner_frequency >> 8) & 0x7f;
-       pllbuf[1] = tuner_frequency & 0xff;
-       pllbuf[2] = 0xca;
-       pllbuf[3] = (cp << 5) | (filter << 3) | band;
-       return 0;
-}
-
-/*
- *                         7   6       5       4       3       2       1       0
- * Address Byte             1  1       0       0       0       MA1     MA0     R/~W=0
- *
- * Program divider byte 1   0  n14     n13     n12     n11     n10     n9      n8
- * Program divider byte 2      n7      n6      n5      n4      n3      n2      n1      n0
- *
- * Control byte             1  CP      T2      T1      T0      RSA     RSB     OS
- *
- * Band Switch byte         X  X       X       P4      P3      P2      P1      P0
- *
- * Auxiliary byte           ATC        AL2     AL1     AL0     0       0       0       0
- *
- * Address: MA1        MA0     Address
- *          0  0       c0
- *          0  1       c2 (always valid)
- *          1  0       c4
- *          1  1       c6
- */
-static int lg_tdtp_e102p_tua6034(struct dvb_frontend_parameters* fep, u8 pllbuf[4])
-{
-       u32 div;
-       u8 p210, p3;
-
-#define TUNER_MUL 62500
-
-       div = (fep->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL;
-//     div = ((fep->frequency/1000 + 36166) * 6) / 1000;
-
-       if (fep->frequency < 174500000)
-               p210 = 1; // not supported by the tdtp_e102p
-       else if (fep->frequency < 230000000) // VHF
-               p210 = 2;
-       else
-               p210 = 4;
-
-       if (fep->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
-               p3 = 0;
-       else
-               p3 = 1;
-
-       pllbuf[0] = (div >> 8) & 0x7f;
-       pllbuf[1] = div & 0xff;
-       pllbuf[2] = 0xce;
-//     pllbuf[2] = 0xcc;
-       pllbuf[3] = (p3 << 3) | p210;
-
-       return 0;
-}
-
-static int lg_tdtp_e102p_mt352_demod_init(struct dvb_frontend *fe)
-{
-       static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d };
-       static u8 mt352_reset[] = { 0x50, 0x80 };
-       static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
-       static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
-       static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 };
-
-       static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff };
-       static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff };
-       static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 };
-       static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 };
-       static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f };
-
-       static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
-       static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 };
-
-       mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
-       udelay(2000);
-       mt352_write(fe, mt352_reset, sizeof(mt352_reset));
-       mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
-
-       mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-       mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
-
-       mt352_write(fe, mt352_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1));
-       mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2));
-       mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3));
-       mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4));
-       mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5));
-
-       mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
-       mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
-
-       return 0;
-}
-
-static int dibusb_general_demod_init(struct dvb_frontend *fe)
-{
-       struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
-       switch (dib->dibdev->dev_cl->id) {
-               case UMT2_0:
-                       return lg_tdtp_e102p_mt352_demod_init(fe);
-               default: /* other device classes do not have device specific demod inits */
-                       break;
-       }
-       return 0;
-}
-
-static u8 dibusb_general_pll_addr(struct dvb_frontend *fe)
-{
-       struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
-       return dib->tuner->pll_addr;
-}
-
-static int dibusb_pll_i2c_helper(struct usb_dibusb *dib, u8 pll_buf[5], u8 buf[4])
-{
-       if (pll_buf == NULL) {
-               struct i2c_msg msg = {
-                       .addr = dib->tuner->pll_addr,
-                       .flags = 0,
-                       .buf = buf,
-                       .len = sizeof(buf)
-               };
-               if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1)
-                       return -EIO;
-               msleep(1);
-       } else {
-               pll_buf[0] = dib->tuner->pll_addr << 1;
-               memcpy(&pll_buf[1],buf,4);
-       }
-
-       return 0;
-}
-
-static int dibusb_general_pll_init(struct dvb_frontend *fe,
-               u8 pll_buf[5])
-{
-       struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
-       u8 buf[4];
-       int ret=0;
-       switch (dib->tuner->id) {
-               case DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5:
-                       ret = panasonic_cofdm_env77h11d5_tda6650_init(fe,buf);
-                       break;
-               default:
-                       break;
-       }
-
-       if (ret)
-               return ret;
-
-       return dibusb_pll_i2c_helper(dib,pll_buf,buf);
-}
-
-static int dibusb_general_pll_set(struct dvb_frontend *fe,
-               struct dvb_frontend_parameters *fep, u8 pll_buf[5])
-{
-       struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
-       u8 buf[4];
-       int ret=0;
-
-       switch (dib->tuner->id) {
-               case DIBUSB_TUNER_CABLE_THOMSON:
-                       ret = thomson_cable_eu_pll_set(fep, buf);
-                       break;
-               case DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5:
-                       ret = panasonic_cofdm_env57h1xd5_pll_set(fep, buf);
-                       break;
-               case DIBUSB_TUNER_CABLE_LG_TDTP_E102P:
-                       ret = lg_tdtp_e102p_tua6034(fep, buf);
-                       break;
-               case DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5:
-                       ret = panasonic_cofdm_env77h11d5_tda6650_set(fep,buf);
-                       break;
-               default:
-                       warn("no pll programming routine found for tuner %d.\n",dib->tuner->id);
-                       ret = -ENODEV;
-                       break;
-       }
-
-       if (ret)
-               return ret;
-
-       return dibusb_pll_i2c_helper(dib,pll_buf,buf);
-}
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c b/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
deleted file mode 100644 (file)
index 504ba47..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * dvb-dibusb-firmware.c is part of the driver for mobile USB Budget DVB-T devices 
- * based on reference design made by DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * see dvb-dibusb-core.c for more copyright details.
- *
- * This file contains functions for downloading the firmware to the device.
- */
-#include "dvb-dibusb.h"
-
-#include <linux/firmware.h>
-#include <linux/usb.h>
-
-/*
- * load a firmware packet to the device 
- */
-static int dibusb_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
-{
-       return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
-                       0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
-}
-
-int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev)
-{
-       const struct firmware *fw = NULL;
-       u16 addr;
-       u8 *b,*p;
-       int ret = 0,i;
-       
-       if ((ret = request_firmware(&fw, dibdev->dev_cl->firmware, &udev->dev)) != 0) {
-               err("did not find the firmware file. (%s) "
-                       "Please see linux/Documentation/dvb/ for more details on firmware-problems.",
-                       dibdev->dev_cl->firmware);
-               return ret;
-       }
-
-       info("downloading firmware from file '%s'.",dibdev->dev_cl->firmware);
-       
-       p = kmalloc(fw->size,GFP_KERNEL);       
-       if (p != NULL) {
-               u8 reset;
-               /*
-                * you cannot use the fw->data as buffer for 
-                * usb_control_msg, a new buffer has to be
-                * created
-                */
-               memcpy(p,fw->data,fw->size);
-
-               /* stop the CPU */
-               reset = 1;
-               if ((ret = dibusb_writemem(udev,dibdev->dev_cl->usb_ctrl->cpu_cs_register,&reset,1)) != 1) 
-                       err("could not stop the USB controller CPU.");
-               for(i = 0; p[i+3] == 0 && i < fw->size; ) { 
-                       b = (u8 *) &p[i];
-                       addr = *((u16 *) &b[1]);
-
-                       ret = dibusb_writemem(udev,addr,&b[4],b[0]);
-               
-                       if (ret != b[0]) {
-                               err("error while transferring firmware "
-                                       "(transferred size: %d, block size: %d)",
-                                       ret,b[0]);
-                               ret = -EINVAL;
-                               break;
-                       }
-                       i += 5 + b[0];
-               }
-               /* length in ret */
-               if (ret > 0)
-                       ret = 0;
-               /* restart the CPU */
-               reset = 0;
-               if (ret || dibusb_writemem(udev,dibdev->dev_cl->usb_ctrl->cpu_cs_register,&reset,1) != 1) {
-                       err("could not restart the USB controller CPU.");
-                       ret = -EINVAL;
-               }
-
-               kfree(p);
-       } else { 
-               ret = -ENOMEM;
-       }
-       release_firmware(fw);
-
-       return ret;
-}
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-remote.c b/drivers/media/dvb/dibusb/dvb-dibusb-remote.c
deleted file mode 100644 (file)
index 9dc8b15..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * dvb-dibusb-remote.c is part of the driver for mobile USB Budget DVB-T devices
- * based on reference design made by DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * see dvb-dibusb-core.c for more copyright details.
- *
- * This file contains functions for handling the event device on the software
- * side and the remote control on the hardware side.
- */
-#include "dvb-dibusb.h"
-
-/* Table to map raw key codes to key events.  This should not be hard-wired
-   into the kernel.  */
-static const struct { u8 c0, c1, c2; uint32_t key; } nec_rc_keys [] =
-{
-       /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
-       { 0x00, 0xff, 0x16, KEY_POWER },
-       { 0x00, 0xff, 0x10, KEY_MUTE },
-       { 0x00, 0xff, 0x03, KEY_1 },
-       { 0x00, 0xff, 0x01, KEY_2 },
-       { 0x00, 0xff, 0x06, KEY_3 },
-       { 0x00, 0xff, 0x09, KEY_4 },
-       { 0x00, 0xff, 0x1d, KEY_5 },
-       { 0x00, 0xff, 0x1f, KEY_6 },
-       { 0x00, 0xff, 0x0d, KEY_7 },
-       { 0x00, 0xff, 0x19, KEY_8 },
-       { 0x00, 0xff, 0x1b, KEY_9 },
-       { 0x00, 0xff, 0x15, KEY_0 },
-       { 0x00, 0xff, 0x05, KEY_CHANNELUP },
-       { 0x00, 0xff, 0x02, KEY_CHANNELDOWN },
-       { 0x00, 0xff, 0x1e, KEY_VOLUMEUP },
-       { 0x00, 0xff, 0x0a, KEY_VOLUMEDOWN },
-       { 0x00, 0xff, 0x11, KEY_RECORD },
-       { 0x00, 0xff, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
-       { 0x00, 0xff, 0x14, KEY_PLAY },
-       { 0x00, 0xff, 0x1a, KEY_STOP },
-       { 0x00, 0xff, 0x40, KEY_REWIND },
-       { 0x00, 0xff, 0x12, KEY_FASTFORWARD },
-       { 0x00, 0xff, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
-       { 0x00, 0xff, 0x4c, KEY_PAUSE },
-       { 0x00, 0xff, 0x4d, KEY_SCREEN }, /* Full screen mode. */
-       { 0x00, 0xff, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
-       /* additional keys TwinHan VisionPlus, the Artec seemingly not have */
-       { 0x00, 0xff, 0x0c, KEY_CANCEL }, /* Cancel */
-       { 0x00, 0xff, 0x1c, KEY_EPG }, /* EPG */
-       { 0x00, 0xff, 0x00, KEY_TAB }, /* Tab */
-       { 0x00, 0xff, 0x48, KEY_INFO }, /* Preview */
-       { 0x00, 0xff, 0x04, KEY_LIST }, /* RecordList */
-       { 0x00, 0xff, 0x0f, KEY_TEXT }, /* Teletext */
-       /* Key codes for the KWorld/ADSTech/JetWay remote. */
-       { 0x86, 0x6b, 0x12, KEY_POWER },
-       { 0x86, 0x6b, 0x0f, KEY_SELECT }, /* source */
-       { 0x86, 0x6b, 0x0c, KEY_UNKNOWN }, /* scan */
-       { 0x86, 0x6b, 0x0b, KEY_EPG },
-       { 0x86, 0x6b, 0x10, KEY_MUTE },
-       { 0x86, 0x6b, 0x01, KEY_1 },
-       { 0x86, 0x6b, 0x02, KEY_2 },
-       { 0x86, 0x6b, 0x03, KEY_3 },
-       { 0x86, 0x6b, 0x04, KEY_4 },
-       { 0x86, 0x6b, 0x05, KEY_5 },
-       { 0x86, 0x6b, 0x06, KEY_6 },
-       { 0x86, 0x6b, 0x07, KEY_7 },
-       { 0x86, 0x6b, 0x08, KEY_8 },
-       { 0x86, 0x6b, 0x09, KEY_9 },
-       { 0x86, 0x6b, 0x0a, KEY_0 },
-       { 0x86, 0x6b, 0x18, KEY_ZOOM },
-       { 0x86, 0x6b, 0x1c, KEY_UNKNOWN }, /* preview */
-       { 0x86, 0x6b, 0x13, KEY_UNKNOWN }, /* snap */
-       { 0x86, 0x6b, 0x00, KEY_UNDO },
-       { 0x86, 0x6b, 0x1d, KEY_RECORD },
-       { 0x86, 0x6b, 0x0d, KEY_STOP },
-       { 0x86, 0x6b, 0x0e, KEY_PAUSE },
-       { 0x86, 0x6b, 0x16, KEY_PLAY },
-       { 0x86, 0x6b, 0x11, KEY_BACK },
-       { 0x86, 0x6b, 0x19, KEY_FORWARD },
-       { 0x86, 0x6b, 0x14, KEY_UNKNOWN }, /* pip */
-       { 0x86, 0x6b, 0x15, KEY_ESC },
-       { 0x86, 0x6b, 0x1a, KEY_UP },
-       { 0x86, 0x6b, 0x1e, KEY_DOWN },
-       { 0x86, 0x6b, 0x1f, KEY_LEFT },
-       { 0x86, 0x6b, 0x1b, KEY_RIGHT },
-};
-
-/* Hauppauge NOVA-T USB2 keys */
-static const struct { u16 raw; uint32_t key; } haupp_rc_keys [] = {
-       { 0xddf, KEY_GOTO },
-       { 0xdef, KEY_POWER },
-       { 0xce7, KEY_TV },
-       { 0xcc7, KEY_VIDEO },
-       { 0xccf, KEY_AUDIO },
-       { 0xcd7, KEY_MEDIA },
-       { 0xcdf, KEY_EPG },
-       { 0xca7, KEY_UP },
-       { 0xc67, KEY_RADIO },
-       { 0xcb7, KEY_LEFT },
-       { 0xd2f, KEY_OK },
-       { 0xcbf, KEY_RIGHT },
-       { 0xcff, KEY_BACK },
-       { 0xcaf, KEY_DOWN },
-       { 0xc6f, KEY_MENU },
-       { 0xc87, KEY_VOLUMEUP },
-       { 0xc8f, KEY_VOLUMEDOWN },
-       { 0xc97, KEY_CHANNEL },
-       { 0xc7f, KEY_MUTE },
-       { 0xd07, KEY_CHANNELUP },
-       { 0xd0f, KEY_CHANNELDOWN },
-       { 0xdbf, KEY_RECORD },
-       { 0xdb7, KEY_STOP },
-       { 0xd97, KEY_REWIND },
-       { 0xdaf, KEY_PLAY },
-       { 0xda7, KEY_FASTFORWARD },
-       { 0xd27, KEY_LAST }, /* Skip backwards */
-       { 0xd87, KEY_PAUSE },
-       { 0xcf7, KEY_NEXT },
-       { 0xc07, KEY_0 },
-       { 0xc0f, KEY_1 },
-       { 0xc17, KEY_2 },
-       { 0xc1f, KEY_3 },
-       { 0xc27, KEY_4 },
-       { 0xc2f, KEY_5 },
-       { 0xc37, KEY_6 },
-       { 0xc3f, KEY_7 },
-       { 0xc47, KEY_8 },
-       { 0xc4f, KEY_9 },
-       { 0xc57, KEY_KPASTERISK },
-       { 0xc77, KEY_GRAVE }, /* # */
-       { 0xc5f, KEY_RED },
-       { 0xd77, KEY_GREEN },
-       { 0xdc7, KEY_YELLOW },
-       { 0xd4f, KEY_BLUE},
-};
-
-static int dibusb_key2event_nec(struct usb_dibusb *dib,u8 rb[5])
-{
-       int i;
-       switch (rb[0]) {
-               case DIBUSB_RC_NEC_KEY_PRESSED:
-                       /* rb[1-3] is the actual key, rb[4] is a checksum */
-                       deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
-                               rb[1], rb[2], rb[3], rb[4]);
-
-                       if ((0xff - rb[3]) != rb[4]) {
-                               deb_rc("remote control checksum failed.\n");
-                               break;
-                       }
-
-                       /* See if we can match the raw key code. */
-                       for (i = 0; i < sizeof(nec_rc_keys)/sizeof(nec_rc_keys[0]); i++) {
-                               if (nec_rc_keys[i].c0 == rb[1] &&
-                                       nec_rc_keys[i].c1 == rb[2] &&
-                                       nec_rc_keys[i].c2 == rb[3]) {
-
-                                       dib->last_event = nec_rc_keys[i].key;
-                                       return 1;
-                               }
-                       }
-                       break;
-               case DIBUSB_RC_NEC_KEY_REPEATED:
-                       /* rb[1]..rb[4] are always zero.*/
-                       /* Repeats often seem to occur so for the moment just ignore this. */
-                       return 0;
-               case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */
-               default:
-                       break;
-       }
-       return -1;
-}
-
-static int dibusb_key2event_hauppauge(struct usb_dibusb *dib,u8 rb[4])
-{
-       u16 raw;
-       int i,state;
-       switch (rb[0]) {
-               case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED:
-                       raw = ((rb[1] & 0x0f) << 8) | rb[2];
-
-                       state = !!(rb[1] & 0x40);
-
-                       deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to %04x state: %d\n",rb[1],rb[2],rb[3],raw,state);
-                       for (i = 0; i < sizeof(haupp_rc_keys)/sizeof(haupp_rc_keys[0]); i++) {
-                               if (haupp_rc_keys[i].raw == raw) {
-                                       if (dib->last_event == haupp_rc_keys[i].key &&
-                                               dib->last_state == state) {
-                                               deb_rc("key repeat\n");
-                                               return 0;
-                                       } else {
-                                               dib->last_event = haupp_rc_keys[i].key;
-                                               dib->last_state = state;
-                                               return 1;
-                                       }
-                               }
-                       }
-
-                       break;
-               case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY:
-               default:
-                       break;
-       }
-       return -1;
-}
-
-/*
- * Read the remote control and feed the appropriate event.
- * NEC protocol is used for remote controls
- */
-static int dibusb_read_remote_control(struct usb_dibusb *dib)
-{
-       u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5];
-       int ret,event = 0;
-
-       if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5)))
-               return ret;
-
-       switch (dib->dibdev->dev_cl->remote_type) {
-               case DIBUSB_RC_NEC_PROTOCOL:
-                       event = dibusb_key2event_nec(dib,rb);
-                       break;
-               case DIBUSB_RC_HAUPPAUGE_PROTO:
-                       event = dibusb_key2event_hauppauge(dib,rb);
-               default:
-                       break;
-       }
-
-       /* key repeat */
-       if (event == 0)
-               if (++dib->repeat_key_count < dib->rc_key_repeat_count) {
-                       deb_rc("key repeat dropped. (%d)\n",dib->repeat_key_count);
-                       event = -1; /* skip this key repeat */
-               }
-
-       if (event == 1 || event == 0) {
-               deb_rc("Translated key 0x%04x\n",event);
-
-               /* Signal down and up events for this key. */
-               input_report_key(&dib->rc_input_dev, dib->last_event, 1);
-               input_report_key(&dib->rc_input_dev, dib->last_event, 0);
-               input_sync(&dib->rc_input_dev);
-
-               if (event == 1)
-                       dib->repeat_key_count = 0;
-       }
-       return 0;
-}
-
-/* Remote-control poll function - called every dib->rc_query_interval ms to see
-   whether the remote control has received anything. */
-static void dibusb_remote_query(void *data)
-{
-       struct usb_dibusb *dib = (struct usb_dibusb *) data;
-       /* TODO: need a lock here.  We can simply skip checking for the remote control
-          if we're busy. */
-       dibusb_read_remote_control(dib);
-       schedule_delayed_work(&dib->rc_query_work,
-                             msecs_to_jiffies(dib->rc_query_interval));
-}
-
-int dibusb_remote_init(struct usb_dibusb *dib)
-{
-       int i;
-
-       if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO)
-               return 0;
-       
-       /* Initialise the remote-control structures.*/
-       init_input_dev(&dib->rc_input_dev);
-
-       dib->rc_input_dev.evbit[0] = BIT(EV_KEY);
-       dib->rc_input_dev.keycodesize = sizeof(unsigned char);
-       dib->rc_input_dev.keycodemax = KEY_MAX;
-       dib->rc_input_dev.name = DRIVER_DESC " remote control";
-
-       switch (dib->dibdev->dev_cl->remote_type) {
-               case DIBUSB_RC_NEC_PROTOCOL:
-                       for (i=0; i<sizeof(nec_rc_keys)/sizeof(nec_rc_keys[0]); i++)
-                               set_bit(nec_rc_keys[i].key, dib->rc_input_dev.keybit);
-                       break;
-               case DIBUSB_RC_HAUPPAUGE_PROTO:
-                       for (i=0; i<sizeof(haupp_rc_keys)/sizeof(haupp_rc_keys[0]); i++)
-                               set_bit(haupp_rc_keys[i].key, dib->rc_input_dev.keybit);
-                       break;
-               default:
-                       break;
-       }
-
-
-       input_register_device(&dib->rc_input_dev);
-
-       INIT_WORK(&dib->rc_query_work, dibusb_remote_query, dib);
-
-       /* Start the remote-control polling. */
-       if (dib->rc_query_interval < 40)
-               dib->rc_query_interval = 100; /* default */
-
-       info("schedule remote query interval to %d msecs.",dib->rc_query_interval);
-       schedule_delayed_work(&dib->rc_query_work,msecs_to_jiffies(dib->rc_query_interval));
-
-       dib->init_state |= DIBUSB_STATE_REMOTE;
-       
-       return 0;
-}
-
-int dibusb_remote_exit(struct usb_dibusb *dib)
-{
-       if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO)
-               return 0;
-
-       if (dib->init_state & DIBUSB_STATE_REMOTE) {
-               cancel_delayed_work(&dib->rc_query_work);
-               flush_scheduled_work();
-               input_unregister_device(&dib->rc_input_dev);
-       }
-       dib->init_state &= ~DIBUSB_STATE_REMOTE;
-       return 0;
-}
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-usb.c b/drivers/media/dvb/dibusb/dvb-dibusb-usb.c
deleted file mode 100644 (file)
index 642f059..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * dvb-dibusb-usb.c is part of the driver for mobile USB Budget DVB-T devices
- * based on reference design made by DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * see dvb-dibusb-core.c for more copyright details.
- *
- * This file contains functions for initializing and handling the
- * usb specific stuff.
- */
-#include "dvb-dibusb.h"
-
-#include <linux/version.h>
-#include <linux/pci.h>
-
-int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
-               u16 rlen)
-{
-       int actlen,ret = -ENOMEM;
-
-       if (wbuf == NULL || wlen == 0)
-               return -EINVAL;
-
-       if ((ret = down_interruptible(&dib->usb_sem)))
-               return ret;
-
-       debug_dump(wbuf,wlen);
-
-       ret = usb_bulk_msg(dib->udev,usb_sndbulkpipe(dib->udev,
-                       dib->dibdev->dev_cl->pipe_cmd), wbuf,wlen,&actlen,
-                       DIBUSB_I2C_TIMEOUT);
-
-       if (ret)
-               err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
-       else
-               ret = actlen != wlen ? -1 : 0;
-
-       /* an answer is expected, and no error before */
-       if (!ret && rbuf && rlen) {
-               ret = usb_bulk_msg(dib->udev,usb_rcvbulkpipe(dib->udev,
-                               dib->dibdev->dev_cl->pipe_cmd),rbuf,rlen,&actlen,
-                               DIBUSB_I2C_TIMEOUT);
-
-               if (ret)
-                       err("recv bulk message failed: %d",ret);
-               else {
-                       deb_alot("rlen: %d\n",rlen);
-                       debug_dump(rbuf,actlen);
-               }
-       }
-
-       up(&dib->usb_sem);
-       return ret;
-}
-
-/*
- * Cypress controls
- */
-int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
-{
-       return dibusb_readwrite_usb(dib,buf,len,NULL,0);
-}
-
-#if 0
-/*
- * #if 0'ing the following functions as they are not in use _now_,
- * but probably will be sometime.
- */
-/*
- * do not use this, just a workaround for a bug,
- * which will hopefully never occur :).
- */
-int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
-{
-       u8 b[1] = { DIBUSB_REQ_INTR_READ };
-       return dibusb_write_usb(dib,b,1);
-}
-#endif
-
-/*
- * ioctl for the firmware
- */
-static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen)
-{
-       u8 b[34];
-       int size = plen > 32 ? 32 : plen;
-       memset(b,0,34);
-       b[0] = DIBUSB_REQ_SET_IOCTL;
-       b[1] = cmd;
-
-       if (size > 0)
-               memcpy(&b[2],param,size);
-
-       return dibusb_write_usb(dib,b,34); //2+size);
-}
-
-/*
- * ioctl for power control
- */
-int dibusb_hw_wakeup(struct dvb_frontend *fe)
-{
-       struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
-       u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP };
-       deb_info("dibusb-device is getting up.\n");
-
-       switch (dib->dibdev->dev_cl->id) {
-               case DTT200U:
-                       break;
-               default:
-                       dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
-                       break;
-       }
-
-       if (dib->fe_init)
-               return dib->fe_init(fe);
-
-       return 0;
-}
-
-int dibusb_hw_sleep(struct dvb_frontend *fe)
-{
-       struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
-       u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
-       deb_info("dibusb-device is going to bed.\n");
-       /* workaround, something is wrong, when dibusb 1.1 device are going to bed too late */
-       switch (dib->dibdev->dev_cl->id) {
-               case DIBUSB1_1:
-               case NOVAT_USB2:
-               case DTT200U:
-                       break;
-               default:
-                       dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
-                       break;
-       }
-       if (dib->fe_sleep)
-               return dib->fe_sleep(fe);
-
-       return 0;
-}
-
-int dibusb_set_streaming_mode(struct usb_dibusb *dib,u8 mode)
-{
-       u8 b[2] = { DIBUSB_REQ_SET_STREAMING_MODE, mode };
-       return dibusb_readwrite_usb(dib,b,2,NULL,0);
-}
-
-static int dibusb_urb_kill(struct usb_dibusb *dib)
-{
-       int i;
-deb_info("trying to kill urbs\n");
-       if (dib->init_state & DIBUSB_STATE_URB_SUBMIT) {
-               for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
-                       deb_info("killing URB no. %d.\n",i);
-
-                       /* stop the URB */
-                       usb_kill_urb(dib->urb_list[i]);
-               }
-       } else
-       deb_info(" URBs not killed.\n");
-       dib->init_state &= ~DIBUSB_STATE_URB_SUBMIT;
-       return 0;
-}
-
-static int dibusb_urb_submit(struct usb_dibusb *dib)
-{
-       int i,ret;
-       if (dib->init_state & DIBUSB_STATE_URB_INIT) {
-               for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
-                       deb_info("submitting URB no. %d\n",i);
-                       if ((ret = usb_submit_urb(dib->urb_list[i],GFP_ATOMIC))) {
-                               err("could not submit buffer urb no. %d - get them all back\n",i);
-                               dibusb_urb_kill(dib);
-                               return ret;
-                       }
-                       dib->init_state |= DIBUSB_STATE_URB_SUBMIT;
-               }
-       }
-       return 0;
-}
-
-int dibusb_streaming(struct usb_dibusb *dib,int onoff)
-{
-       if (onoff)
-               dibusb_urb_submit(dib);
-       else
-               dibusb_urb_kill(dib);
-
-       switch (dib->dibdev->dev_cl->id) {
-               case DIBUSB2_0:
-               case DIBUSB2_0B:
-               case NOVAT_USB2:
-               case UMT2_0:
-                       if (onoff)
-                               return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_ENABLE_STREAM,NULL,0);
-                       else
-                               return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_DISABLE_STREAM,NULL,0);
-                       break;
-               default:
-                       break;
-       }
-       return 0;
-}
-
-int dibusb_urb_init(struct usb_dibusb *dib)
-{
-       int i,bufsize,def_pid_parse = 1;
-
-       /*
-        * when reloading the driver w/o replugging the device
-        * a timeout occures, this helps
-        */
-       usb_clear_halt(dib->udev,usb_sndbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
-       usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
-       usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data));
-
-       /* allocate the array for the data transfer URBs */
-       dib->urb_list = kmalloc(dib->dibdev->dev_cl->urb_count*sizeof(struct urb *),GFP_KERNEL);
-       if (dib->urb_list == NULL)
-               return -ENOMEM;
-       memset(dib->urb_list,0,dib->dibdev->dev_cl->urb_count*sizeof(struct urb *));
-
-       dib->init_state |= DIBUSB_STATE_URB_LIST;
-
-       bufsize = dib->dibdev->dev_cl->urb_count*dib->dibdev->dev_cl->urb_buffer_size;
-       deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
-       /* allocate the actual buffer for the URBs */
-       if ((dib->buffer = pci_alloc_consistent(NULL,bufsize,&dib->dma_handle)) == NULL) {
-               deb_info("not enough memory.\n");
-               return -ENOMEM;
-       }
-       deb_info("allocation complete\n");
-       memset(dib->buffer,0,bufsize);
-
-       dib->init_state |= DIBUSB_STATE_URB_BUF;
-
-       /* allocate and submit the URBs */
-       for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
-               if (!(dib->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) {
-                       return -ENOMEM;
-               }
-
-               usb_fill_bulk_urb( dib->urb_list[i], dib->udev,
-                               usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data),
-                               &dib->buffer[i*dib->dibdev->dev_cl->urb_buffer_size],
-                               dib->dibdev->dev_cl->urb_buffer_size,
-                               dibusb_urb_complete, dib);
-
-               dib->urb_list[i]->transfer_flags = 0;
-
-               dib->init_state |= DIBUSB_STATE_URB_INIT;
-       }
-
-       /* dib->pid_parse here contains the value of the module parameter */
-       /* decide if pid parsing can be deactivated:
-        * is possible (by device type) and wanted (by user)
-        */
-       switch (dib->dibdev->dev_cl->id) {
-               case DIBUSB2_0:
-               case DIBUSB2_0B:
-                       if (dib->udev->speed == USB_SPEED_HIGH && !dib->pid_parse) {
-                               def_pid_parse = 0;
-                               info("running at HIGH speed, will deliver the complete TS.");
-                       } else
-                               info("will use pid_parsing.");
-                       break;
-               default:
-                       break;
-       }
-       /* from here on it contains the device and user decision */
-       dib->pid_parse = def_pid_parse;
-
-       return 0;
-}
-
-int dibusb_urb_exit(struct usb_dibusb *dib)
-{
-       int i;
-
-       dibusb_urb_kill(dib);
-
-       if (dib->init_state & DIBUSB_STATE_URB_LIST) {
-               for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
-                       if (dib->urb_list[i] != NULL) {
-                               deb_info("freeing URB no. %d.\n",i);
-                               /* free the URBs */
-                               usb_free_urb(dib->urb_list[i]);
-                       }
-               }
-               /* free the urb array */
-               kfree(dib->urb_list);
-               dib->init_state &= ~DIBUSB_STATE_URB_LIST;
-       }
-
-       if (dib->init_state & DIBUSB_STATE_URB_BUF)
-               pci_free_consistent(NULL,
-                       dib->dibdev->dev_cl->urb_buffer_size*dib->dibdev->dev_cl->urb_count,
-                       dib->buffer,dib->dma_handle);
-
-       dib->init_state &= ~DIBUSB_STATE_URB_BUF;
-       dib->init_state &= ~DIBUSB_STATE_URB_INIT;
-       return 0;
-}
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb.h b/drivers/media/dvb/dibusb/dvb-dibusb.h
deleted file mode 100644 (file)
index c965b64..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * dvb-dibusb.h
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.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.
- *
- * for more information see dvb-dibusb-core.c .
- */
-#ifndef __DVB_DIBUSB_H__
-#define __DVB_DIBUSB_H__
-
-#include <linux/input.h>
-#include <linux/config.h>
-#include <linux/usb.h>
-
-#include "dvb_frontend.h"
-#include "dvb_demux.h"
-#include "dvb_net.h"
-#include "dmxdev.h"
-
-#include "dib3000.h"
-#include "mt352.h"
-
-/* debug */
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
-#define dprintk(level,args...) \
-           do { if ((dvb_dibusb_debug & level)) { printk(args); } } while (0)
-
-#define debug_dump(b,l) {\
-       int i; \
-       for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \
-       deb_xfer("\n");\
-}
-
-#else
-#define dprintk(args...)
-#define debug_dump(b,l)
-#endif
-
-extern int dvb_dibusb_debug;
-
-/* Version information */
-#define DRIVER_VERSION "0.3"
-#define DRIVER_DESC "DiBcom based USB Budget DVB-T device"
-#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
-
-#define deb_info(args...) dprintk(0x01,args)
-#define deb_xfer(args...) dprintk(0x02,args)
-#define deb_alot(args...) dprintk(0x04,args)
-#define deb_ts(args...)   dprintk(0x08,args)
-#define deb_err(args...)  dprintk(0x10,args)
-#define deb_rc(args...)   dprintk(0x20,args)
-
-/* generic log methods - taken from usb.h */
-#undef err
-#define err(format, arg...)  printk(KERN_ERR     "dvb-dibusb: " format "\n" , ## arg)
-#undef info
-#define info(format, arg...) printk(KERN_INFO    "dvb-dibusb: " format "\n" , ## arg)
-#undef warn
-#define warn(format, arg...) printk(KERN_WARNING "dvb-dibusb: " format "\n" , ## arg)
-
-struct dibusb_usb_controller {
-       const char *name;       /* name of the usb controller */
-       u16 cpu_cs_register;    /* needs to be restarted, when the firmware has been downloaded. */
-};
-
-typedef enum {
-       DIBUSB1_1 = 0,
-       DIBUSB1_1_AN2235,
-       DIBUSB2_0,
-       UMT2_0,
-       DIBUSB2_0B,
-       NOVAT_USB2,
-       DTT200U,
-} dibusb_class_t;
-
-typedef enum {
-       DIBUSB_TUNER_CABLE_THOMSON = 0,
-       DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5,
-       DIBUSB_TUNER_CABLE_LG_TDTP_E102P,
-       DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5,
-} dibusb_tuner_t;
-
-typedef enum {
-       DIBUSB_DIB3000MB = 0,
-       DIBUSB_DIB3000MC,
-       DIBUSB_MT352,
-       DTT200U_FE,
-} dibusb_demodulator_t;
-
-typedef enum {
-       DIBUSB_RC_NO = 0,
-       DIBUSB_RC_NEC_PROTOCOL,
-       DIBUSB_RC_HAUPPAUGE_PROTO,
-} dibusb_remote_t;
-
-struct dibusb_tuner {
-       dibusb_tuner_t id;
-
-       u8 pll_addr;       /* tuner i2c address */
-};
-extern struct dibusb_tuner dibusb_tuner[];
-
-#define DIBUSB_POSSIBLE_I2C_ADDR_NUM 4
-struct dibusb_demod {
-       dibusb_demodulator_t id;
-
-       int pid_filter_count;                       /* counter of the internal pid_filter */
-       u8 i2c_addrs[DIBUSB_POSSIBLE_I2C_ADDR_NUM]; /* list of possible i2c addresses of the demod */
-};
-
-#define DIBUSB_MAX_TUNER_NUM 2
-struct dibusb_device_class {
-       dibusb_class_t id;
-
-       const struct dibusb_usb_controller *usb_ctrl; /* usb controller */
-       const char *firmware;                         /* valid firmware filenames */
-
-       int pipe_cmd;                                 /* command pipe (read/write) */
-       int pipe_data;                                /* data pipe */
-
-       int urb_count;                                /* number of data URBs to be submitted */
-       int urb_buffer_size;                          /* the size of the buffer for each URB */
-
-       dibusb_remote_t remote_type;                  /* does this device have a ir-receiver */
-
-       struct dibusb_demod *demod;                   /* which demodulator is mount */
-       struct dibusb_tuner *tuner;                   /* which tuner can be found here */
-};
-
-#define DIBUSB_ID_MAX_NUM 15
-struct dibusb_usb_device {
-       const char *name;                                 /* real name of the box */
-       struct dibusb_device_class *dev_cl;               /* which dibusb_device_class is this device part of */
-
-       struct usb_device_id *cold_ids[DIBUSB_ID_MAX_NUM]; /* list of USB ids when this device is at pre firmware state */
-       struct usb_device_id *warm_ids[DIBUSB_ID_MAX_NUM]; /* list of USB ids when this device is at post firmware state */
-};
-
-/* a PID for the pid_filter list, when in use */
-struct dibusb_pid
-{
-       int index;
-       u16 pid;
-       int active;
-};
-
-struct usb_dibusb {
-       /* usb */
-       struct usb_device * udev;
-
-       struct dibusb_usb_device * dibdev;
-
-#define DIBUSB_STATE_INIT       0x000
-#define DIBUSB_STATE_URB_LIST   0x001
-#define DIBUSB_STATE_URB_BUF    0x002
-#define DIBUSB_STATE_URB_INIT  0x004
-#define DIBUSB_STATE_DVB        0x008
-#define DIBUSB_STATE_I2C        0x010
-#define DIBUSB_STATE_REMOTE            0x020
-#define DIBUSB_STATE_URB_SUBMIT 0x040
-       int init_state;
-
-       int feedcount;
-       struct dib_fe_xfer_ops xfer_ops;
-
-       struct dibusb_tuner *tuner;
-
-       struct urb **urb_list;
-       u8 *buffer;
-       dma_addr_t dma_handle;
-
-       /* I2C */
-       struct i2c_adapter i2c_adap;
-
-       /* locking */
-       struct semaphore usb_sem;
-       struct semaphore i2c_sem;
-
-       /* dvb */
-       struct dvb_adapter adapter;
-       struct dmxdev dmxdev;
-       struct dvb_demux demux;
-       struct dvb_net dvb_net;
-       struct dvb_frontend* fe;
-
-       int (*fe_sleep) (struct dvb_frontend *);
-       int (*fe_init) (struct dvb_frontend *);
-
-       /* remote control */
-       struct input_dev rc_input_dev;
-       struct work_struct rc_query_work;
-       int last_event;
-       int last_state; /* for Hauppauge RC protocol */
-       int repeat_key_count;
-       int rc_key_repeat_count; /* module parameter */
-
-       /* module parameters */
-       int pid_parse;
-       int rc_query_interval;
-};
-
-/* commonly used functions in the separated files */
-
-/* dvb-dibusb-firmware.c */
-int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev);
-
-/* dvb-dibusb-remote.c */
-int dibusb_remote_exit(struct usb_dibusb *dib);
-int dibusb_remote_init(struct usb_dibusb *dib);
-
-/* dvb-dibusb-fe-i2c.c */
-int dibusb_fe_init(struct usb_dibusb* dib);
-int dibusb_fe_exit(struct usb_dibusb *dib);
-int dibusb_i2c_init(struct usb_dibusb *dib);
-int dibusb_i2c_exit(struct usb_dibusb *dib);
-
-/* dvb-dibusb-dvb.c */
-void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs);
-int dibusb_dvb_init(struct usb_dibusb *dib);
-int dibusb_dvb_exit(struct usb_dibusb *dib);
-
-/* dvb-dibusb-usb.c */
-int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
-       u16 rlen);
-int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len);
-
-int dibusb_hw_wakeup(struct dvb_frontend *);
-int dibusb_hw_sleep(struct dvb_frontend *);
-int dibusb_set_streaming_mode(struct usb_dibusb *,u8);
-int dibusb_streaming(struct usb_dibusb *,int);
-
-int dibusb_urb_init(struct usb_dibusb *);
-int dibusb_urb_exit(struct usb_dibusb *);
-
-/* dvb-fe-dtt200u.c */
-struct dvb_frontend* dtt200u_fe_attach(struct usb_dibusb *,struct dib_fe_xfer_ops *);
-
-/* i2c and transfer stuff */
-#define DIBUSB_I2C_TIMEOUT                             5000
-
-/*
- * protocol of all dibusb related devices
- */
-
-/*
- * bulk msg to/from endpoint 0x01
- *
- * general structure:
- * request_byte parameter_bytes
- */
-
-#define DIBUSB_REQ_START_READ                  0x00
-#define DIBUSB_REQ_START_DEMOD                 0x01
-
-/*
- * i2c read
- * bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word
- * bulk read:  byte_buffer (length_word bytes)
- */
-#define DIBUSB_REQ_I2C_READ                    0x02
-
-/*
- * i2c write
- * bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes
- */
-#define DIBUSB_REQ_I2C_WRITE                   0x03
-
-/*
- * polling the value of the remote control
- * bulk write: 0x04
- * bulk read:  byte_buffer (5 bytes)
- *
- * first byte of byte_buffer shows the status (0x00, 0x01, 0x02)
- */
-#define DIBUSB_REQ_POLL_REMOTE                 0x04
-
-#define DIBUSB_RC_NEC_EMPTY                            0x00
-#define DIBUSB_RC_NEC_KEY_PRESSED              0x01
-#define DIBUSB_RC_NEC_KEY_REPEATED             0x02
-
-/* additional status values for Hauppauge Remote Control Protocol */
-#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED        0x01
-#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY  0x03
-
-/* streaming mode:
- * bulk write: 0x05 mode_byte
- *
- * mode_byte is mostly 0x00
- */
-#define DIBUSB_REQ_SET_STREAMING_MODE  0x05
-
-/* interrupt the internal read loop, when blocking */
-#define DIBUSB_REQ_INTR_READ                   0x06
-
-/* io control
- * 0x07 cmd_byte param_bytes
- *
- * param_bytes can be up to 32 bytes
- *
- * cmd_byte function    parameter name
- * 0x00     power mode
- *                      0x00      sleep
- *                      0x01      wakeup
- *
- * 0x01     enable streaming
- * 0x02     disable streaming
- *
- *
- */
-#define DIBUSB_REQ_SET_IOCTL                   0x07
-
-/* IOCTL commands */
-
-/* change the power mode in firmware */
-#define DIBUSB_IOCTL_CMD_POWER_MODE            0x00
-#define DIBUSB_IOCTL_POWER_SLEEP                       0x00
-#define DIBUSB_IOCTL_POWER_WAKEUP                      0x01
-
-/* modify streaming of the FX2 */
-#define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01
-#define DIBUSB_IOCTL_CMD_DISABLE_STREAM        0x02
-
-#endif
diff --git a/drivers/media/dvb/dibusb/dvb-fe-dtt200u.c b/drivers/media/dvb/dibusb/dvb-fe-dtt200u.c
deleted file mode 100644 (file)
index 1872aa6..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * dvb-dtt200u-fe.c is a driver which implements the frontend-part of the
- * Yakumo/Typhoon/Hama USB2.0 boxes. It is hard-wired to the dibusb-driver as
- * it uses the usb-transfer functions directly (maybe creating a
- * generic-dvb-usb-lib for all usb-drivers will be reduce some more code.)
- *
- * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
- *
- * see dvb-dibusb-core.c for copyright details.
- */
-
-/* guessed protocol description (reverse engineered):
- * read
- *  00 - USB type 0x02 for usb2.0, 0x01 for usb1.1
- *  81 - <TS_LOCK> <current frequency divided by 250000>
- *  82 - crash - do not touch
- *  83 - crash - do not touch
- *  84 - remote control
- *  85 - crash - do not touch (OK, stop testing here)
- *  88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
- *  89 - noise-to-signal
- *     8a - unkown 1 byte - signal_strength
- *  8c - ber ???
- *  8d - ber
- *  8e - unc
- *
- * write
- *  02 - bandwidth
- *  03 - frequency (divided by 250000)
- *  04 - pid table (index pid(7:0) pid(12:8))
- *  05 - reset the pid table
- *  08 - demod transfer enabled or not (FX2 transfer is enabled by default)
- */
-
-#include "dvb-dibusb.h"
-#include "dvb_frontend.h"
-
-struct dtt200u_fe_state {
-       struct usb_dibusb *dib;
-
-       struct dvb_frontend_parameters fep;
-       struct dvb_frontend frontend;
-};
-
-#define moan(which,what) info("unexpected value in '%s' for cmd '%02x' - please report to linux-dvb@linuxtv.org",which,what)
-
-static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
-{
-       struct dtt200u_fe_state *state = fe->demodulator_priv;
-       u8 bw[1] = { 0x81 };
-       u8 br[3] = { 0 };
-//     u8 bdeb[5] = { 0 };
-
-       dibusb_readwrite_usb(state->dib,bw,1,br,3);
-       switch (br[0]) {
-               case 0x01:
-                       *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-                       break;
-               case 0x00:
-                       *stat = 0;
-                       break;
-               default:
-                       moan("br[0]",0x81);
-                       break;
-       }
-
-//     bw[0] = 0x88;
-//     dibusb_readwrite_usb(state->dib,bw,1,bdeb,5);
-
-//     deb_info("%02x: %02x %02x %02x %02x %02x\n",bw[0],bdeb[0],bdeb[1],bdeb[2],bdeb[3],bdeb[4]);
-
-       return 0;
-}
-static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
-{
-       struct dtt200u_fe_state *state = fe->demodulator_priv;
-       u8 bw[1] = { 0x8d };
-       *ber = 0;
-       dibusb_readwrite_usb(state->dib,bw,1,(u8*) ber, 3);
-       return 0;
-}
-
-static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
-{
-       struct dtt200u_fe_state *state = fe->demodulator_priv;
-       u8 bw[1] = { 0x8c };
-       *unc = 0;
-       dibusb_readwrite_usb(state->dib,bw,1,(u8*) unc, 3);
-       return 0;
-}
-
-static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
-{
-       struct dtt200u_fe_state *state = fe->demodulator_priv;
-       u8 bw[1] = { 0x8a };
-       u8 b;
-       dibusb_readwrite_usb(state->dib,bw,1,&b, 1);
-       *strength = (b << 8) | b;
-       return 0;
-}
-
-static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
-{
-       struct dtt200u_fe_state *state = fe->demodulator_priv;
-       u8 bw[1] = { 0x89 };
-       u8 br[1] = { 0 };
-       dibusb_readwrite_usb(state->dib,bw,1,br,1);
-       *snr = ((0xff - br[0]) << 8) | (0xff - br[0]);
-       return 0;
-}
-
-static int dtt200u_fe_init(struct dvb_frontend* fe)
-{
-       struct dtt200u_fe_state *state = fe->demodulator_priv;
-       u8 b[] = { 0x01 };
-       return dibusb_write_usb(state->dib,b,1);
-}
-
-static int dtt200u_fe_sleep(struct dvb_frontend* fe)
-{
-       return dtt200u_fe_init(fe);
-}
-
-static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
-{
-       tune->min_delay_ms = 1500;
-       tune->step_size = 166667;
-       tune->max_drift = 166667 * 2;
-       return 0;
-}
-
-static int dtt200u_fe_set_frontend(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *fep)
-{
-       struct dtt200u_fe_state *state = fe->demodulator_priv;
-       u16 freq = fep->frequency / 250000;
-       u8 bw,bwbuf[2] = { 0x03, 0 }, freqbuf[3] = { 0x02, 0, 0 };
-
-       switch (fep->u.ofdm.bandwidth) {
-               case BANDWIDTH_8_MHZ: bw = 8; break;
-               case BANDWIDTH_7_MHZ: bw = 7; break;
-               case BANDWIDTH_6_MHZ: bw = 6; break;
-               case BANDWIDTH_AUTO: return -EOPNOTSUPP;
-               default:
-                       return -EINVAL;
-       }
-       deb_info("set_frontend\n");
-
-       bwbuf[1] = bw;
-       dibusb_write_usb(state->dib,bwbuf,2);
-
-       freqbuf[1] = freq & 0xff;
-       freqbuf[2] = (freq >> 8) & 0xff;
-       dibusb_write_usb(state->dib,freqbuf,3);
-
-       memcpy(&state->fep,fep,sizeof(struct dvb_frontend_parameters));
-
-       return 0;
-}
-
-static int dtt200u_fe_get_frontend(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *fep)
-{
-       struct dtt200u_fe_state *state = fe->demodulator_priv;
-       memcpy(fep,&state->fep,sizeof(struct dvb_frontend_parameters));
-       return 0;
-}
-
-static void dtt200u_fe_release(struct dvb_frontend* fe)
-{
-       struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
-       kfree(state);
-}
-
-static int dtt200u_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff)
-{
-       struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
-       u8 b_pid[4];
-       pid = onoff ? pid : 0;
-
-       b_pid[0] = 0x04;
-       b_pid[1] = index;
-       b_pid[2] = pid & 0xff;
-       b_pid[3] = (pid >> 8) & 0xff;
-
-       dibusb_write_usb(state->dib,b_pid,4);
-       return 0;
-}
-
-static int dtt200u_fifo_control(struct dvb_frontend *fe, int onoff)
-{
-       struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
-       u8 b_streaming[2] = { 0x08, onoff };
-       u8 b_rst_pid[1] = { 0x05 };
-
-       dibusb_write_usb(state->dib,b_streaming,2);
-
-       if (!onoff)
-               dibusb_write_usb(state->dib,b_rst_pid,1);
-       return 0;
-}
-
-static struct dvb_frontend_ops dtt200u_fe_ops;
-
-struct dvb_frontend* dtt200u_fe_attach(struct usb_dibusb *dib, struct dib_fe_xfer_ops *xfer_ops)
-{
-       struct dtt200u_fe_state* state = NULL;
-
-       /* allocate memory for the internal state */
-       state = (struct dtt200u_fe_state*) kmalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL);
-       if (state == NULL)
-               goto error;
-       memset(state,0,sizeof(struct dtt200u_fe_state));
-
-       deb_info("attaching frontend dtt200u\n");
-
-       state->dib = dib;
-
-       state->frontend.ops = &dtt200u_fe_ops;
-       state->frontend.demodulator_priv = state;
-
-       xfer_ops->fifo_ctrl = dtt200u_fifo_control;
-       xfer_ops->pid_ctrl = dtt200u_pid_control;
-
-       goto success;
-error:
-       return NULL;
-success:
-       return &state->frontend;
-}
-
-static struct dvb_frontend_ops dtt200u_fe_ops = {
-       .info = {
-               .name                   = "DTT200U (Yakumo/Typhoon/Hama) DVB-T",
-               .type                   = FE_OFDM,
-               .frequency_min          = 44250000,
-               .frequency_max          = 867250000,
-               .frequency_stepsize     = 250000,
-               .caps = FE_CAN_INVERSION_AUTO |
-                               FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-                               FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-                               FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-                               FE_CAN_TRANSMISSION_MODE_AUTO |
-                               FE_CAN_GUARD_INTERVAL_AUTO |
-                               FE_CAN_RECOVER |
-                               FE_CAN_HIERARCHY_AUTO,
-       },
-
-       .release = dtt200u_fe_release,
-
-       .init = dtt200u_fe_init,
-       .sleep = dtt200u_fe_sleep,
-
-       .set_frontend = dtt200u_fe_set_frontend,
-       .get_frontend = dtt200u_fe_get_frontend,
-       .get_tune_settings = dtt200u_fe_get_tune_settings,
-
-       .read_status = dtt200u_fe_read_status,
-       .read_ber = dtt200u_fe_read_ber,
-       .read_signal_strength = dtt200u_fe_read_signal_strength,
-       .read_snr = dtt200u_fe_read_snr,
-       .read_ucblocks = dtt200u_fe_read_unc_blocks,
-};
index d19301d90a09937a481ef21666096aa121ebf575..f11daae91cd4e07ce54bdb375f5f10aed22aa104 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/moduleparam.h>
 #include <linux/list.h>
 #include <linux/suspend.h>
+#include <linux/jiffies.h>
 #include <asm/processor.h>
 #include <asm/semaphore.h>
 
@@ -327,7 +328,8 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
                return 1;
 
        if (fepriv->dvbdev->writers == 1)
-               if (jiffies - fepriv->release_jiffies > dvb_shutdown_timeout * HZ)
+               if (time_after(jiffies, fepriv->release_jiffies +
+                                       dvb_shutdown_timeout * HZ))
                        return 1;
 
        return 0;
@@ -389,8 +391,7 @@ static int dvb_frontend_thread(void *data)
                        break;
                }
 
-               if (current->flags & PF_FREEZE)
-                       refrigerator(PF_FREEZE);
+               try_to_freeze();
 
                if (down_interruptible(&fepriv->sem))
                        break;
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
new file mode 100644 (file)
index 0000000..8aa32f6
--- /dev/null
@@ -0,0 +1,99 @@
+config DVB_USB
+       tristate "Support for various USB DVB devices"
+       depends on DVB_CORE && USB
+       select FW_LOADER
+       help
+         By enabling this you will be able to choose the various USB 1.1 and
+         USB2.0 DVB devices.
+
+         Almost every USB device needs a firmware, please look into
+         <file:Documentation/dvb/README.dvb-usb>
+
+         Say Y if you own an USB DVB device.
+
+config DVB_USB_DEBUG
+       bool "Enable extended debug support for all DVB-USB devices"
+       depends on DVB_USB
+       help
+         Say Y if you want to enable debuging. See modinfo dvb-usb (and the
+         appropriate drivers) for debug levels.
+
+config DVB_USB_A800
+       tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
+       depends on DVB_USB
+       help
+         Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
+
+config DVB_USB_DIBUSB_MB
+       tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
+       depends on DVB_USB
+       help
+         Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
+         DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
+
+         Devices supported by this driver:
+           TwinhanDTV USB-Ter (VP7041)
+           TwinhanDTV Magic Box (VP7041e)
+           KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
+           Hama DVB-T USB1.1-Box
+           DiBcom USB1.1 reference devices (non-public)
+           Ultima Electronic/Artec T1 USB TVBOX
+           Compro Videomate DVB-U2000 - DVB-T USB
+           Grandtec DVB-T USB
+           Avermedia AverTV DVBT USB1.1
+           Artec T1 USB1.1 boxes
+
+         The VP7041 seems to be identical to "CTS Portable" (Chinese
+         Television System).
+
+         Say Y if you own such a device and want to use it. You should build it as
+         a module.
+
+config DVB_USB_DIBUSB_MC
+       tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
+       depends on DVB_USB
+       help
+         Support for 2.0 DVB-T receivers based on reference designs made by
+         DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
+
+         Devices supported by this driver:
+           DiBcom USB2.0 reference devices (non-public)
+           Artec T1 USB2.0 boxes
+
+         Say Y if you own such a device and want to use it. You should build it as
+         a module.
+
+config DVB_USB_UMT_010
+       tristate "HanfTek UMT-010 DVB-T USB2.0 support"
+       depends on DVB_USB
+       help
+         Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
+
+config DVB_USB_DIGITV
+       tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
+       depends on DVB_USB
+       help
+         Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver.
+
+config DVB_USB_VP7045
+       tristate "TwinhanDTV Alpha/MagicBoxII and DNTV tinyUSB2 DVB-T USB2.0 support"
+       depends on DVB_USB
+       help
+         Say Y here to support the
+           TwinhanDTV Alpha (stick) (VP-7045),
+               TwinhanDTV MagicBox II (VP-7046) and
+               DigitalNow TinyUSB 2 DVB-t DVB-T USB2.0 receivers.
+
+config DVB_USB_NOVA_T_USB2
+       tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
+       depends on DVB_USB
+       help
+         Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
+
+config DVB_USB_DTT200U
+       tristate "Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 support"
+       depends on DVB_USB
+       help
+         Say Y here to support the Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver.
+
+         The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan).
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
new file mode 100644 (file)
index 0000000..d65b50f
--- /dev/null
@@ -0,0 +1,30 @@
+dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o
+obj-$(CONFIG_DVB_USB) += dvb-usb.o
+
+dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o
+obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o
+
+dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o
+obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o
+
+dvb-usb-dibusb-common-objs = dibusb-common.o
+
+dvb-usb-a800-objs = a800.o
+obj-$(CONFIG_DVB_USB_A800) += dvb-usb-dibusb-common.o dvb-usb-a800.o
+
+dvb-usb-dibusb-mb-objs = dibusb-mb.o
+obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o
+
+dvb-usb-dibusb-mc-objs = dibusb-mc.o
+obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc.o
+
+dvb-usb-nova-t-usb2-objs = nova-t-usb2.o
+obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2.o
+
+dvb-usb-umt-010-objs = umt-010.o
+obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o
+
+dvb-usb-digitv-objs = digitv.o
+obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
new file mode 100644 (file)
index 0000000..a354293
--- /dev/null
@@ -0,0 +1,176 @@
+/* DVB USB framework compliant Linux driver for the AVerMedia AverTV DVB-T
+ * USB2.0 (A800) DVB-T receiver.
+ *
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * Thanks to
+ *   - AVerMedia who kindly provided information and
+ *   - Glen Harris who suffered from my mistakes during development.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (rc=1 (or-able))." DVB_USB_DEBUG_STATUS);
+#define deb_rc(args...)   dprintk(debug,0x01,args)
+
+static int a800_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       /* do nothing for the AVerMedia */
+       return 0;
+}
+
+static struct dvb_usb_rc_key a800_rc_keys[] = {
+       { 0x02, 0x01, KEY_PROG1 },       /* SOURCE */
+       { 0x02, 0x00, KEY_POWER },       /* POWER */
+       { 0x02, 0x05, KEY_1 },           /* 1 */
+       { 0x02, 0x06, KEY_2 },           /* 2 */
+       { 0x02, 0x07, KEY_3 },           /* 3 */
+       { 0x02, 0x09, KEY_4 },           /* 4 */
+       { 0x02, 0x0a, KEY_5 },           /* 5 */
+       { 0x02, 0x0b, KEY_6 },           /* 6 */
+       { 0x02, 0x0d, KEY_7 },           /* 7 */
+       { 0x02, 0x0e, KEY_8 },           /* 8 */
+       { 0x02, 0x0f, KEY_9 },           /* 9 */
+       { 0x02, 0x12, KEY_LEFT },        /* L / DISPLAY */
+       { 0x02, 0x11, KEY_0 },           /* 0 */
+       { 0x02, 0x13, KEY_RIGHT },       /* R / CH RTN */
+       { 0x02, 0x17, KEY_PROG2 },       /* SNAP SHOT */
+       { 0x02, 0x10, KEY_PROG3 },       /* 16-CH PREV */
+       { 0x02, 0x03, KEY_CHANNELUP },   /* CH UP */
+       { 0x02, 0x1e, KEY_VOLUMEDOWN },  /* VOL DOWN */
+       { 0x02, 0x0c, KEY_ZOOM },        /* FULL SCREEN */
+       { 0x02, 0x1f, KEY_VOLUMEUP },    /* VOL UP */
+       { 0x02, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */
+       { 0x02, 0x14, KEY_MUTE },        /* MUTE */
+       { 0x02, 0x08, KEY_AUDIO },       /* AUDIO */
+       { 0x02, 0x19, KEY_RECORD },      /* RECORD */
+       { 0x02, 0x18, KEY_PLAY },        /* PLAY */
+       { 0x02, 0x1b, KEY_STOP },        /* STOP */
+       { 0x02, 0x1a, KEY_PLAYPAUSE },   /* TIMESHIFT / PAUSE */
+       { 0x02, 0x1d, KEY_BACK },        /* << / RED */
+       { 0x02, 0x1c, KEY_FORWARD },     /* >> / YELLOW */
+       { 0x02, 0x03, KEY_TEXT },        /* TELETEXT */
+       { 0x02, 0x01, KEY_FIRST },       /* |<< / GREEN */
+       { 0x02, 0x00, KEY_LAST },        /* >>| / BLUE */
+       { 0x02, 0x04, KEY_EPG },         /* EPG */
+       { 0x02, 0x15, KEY_MENU },        /* MENU */
+};
+
+int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+       u8 key[5];
+       if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0),
+                               0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5,
+                               2*HZ) != 5)
+               return -ENODEV;
+
+       /* call the universal NEC remote processor, to find out the key's state and event */
+       dvb_usb_nec_rc_key_to_event(d,key,event,state);
+       if (key[0] != 0)
+               deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
+       return 0;
+}
+
+/* USB Driver stuff */
+static struct dvb_usb_properties a800_properties;
+
+static int a800_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       return dvb_usb_device_init(intf,&a800_properties,THIS_MODULE);
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id a800_table [] = {
+/* 00 */       { USB_DEVICE(USB_VID_AVERMEDIA,     USB_PID_AVERMEDIA_DVBT_USB2_COLD) },
+/* 01 */       { USB_DEVICE(USB_VID_AVERMEDIA,     USB_PID_AVERMEDIA_DVBT_USB2_WARM) },
+                       { }             /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, a800_table);
+
+static struct dvb_usb_properties a800_properties = {
+       .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+       .pid_filter_count = 32,
+
+       .usb_ctrl = CYPRESS_FX2,
+
+       .firmware = "dvb-usb-avertv-a800-02.fw",
+
+       .size_of_priv     = sizeof(struct dibusb_state),
+
+       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
+       .pid_filter       = dibusb_pid_filter,
+       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+       .power_ctrl       = a800_power_ctrl,
+       .frontend_attach  = dibusb_dib3000mc_frontend_attach,
+       .tuner_attach     = dibusb_dib3000mc_tuner_attach,
+
+       .rc_interval      = DEFAULT_RC_INTERVAL,
+       .rc_key_map       = a800_rc_keys,
+       .rc_key_map_size  = ARRAY_SIZE(a800_rc_keys),
+       .rc_query         = a800_rc_query,
+
+       .i2c_algo         = &dibusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 7,
+               .endpoint = 0x06,
+               .u = {
+                       .bulk = {
+                               .buffersize = 4096,
+                       }
+               }
+       },
+
+       .num_device_descs = 1,
+       .devices = {
+               {   "AVerMedia AverTV DVB-T USB 2.0 (A800)",
+                       { &a800_table[0], NULL },
+                       { &a800_table[1], NULL },
+               },
+       }
+};
+
+static struct usb_driver a800_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "AVerMedia AverTV DVB-T USB 2.0 (A800)",
+       .probe          = a800_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table       = a800_table,
+};
+
+/* module stuff */
+static int __init a800_module_init(void)
+{
+       int result;
+       if ((result = usb_register(&a800_driver))) {
+               err("usb_register failed. Error number %d",result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit a800_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&a800_driver);
+}
+
+module_init (a800_module_init);
+module_exit (a800_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("AVerMedia AverTV DVB-T USB 2.0 (A800)");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
new file mode 100644 (file)
index 0000000..63b626f
--- /dev/null
@@ -0,0 +1,272 @@
+/* Common methods for dibusb-based-receivers.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS);
+MODULE_LICENSE("GPL");
+
+#define deb_info(args...) dprintk(debug,0x01,args)
+
+/* common stuff used by the different dibusb modules */
+int dibusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       if (d->priv != NULL) {
+               struct dib_fe_xfer_ops *ops = d->priv;
+               if (ops->fifo_ctrl != NULL)
+                       if (ops->fifo_ctrl(d->fe,onoff)) {
+                               err("error while controlling the fifo of the demod.");
+                               return -ENODEV;
+                       }
+       }
+       return 0;
+}
+EXPORT_SYMBOL(dibusb_streaming_ctrl);
+
+int dibusb_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff)
+{
+       if (d->priv != NULL) {
+               struct dib_fe_xfer_ops *ops = d->priv;
+               if (d->pid_filtering && ops->pid_ctrl != NULL)
+                       ops->pid_ctrl(d->fe,index,pid,onoff);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(dibusb_pid_filter);
+
+int dibusb_pid_filter_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       if (d->priv != NULL) {
+               struct dib_fe_xfer_ops *ops = d->priv;
+               if (ops->pid_parse != NULL)
+                       if (ops->pid_parse(d->fe,onoff) < 0)
+                               err("could not handle pid_parser");
+       }
+       return 0;
+}
+EXPORT_SYMBOL(dibusb_pid_filter_ctrl);
+
+int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       u8 b[3];
+       int ret;
+       b[0] = DIBUSB_REQ_SET_IOCTL;
+       b[1] = DIBUSB_IOCTL_CMD_POWER_MODE;
+       b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP;
+       ret = dvb_usb_generic_write(d,b,3);
+       msleep(10);
+       return ret;
+}
+EXPORT_SYMBOL(dibusb_power_ctrl);
+
+int dibusb2_0_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       u8 b[2];
+       b[0] = DIBUSB_REQ_SET_IOCTL;
+       b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM;
+
+       dvb_usb_generic_write(d,b,3);
+
+       return dibusb_streaming_ctrl(d,onoff);
+}
+EXPORT_SYMBOL(dibusb2_0_streaming_ctrl);
+
+int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       if (onoff) {
+               u8 b[3] = { DIBUSB_REQ_SET_IOCTL, DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP };
+               return dvb_usb_generic_write(d,b,3);
+       } else
+               return 0;
+}
+EXPORT_SYMBOL(dibusb2_0_power_ctrl);
+
+static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr,
+                         u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+       u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
+       /* write only ? */
+       int wo = (rbuf == NULL || rlen == 0),
+               len = 2 + wlen + (wo ? 0 : 2);
+
+       sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
+       sndbuf[1] = (addr << 1) | (wo ? 0 : 1);
+
+       memcpy(&sndbuf[2],wbuf,wlen);
+
+       if (!wo) {
+               sndbuf[wlen+2] = (rlen >> 8) & 0xff;
+               sndbuf[wlen+3] = rlen & 0xff;
+       }
+
+       return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0);
+}
+
+/*
+ * I2C master xfer function
+ */
+static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int i;
+
+       if (down_interruptible(&d->i2c_sem) < 0)
+               return -EAGAIN;
+
+       if (num > 2)
+               warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+       for (i = 0; i < num; i++) {
+               /* write/read request */
+               if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+                       if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,
+                                               msg[i+1].buf,msg[i+1].len) < 0)
+                               break;
+                       i++;
+               } else
+                       if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
+                               break;
+       }
+
+       up(&d->i2c_sem);
+       return i;
+}
+
+static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+struct i2c_algorithm dibusb_i2c_algo = {
+       .name          = "DiBcom USB I2C algorithm",
+       .id            = I2C_ALGO_BIT,
+       .master_xfer   = dibusb_i2c_xfer,
+       .functionality = dibusb_i2c_func,
+};
+EXPORT_SYMBOL(dibusb_i2c_algo);
+
+int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val)
+{
+       u8 wbuf[1] = { offs };
+       return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1);
+}
+EXPORT_SYMBOL(dibusb_read_eeprom_byte);
+
+int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *d)
+{
+       struct dib3000_config demod_cfg;
+       struct dibusb_state *st = d->priv;
+
+       demod_cfg.pll_set = dvb_usb_pll_set_i2c;
+       demod_cfg.pll_init = dvb_usb_pll_init_i2c;
+
+       for (demod_cfg.demod_address = 0x8; demod_cfg.demod_address < 0xd; demod_cfg.demod_address++)
+               if ((d->fe = dib3000mc_attach(&demod_cfg,&d->i2c_adap,&st->ops)) != NULL) {
+                       d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
+                       return 0;
+               }
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach);
+
+int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *d)
+{
+       d->pll_addr = 0x60;
+       d->pll_desc = &dvb_pll_env57h1xd5;
+       return 0;
+}
+EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
+
+/*
+ * common remote control stuff
+ */
+struct dvb_usb_rc_key dibusb_rc_keys[] = {
+       /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
+       { 0x00, 0x16, KEY_POWER },
+       { 0x00, 0x10, KEY_MUTE },
+       { 0x00, 0x03, KEY_1 },
+       { 0x00, 0x01, KEY_2 },
+       { 0x00, 0x06, KEY_3 },
+       { 0x00, 0x09, KEY_4 },
+       { 0x00, 0x1d, KEY_5 },
+       { 0x00, 0x1f, KEY_6 },
+       { 0x00, 0x0d, KEY_7 },
+       { 0x00, 0x19, KEY_8 },
+       { 0x00, 0x1b, KEY_9 },
+       { 0x00, 0x15, KEY_0 },
+       { 0x00, 0x05, KEY_CHANNELUP },
+       { 0x00, 0x02, KEY_CHANNELDOWN },
+       { 0x00, 0x1e, KEY_VOLUMEUP },
+       { 0x00, 0x0a, KEY_VOLUMEDOWN },
+       { 0x00, 0x11, KEY_RECORD },
+       { 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
+       { 0x00, 0x14, KEY_PLAY },
+       { 0x00, 0x1a, KEY_STOP },
+       { 0x00, 0x40, KEY_REWIND },
+       { 0x00, 0x12, KEY_FASTFORWARD },
+       { 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
+       { 0x00, 0x4c, KEY_PAUSE },
+       { 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */
+       { 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
+       /* additional keys TwinHan VisionPlus, the Artec seemingly not have */
+       { 0x00, 0x0c, KEY_CANCEL }, /* Cancel */
+       { 0x00, 0x1c, KEY_EPG }, /* EPG */
+       { 0x00, 0x00, KEY_TAB }, /* Tab */
+       { 0x00, 0x48, KEY_INFO }, /* Preview */
+       { 0x00, 0x04, KEY_LIST }, /* RecordList */
+       { 0x00, 0x0f, KEY_TEXT }, /* Teletext */
+       /* Key codes for the KWorld/ADSTech/JetWay remote. */
+       { 0x86, 0x12, KEY_POWER },
+       { 0x86, 0x0f, KEY_SELECT }, /* source */
+       { 0x86, 0x0c, KEY_UNKNOWN }, /* scan */
+       { 0x86, 0x0b, KEY_EPG },
+       { 0x86, 0x10, KEY_MUTE },
+       { 0x86, 0x01, KEY_1 },
+       { 0x86, 0x02, KEY_2 },
+       { 0x86, 0x03, KEY_3 },
+       { 0x86, 0x04, KEY_4 },
+       { 0x86, 0x05, KEY_5 },
+       { 0x86, 0x06, KEY_6 },
+       { 0x86, 0x07, KEY_7 },
+       { 0x86, 0x08, KEY_8 },
+       { 0x86, 0x09, KEY_9 },
+       { 0x86, 0x0a, KEY_0 },
+       { 0x86, 0x18, KEY_ZOOM },
+       { 0x86, 0x1c, KEY_UNKNOWN }, /* preview */
+       { 0x86, 0x13, KEY_UNKNOWN }, /* snap */
+       { 0x86, 0x00, KEY_UNDO },
+       { 0x86, 0x1d, KEY_RECORD },
+       { 0x86, 0x0d, KEY_STOP },
+       { 0x86, 0x0e, KEY_PAUSE },
+       { 0x86, 0x16, KEY_PLAY },
+       { 0x86, 0x11, KEY_BACK },
+       { 0x86, 0x19, KEY_FORWARD },
+       { 0x86, 0x14, KEY_UNKNOWN }, /* pip */
+       { 0x86, 0x15, KEY_ESC },
+       { 0x86, 0x1a, KEY_UP },
+       { 0x86, 0x1e, KEY_DOWN },
+       { 0x86, 0x1f, KEY_LEFT },
+       { 0x86, 0x1b, KEY_RIGHT },
+};
+EXPORT_SYMBOL(dibusb_rc_keys);
+
+int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+       u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE;
+       dvb_usb_generic_rw(d,&cmd,1,key,5,0);
+       dvb_usb_nec_rc_key_to_event(d,key,event,state);
+       if (key[0] != 0)
+               deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
+       return 0;
+}
+EXPORT_SYMBOL(dibusb_rc_query);
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
new file mode 100644 (file)
index 0000000..a0ffbb5
--- /dev/null
@@ -0,0 +1,316 @@
+/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
+ * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * based on GPL code from DiBcom, which has
+ * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_device *d)
+{
+       struct dib3000_config demod_cfg;
+       struct dibusb_state *st = d->priv;
+
+       demod_cfg.demod_address = 0x8;
+       demod_cfg.pll_set = dvb_usb_pll_set_i2c;
+       demod_cfg.pll_init = dvb_usb_pll_init_i2c;
+
+       if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL)
+               return -ENODEV;
+
+       d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
+
+       return 0;
+}
+
+/* some of the dibusb 1.1 device aren't equipped with the default tuner
+ * (Thomson Cable), but with a Panasonic ENV77H11D5.  This function figures
+ * this out. */
+static int dibusb_dib3000mb_tuner_attach (struct dvb_usb_device *d)
+{
+       u8 b[2] = { 0,0 }, b2[1];
+       int ret = 0;
+       struct i2c_msg msg[2] = {
+               { .flags = 0,        .buf = b,  .len = 2 },
+               { .flags = I2C_M_RD, .buf = b2, .len = 1 },
+       };
+
+       /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
+       msg[0].addr = msg[1].addr = 0x60;
+
+       if (d->tuner_pass_ctrl)
+               d->tuner_pass_ctrl(d->fe,1,msg[0].addr);
+
+       if (i2c_transfer (&d->i2c_adap, msg, 2) != 2) {
+               err("tuner i2c write failed.");
+               ret = -EREMOTEIO;
+       }
+
+       if (d->tuner_pass_ctrl)
+               d->tuner_pass_ctrl(d->fe,0,msg[0].addr);
+
+       if (b2[0] == 0xfe) {
+               info("this device has the Thomson Cable onboard. Which is default.");
+               d->pll_addr = 0x61;
+               d->pll_desc = &dvb_pll_tua6010xs;
+       } else {
+               u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
+               info("this device has the Panasonic ENV77H11D5 onboard.");
+               d->pll_addr = 0x60;
+               memcpy(d->pll_init,bpll,4);
+               d->pll_desc = &dvb_pll_tda665x;
+       }
+
+       return ret;
+}
+
+/* USB Driver stuff */
+static struct dvb_usb_properties dibusb1_1_properties;
+static struct dvb_usb_properties dibusb1_1_an2235_properties;
+static struct dvb_usb_properties dibusb2_0b_properties;
+
+static int dibusb_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       if (dvb_usb_device_init(intf,&dibusb1_1_properties,THIS_MODULE) == 0 ||
+               dvb_usb_device_init(intf,&dibusb1_1_an2235_properties,THIS_MODULE) == 0 ||
+               dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE) == 0)
+               return 0;
+
+       return -EINVAL;
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id dibusb_dib3000mb_table [] = {
+/* 00 */       { USB_DEVICE(USB_VID_AVERMEDIA_UNK,     USB_PID_AVERMEDIA_DVBT_USB_COLD)},
+/* 01 */       { USB_DEVICE(USB_VID_AVERMEDIA_UNK,     USB_PID_AVERMEDIA_DVBT_USB_WARM)},
+/* 02 */       { USB_DEVICE(USB_VID_COMPRO,            USB_PID_COMPRO_DVBU2000_COLD) },
+/* 03 */       { USB_DEVICE(USB_VID_COMPRO,            USB_PID_COMPRO_DVBU2000_WARM) },
+/* 04 */       { USB_DEVICE(USB_VID_COMPRO_UNK,        USB_PID_COMPRO_DVBU2000_UNK_COLD) },
+/* 05 */       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3000_COLD) },
+/* 06 */       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3000_WARM) },
+/* 07 */       { USB_DEVICE(USB_VID_EMPIA,                     USB_PID_KWORLD_VSTREAM_COLD) },
+/* 08 */       { USB_DEVICE(USB_VID_EMPIA,                     USB_PID_KWORLD_VSTREAM_WARM) },
+/* 09 */       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB_COLD) },
+/* 10 */       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB_WARM) },
+/* 11 */       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_DIBCOM_MOD3000_COLD) },
+/* 12 */       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_DIBCOM_MOD3000_WARM) },
+/* 13 */       { USB_DEVICE(USB_VID_HYPER_PALTEK,      USB_PID_UNK_HYPER_PALTEK_COLD) },
+/* 14 */       { USB_DEVICE(USB_VID_HYPER_PALTEK,      USB_PID_UNK_HYPER_PALTEK_WARM) },
+/* 15 */       { USB_DEVICE(USB_VID_VISIONPLUS,        USB_PID_TWINHAN_VP7041_COLD) },
+/* 16 */       { USB_DEVICE(USB_VID_VISIONPLUS,        USB_PID_TWINHAN_VP7041_WARM) },
+/* 17 */       { USB_DEVICE(USB_VID_TWINHAN,           USB_PID_TWINHAN_VP7041_COLD) },
+/* 18 */       { USB_DEVICE(USB_VID_TWINHAN,           USB_PID_TWINHAN_VP7041_WARM) },
+/* 19 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
+/* 20 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
+/* 21 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
+/* 22 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
+/* 23 */       { USB_DEVICE(USB_VID_ADSTECH,           USB_PID_ADSTECH_USB2_COLD) },
+/* 24 */       { USB_DEVICE(USB_VID_ADSTECH,           USB_PID_ADSTECH_USB2_WARM) },
+                       { }             /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
+
+static struct dvb_usb_properties dibusb1_1_properties = {
+       .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+       .pid_filter_count = 16,
+
+       .usb_ctrl = CYPRESS_AN2135,
+
+       .firmware = "dvb-usb-dibusb-5.0.0.11.fw",
+
+       .size_of_priv     = sizeof(struct dibusb_state),
+
+       .streaming_ctrl   = dibusb_streaming_ctrl,
+       .pid_filter       = dibusb_pid_filter,
+       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+       .power_ctrl       = dibusb_power_ctrl,
+       .frontend_attach  = dibusb_dib3000mb_frontend_attach,
+       .tuner_attach     = dibusb_dib3000mb_tuner_attach,
+
+       .rc_interval      = DEFAULT_RC_INTERVAL,
+       .rc_key_map       = dibusb_rc_keys,
+       .rc_key_map_size  = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
+       .rc_query         = dibusb_rc_query,
+
+       .i2c_algo         = &dibusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 7,
+               .endpoint = 0x02,
+               .u = {
+                       .bulk = {
+                               .buffersize = 4096,
+                       }
+               }
+       },
+
+       .num_device_descs = 8,
+       .devices = {
+               {       "AVerMedia AverTV DVBT USB1.1",
+                       { &dibusb_dib3000mb_table[0],  NULL },
+                       { &dibusb_dib3000mb_table[1],  NULL },
+               },
+               {       "Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)",
+                       { &dibusb_dib3000mb_table[2], &dibusb_dib3000mb_table[4], NULL},
+                       { &dibusb_dib3000mb_table[3], NULL },
+               },
+               {       "DiBcom USB1.1 DVB-T reference design (MOD3000)",
+                       { &dibusb_dib3000mb_table[5],  NULL },
+                       { &dibusb_dib3000mb_table[6],  NULL },
+               },
+               {       "KWorld V-Stream XPERT DTV - DVB-T USB1.1",
+                       { &dibusb_dib3000mb_table[7], NULL },
+                       { &dibusb_dib3000mb_table[8], NULL },
+               },
+               {       "Grandtec USB1.1 DVB-T",
+                       { &dibusb_dib3000mb_table[9],  &dibusb_dib3000mb_table[11], NULL },
+                       { &dibusb_dib3000mb_table[10], &dibusb_dib3000mb_table[12], NULL },
+               },
+               {       "Unkown USB1.1 DVB-T device ???? please report the name to the author",
+                       { &dibusb_dib3000mb_table[13], NULL },
+                       { &dibusb_dib3000mb_table[14], NULL },
+               },
+               {       "TwinhanDTV USB-Ter USB1.1 / Magic Box I / HAMA USB1.1 DVB-T device",
+                       { &dibusb_dib3000mb_table[15], &dibusb_dib3000mb_table[17], NULL},
+                       { &dibusb_dib3000mb_table[16], &dibusb_dib3000mb_table[18], NULL},
+               },
+               {       "Artec T1 USB1.1 TVBOX with AN2135",
+                       { &dibusb_dib3000mb_table[19], NULL },
+                       { &dibusb_dib3000mb_table[20], NULL },
+               },
+       }
+};
+
+static struct dvb_usb_properties dibusb1_1_an2235_properties = {
+       .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = CYPRESS_AN2235,
+
+       .firmware = "dvb-usb-dibusb-an2235-01.fw",
+
+       .size_of_priv     = sizeof(struct dibusb_state),
+
+       .streaming_ctrl   = dibusb_streaming_ctrl,
+       .pid_filter       = dibusb_pid_filter,
+       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+       .power_ctrl       = dibusb_power_ctrl,
+       .frontend_attach  = dibusb_dib3000mb_frontend_attach,
+       .tuner_attach     = dibusb_dib3000mb_tuner_attach,
+
+       .rc_interval      = DEFAULT_RC_INTERVAL,
+       .rc_key_map       = dibusb_rc_keys,
+       .rc_key_map_size  = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
+       .rc_query         = dibusb_rc_query,
+
+       .i2c_algo         = &dibusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 7,
+               .endpoint = 0x02,
+               .u = {
+                       .bulk = {
+                               .buffersize = 4096,
+                       }
+               }
+       },
+
+       .num_device_descs = 1,
+       .devices = {
+               {       "Artec T1 USB1.1 TVBOX with AN2235",
+                       { &dibusb_dib3000mb_table[20], NULL },
+                       { &dibusb_dib3000mb_table[21], NULL },
+               },
+       }
+};
+
+static struct dvb_usb_properties dibusb2_0b_properties = {
+       .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = CYPRESS_FX2,
+
+       .firmware = "dvb-usb-adstech-usb2-01.fw",
+
+       .size_of_priv     = sizeof(struct dibusb_state),
+
+       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
+       .pid_filter       = dibusb_pid_filter,
+       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+       .power_ctrl       = dibusb2_0_power_ctrl,
+       .frontend_attach  = dibusb_dib3000mb_frontend_attach,
+       .tuner_attach     = dibusb_dib3000mb_tuner_attach,
+
+       .rc_interval      = DEFAULT_RC_INTERVAL,
+       .rc_key_map       = dibusb_rc_keys,
+       .rc_key_map_size  = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
+       .rc_query         = dibusb_rc_query,
+
+       .i2c_algo         = &dibusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 7,
+               .endpoint = 0x06,
+               .u = {
+                       .bulk = {
+                               .buffersize = 4096,
+                       }
+               }
+       },
+
+       .num_device_descs = 2,
+       .devices = {
+               {       "KWorld/ADSTech Instant DVB-T USB 2.0",
+                       { &dibusb_dib3000mb_table[23], NULL },
+                       { &dibusb_dib3000mb_table[24], NULL }, /* device ID with default DIBUSB2_0-firmware */
+               },
+       }
+};
+
+static struct usb_driver dibusb_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "DiBcom based USB DVB-T devices (DiB3000M-B based)",
+       .probe          = dibusb_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table       = dibusb_dib3000mb_table,
+};
+
+/* module stuff */
+static int __init dibusb_module_init(void)
+{
+       int result;
+       if ((result = usb_register(&dibusb_driver))) {
+               err("usb_register failed. Error number %d",result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit dibusb_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&dibusb_driver);
+}
+
+module_init (dibusb_module_init);
+module_exit (dibusb_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
new file mode 100644 (file)
index 0000000..aad8ed3
--- /dev/null
@@ -0,0 +1,116 @@
+/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
+ * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-C/P)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * based on GPL code from DiBcom, which has
+ * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+/* USB Driver stuff */
+static struct dvb_usb_properties dibusb_mc_properties;
+
+static int dibusb_mc_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       return dvb_usb_device_init(intf,&dibusb_mc_properties,THIS_MODULE);
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id dibusb_dib3000mc_table [] = {
+/* 00 */       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3001_COLD) },
+/* 01 */       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3001_WARM) },
+/* 02 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+                       { }             /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table);
+
+static struct dvb_usb_properties dibusb_mc_properties = {
+       .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+       .pid_filter_count = 32,
+
+       .usb_ctrl = CYPRESS_FX2,
+       .firmware = "dvb-usb-dibusb-6.0.0.8.fw",
+
+       .size_of_priv     = sizeof(struct dibusb_state),
+
+       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
+       .pid_filter       = dibusb_pid_filter,
+       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+       .power_ctrl       = dibusb2_0_power_ctrl,
+       .frontend_attach  = dibusb_dib3000mc_frontend_attach,
+       .tuner_attach     = dibusb_dib3000mc_tuner_attach,
+
+       .rc_interval      = DEFAULT_RC_INTERVAL,
+       .rc_key_map       = dibusb_rc_keys,
+       .rc_key_map_size  = 63, /* FIXME */
+       .rc_query         = dibusb_rc_query,
+
+       .i2c_algo         = &dibusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 7,
+               .endpoint = 0x06,
+               .u = {
+                       .bulk = {
+                               .buffersize = 4096,
+                       }
+               }
+       },
+
+       .num_device_descs = 2,
+       .devices = {
+               {   "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
+                       { &dibusb_dib3000mc_table[0], NULL },
+                       { &dibusb_dib3000mc_table[1], NULL },
+               },
+               {   "Artec T1 USB2.0 TVBOX (please report the warm ID)",
+                       { &dibusb_dib3000mc_table[2], NULL },
+                       { NULL },
+               },
+       }
+};
+
+static struct usb_driver dibusb_mc_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "DiBcom based USB2.0 DVB-T (DiB3000M-C/P based) devices",
+       .probe          = dibusb_mc_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table       = dibusb_dib3000mc_table,
+};
+
+/* module stuff */
+static int __init dibusb_mc_module_init(void)
+{
+       int result;
+       if ((result = usb_register(&dibusb_mc_driver))) {
+               err("usb_register failed. Error number %d",result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit dibusb_mc_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&dibusb_mc_driver);
+}
+
+module_init (dibusb_mc_module_init);
+module_exit (dibusb_mc_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for DiBcom USB2.0 DVB-T (DiB3000M-C/P based) devices");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
new file mode 100644 (file)
index 0000000..6611f62
--- /dev/null
@@ -0,0 +1,122 @@
+/* Header file for all dibusb-based-receivers.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_DIBUSB_H_
+#define _DVB_USB_DIBUSB_H_
+
+#define DVB_USB_LOG_PREFIX "dibusb"
+#include "dvb-usb.h"
+
+#include "dib3000.h"
+
+/*
+ * protocol of all dibusb related devices
+ */
+
+/*
+ * bulk msg to/from endpoint 0x01
+ *
+ * general structure:
+ * request_byte parameter_bytes
+ */
+
+#define DIBUSB_REQ_START_READ                  0x00
+#define DIBUSB_REQ_START_DEMOD                 0x01
+
+/*
+ * i2c read
+ * bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word
+ * bulk read:  byte_buffer (length_word bytes)
+ */
+#define DIBUSB_REQ_I2C_READ                    0x02
+
+/*
+ * i2c write
+ * bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes
+ */
+#define DIBUSB_REQ_I2C_WRITE                   0x03
+
+/*
+ * polling the value of the remote control
+ * bulk write: 0x04
+ * bulk read:  byte_buffer (5 bytes)
+ */
+#define DIBUSB_REQ_POLL_REMOTE       0x04
+
+/* additional status values for Hauppauge Remote Control Protocol */
+#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED        0x01
+#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY  0x03
+
+/* streaming mode:
+ * bulk write: 0x05 mode_byte
+ *
+ * mode_byte is mostly 0x00
+ */
+#define DIBUSB_REQ_SET_STREAMING_MODE  0x05
+
+/* interrupt the internal read loop, when blocking */
+#define DIBUSB_REQ_INTR_READ                   0x06
+
+/* io control
+ * 0x07 cmd_byte param_bytes
+ *
+ * param_bytes can be up to 32 bytes
+ *
+ * cmd_byte function    parameter name
+ * 0x00     power mode
+ *                      0x00      sleep
+ *                      0x01      wakeup
+ *
+ * 0x01     enable streaming
+ * 0x02     disable streaming
+ *
+ *
+ */
+#define DIBUSB_REQ_SET_IOCTL                   0x07
+
+/* IOCTL commands */
+
+/* change the power mode in firmware */
+#define DIBUSB_IOCTL_CMD_POWER_MODE            0x00
+#define DIBUSB_IOCTL_POWER_SLEEP                       0x00
+#define DIBUSB_IOCTL_POWER_WAKEUP                      0x01
+
+/* modify streaming of the FX2 */
+#define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01
+#define DIBUSB_IOCTL_CMD_DISABLE_STREAM        0x02
+
+struct dibusb_state {
+       struct dib_fe_xfer_ops ops;
+
+       /* for RC5 remote control */
+       int old_toggle;
+       int last_repeat_count;
+};
+
+extern struct i2c_algorithm dibusb_i2c_algo;
+
+extern int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *);
+extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *);
+
+extern int dibusb_streaming_ctrl(struct dvb_usb_device *, int);
+extern int dibusb_pid_filter(struct dvb_usb_device *, int, u16, int);
+extern int dibusb_pid_filter_ctrl(struct dvb_usb_device *, int);
+extern int dibusb_power_ctrl(struct dvb_usb_device *, int);
+extern int dibusb2_0_streaming_ctrl(struct dvb_usb_device *, int);
+extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int);
+
+#define DEFAULT_RC_INTERVAL 150
+//#define DEFAULT_RC_INTERVAL 100000
+
+extern struct dvb_usb_rc_key dibusb_rc_keys[];
+extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *);
+extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *);
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
new file mode 100644 (file)
index 0000000..5acf3fd
--- /dev/null
@@ -0,0 +1,282 @@
+/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0
+ * receiver
+ *
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) and
+ *                    Allan Third (allan.third@cs.man.ac.uk)
+ *
+ * partly based on the SDK published by Nebula Electronics (TODO do we want this line ?)
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "digitv.h"
+
+#include "mt352.h"
+#include "nxt6000.h"
+
+/* debug */
+int dvb_usb_digitv_debug;
+module_param_named(debug,dvb_usb_digitv_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+static int digitv_ctrl_msg(struct dvb_usb_device *d,
+               u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+       int wo = (rbuf == NULL || rlen == 0); /* write-only */
+       u8 sndbuf[7],rcvbuf[7];
+       memset(sndbuf,0,7); memset(rcvbuf,0,7);
+
+       sndbuf[0] = cmd;
+       sndbuf[1] = vv;
+       sndbuf[2] = wo ? wlen : rlen;
+
+       if (!wo) {
+               memcpy(&sndbuf[3],wbuf,wlen);
+               dvb_usb_generic_write(d,sndbuf,7);
+       } else {
+               dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10);
+               memcpy(&rbuf,&rcvbuf[3],rlen);
+       }
+       return 0;
+}
+
+/* I2C */
+static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int i;
+
+       if (down_interruptible(&d->i2c_sem) < 0)
+               return -EAGAIN;
+
+       if (num > 2)
+               warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+       for (i = 0; i < num; i++) {
+               /* write/read request */
+               if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+                       if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0,
+                                               msg[i+1].buf,msg[i+1].len) < 0)
+                               break;
+                       i++;
+               } else
+                       if (digitv_ctrl_msg(d,USB_WRITE_COFDM, msg[i].buf[0],
+                                               &msg[i].buf[1],msg[i].len-1,NULL,0) < 0)
+                               break;
+       }
+
+       up(&d->i2c_sem);
+       return i;
+}
+
+static u32 digitv_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm digitv_i2c_algo = {
+       .name          = "Nebula DigiTV USB I2C algorithm",
+       .id            = I2C_ALGO_BIT,
+       .master_xfer   = digitv_i2c_xfer,
+       .functionality = digitv_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int digitv_identify_state (struct usb_device *udev, struct
+               dvb_usb_properties *props, struct dvb_usb_device_description **desc,
+               int *cold)
+{
+       *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
+       return 0;
+}
+
+static int digitv_mt352_demod_init(struct dvb_frontend *fe)
+{
+       static u8 mt352_clock_config[] = { 0x89, 0x38, 0x2d };
+       static u8 mt352_reset[] = { 0x50, 0x80 };
+       static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
+
+       static u8 mt352_agc_cfg[] = { 0x68, 0xa0 };
+       static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0xa0 };
+       static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
+       static u8 mt352_agc_target[] = { 0x67, 0x20 };
+
+       static u8 mt352_rs_err_per[] = { 0x7c, 0x00, 0x01 };
+       static u8 mt352_snr_select[] = { 0x79, 0x00, 0x20 };
+
+       static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x05 };
+
+       static u8 mt352_scan_ctl[] = { 0x88, 0x0f };
+       static u8 mt352_capt_range[] = { 0x75, 0x32 };
+
+       mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+       mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+       msleep(1);
+       mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
+
+       mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
+       mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+       mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
+       mt352_write(fe, mt352_agc_target, sizeof(mt352_agc_target));
+
+
+       mt352_write(fe, mt352_rs_err_per, sizeof(mt352_rs_err_per));
+       mt352_write(fe, mt352_snr_select, sizeof(mt352_snr_select));
+
+       mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
+
+       mt352_write(fe, mt352_scan_ctl, sizeof(mt352_scan_ctl));
+       mt352_write(fe, mt352_capt_range, sizeof(mt352_capt_range));
+
+       return 0;
+}
+
+static struct mt352_config digitv_mt352_config = {
+       .demod_address = 0x0, /* ignored by the digitv anyway */
+       .demod_init = digitv_mt352_demod_init,
+       .pll_set = NULL, /* TODO */
+};
+
+static struct nxt6000_config digitv_nxt6000_config = {
+       .demod_address = 0x0, /* ignored by the digitv anyway */
+       .clock_inversion = 0x0,
+
+       .pll_init = NULL,
+       .pll_set = NULL,
+};
+
+static int digitv_frontend_attach(struct dvb_usb_device *d)
+{
+       if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) == NULL)
+               return 0;
+       if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) == NULL) {
+
+               warn("nxt6000 support is not done yet, in fact you are one of the first "
+                               "person who wants to use this device in Linux. Please report to "
+                               "linux-dvb@linuxtv.org");
+
+               return 0;
+       }
+       return -EIO;
+}
+
+static struct dvb_usb_rc_key digitv_rc_keys[] = {
+       { 0x00, 0x16, KEY_POWER }, /* dummy key */
+};
+
+/* TODO is it really the NEC protocol ? */
+int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+       u8 key[5];
+
+       digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4);
+       /* TODO state, maybe it is VV ? */
+       if (key[1] != 0)
+               key[0] = 0x01; /* if something is inside the buffer, simulate key press */
+
+       /* call the universal NEC remote processor, to find out the key's state and event */
+       dvb_usb_nec_rc_key_to_event(d,key,event,state);
+       if (key[0] != 0)
+               deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
+       return 0;
+}
+
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_properties digitv_properties;
+
+static int digitv_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       return dvb_usb_device_init(intf,&digitv_properties,THIS_MODULE);
+}
+
+static struct usb_device_id digitv_table [] = {
+               { USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) },
+               { }             /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, digitv_table);
+
+static struct dvb_usb_properties digitv_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl = CYPRESS_FX2,
+       .firmware = "dvb-usb-digitv-01.fw",
+
+       .size_of_priv     = 0,
+
+       .streaming_ctrl   = NULL,
+       .pid_filter       = NULL,
+       .pid_filter_ctrl  = NULL,
+       .power_ctrl       = NULL,
+       .frontend_attach  = digitv_frontend_attach,
+       .tuner_attach     = NULL, // digitv_tuner_attach,
+       .read_mac_address = NULL,
+
+       .rc_interval      = 1000,
+       .rc_key_map       = digitv_rc_keys,
+       .rc_key_map_size  = ARRAY_SIZE(digitv_rc_keys),
+       .rc_query         = digitv_rc_query,
+
+       .identify_state   = digitv_identify_state,
+
+       .i2c_algo         = &digitv_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 7,
+               .endpoint = 0x02,
+               .u = {
+                       .bulk = {
+                               .buffersize = 4096,
+                       }
+               }
+       },
+
+       .num_device_descs = 2,
+       .devices = {
+               {   "Nebula Electronics uDigiTV DVB-T USB2.0)",
+                       { &digitv_table[0], NULL },
+                       { NULL },
+               },
+       }
+};
+
+static struct usb_driver digitv_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "Nebula Electronics uDigiTV DVB-T USB2.0 device",
+       .probe          = digitv_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table       = digitv_table,
+};
+
+/* module stuff */
+static int __init digitv_module_init(void)
+{
+       int result;
+       if ((result = usb_register(&digitv_driver))) {
+               err("usb_register failed. Error number %d",result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit digitv_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&digitv_driver);
+}
+
+module_init (digitv_module_init);
+module_exit (digitv_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0");
+MODULE_VERSION("1.0-alpha");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h
new file mode 100644 (file)
index 0000000..477ee42
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef _DVB_USB_DIGITV_H_
+#define _DVB_USB_DIGITV_H_
+
+#define DVB_USB_LOG_PREFIX "digitv"
+#include "dvb-usb.h"
+
+extern int dvb_usb_digitv_debug;
+#define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
+
+/* protocol (from usblogging and the SDK:
+ *
+ * Always 7 bytes bulk message(s) for controlling
+ *
+ * First byte describes the command. Reads are 2 consecutive transfer (as always).
+ *
+ * General structure:
+ *
+ * write or first message of a read:
+ * <cmdbyte> VV <len> B0 B1 B2 B3
+ *
+ * second message of a read
+ * <cmdbyte> VV <len> R0 R1 R2 R3
+ *
+ * whereas 0 < len <= 4
+ *
+ * I2C address is stored somewhere inside the device.
+ *
+ * 0x01 read from EEPROM
+ *  VV = offset; B* = 0; R* = value(s)
+ *
+ * 0x02 read register of the COFDM
+ *  VV = register; B* = 0; R* = value(s)
+ *
+ * 0x05 write register of the COFDM
+ *  VV = register; B* = value(s);
+ *
+ * 0x06 write to the tuner (only for NXT6000)
+ *  VV = 0; B* = PLL data; len = 4;
+ *
+ * 0x03 read remote control
+ *  VV = 0; B* = 0; len = 4; R* = key
+ *
+ * 0x07 write to the remote (don't know why one should this, resetting ?)
+ *  VV = 0; B* = key; len = 4;
+ *
+ * 0x08 write remote type
+ *  VV = 0; B[0] = 0x01, len = 4
+ *
+ * 0x09 write device init
+ *  TODO
+ */
+#define USB_READ_EEPROM         1
+
+#define USB_READ_COFDM          2
+#define USB_WRITE_COFDM         5
+
+#define USB_WRITE_TUNER         6
+
+#define USB_READ_REMOTE         3
+#define USB_WRITE_REMOTE        7
+#define USB_WRITE_REMOTE_TYPE   8
+
+#define USB_DEV_INIT            9
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
new file mode 100644 (file)
index 0000000..d17d768
--- /dev/null
@@ -0,0 +1,206 @@
+/* Frontend part of the Linux driver for the Yakumo/Hama/Typhoon DVB-T
+ * USB2.0 receiver.
+ *
+ * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dtt200u.h"
+
+struct dtt200u_fe_state {
+       struct dvb_usb_device *d;
+
+       struct dvb_frontend_parameters fep;
+       struct dvb_frontend frontend;
+};
+
+#define moan(which,what) info("unexpected value in '%s' for cmd '%02x' - please report to linux-dvb@linuxtv.org",which,what)
+
+static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
+{
+       struct dtt200u_fe_state *state = fe->demodulator_priv;
+       u8 bw = GET_TUNE_STAT;
+       u8 br[3] = { 0 };
+//     u8 bdeb[5] = { 0 };
+
+       dvb_usb_generic_rw(state->d,&bw,1,br,3,0);
+       switch (br[0]) {
+               case 0x01:
+                       *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+                       break;
+               case 0x00:
+                       *stat = 0;
+                       break;
+               default:
+                       moan("br[0]",GET_TUNE_STAT);
+                       break;
+       }
+
+//     bw[0] = 0x88;
+//     dvb_usb_generic_rw(state->d,bw,1,bdeb,5,0);
+
+//     deb_info("%02x: %02x %02x %02x %02x %02x\n",bw[0],bdeb[0],bdeb[1],bdeb[2],bdeb[3],bdeb[4]);
+
+       return 0;
+}
+static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+       struct dtt200u_fe_state *state = fe->demodulator_priv;
+       u8 bw = GET_BER;
+       *ber = 0;
+       dvb_usb_generic_rw(state->d,&bw,1,(u8*) ber,3,0);
+       return 0;
+}
+
+static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+       struct dtt200u_fe_state *state = fe->demodulator_priv;
+       u8 bw = GET_UNK;
+       *unc = 0;
+       dvb_usb_generic_rw(state->d,&bw,1,(u8*) unc,3,0);
+       return 0;
+}
+
+static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+       struct dtt200u_fe_state *state = fe->demodulator_priv;
+       u8 bw = GET_SIG_STRENGTH, b;
+       dvb_usb_generic_rw(state->d,&bw,1,&b,1,0);
+       *strength = (b << 8) | b;
+       return 0;
+}
+
+static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+       struct dtt200u_fe_state *state = fe->demodulator_priv;
+       u8 bw = GET_SNR,br;
+       dvb_usb_generic_rw(state->d,&bw,1,&br,1,0);
+       *snr = ~((br << 8) | br);
+       return 0;
+}
+
+static int dtt200u_fe_init(struct dvb_frontend* fe)
+{
+       struct dtt200u_fe_state *state = fe->demodulator_priv;
+       u8 b = RESET_DEMOD;
+       return dvb_usb_generic_write(state->d,&b,1);
+}
+
+static int dtt200u_fe_sleep(struct dvb_frontend* fe)
+{
+       return dtt200u_fe_init(fe);
+}
+
+static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+       tune->min_delay_ms = 1500;
+       tune->step_size = 166667;
+       tune->max_drift = 166667 * 2;
+       return 0;
+}
+
+static int dtt200u_fe_set_frontend(struct dvb_frontend* fe,
+                                 struct dvb_frontend_parameters *fep)
+{
+       struct dtt200u_fe_state *state = fe->demodulator_priv;
+       u16 freq = fep->frequency / 250000;
+       u8 bw,bwbuf[2] = { SET_BANDWIDTH, 0 }, freqbuf[3] = { SET_FREQUENCY, 0, 0 };
+
+       switch (fep->u.ofdm.bandwidth) {
+               case BANDWIDTH_8_MHZ: bw = 8; break;
+               case BANDWIDTH_7_MHZ: bw = 7; break;
+               case BANDWIDTH_6_MHZ: bw = 6; break;
+               case BANDWIDTH_AUTO: return -EOPNOTSUPP;
+               default:
+                       return -EINVAL;
+       }
+       deb_info("set_frontend\n");
+
+       bwbuf[1] = bw;
+       dvb_usb_generic_write(state->d,bwbuf,2);
+
+       freqbuf[1] = freq & 0xff;
+       freqbuf[2] = (freq >> 8) & 0xff;
+       dvb_usb_generic_write(state->d,freqbuf,3);
+
+       memcpy(&state->fep,fep,sizeof(struct dvb_frontend_parameters));
+
+       return 0;
+}
+
+static int dtt200u_fe_get_frontend(struct dvb_frontend* fe,
+                                 struct dvb_frontend_parameters *fep)
+{
+       struct dtt200u_fe_state *state = fe->demodulator_priv;
+       memcpy(fep,&state->fep,sizeof(struct dvb_frontend_parameters));
+       return 0;
+}
+
+static void dtt200u_fe_release(struct dvb_frontend* fe)
+{
+       struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops dtt200u_fe_ops;
+
+struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d)
+{
+       struct dtt200u_fe_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct dtt200u_fe_state*) kmalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+       memset(state,0,sizeof(struct dtt200u_fe_state));
+
+       deb_info("attaching frontend dtt200u\n");
+
+       state->d = d;
+
+       state->frontend.ops = &dtt200u_fe_ops;
+       state->frontend.demodulator_priv = state;
+
+       goto success;
+error:
+       return NULL;
+success:
+       return &state->frontend;
+}
+
+static struct dvb_frontend_ops dtt200u_fe_ops = {
+       .info = {
+               .name                   = "DTT200U (Yakumo/Typhoon/Hama) DVB-T",
+               .type                   = FE_OFDM,
+               .frequency_min          = 44250000,
+               .frequency_max          = 867250000,
+               .frequency_stepsize     = 250000,
+               .caps = FE_CAN_INVERSION_AUTO |
+                               FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                               FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                               FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                               FE_CAN_TRANSMISSION_MODE_AUTO |
+                               FE_CAN_GUARD_INTERVAL_AUTO |
+                               FE_CAN_RECOVER |
+                               FE_CAN_HIERARCHY_AUTO,
+       },
+
+       .release = dtt200u_fe_release,
+
+       .init = dtt200u_fe_init,
+       .sleep = dtt200u_fe_sleep,
+
+       .set_frontend = dtt200u_fe_set_frontend,
+       .get_frontend = dtt200u_fe_get_frontend,
+       .get_tune_settings = dtt200u_fe_get_tune_settings,
+
+       .read_status = dtt200u_fe_read_status,
+       .read_ber = dtt200u_fe_read_ber,
+       .read_signal_strength = dtt200u_fe_read_signal_strength,
+       .read_snr = dtt200u_fe_read_snr,
+       .read_ucblocks = dtt200u_fe_read_unc_blocks,
+};
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
new file mode 100644 (file)
index 0000000..fb2b5a2
--- /dev/null
@@ -0,0 +1,171 @@
+/* DVB USB library compliant Linux driver for the Yakumo/Hama/Typhoon DVB-T
+ * USB2.0 receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dtt200u.h"
+
+/* debug */
+int dvb_usb_dtt200u_debug;
+module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS);
+
+static int dtt200u_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       u8 b_streaming[2] = { SET_TS_CTRL, onoff };
+       u8 b_rst_pid = RESET_PID_FILTER;
+
+       dvb_usb_generic_write(d,b_streaming,2);
+
+       if (!onoff)
+               dvb_usb_generic_write(d,&b_rst_pid,1);
+       return 0;
+}
+
+static int dtt200u_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff)
+{
+       u8 b_pid[4];
+       pid = onoff ? pid : 0;
+
+       b_pid[0] = SET_PID_FILTER;
+       b_pid[1] = index;
+       b_pid[2] = pid & 0xff;
+       b_pid[3] = (pid >> 8) & 0xff;
+
+       return dvb_usb_generic_write(d,b_pid,4);
+}
+
+/* remote control */
+/* key list for the tiny remote control (Yakumo, don't know about the others) */
+static struct dvb_usb_rc_key dtt200u_rc_keys[] = {
+       { 0x80, 0x01, KEY_MUTE },
+       { 0x80, 0x02, KEY_CHANNELDOWN },
+       { 0x80, 0x03, KEY_VOLUMEDOWN },
+       { 0x80, 0x04, KEY_1 },
+       { 0x80, 0x05, KEY_2 },
+       { 0x80, 0x06, KEY_3 },
+       { 0x80, 0x07, KEY_4 },
+       { 0x80, 0x08, KEY_5 },
+       { 0x80, 0x09, KEY_6 },
+       { 0x80, 0x0a, KEY_7 },
+       { 0x00, 0x0c, KEY_ZOOM },
+       { 0x80, 0x0d, KEY_0 },
+       { 0x00, 0x0e, KEY_SELECT },
+       { 0x80, 0x12, KEY_POWER },
+       { 0x80, 0x1a, KEY_CHANNELUP },
+       { 0x80, 0x1b, KEY_8 },
+       { 0x80, 0x1e, KEY_VOLUMEUP },
+       { 0x80, 0x1f, KEY_9 },
+};
+
+static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+       u8 key[5],cmd = GET_RC_KEY;
+       dvb_usb_generic_rw(d,&cmd,1,key,5,0);
+       dvb_usb_nec_rc_key_to_event(d,key,event,state);
+       if (key[0] != 0)
+               deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
+       return 0;
+}
+
+static int dtt200u_frontend_attach(struct dvb_usb_device *d)
+{
+       d->fe = dtt200u_fe_attach(d);
+       return 0;
+}
+
+static struct dvb_usb_properties dtt200u_properties;
+
+static int dtt200u_usb_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       return dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE);
+}
+
+static struct usb_device_id dtt200u_usb_table [] = {
+           { USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_DTT200U_COLD) },
+           { USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_DTT200U_WARM) },
+           { 0 },
+};
+MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
+
+static struct dvb_usb_properties dtt200u_properties = {
+       .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
+       .pid_filter_count = 255, /* It is a guess, but there are at least 10 */
+
+       .usb_ctrl = CYPRESS_FX2,
+       .firmware = "dvb-usb-dtt200u-01.fw",
+
+       .streaming_ctrl  = dtt200u_streaming_ctrl,
+       .pid_filter      = dtt200u_pid_filter,
+       .frontend_attach = dtt200u_frontend_attach,
+
+       .rc_interval     = 200,
+       .rc_key_map      = dtt200u_rc_keys,
+       .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
+       .rc_query        = dtt200u_rc_query,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 7,
+               .endpoint = 0x02,
+               .u = {
+                       .bulk = {
+                               .buffersize = 4096,
+                       }
+               }
+       },
+
+       .num_device_descs = 1,
+       .devices = {
+               { .name = "Yakumo/Hama/Typhoon DVB-T USB2.0)",
+                 .cold_ids = { &dtt200u_usb_table[0], &dtt200u_usb_table[2] },
+                 .warm_ids = { &dtt200u_usb_table[1], NULL },
+               },
+               { 0 },
+       }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver dtt200u_usb_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "Yakumo/Hama/Typhoon DVB-T USB2.0",
+       .probe          = dtt200u_usb_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table       = dtt200u_usb_table,
+};
+
+/* module stuff */
+static int __init dtt200u_usb_module_init(void)
+{
+       int result;
+       if ((result = usb_register(&dtt200u_usb_driver))) {
+               err("usb_register failed. (%d)",result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit dtt200u_usb_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&dtt200u_usb_driver);
+}
+
+module_init(dtt200u_usb_module_init);
+module_exit(dtt200u_usb_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for the Yakumo/Hama/Typhoon DVB-T USB2.0 device");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/dvb/dvb-usb/dtt200u.h
new file mode 100644 (file)
index 0000000..ed41420
--- /dev/null
@@ -0,0 +1,66 @@
+/* Common header file of Linux driver for the Yakumo/Hama/Typhoon DVB-T
+ * USB2.0 receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_DTT200U_H_
+#define _DVB_USB_DTT200U_H_
+
+#define DVB_USB_LOG_PREFIX "dtt200u"
+#include "dvb-usb.h"
+
+extern int dvb_usb_dtt200u_debug;
+#define deb_info(args...) dprintk(dvb_usb_dtt200u_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_dtt200u_debug,0x02,args)
+
+/* guessed protocol description (reverse engineered):
+ * read
+ *  00 - USB type 0x02 for usb2.0, 0x01 for usb1.1
+ *  81 - <TS_LOCK> <current frequency divided by 250000>
+ *  82 - crash - do not touch
+ *  83 - crash - do not touch
+ *  84 - remote control
+ *  85 - crash - do not touch (OK, stop testing here)
+ *  88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
+ *  89 - noise-to-signal
+ *     8a - unkown 1 byte - signal_strength
+ *  8c - ber ???
+ *  8d - ber
+ *  8e - unc
+ */
+
+#define GET_SPEED        0x00
+#define GET_TUNE_STAT    0x81
+#define GET_RC_KEY       0x84
+#define GET_STATUS       0x88
+#define GET_SNR          0x89
+#define GET_SIG_STRENGTH 0x8a
+#define GET_UNK          0x8c
+#define GET_BER          0x8d
+#define GET_UNC          0x8e
+
+/* write
+ *  01 - reset the demod
+ *  02 - frequency (divided by 250000)
+ *  03 - bandwidth
+ *  04 - pid table (index pid(7:0) pid(12:8))
+ *  05 - reset the pid table
+ *  08 - demod transfer enabled or not (FX2 transfer is enabled by default)
+ */
+
+#define RESET_DEMOD      0x01
+#define SET_FREQUENCY    0x02
+#define SET_BANDWIDTH    0x03
+#define SET_PID_FILTER   0x04
+#define RESET_PID_FILTER 0x05
+#define SET_TS_CTRL      0x08
+
+extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d);
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
new file mode 100644 (file)
index 0000000..67e0d73
--- /dev/null
@@ -0,0 +1,44 @@
+/* dvb-usb-common.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * a header file containing prototypes and types for internal use of the dvb-usb-lib
+ */
+#ifndef _DVB_USB_COMMON_H_
+#define _DVB_USB_COMMON_H_
+
+#define DVB_USB_LOG_PREFIX "dvb-usb"
+#include "dvb-usb.h"
+
+extern int dvb_usb_debug;
+
+#define deb_info(args...) dprintk(dvb_usb_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_debug,0x02,args)
+#define deb_pll(args...) dprintk(dvb_usb_debug,0x04,args)
+#define deb_ts(args...)   dprintk(dvb_usb_debug,0x08,args)
+#define deb_err(args...)  dprintk(dvb_usb_debug,0x10,args)
+#define deb_rc(args...)   dprintk(dvb_usb_debug,0x20,args)
+#define deb_fw(args...)   dprintk(dvb_usb_debug,0x40,args)
+
+/* commonly used  methods */
+extern int usb_cypress_load_firmware(struct usb_device *, const char *, int);
+
+extern int dvb_usb_urb_submit(struct dvb_usb_device *);
+extern int dvb_usb_urb_kill(struct dvb_usb_device *);
+extern int dvb_usb_urb_init(struct dvb_usb_device *);
+extern int dvb_usb_urb_exit(struct dvb_usb_device *);
+
+extern int dvb_usb_i2c_init(struct dvb_usb_device *);
+extern int dvb_usb_i2c_exit(struct dvb_usb_device *);
+
+extern int dvb_usb_dvb_init(struct dvb_usb_device *);
+extern int dvb_usb_dvb_exit(struct dvb_usb_device *);
+
+extern int dvb_usb_fe_init(struct dvb_usb_device *);
+extern int dvb_usb_fe_exit(struct dvb_usb_device *);
+
+extern int dvb_usb_remote_init(struct dvb_usb_device *);
+extern int dvb_usb_remote_exit(struct dvb_usb_device *);
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
new file mode 100644 (file)
index 0000000..bdd72f7
--- /dev/null
@@ -0,0 +1,210 @@
+/* dvb-usb-dvb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing and handling the
+ * linux-dvb API.
+ */
+#include "dvb-usb-common.h"
+
+static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+       struct dvb_usb_device *d = dvbdmxfeed->demux->priv;
+       int newfeedcount,ret;
+
+       if (d == NULL)
+               return -ENODEV;
+
+       newfeedcount = d->feedcount + (onoff ? 1 : -1);
+
+       /*
+        * stop feed before setting a new pid if there will be no pid anymore
+        */
+       if (newfeedcount == 0) {
+               deb_ts("stop feeding\n");
+
+               if (d->props.streaming_ctrl != NULL)
+                       if ((ret = d->props.streaming_ctrl(d,0)))
+                               err("error while stopping stream.");
+
+               dvb_usb_urb_kill(d);
+       }
+
+       d->feedcount = newfeedcount;
+
+       /* activate the pid on the device specific pid_filter */
+       deb_ts("setting pid: %5d %04x at index %d '%s'\n",dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? "on" : "off");
+       if (d->props.caps & DVB_USB_HAS_PID_FILTER &&
+               d->pid_filtering &&
+               d->props.pid_filter != NULL)
+               d->props.pid_filter(d,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
+
+       /* start the feed if this was the first feed and there is still a feed
+        * for reception.
+        */
+       if (d->feedcount == onoff && d->feedcount > 0) {
+
+               deb_ts("controlling pid parser\n");
+               if (d->props.caps & DVB_USB_HAS_PID_FILTER &&
+                       d->props.caps & DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF &&
+                       d->props.pid_filter_ctrl != NULL)
+                       if (d->props.pid_filter_ctrl(d,d->pid_filtering) < 0)
+                               err("could not handle pid_parser");
+
+               deb_ts("start feeding\n");
+               if (d->props.streaming_ctrl != NULL)
+                       if (d->props.streaming_ctrl(d,1)) {
+                               err("error while enabling fifo.");
+                               return -ENODEV;
+                       }
+
+               dvb_usb_urb_submit(d);
+       }
+       return 0;
+}
+
+static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
+       return dvb_usb_ctrl_feed(dvbdmxfeed,1);
+}
+
+static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
+       return dvb_usb_ctrl_feed(dvbdmxfeed,0);
+}
+
+int dvb_usb_dvb_init(struct dvb_usb_device *d)
+{
+       int ret;
+
+       if ((ret = dvb_register_adapter(&d->dvb_adap, d->desc->name,
+                       d->owner)) < 0) {
+               deb_info("dvb_register_adapter failed: error %d", ret);
+               goto err;
+       }
+       d->dvb_adap.priv = d;
+
+       if (d->props.read_mac_address) {
+               if (d->props.read_mac_address(d,d->dvb_adap.proposed_mac) == 0)
+                       info("MAC address: %02x:%02x:%02x:%02x:%02x:%02x",d->dvb_adap.proposed_mac[0],
+                                       d->dvb_adap.proposed_mac[1],d->dvb_adap.proposed_mac[2],
+                                       d->dvb_adap.proposed_mac[3],d->dvb_adap.proposed_mac[4],
+                                       d->dvb_adap.proposed_mac[5]);
+               else
+                       err("MAC address reading failed.");
+       }
+
+
+       d->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+       d->demux.priv = d;
+
+       d->demux.feednum = d->demux.filternum = d->max_feed_count;
+       d->demux.start_feed = dvb_usb_start_feed;
+       d->demux.stop_feed  = dvb_usb_stop_feed;
+       d->demux.write_to_decoder = NULL;
+       if ((ret = dvb_dmx_init(&d->demux)) < 0) {
+               err("dvb_dmx_init failed: error %d",ret);
+               goto err_dmx;
+       }
+
+       d->dmxdev.filternum = d->demux.filternum;
+       d->dmxdev.demux = &d->demux.dmx;
+       d->dmxdev.capabilities = 0;
+       if ((ret = dvb_dmxdev_init(&d->dmxdev, &d->dvb_adap)) < 0) {
+               err("dvb_dmxdev_init failed: error %d",ret);
+               goto err_dmx_dev;
+       }
+
+       dvb_net_init(&d->dvb_adap, &d->dvb_net, &d->demux.dmx);
+
+       goto success;
+err_dmx_dev:
+       dvb_dmx_release(&d->demux);
+err_dmx:
+       dvb_unregister_adapter(&d->dvb_adap);
+err:
+       return ret;
+success:
+       d->state |= DVB_USB_STATE_DVB;
+       return 0;
+}
+
+int dvb_usb_dvb_exit(struct dvb_usb_device *d)
+{
+       if (d->state & DVB_USB_STATE_DVB) {
+               deb_info("unregistering DVB part\n");
+               dvb_net_release(&d->dvb_net);
+               d->demux.dmx.close(&d->demux.dmx);
+               dvb_dmxdev_release(&d->dmxdev);
+               dvb_dmx_release(&d->demux);
+               dvb_unregister_adapter(&d->dvb_adap);
+               d->state &= ~DVB_USB_STATE_DVB;
+       }
+       return 0;
+}
+
+static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
+{
+       struct dvb_usb_device *d = fe->dvb->priv;
+
+       if (d->props.power_ctrl)
+               d->props.power_ctrl(d,1);
+
+       if (d->fe_init)
+               d->fe_init(fe);
+
+       return 0;
+}
+
+static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
+{
+       struct dvb_usb_device *d = fe->dvb->priv;
+
+       if (d->fe_sleep)
+               d->fe_sleep(fe);
+
+       if (d->props.power_ctrl)
+               d->props.power_ctrl(d,0);
+
+       return 0;
+}
+
+int dvb_usb_fe_init(struct dvb_usb_device* d)
+{
+       if (d->props.frontend_attach == NULL) {
+               err("strange '%s' don't want to attach a frontend.",d->desc->name);
+               return 0;
+       }
+
+       d->props.frontend_attach(d);
+
+       /* re-assign sleep and wakeup functions */
+       if (d->fe != NULL) {
+               d->fe_init = d->fe->ops->init;   d->fe->ops->init  = dvb_usb_fe_wakeup;
+               d->fe_sleep = d->fe->ops->sleep; d->fe->ops->sleep = dvb_usb_fe_sleep;
+
+               if (dvb_register_frontend(&d->dvb_adap, d->fe)) {
+                       err("Frontend registration failed.");
+                       if (d->fe->ops->release)
+                               d->fe->ops->release(d->fe);
+                       d->fe = NULL;
+                       return -ENODEV;
+               }
+       } else
+               err("no frontend was attached by '%s'",d->desc->name);
+
+       if (d->props.tuner_attach != NULL)
+               d->props.tuner_attach(d);
+
+       return 0;
+}
+
+int dvb_usb_fe_exit(struct dvb_usb_device *d)
+{
+       if (d->fe != NULL)
+               dvb_unregister_frontend(d->fe);
+       return 0;
+}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
new file mode 100644 (file)
index 0000000..5244e39
--- /dev/null
@@ -0,0 +1,100 @@
+/* dvb-usb-firmware.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices.
+ *
+ * FIXME: This part does actually not belong to dvb-usb, but to the usb-subsystem.
+ */
+#include "dvb-usb-common.h"
+
+#include <linux/firmware.h>
+#include <linux/usb.h>
+
+struct usb_cypress_controller {
+       int id;
+       const char *name;       /* name of the usb controller */
+       u16 cpu_cs_register;    /* needs to be restarted, when the firmware has been downloaded. */
+};
+
+static struct usb_cypress_controller cypress[] = {
+       { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 },
+       { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 },
+       { .id = CYPRESS_FX2,    .name = "Cypress FX2",    .cpu_cs_register = 0xe600 },
+};
+
+/*
+ * load a firmware packet to the device
+ */
+static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
+{
+       return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
+                       0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ);
+}
+
+int usb_cypress_load_firmware(struct usb_device *udev, const char *filename, int type)
+{
+       const struct firmware *fw = NULL;
+       u16 addr;
+       u8 *b,*p;
+       int ret = 0,i;
+
+       if ((ret = request_firmware(&fw, filename, &udev->dev)) != 0) {
+               err("did not find the firmware file. (%s) "
+                       "Please see linux/Documentation/dvb/ for more details on firmware-problems.",
+                       filename);
+               return ret;
+       }
+
+       info("downloading firmware from file '%s' to the '%s'",filename,cypress[type].name);
+
+       p = kmalloc(fw->size,GFP_KERNEL);
+       if (p != NULL) {
+               u8 reset;
+               /*
+                * you cannot use the fw->data as buffer for
+                * usb_control_msg, a new buffer has to be
+                * created
+                */
+               memcpy(p,fw->data,fw->size);
+
+               /* stop the CPU */
+               reset = 1;
+               if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
+                       err("could not stop the USB controller CPU.");
+               for(i = 0; p[i+3] == 0 && i < fw->size; ) {
+                       b = (u8 *) &p[i];
+                       addr = cpu_to_le16( *((u16 *) &b[1]) );
+
+                       deb_fw("writing to address 0x%04x (buffer: 0x%02x%02x)\n",addr,b[1],b[2]);
+
+                       ret = usb_cypress_writemem(udev,addr,&b[4],b[0]);
+
+                       if (ret != b[0]) {
+                               err("error while transferring firmware "
+                                       "(transferred size: %d, block size: %d)",
+                                       ret,b[0]);
+                               ret = -EINVAL;
+                               break;
+                       }
+                       i += 5 + b[0];
+               }
+               /* length in ret */
+               if (ret > 0)
+                       ret = 0;
+               /* restart the CPU */
+               reset = 0;
+               if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
+                       err("could not restart the USB controller CPU.");
+                       ret = -EINVAL;
+               }
+
+               kfree(p);
+       } else {
+               ret = -ENOMEM;
+       }
+       release_firmware(fw);
+
+       return ret;
+}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
new file mode 100644 (file)
index 0000000..9f0a8d9
--- /dev/null
@@ -0,0 +1,118 @@
+/* dvb-usb-i2c.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for (de-)initializing an I2C adapter.
+ */
+#include "dvb-usb-common.h"
+
+int dvb_usb_i2c_init(struct dvb_usb_device *d)
+{
+       int ret = 0;
+
+       if (!(d->props.caps & DVB_USB_IS_AN_I2C_ADAPTER))
+               return 0;
+
+       if (d->props.i2c_algo == NULL) {
+               err("no i2c algorithm specified");
+               return -EINVAL;
+       }
+
+       strncpy(d->i2c_adap.name,d->desc->name,I2C_NAME_SIZE);
+#ifdef I2C_ADAP_CLASS_TV_DIGITAL
+       d->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
+#else
+       d->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
+#endif
+       d->i2c_adap.algo      = d->props.i2c_algo;
+       d->i2c_adap.algo_data = NULL;
+       d->i2c_adap.id        = I2C_ALGO_BIT;
+
+       i2c_set_adapdata(&d->i2c_adap, d);
+
+       if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0)
+               err("could not add i2c adapter");
+
+       d->state |= DVB_USB_STATE_I2C;
+
+       return ret;
+}
+
+int dvb_usb_i2c_exit(struct dvb_usb_device *d)
+{
+       if (d->state & DVB_USB_STATE_I2C)
+               i2c_del_adapter(&d->i2c_adap);
+       d->state &= ~DVB_USB_STATE_I2C;
+       return 0;
+}
+
+int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
+{
+       struct dvb_usb_device *d = fe->dvb->priv;
+       struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
+       int ret = 0;
+
+       /* if there is nothing to initialize */
+       if (d->pll_init[0] == 0x00 && d->pll_init[1] == 0x00 &&
+               d->pll_init[2] == 0x00 && d->pll_init[3] == 0x00)
+               return 0;
+
+       if (d->tuner_pass_ctrl)
+               d->tuner_pass_ctrl(fe,1,d->pll_addr);
+
+       deb_pll("pll init: %x\n",d->pll_addr);
+       deb_pll("pll-buf: %x %x %x %x\n",d->pll_init[0],d->pll_init[1],
+                       d->pll_init[2],d->pll_init[3]);
+
+       if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
+               err("tuner i2c write failed for pll_init.");
+               ret = -EREMOTEIO;
+       }
+       msleep(1);
+
+       if (d->tuner_pass_ctrl)
+               d->tuner_pass_ctrl(fe,0,d->pll_addr);
+       return ret;
+}
+EXPORT_SYMBOL(dvb_usb_pll_init_i2c);
+
+int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 b[5])
+{
+       struct dvb_usb_device *d = fe->dvb->priv;
+
+       deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
+
+       b[0] = d->pll_addr << 1;
+       dvb_pll_configure(d->pll_desc,&b[1],fep->frequency,fep->u.ofdm.bandwidth);
+
+       deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
+
+       return 0;
+}
+EXPORT_SYMBOL(dvb_usb_pll_set);
+
+int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+{
+       struct dvb_usb_device *d = fe->dvb->priv;
+       int ret = 0;
+       u8 b[5];
+       struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
+
+       dvb_usb_pll_set(fe,fep,b);
+
+       if (d->tuner_pass_ctrl)
+               d->tuner_pass_ctrl(fe,1,d->pll_addr);
+
+       if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
+               err("tuner i2c write failed for pll_set.");
+               ret = -EREMOTEIO;
+       }
+       msleep(1);
+
+       if (d->tuner_pass_ctrl)
+               d->tuner_pass_ctrl(fe,0,d->pll_addr);
+
+       return ret;
+}
+EXPORT_SYMBOL(dvb_usb_pll_set_i2c);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
new file mode 100644 (file)
index 0000000..bcb3419
--- /dev/null
@@ -0,0 +1,83 @@
+/* dvb-usb-ids.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) see
+ * dvb-usb-init.c for copyright information.
+ *
+ * a header file containing define's for the USB device supported by the
+ * various drivers.
+ */
+#ifndef _DVB_USB_IDS_H_
+#define _DVB_USB_IDS_H_
+
+/* Vendor IDs */
+#define USB_VID_ADSTECH                                                0x06e1
+#define USB_VID_ANCHOR                                         0x0547
+#define USB_VID_AVERMEDIA_UNK                          0x14aa
+#define USB_VID_AVERMEDIA                                      0x07ca
+#define USB_VID_COMPRO                                         0x185b
+#define USB_VID_COMPRO_UNK                                     0x145f
+#define USB_VID_CYPRESS                                                0x04b4
+#define USB_VID_DIBCOM                                         0x10b8
+#define USB_VID_DVICO                                          0x0fe9
+#define USB_VID_EMPIA                                          0xeb1a
+#define USB_VID_GRANDTEC                                       0x5032
+#define USB_VID_HANFTEK                                                0x15f4
+#define USB_VID_HAUPPAUGE                                      0x2040
+#define USB_VID_HYPER_PALTEK                           0x1025
+#define USB_VID_VISIONPLUS                                     0x13d3
+#define USB_VID_TWINHAN                                                0x1822
+#define USB_VID_ULTIMA_ELECTRONIC                      0x05d8
+
+/* Product IDs */
+#define USB_PID_ADSTECH_USB2_COLD                      0xa333
+#define USB_PID_ADSTECH_USB2_WARM                      0xa334
+#define USB_PID_AVERMEDIA_DVBT_USB_COLD                0x0001
+#define USB_PID_AVERMEDIA_DVBT_USB_WARM                0x0002
+#define USB_PID_AVERMEDIA_DVBT_USB2_COLD       0xa800
+#define USB_PID_AVERMEDIA_DVBT_USB2_WARM       0xa801
+#define USB_PID_COMPRO_DVBU2000_COLD           0xd000
+#define USB_PID_COMPRO_DVBU2000_WARM           0xd001
+#define USB_PID_COMPRO_DVBU2000_UNK_COLD       0x010c
+#define USB_PID_COMPRO_DVBU2000_UNK_WARM       0x010d
+#define USB_PID_DIBCOM_MOD3000_COLD                    0x0bb8
+#define USB_PID_DIBCOM_MOD3000_WARM                    0x0bb9
+#define USB_PID_DIBCOM_MOD3001_COLD                    0x0bc6
+#define USB_PID_DIBCOM_MOD3001_WARM                    0x0bc7
+#define USB_PID_DIBCOM_ANCHOR_2135_COLD                0x2131
+#define USB_PID_GRANDTEC_DVBT_USB_COLD         0x0fa0
+#define USB_PID_GRANDTEC_DVBT_USB_WARM         0x0fa1
+#define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
+#define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
+#define USB_PID_TWINHAN_VP7041_COLD                    0x3201
+#define USB_PID_TWINHAN_VP7041_WARM                    0x3202
+#define USB_PID_TWINHAN_VP7045_COLD                    0x3205
+#define USB_PID_TWINHAN_VP7045_WARM                    0x3206
+#define USB_PID_DNTV_TINYUSB2_COLD                     0x3223
+#define USB_PID_DNTV_TINYUSB2_WARM                     0x3224
+#define USB_PID_TWINHAN_VP7021_COLD                    0x3207
+#define USB_PID_TWINHAN_VP7021_WARM                    0x3208
+#define USB_PID_ULTIMA_TVBOX_COLD                      0x8105
+#define USB_PID_ULTIMA_TVBOX_WARM                      0x8106
+#define USB_PID_ULTIMA_TVBOX_AN2235_COLD       0x8107
+#define USB_PID_ULTIMA_TVBOX_AN2235_WARM       0x8108
+#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD       0x2235
+#define USB_PID_ULTIMA_TVBOX_USB2_COLD         0x8109
+#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD      0x8613
+#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM      0x1002
+#define USB_PID_UNK_HYPER_PALTEK_COLD          0x005e
+#define USB_PID_UNK_HYPER_PALTEK_WARM          0x005f
+#define USB_PID_HANFTEK_UMT_010_COLD           0x0001
+#define USB_PID_HANFTEK_UMT_010_WARM           0x0015
+#define USB_PID_DTT200U_COLD                           0x0201
+#define USB_PID_DTT200U_WARM                           0x0301
+#define USB_PID_WINTV_NOVA_T_USB2_COLD         0x9300
+#define USB_PID_WINTV_NOVA_T_USB2_WARM         0x9301
+#define USB_PID_NEBULA_DIGITV                          0x0201
+#define USB_PID_DVICO_BLUEBIRD_LGZ201          0xdb00
+#define USB_PID_DVICO_BLUEBIRD_TH7579          0xdb10
+#define USB_PID_DVICO_BLUEBIRD_LGDT                    0xd820
+#define USB_PID_DVICO_BLUEBIRD_LGZ201_1                0xdb01
+#define USB_PID_DVICO_BLUEBIRD_TH7579_2                0xdb11
+
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
new file mode 100644 (file)
index 0000000..3aadec9
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * DVB USB library - provides a generic interface for a DVB USB device driver.
+ *
+ * dvb-usb-init.c
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dvb-usb-common.h"
+
+/* debug */
+int dvb_usb_debug;
+module_param_named(debug,dvb_usb_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." DVB_USB_DEBUG_STATUS);
+
+/* general initialization functions */
+int dvb_usb_exit(struct dvb_usb_device *d)
+{
+       deb_info("state before exiting everything: %x\n",d->state);
+       dvb_usb_remote_exit(d);
+       dvb_usb_fe_exit(d);
+       dvb_usb_i2c_exit(d);
+       dvb_usb_dvb_exit(d);
+       dvb_usb_urb_exit(d);
+       deb_info("state should be zero now: %x\n",d->state);
+       d->state = DVB_USB_STATE_INIT;
+       kfree(d->priv);
+       kfree(d);
+       return 0;
+}
+
+static int dvb_usb_init(struct dvb_usb_device *d)
+{
+       int ret = 0;
+
+       sema_init(&d->usb_sem, 1);
+       sema_init(&d->i2c_sem, 1);
+
+       d->state = DVB_USB_STATE_INIT;
+
+/* check the capabilites and set appropriate variables */
+
+/* speed - when running at FULL speed we need a HW PID filter */
+       if (d->udev->speed == USB_SPEED_FULL && !(d->props.caps & DVB_USB_HAS_PID_FILTER)) {
+               err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a HW PID filter)");
+               return -ENODEV;
+       }
+
+       if ((d->udev->speed == USB_SPEED_FULL && d->props.caps & DVB_USB_HAS_PID_FILTER) ||
+               (d->props.caps & DVB_USB_NEED_PID_FILTERING)) {
+               info("will use the device's hw PID filter.");
+               d->pid_filtering = 1;
+               d->max_feed_count = d->props.pid_filter_count;
+       } else {
+               info("will pass the complete MPEG2 transport stream to the demuxer.");
+               d->pid_filtering = 0;
+               d->max_feed_count = 255;
+       }
+
+       if (d->props.power_ctrl)
+               d->props.power_ctrl(d,1);
+
+       if ((ret = dvb_usb_urb_init(d)) ||
+               (ret = dvb_usb_dvb_init(d)) ||
+               (ret = dvb_usb_i2c_init(d)) ||
+               (ret = dvb_usb_fe_init(d))) {
+               dvb_usb_exit(d);
+               return ret;
+       }
+
+       if ((ret = dvb_usb_remote_init(d)))
+               err("could not initialize remote control.");
+
+       if (d->props.power_ctrl)
+               d->props.power_ctrl(d,0);
+
+       return 0;
+}
+
+/* determine the name and the state of the just found USB device */
+static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_properties *props, int *cold)
+{
+       int i,j;
+       struct dvb_usb_device_description *desc = NULL;
+       *cold = -1;
+
+       for (i = 0; i < props->num_device_descs; i++) {
+
+               for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) {
+                       deb_info("check for cold %x %x\n",props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
+                       if (props->devices[i].cold_ids[j]->idVendor  == le16_to_cpu(udev->descriptor.idVendor) &&
+                               props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
+                               *cold = 1;
+                               desc = &props->devices[i];
+                               break;
+                       }
+               }
+
+               if (desc != NULL)
+                       break;
+
+               for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) {
+                       deb_info("check for warm %x %x\n",props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
+                       if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
+                               props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
+                               *cold = 0;
+                               desc = &props->devices[i];
+                               break;
+                       }
+               }
+       }
+
+       if (desc != NULL && props->identify_state != NULL)
+               props->identify_state(udev,props,&desc,cold);
+
+       return desc;
+}
+
+/*
+ * USB
+ */
+int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties *props, struct module *owner)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct dvb_usb_device *d = NULL;
+       struct dvb_usb_device_description *desc = NULL;
+
+       int ret = -ENOMEM,cold=0;
+
+       if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) {
+               deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
+               return -ENODEV;
+       }
+
+       if (cold) {
+               info("found a '%s' in cold state, will try to load a firmware",desc->name);
+               ret = usb_cypress_load_firmware(udev,props->firmware,props->usb_ctrl);
+       } else {
+               info("found a '%s' in warm state.",desc->name);
+               d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
+               if (d == NULL) {
+                       err("no memory for 'struct dvb_usb_device'");
+                       return ret;
+               }
+               memset(d,0,sizeof(struct dvb_usb_device));
+
+               d->udev = udev;
+               memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
+               d->desc = desc;
+               d->owner = owner;
+
+               if (d->props.size_of_priv > 0) {
+                       d->priv = kmalloc(d->props.size_of_priv,GFP_KERNEL);
+                       if (d->priv == NULL) {
+                               err("no memory for priv in 'struct dvb_usb_device'");
+                               kfree(d);
+                               return -ENOMEM;
+                       }
+                       memset(d->priv,0,d->props.size_of_priv);
+               }
+
+               usb_set_intfdata(intf, d);
+
+               ret = dvb_usb_init(d);
+       }
+
+       if (ret == 0)
+               info("%s successfully initialized and connected.",desc->name);
+       else
+               info("%s error while loading driver (%d)",desc->name,ret);
+       return ret;
+}
+EXPORT_SYMBOL(dvb_usb_device_init);
+
+void dvb_usb_device_exit(struct usb_interface *intf)
+{
+       struct dvb_usb_device *d = usb_get_intfdata(intf);
+       const char *name = "generic DVB-USB module";
+
+       usb_set_intfdata(intf,NULL);
+       if (d != NULL && d->desc != NULL) {
+               name = d->desc->name;
+               dvb_usb_exit(d);
+       }
+       info("%s successfully deinitialized and disconnected.",name);
+
+}
+EXPORT_SYMBOL(dvb_usb_device_exit);
+
+/* module stuff */
+static int __init dvb_usb_module_init(void)
+{
+       return 0;
+}
+
+static void __exit dvb_usb_module_exit(void)
+{
+}
+
+module_init (dvb_usb_module_init);
+module_exit (dvb_usb_module_exit);
+
+MODULE_VERSION("0.3");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
new file mode 100644 (file)
index 0000000..9f1e23f
--- /dev/null
@@ -0,0 +1,175 @@
+/* dvb-usb-remote.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing the the input-device and for handling remote-control-queries.
+ */
+#include "dvb-usb-common.h"
+
+/* Remote-control poll function - called every dib->rc_query_interval ms to see
+ * whether the remote control has received anything.
+ *
+ * TODO: Fix the repeat rate of the input device.
+ */
+static void dvb_usb_read_remote_control(void *data)
+{
+       struct dvb_usb_device *d = data;
+       u32 event;
+       int state;
+
+       /* TODO: need a lock here.  We can simply skip checking for the remote control
+          if we're busy. */
+
+       if (d->props.rc_query(d,&event,&state)) {
+               err("error while querying for an remote control event.");
+               goto schedule;
+       }
+
+
+       switch (state) {
+               case REMOTE_NO_KEY_PRESSED:
+                       break;
+               case REMOTE_KEY_PRESSED:
+                       deb_rc("key pressed\n");
+                       d->last_event = event;
+               case REMOTE_KEY_REPEAT:
+                       deb_rc("key repeated\n");
+                       input_event(&d->rc_input_dev, EV_KEY, event, 1);
+                       input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0);
+                       input_sync(&d->rc_input_dev);
+                       break;
+               default:
+                       break;
+       }
+
+/* improved repeat handling ???
+       switch (state) {
+               case REMOTE_NO_KEY_PRESSED:
+                       deb_rc("NO KEY PRESSED\n");
+                       if (d->last_state != REMOTE_NO_KEY_PRESSED) {
+                               deb_rc("releasing event %d\n",d->last_event);
+                               input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0);
+                               input_sync(&d->rc_input_dev);
+                       }
+                       d->last_state = REMOTE_NO_KEY_PRESSED;
+                       d->last_event = 0;
+                       break;
+               case REMOTE_KEY_PRESSED:
+                       deb_rc("KEY PRESSED\n");
+                       deb_rc("pressing event %d\n",event);
+
+                       input_event(&d->rc_input_dev, EV_KEY, event, 1);
+                       input_sync(&d->rc_input_dev);
+
+                       d->last_event = event;
+                       d->last_state = REMOTE_KEY_PRESSED;
+                       break;
+               case REMOTE_KEY_REPEAT:
+                       deb_rc("KEY_REPEAT\n");
+                       if (d->last_state != REMOTE_NO_KEY_PRESSED) {
+                               deb_rc("repeating event %d\n",d->last_event);
+                               input_event(&d->rc_input_dev, EV_KEY, d->last_event, 2);
+                               input_sync(&d->rc_input_dev);
+                               d->last_state = REMOTE_KEY_REPEAT;
+                       }
+               default:
+                       break;
+       }
+*/
+
+schedule:
+       schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
+}
+
+int dvb_usb_remote_init(struct dvb_usb_device *d)
+{
+       int i;
+       if (d->props.rc_key_map == NULL)
+               return 0;
+
+       /* Initialise the remote-control structures.*/
+       init_input_dev(&d->rc_input_dev);
+
+       d->rc_input_dev.evbit[0] = BIT(EV_KEY);
+       d->rc_input_dev.keycodesize = sizeof(unsigned char);
+       d->rc_input_dev.keycodemax = KEY_MAX;
+       d->rc_input_dev.name = "IR-receiver inside an USB DVB receiver";
+
+       /* set the bits for the keys */
+       deb_rc("key map size: %d\n",d->props.rc_key_map_size);
+       for (i = 0; i < d->props.rc_key_map_size; i++) {
+               deb_rc("setting bit for event %d item %d\n",d->props.rc_key_map[i].event, i);
+               set_bit(d->props.rc_key_map[i].event, d->rc_input_dev.keybit);
+       }
+
+       /* Start the remote-control polling. */
+       if (d->props.rc_interval < 40)
+               d->props.rc_interval = 100; /* default */
+
+       /* setting these two values to non-zero, we have to manage key repeats */
+       d->rc_input_dev.rep[REP_PERIOD] = d->props.rc_interval;
+       d->rc_input_dev.rep[REP_DELAY]  = d->props.rc_interval + 150;
+
+       input_register_device(&d->rc_input_dev);
+
+       INIT_WORK(&d->rc_query_work, dvb_usb_read_remote_control, d);
+
+       info("schedule remote query interval to %d msecs.",d->props.rc_interval);
+       schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
+
+       d->state |= DVB_USB_STATE_REMOTE;
+
+       return 0;
+}
+
+int dvb_usb_remote_exit(struct dvb_usb_device *d)
+{
+       if (d->state & DVB_USB_STATE_REMOTE) {
+               cancel_delayed_work(&d->rc_query_work);
+               flush_scheduled_work();
+               input_unregister_device(&d->rc_input_dev);
+       }
+       d->state &= ~DVB_USB_STATE_REMOTE;
+       return 0;
+}
+
+#define DVB_USB_RC_NEC_EMPTY           0x00
+#define DVB_USB_RC_NEC_KEY_PRESSED     0x01
+#define DVB_USB_RC_NEC_KEY_REPEATED    0x02
+int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
+               u8 keybuf[5], u32 *event, int *state)
+{
+       int i;
+       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       *event = 0;
+       *state = REMOTE_NO_KEY_PRESSED;
+       switch (keybuf[0]) {
+               case DVB_USB_RC_NEC_EMPTY:
+                       break;
+               case DVB_USB_RC_NEC_KEY_PRESSED:
+                       if ((u8) ~keybuf[1] != keybuf[2] ||
+                               (u8) ~keybuf[3] != keybuf[4]) {
+                               deb_err("remote control checksum failed.\n");
+                               break;
+                       }
+                       /* See if we can match the raw key code. */
+                       for (i = 0; i < sizeof(keymap)/sizeof(struct dvb_usb_rc_key); i++)
+                               if (keymap[i].custom == keybuf[1] &&
+                                       keymap[i].data == keybuf[3]) {
+                                       *event = keymap[i].event;
+                                       *state = REMOTE_KEY_PRESSED;
+                                       break;
+                               }
+                       deb_err("key mapping failed - no appropriate key found in keymapping\n");
+                       break;
+               case DVB_USB_RC_NEC_KEY_REPEATED:
+                       *state = REMOTE_KEY_REPEAT;
+                       break;
+               default:
+                       deb_err("unkown type of remote status: %d\n",keybuf[0]);
+                       break;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
new file mode 100644 (file)
index 0000000..83d476f
--- /dev/null
@@ -0,0 +1,211 @@
+/* dvb-usb-urb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing and handling the
+ * USB and URB stuff.
+ */
+#include "dvb-usb-common.h"
+
+int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
+       u16 rlen, int delay_ms)
+{
+       int actlen,ret = -ENOMEM;
+
+       if (d->props.generic_bulk_ctrl_endpoint == 0) {
+               err("endpoint for generic control not specified.");
+               return -EINVAL;
+       }
+
+       if (wbuf == NULL || wlen == 0)
+               return -EINVAL;
+
+       if ((ret = down_interruptible(&d->usb_sem)))
+               return ret;
+
+       debug_dump(wbuf,wlen,deb_xfer);
+
+       ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev,
+                       d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen,
+                       2*HZ);
+
+       if (ret)
+               err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
+       else
+               ret = actlen != wlen ? -1 : 0;
+
+       /* an answer is expected, and no error before */
+       if (!ret && rbuf && rlen) {
+               if (delay_ms)
+                       msleep(delay_ms);
+
+               ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev,
+                               d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen,
+                               2*HZ);
+
+               if (ret)
+                       err("recv bulk message failed: %d",ret);
+               else
+                       debug_dump(rbuf,actlen,deb_xfer);
+       }
+
+       up(&d->usb_sem);
+       return ret;
+}
+EXPORT_SYMBOL(dvb_usb_generic_rw);
+
+int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
+{
+       return dvb_usb_generic_rw(d,buf,len,NULL,0,0);
+}
+EXPORT_SYMBOL(dvb_usb_generic_write);
+
+static void dvb_usb_bulk_urb_complete(struct urb *urb, struct pt_regs *ptregs)
+{
+       struct dvb_usb_device *d = urb->context;
+
+       deb_ts("bulk urb completed. feedcount: %d, status: %d, length: %d\n",d->feedcount,urb->status,
+                       urb->actual_length);
+
+       switch (urb->status) {
+               case 0:         /* success */
+               case -ETIMEDOUT:    /* NAK */
+                       break;
+               case -ECONNRESET:   /* kill */
+               case -ENOENT:
+               case -ESHUTDOWN:
+                       return;
+               default:        /* error */
+                       deb_ts("urb completition error %d.", urb->status);
+                       break;
+       }
+
+       if (d->feedcount > 0 && urb->actual_length > 0) {
+               if (d->state & DVB_USB_STATE_DVB)
+                       dvb_dmx_swfilter(&d->demux, (u8*) urb->transfer_buffer,urb->actual_length);
+       } else
+               deb_ts("URB dropped because of feedcount.\n");
+
+       usb_submit_urb(urb,GFP_ATOMIC);
+}
+
+int dvb_usb_urb_kill(struct dvb_usb_device *d)
+{
+       int i;
+       for (i = 0; i < d->urbs_submitted; i++) {
+               deb_info("killing URB no. %d.\n",i);
+
+               /* stop the URB */
+               usb_kill_urb(d->urb_list[i]);
+       }
+       d->urbs_submitted = 0;
+       return 0;
+}
+
+int dvb_usb_urb_submit(struct dvb_usb_device *d)
+{
+       int i,ret;
+       for (i = 0; i < d->urbs_initialized; i++) {
+               deb_info("submitting URB no. %d\n",i);
+               if ((ret = usb_submit_urb(d->urb_list[i],GFP_ATOMIC))) {
+                       err("could not submit URB no. %d - get them all back\n",i);
+                       dvb_usb_urb_kill(d);
+                       return ret;
+               }
+               d->urbs_submitted++;
+       }
+       return 0;
+}
+
+static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d)
+{
+       int i,bufsize = d->props.urb.count * d->props.urb.u.bulk.buffersize;
+
+       deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
+       /* allocate the actual buffer for the URBs */
+       if ((d->buffer =  usb_buffer_alloc(d->udev, bufsize, SLAB_ATOMIC, &d->dma_handle)) == NULL) {
+               deb_info("not enough memory for urb-buffer allocation.\n");
+               return -ENOMEM;
+       }
+       deb_info("allocation successful\n");
+       memset(d->buffer,0,bufsize);
+
+       d->state |= DVB_USB_STATE_URB_BUF;
+
+       /* allocate the URBs */
+       for (i = 0; i < d->props.urb.count; i++) {
+               if (!(d->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) {
+                       return -ENOMEM;
+               }
+
+               usb_fill_bulk_urb( d->urb_list[i], d->udev,
+                               usb_rcvbulkpipe(d->udev,d->props.urb.endpoint),
+                               &d->buffer[i*d->props.urb.u.bulk.buffersize],
+                               d->props.urb.u.bulk.buffersize,
+                               dvb_usb_bulk_urb_complete, d);
+
+               d->urb_list[i]->transfer_flags = 0;
+               d->urbs_initialized++;
+       }
+       return 0;
+}
+
+int dvb_usb_urb_init(struct dvb_usb_device *d)
+{
+       /*
+        * when reloading the driver w/o replugging the device
+        * sometimes a timeout occures, this helps
+        */
+       if (d->props.generic_bulk_ctrl_endpoint != 0) {
+               usb_clear_halt(d->udev,usb_sndbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
+               usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
+       }
+       usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.urb.endpoint));
+
+       /* allocate the array for the data transfer URBs */
+       d->urb_list = kmalloc(d->props.urb.count * sizeof(struct urb *),GFP_KERNEL);
+       if (d->urb_list == NULL)
+               return -ENOMEM;
+       memset(d->urb_list,0,d->props.urb.count * sizeof(struct urb *));
+       d->state |= DVB_USB_STATE_URB_LIST;
+
+       switch (d->props.urb.type) {
+               case DVB_USB_BULK:
+                       return dvb_usb_bulk_urb_init(d);
+               case DVB_USB_ISOC:
+                       err("isochronous transfer not yet implemented in dvb-usb.");
+                       return -EINVAL;
+               default:
+                       err("unkown URB-type for data transfer.");
+                       return -EINVAL;
+       }
+}
+
+int dvb_usb_urb_exit(struct dvb_usb_device *d)
+{
+       int i;
+
+       dvb_usb_urb_kill(d);
+
+       if (d->state & DVB_USB_STATE_URB_LIST) {
+               for (i = 0; i < d->urbs_initialized; i++) {
+                       if (d->urb_list[i] != NULL) {
+                               deb_info("freeing URB no. %d.\n",i);
+                               /* free the URBs */
+                               usb_free_urb(d->urb_list[i]);
+                       }
+               }
+               d->urbs_initialized = 0;
+               /* free the urb array */
+               kfree(d->urb_list);
+               d->state &= ~DVB_USB_STATE_URB_LIST;
+       }
+
+       if (d->state & DVB_USB_STATE_URB_BUF)
+               usb_buffer_free(d->udev, d->props.urb.u.bulk.buffersize * d->props.urb.count,
+                               d->buffer, d->dma_handle);
+
+       d->state &= ~DVB_USB_STATE_URB_BUF;
+       return 0;
+}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
new file mode 100644 (file)
index 0000000..abcee19
--- /dev/null
@@ -0,0 +1,315 @@
+/* dvb-usb.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * the headerfile, all dvb-usb-drivers have to include.
+ */
+#ifndef __DVB_USB_H__
+#define __DVB_USB_H__
+
+#include <linux/config.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "dvb_frontend.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+#include "dmxdev.h"
+
+#include "dvb-pll.h"
+
+#include "dvb-usb-ids.h"
+
+/* debug */
+#ifdef CONFIG_DVB_USB_DEBUG
+#define dprintk(var,level,args...) \
+           do { if ((var & level)) { printk(args); } } while (0)
+
+#define debug_dump(b,l,func) {\
+       int loop_; \
+       for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \
+       func("\n");\
+}
+#define DVB_USB_DEBUG_STATUS
+#else
+#define dprintk(args...)
+#define debug_dump(b,l,func)
+
+#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)"
+
+#endif
+
+/* generic log methods - taken from usb.h */
+#ifndef DVB_USB_LOG_PREFIX
+ #define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)"
+#endif
+
+#undef err
+#define err(format, arg...)  printk(KERN_ERR     DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) printk(KERN_INFO    DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+
+/**
+ * struct dvb_usb_device_description - name and its according USB IDs
+ * @name: real name of the box, regardless which DVB USB device class is in use
+ * @cold_ids: array of struct usb_device_id which describe the device in
+ *  pre-firmware state
+ * @warm_ids: array of struct usb_device_id which describe the device in
+ *  post-firmware state
+ *
+ * Each DVB USB device class can have one or more actual devices, this struct
+ * assigns a name to it.
+ */
+struct dvb_usb_device_description {
+       const char *name;
+
+#define DVB_USB_ID_MAX_NUM 15
+       struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM];
+       struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
+};
+
+/**
+ * struct dvb_usb_rc_key - a remote control key and its input-event
+ * @custom: the vendor/custom part of the key
+ * @data: the actual key part
+ * @event: the input event assigned to key identified by custom and data
+ */
+struct dvb_usb_rc_key {
+       u8 custom,data;
+       u32 event;
+};
+
+struct dvb_usb_device;
+
+/**
+ * struct dvb_usb_properties - properties of a dvb-usb-device
+ * @caps: capabilites of the DVB USB device.
+ * @pid_filter_count: number of PID filter position in the optional hardware
+ *  PID-filter.
+ *
+ * @usb_ctrl: which USB device-side controller is in use. Needed for firmware
+ *  download.
+ * @firmware: name of the firmware file.
+ *
+ * @size_of_priv: how many bytes shall be allocated for the private field
+ *  of struct dvb_usb_device.
+ *
+ * @power_ctrl: called to enable/disable power of the device.
+ * @streaming_crtl: called to start and stop the MPEG2-TS streaming of the
+ *  device (not URB submitting/killing).
+ * @pid_filter_ctrl: called to en/disable the PID filter, if any.
+ * @pid_filter: called to set/unset a PID for filtering.
+ *
+ * @read_mac_address: called to read the MAC address of the device.
+ *
+ * @frontend_attach: called to attach the possible frontends (fill fe-field
+ *  of struct dvb_usb_device).
+ * @tuner_attach: called to attach the correct tuner and to fill pll_addr,
+ *  pll_desc and pll_init_buf of struct dvb_usb_device).
+ * @identify_state: called to determine the state (cold or warm), when it
+ *  is not distinguishable by the USB IDs.
+ *
+ * @rc_key_map: a hard-wired array of struct dvb_usb_rc_key (NULL to disable
+ *  remote control handling).
+ * @rc_key_map_size: number of items in @rc_key_map.
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ *
+ * @i2c_algo: i2c_algorithm if the device has I2CoverUSB.
+ *
+ * @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic
+ *  endpoint which received control messages with bulk transfers. When this
+ *  is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write-
+ *  helper functions.
+ *
+ * @urb: describes the kind of USB transfer used for MPEG2-TS-streaming.
+ *  Currently only BULK is implemented
+ *
+ * @num_device_descs: number of struct dvb_usb_device_description in @devices
+ * @devices: array of struct dvb_usb_device_description compatibles with these
+ *  properties.
+ */
+struct dvb_usb_properties {
+
+#define DVB_USB_HAS_PID_FILTER               0x01
+#define DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF 0x02
+#define DVB_USB_NEED_PID_FILTERING           0x04
+#define DVB_USB_IS_AN_I2C_ADAPTER            0x08
+       int caps;
+       int pid_filter_count;
+
+#define CYPRESS_AN2135  0
+#define CYPRESS_AN2235  1
+#define CYPRESS_FX2     2
+       int usb_ctrl;
+       const char *firmware;
+
+       int size_of_priv;
+
+       int (*power_ctrl) (struct dvb_usb_device *, int);
+       int (*streaming_ctrl) (struct dvb_usb_device *, int);
+       int (*pid_filter_ctrl) (struct dvb_usb_device *, int);
+       int (*pid_filter) (struct dvb_usb_device *, int, u16, int);
+
+       int (*read_mac_address) (struct dvb_usb_device *, u8 []);
+       int (*frontend_attach) (struct dvb_usb_device *);
+       int (*tuner_attach) (struct dvb_usb_device *);
+
+       int (*identify_state) (struct usb_device *, struct dvb_usb_properties *,
+                       struct dvb_usb_device_description **, int *);
+
+/* remote control properties */
+#define REMOTE_NO_KEY_PRESSED      0x00
+#define REMOTE_KEY_PRESSED         0x01
+#define REMOTE_KEY_REPEAT          0x02
+       struct dvb_usb_rc_key *rc_key_map;
+       int rc_key_map_size;
+       int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
+       int rc_interval;
+
+       struct i2c_algorithm *i2c_algo;
+
+       int generic_bulk_ctrl_endpoint;
+
+       struct {
+#define DVB_USB_BULK  1
+#define DVB_USB_ISOC  2
+               int type;
+               int count;
+               int endpoint;
+
+               union {
+                       struct {
+                               int buffersize; /* per URB */
+                       } bulk;
+                       struct {
+                               int framesperurb;
+                               int framesize;
+                       } isoc;
+               } u;
+       } urb;
+
+       int num_device_descs;
+       struct dvb_usb_device_description devices[8];
+};
+
+
+/**
+ * struct dvb_usb_device - object of a DVB USB device
+ * @props: copy of the struct dvb_usb_properties this device belongs to.
+ * @desc: pointer to the device's struct dvb_usb_device_description.
+ * @state: initialization and runtime state of the device.
+ *
+ * @udev: pointer to the device's struct usb_device.
+ * @urb_list: array of dynamically allocated struct urb for the MPEG2-TS-
+ *  streaming.
+ * @buffer: buffer used to streaming.
+ * @dma_handle: dma_addr_t for buffer.
+ * @urbs_initialized: number of URBs initialized.
+ * @urbs_submitted: number of URBs submitted.
+ * @feedcount: number of reqested feeds (used for streaming-activation)
+ * @pid_filtering: is hardware pid_filtering used or not.
+ * @usb_sem: semaphore of USB control messages (reading needs two messages)
+ * @i2c_sem: semaphore for i2c-transfers
+ * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
+ * @pll_addr: I2C address of the tuner for programming
+ * @pll_init: array containing the initialization buffer
+ * @pll_desc: pointer to the appropriate struct dvb_pll_desc
+ * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod
+ * @dvb_adap: device's dvb_adapter.
+ * @dmxdev: device's dmxdev.
+ * @demux: device's software demuxer.
+ * @dvb_net: device's dvb_net interfaces.
+ * @dvb_frontend: device's frontend.
+ * @max_feed_count: how many feeds can be handled simultaneously by this
+ *  device
+ * @fe_sleep: rerouted frontend-sleep function.
+ * @fe_init: rerouted frontend-init (wakeup) function.
+ * @rc_input_dev: input device for the remote control.
+ * @rc_query_work: struct work_struct frequent rc queries
+ * @last_event: last triggered event
+ * @last_state: last state (no, pressed, repeat)
+ * @owner: owner of the dvb_adapter
+ * @priv: private data of the actual driver (allocate by dvb-usb, size defined
+ *  in size_of_priv of dvb_usb_properties).
+ */
+struct dvb_usb_device {
+       struct dvb_usb_properties props;
+       struct dvb_usb_device_description *desc;
+
+#define DVB_USB_STATE_INIT        0x000
+#define DVB_USB_STATE_URB_LIST    0x001
+#define DVB_USB_STATE_URB_BUF     0x002
+#define DVB_USB_STATE_DVB         0x004
+#define DVB_USB_STATE_I2C         0x008
+#define DVB_USB_STATE_REMOTE      0x010
+#define DVB_USB_STATE_URB_SUBMIT  0x020
+       int state;
+
+       /* usb */
+       struct usb_device *udev;
+       struct urb **urb_list;
+       u8 *buffer;
+       dma_addr_t dma_handle;
+       int urbs_initialized;
+       int urbs_submitted;
+
+       int feedcount;
+       int pid_filtering;
+
+       /* locking */
+       struct semaphore usb_sem;
+
+       /* i2c */
+       struct semaphore i2c_sem;
+       struct i2c_adapter i2c_adap;
+
+       /* tuner programming information */
+       u8 pll_addr;
+       u8 pll_init[4];
+       struct dvb_pll_desc *pll_desc;
+       int (*tuner_pass_ctrl)(struct dvb_frontend *, int, u8);
+
+       /* dvb */
+       struct dvb_adapter dvb_adap;
+       struct dmxdev dmxdev;
+       struct dvb_demux demux;
+       struct dvb_net dvb_net;
+       struct dvb_frontend* fe;
+       int max_feed_count;
+
+       int (*fe_sleep) (struct dvb_frontend *);
+       int (*fe_init)  (struct dvb_frontend *);
+
+       /* remote control */
+       struct input_dev rc_input_dev;
+       struct work_struct rc_query_work;
+       u32 last_event;
+       int last_state;
+
+       struct module *owner;
+
+       void *priv;
+};
+
+extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_properties *, struct module *);
+extern void dvb_usb_device_exit(struct usb_interface *);
+
+/* the generic read/write method for device control */
+extern int dvb_usb_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int);
+extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
+
+/* commonly used remote control parsing */
+extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
+
+/* commonly used pll init and set functions */
+extern int dvb_usb_pll_init_i2c(struct dvb_frontend *);
+extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]);
+extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
+
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
new file mode 100644 (file)
index 0000000..9d83781
--- /dev/null
@@ -0,0 +1,236 @@
+/* DVB USB framework compliant Linux driver for the Hauppauge WinTV-NOVA-T usb2
+ * DVB-T receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc,2=eeprom (|-able))." DVB_USB_DEBUG_STATUS);
+
+#define deb_rc(args...) dprintk(debug,0x01,args)
+#define deb_ee(args...) dprintk(debug,0x02,args)
+
+/* Hauppauge NOVA-T USB2 keys */
+static struct dvb_usb_rc_key haupp_rc_keys [] = {
+       { 0x1e, 0x00, KEY_0 },
+       { 0x1e, 0x01, KEY_1 },
+       { 0x1e, 0x02, KEY_2 },
+       { 0x1e, 0x03, KEY_3 },
+       { 0x1e, 0x04, KEY_4 },
+       { 0x1e, 0x05, KEY_5 },
+       { 0x1e, 0x06, KEY_6 },
+       { 0x1e, 0x07, KEY_7 },
+       { 0x1e, 0x08, KEY_8 },
+       { 0x1e, 0x09, KEY_9 },
+       { 0x1e, 0x0a, KEY_KPASTERISK },
+       { 0x1e, 0x0b, KEY_RED },
+       { 0x1e, 0x0c, KEY_RADIO },
+       { 0x1e, 0x0d, KEY_MENU },
+       { 0x1e, 0x0e, KEY_GRAVE }, /* # */
+       { 0x1e, 0x0f, KEY_MUTE },
+       { 0x1e, 0x10, KEY_VOLUMEUP },
+       { 0x1e, 0x11, KEY_VOLUMEDOWN },
+       { 0x1e, 0x12, KEY_CHANNEL },
+       { 0x1e, 0x14, KEY_UP },
+       { 0x1e, 0x15, KEY_DOWN },
+       { 0x1e, 0x16, KEY_LEFT },
+       { 0x1e, 0x17, KEY_RIGHT },
+       { 0x1e, 0x18, KEY_VIDEO },
+       { 0x1e, 0x19, KEY_AUDIO },
+       { 0x1e, 0x1a, KEY_MEDIA },
+       { 0x1e, 0x1b, KEY_EPG },
+       { 0x1e, 0x1c, KEY_TV },
+       { 0x1e, 0x1e, KEY_NEXT },
+       { 0x1e, 0x1f, KEY_BACK },
+       { 0x1e, 0x20, KEY_CHANNELUP },
+       { 0x1e, 0x21, KEY_CHANNELDOWN },
+       { 0x1e, 0x24, KEY_LAST }, /* Skip backwards */
+       { 0x1e, 0x25, KEY_OK },
+       { 0x1e, 0x29, KEY_BLUE},
+       { 0x1e, 0x2e, KEY_GREEN },
+       { 0x1e, 0x30, KEY_PAUSE },
+       { 0x1e, 0x32, KEY_REWIND },
+       { 0x1e, 0x34, KEY_FASTFORWARD },
+       { 0x1e, 0x35, KEY_PLAY },
+       { 0x1e, 0x36, KEY_STOP },
+       { 0x1e, 0x37, KEY_RECORD },
+       { 0x1e, 0x38, KEY_YELLOW },
+       { 0x1e, 0x3b, KEY_GOTO },
+       { 0x1e, 0x3d, KEY_POWER },
+};
+
+/* Firmware bug? sometimes, when a new key is pressed, the previous pressed key
+ * is delivered. No workaround yet, maybe a new firmware.
+ */
+static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+       u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom;
+       u16 raw;
+       int i;
+       struct dibusb_state *st = d->priv;
+
+       dvb_usb_generic_rw(d,cmd,2,key,5,0);
+
+       *state = REMOTE_NO_KEY_PRESSED;
+       switch (key[0]) {
+               case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED:
+                       raw = ((key[1] << 8) | key[2]) >> 3;
+                       toggle = !!(raw & 0x800);
+                       data = raw & 0x3f;
+                       custom = (raw >> 6) & 0x1f;
+
+                       deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle);
+
+                       for (i = 0; i < ARRAY_SIZE(haupp_rc_keys); i++) {
+                               deb_rc("c: %x, d: %x\n",haupp_rc_keys[i].data,haupp_rc_keys[i].custom);
+                               if (haupp_rc_keys[i].data == data &&
+                                       haupp_rc_keys[i].custom == custom) {
+                                       *event = haupp_rc_keys[i].event;
+                                       *state = REMOTE_KEY_PRESSED;
+                                       if (st->old_toggle == toggle) {
+                                               if (st->last_repeat_count++ < 2)
+                                                       *state = REMOTE_NO_KEY_PRESSED;
+                                       } else {
+                                               st->last_repeat_count = 0;
+                                               st->old_toggle = toggle;
+                                       }
+                                       break;
+                               }
+                       }
+
+                       break;
+               case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY:
+               default:
+                       break;
+       }
+
+       return 0;
+}
+
+static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6])
+{
+       int i;
+       u8 b;
+
+       mac[0] = 0x00;
+       mac[1] = 0x0d;
+       mac[2] = 0xfe;
+
+       /* this is a complete guess, but works for my box */
+       for (i = 136; i < 139; i++) {
+               dibusb_read_eeprom_byte(d,i, &b);
+
+               mac[5 - (i - 136)] = b;
+
+/*             deb_ee("%02x ",b);
+               if ((i+1) % 16 == 0)
+                       deb_ee("\n");*/
+       }
+
+       return 0;
+}
+
+/* USB Driver stuff */
+static struct dvb_usb_properties nova_t_properties;
+
+static int nova_t_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       return dvb_usb_device_init(intf,&nova_t_properties,THIS_MODULE);
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id nova_t_table [] = {
+/* 00 */       { USB_DEVICE(USB_VID_HAUPPAUGE,     USB_PID_WINTV_NOVA_T_USB2_COLD) },
+/* 01 */       { USB_DEVICE(USB_VID_HAUPPAUGE,     USB_PID_WINTV_NOVA_T_USB2_WARM) },
+                       { }             /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, nova_t_table);
+
+static struct dvb_usb_properties nova_t_properties = {
+       .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+       .pid_filter_count = 32,
+
+       .usb_ctrl = CYPRESS_FX2,
+       .firmware = "dvb-usb-nova-t-usb2-01.fw",
+
+       .size_of_priv     = sizeof(struct dibusb_state),
+
+       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
+       .pid_filter       = dibusb_pid_filter,
+       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+       .power_ctrl       = dibusb2_0_power_ctrl,
+       .frontend_attach  = dibusb_dib3000mc_frontend_attach,
+       .tuner_attach     = dibusb_dib3000mc_tuner_attach,
+       .read_mac_address = nova_t_read_mac_address,
+
+       .rc_interval      = 100,
+       .rc_key_map       = haupp_rc_keys,
+       .rc_key_map_size  = ARRAY_SIZE(haupp_rc_keys),
+       .rc_query         = nova_t_rc_query,
+
+       .i2c_algo         = &dibusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 7,
+               .endpoint = 0x06,
+               .u = {
+                       .bulk = {
+                               .buffersize = 4096,
+                       }
+               }
+       },
+
+       .num_device_descs = 1,
+       .devices = {
+               {   "Hauppauge WinTV-NOVA-T usb2",
+                       { &nova_t_table[0], NULL },
+                       { &nova_t_table[1], NULL },
+               },
+       }
+};
+
+static struct usb_driver nova_t_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "Hauppauge WinTV-NOVA-T usb2",
+       .probe          = nova_t_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table       = nova_t_table,
+};
+
+/* module stuff */
+static int __init nova_t_module_init(void)
+{
+       int result;
+       if ((result = usb_register(&nova_t_driver))) {
+               err("usb_register failed. Error number %d",result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit nova_t_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&nova_t_driver);
+}
+
+module_init (nova_t_module_init);
+module_exit (nova_t_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Hauppauge WinTV-NOVA-T usb2");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
new file mode 100644 (file)
index 0000000..aa56042
--- /dev/null
@@ -0,0 +1,162 @@
+/* DVB USB framework compliant Linux driver for the HanfTek UMT-010 USB2.0
+ * DVB-T receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+#include "mt352.h"
+
+static int umt_mt352_demod_init(struct dvb_frontend *fe)
+{
+       static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d };
+       static u8 mt352_reset[] = { 0x50, 0x80 };
+       static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
+       static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
+       static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 };
+
+       static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff };
+       static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff };
+       static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 };
+       static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 };
+       static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f };
+
+       static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
+       static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 };
+
+       mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+       udelay(2000);
+       mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+       mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
+
+       mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+       mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
+
+       mt352_write(fe, mt352_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1));
+       mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2));
+       mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3));
+       mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4));
+       mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5));
+
+       mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
+       mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
+
+       return 0;
+}
+
+static int umt_mt352_frontend_attach(struct dvb_usb_device *d)
+{
+       struct mt352_config umt_config;
+
+       memset(&umt_config,0,sizeof(struct mt352_config));
+       umt_config.demod_init = umt_mt352_demod_init;
+       umt_config.demod_address = 0xf;
+       umt_config.pll_set = dvb_usb_pll_set;
+
+       d->fe = mt352_attach(&umt_config, &d->i2c_adap);
+
+       return 0;
+}
+
+static int umt_tuner_attach (struct dvb_usb_device *d)
+{
+       d->pll_addr = 0x61;
+       d->pll_desc = &dvb_pll_tua6034;
+       return 0;
+}
+
+/* USB Driver stuff */
+static struct dvb_usb_properties umt_properties;
+
+static int umt_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       if (dvb_usb_device_init(intf,&umt_properties,THIS_MODULE) == 0)
+               return 0;
+       return -EINVAL;
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id umt_table [] = {
+/* 00 */       { USB_DEVICE(USB_VID_HANFTEK,           USB_PID_HANFTEK_UMT_010_COLD) },
+/* 01 */       { USB_DEVICE(USB_VID_HANFTEK,           USB_PID_HANFTEK_UMT_010_WARM) },
+                       { }             /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, umt_table);
+
+static struct dvb_usb_properties umt_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl = CYPRESS_FX2,
+       .firmware = "dvb-usb-umt-010-02.fw",
+
+       .size_of_priv     = sizeof(struct dibusb_state),
+
+       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
+       .power_ctrl       = dibusb_power_ctrl,
+       .frontend_attach  = umt_mt352_frontend_attach,
+       .tuner_attach     = umt_tuner_attach,
+
+       .i2c_algo         = &dibusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 20,
+               .endpoint = 0x06,
+               .u = {
+                       .bulk = {
+                               .buffersize = 512,
+                       }
+               }
+       },
+
+       .num_device_descs = 1,
+       .devices = {
+               {       "Hanftek UMT-010 DVB-T USB2.0",
+                       { &umt_table[0], NULL },
+                       { &umt_table[1], NULL },
+               },
+       }
+};
+
+static struct usb_driver umt_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "HanfTek UMT-010 USB2.0 DVB-T devices",
+       .probe          = umt_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table       = umt_table,
+};
+
+/* module stuff */
+static int __init umt_module_init(void)
+{
+       int result;
+       if ((result = usb_register(&umt_driver))) {
+               err("usb_register failed. Error number %d",result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit umt_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&umt_driver);
+}
+
+module_init (umt_module_init);
+module_exit (umt_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for HanfTek UMT 010 USB2.0 DVB-T device");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/vp7045-fe.c b/drivers/media/dvb/dvb-usb/vp7045-fe.c
new file mode 100644 (file)
index 0000000..2746edf
--- /dev/null
@@ -0,0 +1,196 @@
+/* DVB frontend part of the Linux driver for TwinhanDTV Alpha/MagicBoxII USB2.0
+ * DVB-T receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * Thanks to Twinhan who kindly provided hardware and information.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ *
+ */
+#include "vp7045.h"
+
+/* It is a Zarlink MT352 within a Samsung Tuner (DNOS404ZH102A) - 040929 - AAT
+ *
+ * Programming is hidden inside the firmware, so set_frontend is very easy.
+ * Even though there is a Firmware command that one can use to access the demod
+ * via its registers. This is used for status information.
+ */
+
+struct vp7045_fe_state {
+       struct dvb_frontend fe;
+       struct dvb_usb_device *d;
+};
+
+
+static int vp7045_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
+{
+       struct vp7045_fe_state *state = fe->demodulator_priv;
+       u8 s0 = vp7045_read_reg(state->d,0x00),
+          s1 = vp7045_read_reg(state->d,0x01),
+          s3 = vp7045_read_reg(state->d,0x03);
+
+       *status = 0;
+       if (s0 & (1 << 4))
+               *status |= FE_HAS_CARRIER;
+       if (s0 & (1 << 1))
+               *status |= FE_HAS_VITERBI;
+       if (s0 & (1 << 5))
+               *status |= FE_HAS_LOCK;
+       if (s1 & (1 << 1))
+               *status |= FE_HAS_SYNC;
+       if (s3 & (1 << 6))
+               *status |= FE_HAS_SIGNAL;
+
+       if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
+                       (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
+               *status &= ~FE_HAS_LOCK;
+
+       return 0;
+}
+
+static int vp7045_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+       struct vp7045_fe_state *state = fe->demodulator_priv;
+       *ber = (vp7045_read_reg(state->d, 0x0D) << 16) |
+              (vp7045_read_reg(state->d, 0x0E) << 8) |
+               vp7045_read_reg(state->d, 0x0F);
+       return 0;
+}
+
+static int vp7045_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+       struct vp7045_fe_state *state = fe->demodulator_priv;
+       *unc = (vp7045_read_reg(state->d, 0x10) << 8) |
+                   vp7045_read_reg(state->d, 0x11);
+       return 0;
+}
+
+static int vp7045_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+       struct vp7045_fe_state *state = fe->demodulator_priv;
+       u16 signal = (vp7045_read_reg(state->d, 0x14) << 8) |
+               vp7045_read_reg(state->d, 0x15);
+
+       *strength = ~signal;
+       return 0;
+}
+
+static int vp7045_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+       struct vp7045_fe_state *state = fe->demodulator_priv;
+       u8 _snr = vp7045_read_reg(state->d, 0x09);
+       *snr = (_snr << 8) | _snr;
+       return 0;
+}
+
+static int vp7045_fe_init(struct dvb_frontend* fe)
+{
+       return 0;
+}
+
+static int vp7045_fe_sleep(struct dvb_frontend* fe)
+{
+       return 0;
+}
+
+static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+       tune->min_delay_ms = 800;
+       return 0;
+}
+
+static int vp7045_fe_set_frontend(struct dvb_frontend* fe,
+                                 struct dvb_frontend_parameters *fep)
+{
+       struct vp7045_fe_state *state = fe->demodulator_priv;
+       u8 buf[5];
+       u32 freq = fep->frequency / 1000;
+
+       buf[0] = (freq >> 16) & 0xff;
+       buf[1] = (freq >>  8) & 0xff;
+       buf[2] =  freq        & 0xff;
+       buf[3] = 0;
+
+       switch (fep->u.ofdm.bandwidth) {
+               case BANDWIDTH_8_MHZ: buf[4] = 8; break;
+               case BANDWIDTH_7_MHZ: buf[4] = 7; break;
+               case BANDWIDTH_6_MHZ: buf[4] = 6; break;
+               case BANDWIDTH_AUTO: return -EOPNOTSUPP;
+               default:
+                       return -EINVAL;
+       }
+
+       vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200);
+       return 0;
+}
+
+static int vp7045_fe_get_frontend(struct dvb_frontend* fe,
+                                 struct dvb_frontend_parameters *fep)
+{
+       return 0;
+}
+
+static void vp7045_fe_release(struct dvb_frontend* fe)
+{
+       struct vp7045_fe_state *state = fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops vp7045_fe_ops;
+
+struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d)
+{
+       struct vp7045_fe_state *s = kmalloc(sizeof(struct vp7045_fe_state), GFP_KERNEL);
+       if (s == NULL)
+               goto error;
+       memset(s,0,sizeof(struct vp7045_fe_state));
+
+       s->d = d;
+       s->fe.ops = &vp7045_fe_ops;
+       s->fe.demodulator_priv = s;
+
+       goto success;
+error:
+       return NULL;
+success:
+       return &s->fe;
+}
+
+
+static struct dvb_frontend_ops vp7045_fe_ops = {
+       .info = {
+               .name                   = "Twinhan VP7045/46 USB DVB-T",
+               .type                   = FE_OFDM,
+               .frequency_min          = 44250000,
+               .frequency_max          = 867250000,
+               .frequency_stepsize     = 1000,
+               .caps = FE_CAN_INVERSION_AUTO |
+                               FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                               FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                               FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                               FE_CAN_TRANSMISSION_MODE_AUTO |
+                               FE_CAN_GUARD_INTERVAL_AUTO |
+                               FE_CAN_RECOVER |
+                               FE_CAN_HIERARCHY_AUTO,
+       },
+
+       .release = vp7045_fe_release,
+
+       .init = vp7045_fe_init,
+       .sleep = vp7045_fe_sleep,
+
+       .set_frontend = vp7045_fe_set_frontend,
+       .get_frontend = vp7045_fe_get_frontend,
+       .get_tune_settings = vp7045_fe_get_tune_settings,
+
+       .read_status = vp7045_fe_read_status,
+       .read_ber = vp7045_fe_read_ber,
+       .read_signal_strength = vp7045_fe_read_signal_strength,
+       .read_snr = vp7045_fe_read_snr,
+       .read_ucblocks = vp7045_fe_read_unc_blocks,
+};
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
new file mode 100644 (file)
index 0000000..02ecc9a
--- /dev/null
@@ -0,0 +1,263 @@
+/* DVB USB compliant Linux driver for the
+ *  - TwinhanDTV Alpha/MagicBoxII USB2.0 DVB-T receiver
+ *  - DigitalNow TinyUSB2 DVB-t receiver
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * Thanks to Twinhan who kindly provided hardware and information.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "vp7045.h"
+
+/* debug */
+int dvb_usb_vp7045_debug;
+module_param_named(debug,dvb_usb_vp7045_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
+{
+       int ret = 0;
+       u8 inbuf[12] = { 0 }, outbuf[20] = { 0 };
+
+       outbuf[0] = cmd;
+
+       if (outlen > 19)
+               outlen = 19;
+
+       if (inlen > 11)
+               inlen = 11;
+
+       if (out != NULL && outlen > 0)
+               memcpy(&outbuf[1], out, outlen);
+
+       deb_xfer("out buffer: ");
+       debug_dump(outbuf,outlen+1,deb_xfer);
+
+       if ((ret = down_interruptible(&d->usb_sem)))
+               return ret;
+
+       if (usb_control_msg(d->udev,
+                       usb_sndctrlpipe(d->udev,0),
+                       TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,
+                       outbuf, 20, 2*HZ) != 20) {
+               err("USB control message 'out' went wrong.");
+               ret = -EIO;
+               goto unlock;
+       }
+
+       msleep(msec);
+
+       if (usb_control_msg(d->udev,
+                       usb_rcvctrlpipe(d->udev,0),
+                       TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+                       inbuf, 12, 2*HZ) != 12) {
+               err("USB control message 'in' went wrong.");
+               ret = -EIO;
+               goto unlock;
+       }
+
+       deb_xfer("in buffer: ");
+       debug_dump(inbuf,12,deb_xfer);
+
+       if (in != NULL && inlen > 0)
+               memcpy(in,&inbuf[1],inlen);
+
+unlock:
+       up(&d->usb_sem);
+
+       return ret;
+}
+
+u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg)
+{
+       u8 obuf[2] = { 0 },v;
+       obuf[1] = reg;
+
+       vp7045_usb_op(d,TUNER_REG_READ,obuf,2,&v,1,30);
+
+       return v;
+}
+
+static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       u8 v = onoff;
+       return vp7045_usb_op(d,SET_TUNER_POWER,&v,1,NULL,0,150);
+}
+
+/* remote control stuff */
+
+/* The keymapping struct. Somehow this should be loaded to the driver, but
+ * currently it is hardcoded. */
+static struct dvb_usb_rc_key vp7045_rc_keys[] = {
+       /* insert the keys like this. to make the raw keys visible, enable
+        * debug=0x04 when loading dvb-usb-vp7045. */
+
+       /* these keys are probably wrong. I don't have a working IR-receiver on my
+        * vp7045, so I can't test it.  Patches are welcome. */
+       { 0x00, 0x01, KEY_1 },
+       { 0x00, 0x02, KEY_2 },
+};
+
+static int vp7045_rc_query(struct dvb_usb_device *d, u32 *key_buf, int *state)
+{
+       u8 key;
+       int i;
+       vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20);
+
+       deb_rc("remote query key: %x %d\n",key,key);
+
+       if (key == 0x44) {
+               *state = REMOTE_NO_KEY_PRESSED;
+               return 0;
+       }
+
+       for (i = 0; i < sizeof(vp7045_rc_keys)/sizeof(struct dvb_usb_rc_key); i++)
+               if (vp7045_rc_keys[i].data == key) {
+                       *state = REMOTE_KEY_PRESSED;
+                       *key_buf = vp7045_rc_keys[i].event;
+                       break;
+               }
+       return 0;
+}
+
+static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset)
+{
+       int i = 0;
+       u8 v,br[2];
+       for (i=0; i < len; i++) {
+               v = offset + i;
+               vp7045_usb_op(d,GET_EE_VALUE,&v,1,br,2,5);
+               buf[i] = br[1];
+       }
+       deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ",offset, i);
+       debug_dump(buf,i,deb_info);
+       return 0;
+}
+
+
+static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
+{
+       return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR);
+}
+
+static int vp7045_frontend_attach(struct dvb_usb_device *d)
+{
+       u8 buf[255] = { 0 };
+
+       vp7045_usb_op(d,VENDOR_STRING_READ,NULL,0,buf,20,0);
+       buf[10] = '\0';
+       deb_info("firmware says: %s ",buf);
+
+       vp7045_usb_op(d,PRODUCT_STRING_READ,NULL,0,buf,20,0);
+       buf[10] = '\0';
+       deb_info("%s ",buf);
+
+       vp7045_usb_op(d,FW_VERSION_READ,NULL,0,buf,20,0);
+       buf[10] = '\0';
+       deb_info("v%s\n",buf);
+
+/*     Dump the EEPROM */
+/*     vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */
+
+       d->fe = vp7045_fe_attach(d);
+
+       return 0;
+}
+
+static struct dvb_usb_properties vp7045_properties;
+
+static int vp7045_usb_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       return dvb_usb_device_init(intf,&vp7045_properties,THIS_MODULE);
+}
+
+static struct usb_device_id vp7045_usb_table [] = {
+           { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) },
+           { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) },
+           { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) },
+           { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) },
+           { 0 },
+};
+MODULE_DEVICE_TABLE(usb, vp7045_usb_table);
+
+static struct dvb_usb_properties vp7045_properties = {
+       .caps = 0,
+
+       .usb_ctrl = CYPRESS_FX2,
+       .firmware = "dvb-usb-vp7045-01.fw",
+
+       .power_ctrl       = vp7045_power_ctrl,
+       .frontend_attach  = vp7045_frontend_attach,
+       .read_mac_address = vp7045_read_mac_addr,
+
+       .rc_interval      = 400,
+       .rc_key_map       = vp7045_rc_keys,
+       .rc_key_map_size  = ARRAY_SIZE(vp7045_rc_keys),
+       .rc_query         = vp7045_rc_query,
+
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 7,
+               .endpoint = 0x02,
+               .u = {
+                       .bulk = {
+                               .buffersize = 4096,
+                       }
+               }
+       },
+
+       .num_device_descs = 2,
+       .devices = {
+               { .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)",
+                 .cold_ids = { &vp7045_usb_table[0], NULL },
+                 .warm_ids = { &vp7045_usb_table[1], NULL },
+               },
+               { .name = "DigitalNow TinyUSB 2 DVB-t Receiver",
+                 .cold_ids = { &vp7045_usb_table[2], NULL },
+                 .warm_ids = { &vp7045_usb_table[3], NULL },
+               },
+               { 0 },
+       }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver vp7045_usb_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "dvb-usb-vp7045",
+       .probe          = vp7045_usb_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table       = vp7045_usb_table,
+};
+
+/* module stuff */
+static int __init vp7045_usb_module_init(void)
+{
+       int result;
+       if ((result = usb_register(&vp7045_usb_driver))) {
+               err("usb_register failed. (%d)",result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit vp7045_usb_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&vp7045_usb_driver);
+}
+
+module_init(vp7045_usb_module_init);
+module_exit(vp7045_usb_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/vp7045.h b/drivers/media/dvb/dvb-usb/vp7045.h
new file mode 100644 (file)
index 0000000..9ce21a2
--- /dev/null
@@ -0,0 +1,78 @@
+/* Common header-file of the Linux driver for the TwinhanDTV Alpha/MagicBoxII
+ * USB2.0 DVB-T receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * Thanks to Twinhan who kindly provided hardware and information.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_VP7045_H_
+#define _DVB_USB_VP7045_H_
+
+#define DVB_USB_LOG_PREFIX "vp7045"
+#include "dvb-usb.h"
+
+extern int dvb_usb_vp7045_debug;
+#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
+#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
+
+/* vp7045 commands */
+
+/* Twinhan Vendor requests */
+#define TH_COMMAND_IN                     0xC0
+#define TH_COMMAND_OUT                    0xC1
+
+/* command bytes */
+#define TUNER_REG_READ                    0x03
+#define TUNER_REG_WRITE                   0x04
+
+#define RC_VAL_READ                       0x05
+ #define RC_NO_KEY                        0x44
+
+#define SET_TUNER_POWER                   0x06
+#define CHECK_TUNER_POWER                 0x12
+ #define Tuner_Power_ON                   1
+ #define Tuner_Power_OFF                  0
+
+#define GET_USB_SPEED                     0x07
+ #define USB_SPEED_LOW                    0
+ #define USB_SPEED_FULL                   1
+ #define USB_SPEED_HIGH                   2
+
+#define LOCK_TUNER_COMMAND                0x09
+
+#define TUNER_SIGNAL_READ                 0x0A
+
+/* FX2 eeprom */
+#define SET_EE_VALUE                      0x10
+#define GET_EE_VALUE                      0x11
+ #define FX2_ID_ADDR                      0x00
+ #define VID_MSB_ADDR                     0x02
+ #define VID_LSB_ADDR                     0x01
+ #define PID_MSB_ADDR                     0x04
+ #define PID_LSB_ADDR                     0x03
+ #define MAC_0_ADDR                       0x07
+ #define MAC_1_ADDR                       0x08
+ #define MAC_2_ADDR                       0x09
+ #define MAC_3_ADDR                       0x0a
+ #define MAC_4_ADDR                       0x0b
+ #define MAC_5_ADDR                       0x0c
+
+#define RESET_FX2                         0x13
+
+#define FW_VERSION_READ                   0x0B
+#define VENDOR_STRING_READ                0x0C
+#define PRODUCT_STRING_READ               0x0D
+#define FW_BCD_VERSION_READ               0x14
+
+extern struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d);
+extern int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen,int msec);
+extern u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg);
+
+#endif
index 75fb556ec01fe32b99d4f7c06d4ea50de758646d..b4fddf513ebeaa27f10b0d8be421071866a7547f 100644 (file)
@@ -173,4 +173,12 @@ config DVB_OR51132
          An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
          to support this frontend.
 
+config DVB_BCM3510
+       tristate "Broadcom BCM3510"
+       depends on DVB_CORE
+       select FW_LOADER
+       help
+         An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
+         support this frontend.
+
 endmenu
index 7f8784870eab2d1b5dc86850dd7df270cabc5984..91d6d3576d3d366e1460a344fda1fd5dd89472c2 100644 (file)
@@ -28,3 +28,4 @@ obj-$(CONFIG_DVB_STV0297) += stv0297.o
 obj-$(CONFIG_DVB_NXT2002) += nxt2002.o
 obj-$(CONFIG_DVB_OR51211) += or51211.o
 obj-$(CONFIG_DVB_OR51132) += or51132.o
+obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
new file mode 100644 (file)
index 0000000..f5fdc5c
--- /dev/null
@@ -0,0 +1,853 @@
+/*
+ * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
+ *
+ *  Copyright (C) 2001-5, B2C2 inc.
+ *
+ *  GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ *  This driver is "hard-coded" to be used with the 1st generation of
+ *  Technisat/B2C2's Air2PC ATSC PCI/USB cards/boxes. The pll-programming
+ *  (Panasonic CT10S) is located here, which is actually wrong. Unless there is
+ *  another device with a BCM3510, this is no problem.
+ *
+ *  The driver works also with QAM64 DVB-C, but had an unreasonable high
+ *  UNC. (Tested with the Air2PC ATSC 1st generation)
+ *
+ *  You'll need a firmware for this driver in order to get it running. It is
+ *  called "dvb-fe-bcm3510-01.fw".
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+ * Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "bcm3510.h"
+#include "bcm3510_priv.h"
+
+struct bcm3510_state {
+
+       struct i2c_adapter* i2c;
+       struct dvb_frontend_ops ops;
+       const struct bcm3510_config* config;
+       struct dvb_frontend frontend;
+
+       /* demodulator private data */
+       struct semaphore hab_sem;
+       u8 firmware_loaded:1;
+
+       unsigned long next_status_check;
+       unsigned long status_check_interval;
+       struct bcm3510_hab_cmd_status1 status1;
+       struct bcm3510_hab_cmd_status2 status2;
+};
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c (|-able)).");
+
+#define dprintk(level,x...) if (level & debug) printk(x)
+#define dbufout(b,l,m) {\
+           int i; \
+           for (i = 0; i < l; i++) \
+               m("%02x ",b[i]); \
+}
+#define deb_info(args...) dprintk(0x01,args)
+#define deb_i2c(args...)  dprintk(0x02,args)
+#define deb_hab(args...)  dprintk(0x04,args)
+
+/* transfer functions */
+static int bcm3510_writebytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len)
+{
+       u8 b[256];
+       int err;
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = len + 1 };
+
+       b[0] = reg;
+       memcpy(&b[1],buf,len);
+
+       deb_i2c("i2c wr %02x: ",reg);
+       dbufout(buf,len,deb_i2c);
+       deb_i2c("\n");
+
+       if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+
+               deb_info("%s: i2c write error (addr %02x, reg %02x, err == %i)\n",
+                       __FUNCTION__, state->config->demod_address, reg,  err);
+               return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+static int bcm3510_readbytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len)
+{
+       struct i2c_msg msg[] = {
+               { .addr = state->config->demod_address, .flags = 0,        .buf = &reg, .len = 1 },
+               { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf,  .len = len }
+       };
+       int err;
+
+       memset(buf,0,len);
+
+       if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
+               deb_info("%s: i2c read error (addr %02x, reg %02x, err == %i)\n",
+                       __FUNCTION__, state->config->demod_address, reg,  err);
+               return -EREMOTEIO;
+       }
+       deb_i2c("i2c rd %02x: ",reg);
+       dbufout(buf,len,deb_i2c);
+       deb_i2c("\n");
+
+       return 0;
+}
+
+static int bcm3510_writeB(struct bcm3510_state *state, u8 reg, bcm3510_register_value v)
+{
+       return bcm3510_writebytes(state,reg,&v.raw,1);
+}
+
+static int bcm3510_readB(struct bcm3510_state *state, u8 reg, bcm3510_register_value *v)
+{
+       return bcm3510_readbytes(state,reg,&v->raw,1);
+}
+
+/* Host Access Buffer transfers */
+static int bcm3510_hab_get_response(struct bcm3510_state *st, u8 *buf, int len)
+{
+       bcm3510_register_value v;
+       int ret,i;
+
+       v.HABADR_a6.HABADR = 0;
+       if ((ret = bcm3510_writeB(st,0xa6,v)) < 0)
+               return ret;
+
+       for (i = 0; i < len; i++) {
+               if ((ret = bcm3510_readB(st,0xa7,&v)) < 0)
+                       return ret;
+               buf[i] = v.HABDATA_a7;
+       }
+       return 0;
+}
+
+static int bcm3510_hab_send_request(struct bcm3510_state *st, u8 *buf, int len)
+{
+       bcm3510_register_value v,hab;
+       int ret,i;
+       unsigned long t;
+
+/* Check if any previous HAB request still needs to be serviced by the
+ * Aquisition Processor before sending new request */
+       if ((ret = bcm3510_readB(st,0xa8,&v)) < 0)
+               return ret;
+       if (v.HABSTAT_a8.HABR) {
+               deb_info("HAB is running already - clearing it.\n");
+               v.HABSTAT_a8.HABR = 0;
+               bcm3510_writeB(st,0xa8,v);
+//             return -EBUSY;
+       }
+
+/* Send the start HAB Address (automatically incremented after write of
+ * HABDATA) and write the HAB Data */
+       hab.HABADR_a6.HABADR = 0;
+       if ((ret = bcm3510_writeB(st,0xa6,hab)) < 0)
+               return ret;
+
+       for (i = 0; i < len; i++) {
+               hab.HABDATA_a7 = buf[i];
+               if ((ret = bcm3510_writeB(st,0xa7,hab)) < 0)
+                       return ret;
+       }
+
+/* Set the HABR bit to indicate AP request in progress (LBHABR allows HABR to
+ * be written) */
+       v.raw = 0; v.HABSTAT_a8.HABR = 1; v.HABSTAT_a8.LDHABR = 1;
+       if ((ret = bcm3510_writeB(st,0xa8,v)) < 0)
+               return ret;
+
+/* Polling method: Wait until the AP finishes processing the HAB request */
+       t = jiffies + 1*HZ;
+       while (time_before(jiffies, t)) {
+               deb_info("waiting for HAB to complete\n");
+               msleep(10);
+               if ((ret = bcm3510_readB(st,0xa8,&v)) < 0)
+                       return ret;
+
+               if (!v.HABSTAT_a8.HABR)
+                       return 0;
+       }
+
+       deb_info("send_request execution timed out.\n");
+       return -ETIMEDOUT;
+}
+
+static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *obuf, u8 olen, u8 *ibuf, u8 ilen)
+{
+       u8 ob[olen+2],ib[ilen+2];
+       int ret = 0;
+
+       ob[0] = cmd;
+       ob[1] = msgid;
+       memcpy(&ob[2],obuf,olen);
+
+       deb_hab("hab snd: ");
+       dbufout(ob,olen+2,deb_hab);
+       deb_hab("\n");
+
+       if (down_interruptible(&st->hab_sem) < 0)
+               return -EAGAIN;
+
+       if ((ret = bcm3510_hab_send_request(st, ob, olen+2)) < 0 ||
+               (ret = bcm3510_hab_get_response(st, ib, ilen+2)) < 0)
+               goto error;
+
+       deb_hab("hab get: ");
+       dbufout(ib,ilen+2,deb_hab);
+       deb_hab("\n");
+
+       memcpy(ibuf,&ib[2],ilen);
+error:
+       up(&st->hab_sem);
+       return ret;
+}
+
+#if 0
+/* not needed, we use a semaphore to prevent HAB races */
+static int bcm3510_is_ap_ready(struct bcm3510_state *st)
+{
+       bcm3510_register_value ap,hab;
+       int ret;
+
+       if ((ret = bcm3510_readB(st,0xa8,&hab)) < 0 ||
+               (ret = bcm3510_readB(st,0xa2,&ap) < 0))
+               return ret;
+
+       if (ap.APSTAT1_a2.RESET || ap.APSTAT1_a2.IDLE || ap.APSTAT1_a2.STOP || hab.HABSTAT_a8.HABR) {
+               deb_info("AP is busy\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+#endif
+
+static int bcm3510_bert_reset(struct bcm3510_state *st)
+{
+       bcm3510_register_value b;
+       int ret;
+
+       if ((ret < bcm3510_readB(st,0xfa,&b)) < 0)
+               return ret;
+
+       b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
+       b.BERCTL_fa.RESYNC = 1; bcm3510_writeB(st,0xfa,b);
+       b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
+       b.BERCTL_fa.CNTCTL = 1; b.BERCTL_fa.BITCNT = 1; bcm3510_writeB(st,0xfa,b);
+
+       /* clear residual bit counter TODO  */
+       return 0;
+}
+
+static int bcm3510_refresh_state(struct bcm3510_state *st)
+{
+       if (time_after(jiffies,st->next_status_check)) {
+               bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS1, NULL,0, (u8 *)&st->status1, sizeof(st->status1));
+               bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS2, NULL,0, (u8 *)&st->status2, sizeof(st->status2));
+               st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
+       }
+       return 0;
+}
+
+static int bcm3510_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct bcm3510_state* st = fe->demodulator_priv;
+       bcm3510_refresh_state(st);
+
+       *status = 0;
+       if (st->status1.STATUS1.RECEIVER_LOCK)
+               *status |= FE_HAS_LOCK | FE_HAS_SYNC;
+
+       if (st->status1.STATUS1.FEC_LOCK)
+               *status |= FE_HAS_VITERBI;
+
+       if (st->status1.STATUS1.OUT_PLL_LOCK)
+               *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+
+       if (*status & FE_HAS_LOCK)
+               st->status_check_interval = 1500;
+       else /* more frequently checks if no lock has been achieved yet */
+               st->status_check_interval = 500;
+
+       deb_info("real_status: %02x\n",*status);
+       return 0;
+}
+
+static int bcm3510_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+       struct bcm3510_state* st = fe->demodulator_priv;
+       bcm3510_refresh_state(st);
+
+       *ber = (st->status2.LDBER0 << 16) | (st->status2.LDBER1 << 8) | st->status2.LDBER2;
+       return 0;
+}
+
+static int bcm3510_read_unc(struct dvb_frontend* fe, u32* unc)
+{
+       struct bcm3510_state* st = fe->demodulator_priv;
+       bcm3510_refresh_state(st);
+       *unc = (st->status2.LDUERC0 << 8) | st->status2.LDUERC1;
+       return 0;
+}
+
+static int bcm3510_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+       struct bcm3510_state* st = fe->demodulator_priv;
+       s32 t;
+
+       bcm3510_refresh_state(st);
+       t = st->status2.SIGNAL;
+
+       if (t > 190)
+               t = 190;
+       if (t < 90)
+               t = 90;
+
+       t -= 90;
+       t = t * 0xff / 100;
+       /* normalize if necessary */
+       *strength = (t << 8) | t;
+       return 0;
+}
+
+static int bcm3510_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+       struct bcm3510_state* st = fe->demodulator_priv;
+       bcm3510_refresh_state(st);
+
+       *snr = st->status1.SNR_EST0*1000 + ((st->status1.SNR_EST1*1000) >> 8);
+       return 0;
+}
+
+/* tuner frontend programming */
+static int bcm3510_tuner_cmd(struct bcm3510_state* st,u8 bc, u16 n, u8 a)
+{
+       struct bcm3510_hab_cmd_tune c;
+       memset(&c,0,sizeof(struct bcm3510_hab_cmd_tune));
+
+/* I2C Mode disabled,  set 16 control / Data pairs */
+       c.length = 0x10;
+       c.clock_width = 0;
+/* CS1, CS0, DATA, CLK bits control the tuner RF_AGC_SEL pin is set to
+ * logic high (as Configuration) */
+       c.misc = 0x10;
+/* Set duration of the initial state of TUNCTL = 3.34 micro Sec */
+       c.TUNCTL_state = 0x40;
+
+/* PRESCALER DEVIDE RATIO | BC1_2_3_4; (band switch), 1stosc REFERENCE COUNTER REF_S12 and REF_S11 */
+       c.ctl_dat[0].ctrl.size = BITS_8;
+       c.ctl_dat[0].data      = 0x80 | bc;
+
+/* Control DATA pin, 1stosc REFERENCE COUNTER REF_S10 to REF_S3 */
+       c.ctl_dat[1].ctrl.size = BITS_8;
+       c.ctl_dat[1].data      = 4;
+
+/* set CONTROL BIT 1 to 1, 1stosc REFERENCE COUNTER REF_S2 to REF_S1 */
+       c.ctl_dat[2].ctrl.size = BITS_3;
+       c.ctl_dat[2].data      = 0x20;
+
+/* control CS0 pin, pulse byte ? */
+       c.ctl_dat[3].ctrl.size = BITS_3;
+       c.ctl_dat[3].ctrl.clk_off = 1;
+       c.ctl_dat[3].ctrl.cs0  = 1;
+       c.ctl_dat[3].data      = 0x40;
+
+/* PGM_S18 to PGM_S11 */
+       c.ctl_dat[4].ctrl.size = BITS_8;
+       c.ctl_dat[4].data      = n >> 3;
+
+/* PGM_S10 to PGM_S8, SWL_S7 to SWL_S3 */
+       c.ctl_dat[5].ctrl.size = BITS_8;
+       c.ctl_dat[5].data      = ((n & 0x7) << 5) | (a >> 2);
+
+/* SWL_S2 and SWL_S1, set CONTROL BIT 2 to 0 */
+       c.ctl_dat[6].ctrl.size = BITS_3;
+       c.ctl_dat[6].data      = (a << 6) & 0xdf;
+
+/* control CS0 pin, pulse byte ? */
+       c.ctl_dat[7].ctrl.size = BITS_3;
+       c.ctl_dat[7].ctrl.clk_off = 1;
+       c.ctl_dat[7].ctrl.cs0  = 1;
+       c.ctl_dat[7].data      = 0x40;
+
+/* PRESCALER DEVIDE RATIO, 2ndosc REFERENCE COUNTER REF_S12 and REF_S11 */
+       c.ctl_dat[8].ctrl.size = BITS_8;
+       c.ctl_dat[8].data      = 0x80;
+
+/* 2ndosc REFERENCE COUNTER REF_S10 to REF_S3 */
+       c.ctl_dat[9].ctrl.size = BITS_8;
+       c.ctl_dat[9].data      = 0x10;
+
+/* set CONTROL BIT 1 to 1, 2ndosc REFERENCE COUNTER REF_S2 to REF_S1 */
+       c.ctl_dat[10].ctrl.size = BITS_3;
+       c.ctl_dat[10].data      = 0x20;
+
+/* pulse byte */
+       c.ctl_dat[11].ctrl.size = BITS_3;
+       c.ctl_dat[11].ctrl.clk_off = 1;
+       c.ctl_dat[11].ctrl.cs1  = 1;
+       c.ctl_dat[11].data      = 0x40;
+
+/* PGM_S18 to PGM_S11 */
+       c.ctl_dat[12].ctrl.size = BITS_8;
+       c.ctl_dat[12].data      = 0x2a;
+
+/* PGM_S10 to PGM_S8 and SWL_S7 to SWL_S3 */
+       c.ctl_dat[13].ctrl.size = BITS_8;
+       c.ctl_dat[13].data      = 0x8e;
+
+/* SWL_S2 and SWL_S1 and set CONTROL BIT 2 to 0 */
+       c.ctl_dat[14].ctrl.size = BITS_3;
+       c.ctl_dat[14].data      = 0;
+
+/* Pulse Byte */
+       c.ctl_dat[15].ctrl.size = BITS_3;
+       c.ctl_dat[15].ctrl.clk_off = 1;
+       c.ctl_dat[15].ctrl.cs1  = 1;
+       c.ctl_dat[15].data      = 0x40;
+
+       return bcm3510_do_hab_cmd(st,CMD_TUNE, MSGID_TUNE,(u8 *) &c,sizeof(c), NULL, 0);
+}
+
+static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq)
+{
+       u8 bc,a;
+       u16 n;
+       s32 YIntercept,Tfvco1;
+
+       freq /= 1000;
+
+       deb_info("%dkHz:",freq);
+       /* set Band Switch */
+       if (freq <= 168000)
+               bc = 0x1c;
+       else if (freq <= 378000)
+               bc = 0x2c;
+       else
+               bc = 0x30;
+
+       if (freq >= 470000) {
+               freq -= 470001;
+               YIntercept = 18805;
+       } else if (freq >= 90000) {
+               freq -= 90001;
+               YIntercept = 15005;
+       } else if (freq >= 76000){
+               freq -= 76001;
+               YIntercept = 14865;
+       } else {
+               freq -= 54001;
+               YIntercept = 14645;
+       }
+
+       Tfvco1 = (((freq/6000)*60 + YIntercept)*4)/10;
+
+       n = Tfvco1 >> 6;
+       a = Tfvco1 & 0x3f;
+
+       deb_info(" BC1_2_3_4: %x, N: %x A: %x\n", bc, n, a);
+       if (n >= 16 && n <= 2047)
+               return bcm3510_tuner_cmd(st,bc,n,a);
+
+       return -EINVAL;
+}
+
+static int bcm3510_set_frontend(struct dvb_frontend* fe,
+                                            struct dvb_frontend_parameters *p)
+{
+       struct bcm3510_state* st = fe->demodulator_priv;
+       struct bcm3510_hab_cmd_ext_acquire cmd;
+       struct bcm3510_hab_cmd_bert_control bert;
+       int ret;
+
+       memset(&cmd,0,sizeof(cmd));
+       switch (p->u.vsb.modulation) {
+               case QAM_256:
+                       cmd.ACQUIRE0.MODE = 0x1;
+                       cmd.ACQUIRE1.SYM_RATE = 0x1;
+                       cmd.ACQUIRE1.IF_FREQ = 0x1;
+                       break;
+               case QAM_64:
+                       cmd.ACQUIRE0.MODE = 0x2;
+                       cmd.ACQUIRE1.SYM_RATE = 0x2;
+                       cmd.ACQUIRE1.IF_FREQ = 0x1;
+                       break;
+/*             case QAM_256:
+                       cmd.ACQUIRE0.MODE = 0x3;
+                       break;
+               case QAM_128:
+                       cmd.ACQUIRE0.MODE = 0x4;
+                       break;
+               case QAM_64:
+                       cmd.ACQUIRE0.MODE = 0x5;
+                       break;
+               case QAM_32:
+                       cmd.ACQUIRE0.MODE = 0x6;
+                       break;
+               case QAM_16:
+                       cmd.ACQUIRE0.MODE = 0x7;
+                       break;*/
+               case VSB_8:
+                       cmd.ACQUIRE0.MODE = 0x8;
+                       cmd.ACQUIRE1.SYM_RATE = 0x0;
+                       cmd.ACQUIRE1.IF_FREQ = 0x0;
+                       break;
+               case VSB_16:
+                       cmd.ACQUIRE0.MODE = 0x9;
+                       cmd.ACQUIRE1.SYM_RATE = 0x0;
+                       cmd.ACQUIRE1.IF_FREQ = 0x0;
+               default:
+                       return -EINVAL;
+       };
+       cmd.ACQUIRE0.OFFSET = 0;
+       cmd.ACQUIRE0.NTSCSWEEP = 1;
+       cmd.ACQUIRE0.FA = 1;
+       cmd.ACQUIRE0.BW = 0;
+
+/*     if (enableOffset) {
+               cmd.IF_OFFSET0 = xx;
+               cmd.IF_OFFSET1 = xx;
+
+               cmd.SYM_OFFSET0 = xx;
+               cmd.SYM_OFFSET1 = xx;
+               if (enableNtscSweep) {
+                       cmd.NTSC_OFFSET0;
+                       cmd.NTSC_OFFSET1;
+               }
+       } */
+       bcm3510_do_hab_cmd(st, CMD_ACQUIRE, MSGID_EXT_TUNER_ACQUIRE, (u8 *) &cmd, sizeof(cmd), NULL, 0);
+
+/* doing it with different MSGIDs, data book and source differs */
+       bert.BE = 0;
+       bert.unused = 0;
+       bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_CONTROL, (u8 *) &bert, sizeof(bert), NULL, 0);
+       bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_SET, (u8 *) &bert, sizeof(bert), NULL, 0);
+
+       bcm3510_bert_reset(st);
+
+       if ((ret = bcm3510_set_freq(st,p->frequency)) < 0)
+               return ret;
+
+       memset(&st->status1,0,sizeof(st->status1));
+       memset(&st->status2,0,sizeof(st->status2));
+       st->status_check_interval = 500;
+
+/* Give the AP some time */
+       msleep(200);
+
+       return 0;
+}
+
+static int bcm3510_sleep(struct dvb_frontend* fe)
+{
+       return 0;
+}
+
+static int bcm3510_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s)
+{
+       s->min_delay_ms = 1000;
+       s->step_size = 0;
+       s->max_drift = 0;
+       return 0;
+}
+
+static void bcm3510_release(struct dvb_frontend* fe)
+{
+       struct bcm3510_state* state = fe->demodulator_priv;
+       kfree(state);
+}
+
+/* firmware download:
+ * firmware file is build up like this:
+ * 16bit addr, 16bit length, 8byte of length
+ */
+#define BCM3510_DEFAULT_FIRMWARE "dvb-fe-bcm3510-01.fw"
+
+static int bcm3510_write_ram(struct bcm3510_state *st, u16 addr, u8 *b, u16 len)
+{
+       int ret = 0,i;
+       bcm3510_register_value vH, vL,vD;
+
+       vH.MADRH_a9 = addr >> 8;
+       vL.MADRL_aa = addr;
+       if ((ret = bcm3510_writeB(st,0xa9,vH)) < 0) return ret;
+       if ((ret = bcm3510_writeB(st,0xaa,vL)) < 0) return ret;
+
+       for (i = 0; i < len; i++) {
+               vD.MDATA_ab = b[i];
+               if ((ret = bcm3510_writeB(st,0xab,vD)) < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int bcm3510_download_firmware(struct dvb_frontend* fe)
+{
+       struct bcm3510_state* st = fe->demodulator_priv;
+       const struct firmware *fw;
+       u16 addr,len;
+       u8  *b;
+       int ret,i;
+
+       deb_info("requesting firmware\n");
+       if ((ret = st->config->request_firmware(fe, &fw, BCM3510_DEFAULT_FIRMWARE)) < 0) {
+               err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret);
+               return ret;
+       }
+       deb_info("got firmware: %d\n",fw->size);
+
+       b = fw->data;
+       for (i = 0; i < fw->size;) {
+               addr = le16_to_cpu( *( (u16 *)&b[i] ) );
+               len  = le16_to_cpu( *( (u16 *)&b[i+2] ) );
+               deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04x\n",addr,len,fw->size);
+               if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
+                       err("firmware download failed: %d\n",ret);
+                       return ret;
+               }
+               i += 4 + len;
+       }
+       release_firmware(fw);
+       deb_info("firmware download successfully completed\n");
+       return 0;
+}
+
+static int bcm3510_check_firmware_version(struct bcm3510_state *st)
+{
+       struct bcm3510_hab_cmd_get_version_info ver;
+       bcm3510_do_hab_cmd(st,CMD_GET_VERSION_INFO,MSGID_GET_VERSION_INFO,NULL,0,(u8*)&ver,sizeof(ver));
+
+       deb_info("Version information: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+               ver.microcode_version, ver.script_version, ver.config_version, ver.demod_version);
+
+       if (ver.script_version == BCM3510_DEF_SCRIPT_VERSION &&
+               ver.config_version == BCM3510_DEF_CONFIG_VERSION &&
+               ver.demod_version  == BCM3510_DEF_DEMOD_VERSION)
+               return 0;
+
+       deb_info("version check failed\n");
+       return -ENODEV;
+}
+
+/* (un)resetting the AP */
+static int bcm3510_reset(struct bcm3510_state *st)
+{
+       int ret;
+       unsigned long  t;
+       bcm3510_register_value v;
+
+       bcm3510_readB(st,0xa0,&v); v.HCTL1_a0.RESET = 1;
+       if ((ret = bcm3510_writeB(st,0xa0,v)) < 0)
+               return ret;
+
+    t = jiffies + 3*HZ;
+       while (time_before(jiffies, t)) {
+               msleep(10);
+               if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
+                       return ret;
+
+               if (v.APSTAT1_a2.RESET)
+                       return 0;
+       }
+       deb_info("reset timed out\n");
+       return -ETIMEDOUT;
+}
+
+static int bcm3510_clear_reset(struct bcm3510_state *st)
+{
+       bcm3510_register_value v;
+       int ret;
+       unsigned long t;
+
+       v.raw = 0;
+       if ((ret = bcm3510_writeB(st,0xa0,v)) < 0)
+               return ret;
+
+    t = jiffies + 3*HZ;
+       while (time_before(jiffies, t)) {
+               msleep(10);
+               if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
+                       return ret;
+
+               /* verify that reset is cleared */
+               if (!v.APSTAT1_a2.RESET)
+                       return 0;
+       }
+       deb_info("reset clear timed out\n");
+       return -ETIMEDOUT;
+}
+
+static int bcm3510_init_cold(struct bcm3510_state *st)
+{
+       int ret;
+       bcm3510_register_value v;
+
+       /* read Acquisation Processor status register and check it is not in RUN mode */
+       if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
+               return ret;
+       if (v.APSTAT1_a2.RUN) {
+               deb_info("AP is already running - firmware already loaded.\n");
+               return 0;
+       }
+
+       deb_info("reset?\n");
+       if ((ret = bcm3510_reset(st)) < 0)
+               return ret;
+
+       deb_info("tristate?\n");
+       /* tri-state */
+       v.TSTCTL_2e.CTL = 0;
+       if ((ret = bcm3510_writeB(st,0x2e,v)) < 0)
+               return ret;
+
+       deb_info("firmware?\n");
+       if ((ret = bcm3510_download_firmware(&st->frontend)) < 0 ||
+               (ret = bcm3510_clear_reset(st)) < 0)
+               return ret;
+
+       /* anything left here to Let the acquisition processor begin execution at program counter 0000 ??? */
+
+       return 0;
+}
+
+static int bcm3510_init(struct dvb_frontend* fe)
+{
+       struct bcm3510_state* st = fe->demodulator_priv;
+       bcm3510_register_value j;
+       struct bcm3510_hab_cmd_set_agc c;
+       int ret;
+
+       if ((ret = bcm3510_readB(st,0xca,&j)) < 0)
+               return ret;
+
+       deb_info("JDEC: %02x\n",j.raw);
+
+       switch (j.JDEC_ca.JDEC) {
+               case JDEC_WAIT_AT_RAM:
+                       deb_info("attempting to download firmware\n");
+                       if ((ret = bcm3510_init_cold(st)) < 0)
+                               return ret;
+               case JDEC_EEPROM_LOAD_WAIT: /* fall-through is wanted */
+                       deb_info("firmware is loaded\n");
+                       bcm3510_check_firmware_version(st);
+                       break;
+               default:
+                       return -ENODEV;
+       }
+
+       memset(&c,0,1);
+       c.SEL = 1;
+       bcm3510_do_hab_cmd(st,CMD_AUTO_PARAM,MSGID_SET_RF_AGC_SEL,(u8 *)&c,sizeof(c),NULL,0);
+
+       return 0;
+}
+
+
+static struct dvb_frontend_ops bcm3510_ops;
+
+struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config,
+                                  struct i2c_adapter *i2c)
+{
+       struct bcm3510_state* state = NULL;
+       int ret;
+       bcm3510_register_value v;
+
+       /* allocate memory for the internal state */
+       state = kmalloc(sizeof(struct bcm3510_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+       memset(state,0,sizeof(struct bcm3510_state));
+
+       /* setup the state */
+
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+
+       sema_init(&state->hab_sem, 1);
+
+       if ((ret = bcm3510_readB(state,0xe0,&v)) < 0)
+               goto error;
+
+       deb_info("Revision: 0x%1x, Layer: 0x%1x.\n",v.REVID_e0.REV,v.REVID_e0.LAYER);
+
+       if ((v.REVID_e0.REV != 0x1 && v.REVID_e0.LAYER != 0xb) && /* cold */
+               (v.REVID_e0.REV != 0x8 && v.REVID_e0.LAYER != 0x0))   /* warm */
+               goto error;
+
+       info("Revision: 0x%1x, Layer: 0x%1x.",v.REVID_e0.REV,v.REVID_e0.LAYER);
+
+       bcm3510_reset(state);
+
+       return &state->frontend;
+
+error:
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(bcm3510_attach);
+
+static struct dvb_frontend_ops bcm3510_ops = {
+
+       .info = {
+               .name = "Broadcom BCM3510 VSB/QAM frontend",
+               .type = FE_ATSC,
+               .frequency_min =  54000000,
+               .frequency_max = 803000000,
+                /* stepsize is just a guess */
+               .frequency_stepsize = 0,
+               .caps =
+                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_8VSB | FE_CAN_16VSB |
+                       FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256
+       },
+
+       .release = bcm3510_release,
+
+       .init = bcm3510_init,
+       .sleep = bcm3510_sleep,
+
+       .set_frontend = bcm3510_set_frontend,
+       .get_tune_settings = bcm3510_get_tune_settings,
+
+       .read_status = bcm3510_read_status,
+       .read_ber = bcm3510_read_ber,
+       .read_signal_strength = bcm3510_read_signal_strength,
+       .read_snr = bcm3510_read_snr,
+       .read_ucblocks = bcm3510_read_unc,
+};
+
+MODULE_DESCRIPTION("Broadcom BCM3510 ATSC (8VSB/16VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/bcm3510.h b/drivers/media/dvb/frontends/bcm3510.h
new file mode 100644 (file)
index 0000000..80f5d09
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
+ *
+ *  Copyright (C) 2001-5, B2C2 inc.
+ *
+ *  GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef BCM3510_H
+#define BCM3510_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct bcm3510_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* request firmware for device */
+       int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+};
+
+extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
+                                          struct i2c_adapter* i2c);
+
+#endif
diff --git a/drivers/media/dvb/frontends/bcm3510_priv.h b/drivers/media/dvb/frontends/bcm3510_priv.h
new file mode 100644 (file)
index 0000000..3bb1bc2
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
+ *
+ *  Copyright (C) 2001-5, B2C2 inc.
+ *
+ *  GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __BCM3510_PRIV_H__
+#define __BCM3510_PRIV_H__
+
+#define PACKED __attribute__((packed))
+
+#undef err
+#define err(format, arg...)  printk(KERN_ERR     "bcm3510: " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) printk(KERN_INFO    "bcm3510: " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING "bcm3510: " format "\n" , ## arg)
+
+
+#define PANASONIC_FIRST_IF_BASE_IN_KHz  1407500
+#define BCM3510_SYMBOL_RATE             5381000
+
+typedef union {
+       u8 raw;
+
+       struct {
+               u8 CTL   :8;
+       } TSTCTL_2e;
+
+       u8 LDCERC_4e;
+       u8 LDUERC_4f;
+       u8 LD_BER0_65;
+       u8 LD_BER1_66;
+       u8 LD_BER2_67;
+       u8 LD_BER3_68;
+
+       struct {
+               u8 RESET :1;
+               u8 IDLE  :1;
+               u8 STOP  :1;
+               u8 HIRQ0 :1;
+               u8 HIRQ1 :1;
+               u8 na0   :1;
+               u8 HABAV :1;
+               u8 na1   :1;
+       } HCTL1_a0;
+
+       struct {
+               u8 na0    :1;
+               u8 IDLMSK :1;
+               u8 STMSK  :1;
+               u8 I0MSK  :1;
+               u8 I1MSK  :1;
+               u8 na1    :1;
+               u8 HABMSK :1;
+               u8 na2    :1;
+       } HCTLMSK_a1;
+
+       struct {
+               u8 RESET  :1;
+               u8 IDLE   :1;
+               u8 STOP   :1;
+               u8 RUN    :1;
+               u8 HABAV  :1;
+               u8 MEMAV  :1;
+               u8 ALDONE :1;
+               u8 REIRQ  :1;
+       } APSTAT1_a2;
+
+       struct {
+               u8 RSTMSK :1;
+               u8 IMSK   :1;
+               u8 SMSK   :1;
+               u8 RMSK   :1;
+               u8 HABMSK :1;
+               u8 MAVMSK :1;
+               u8 ALDMSK :1;
+               u8 REMSK  :1;
+       } APMSK1_a3;
+
+       u8 APSTAT2_a4;
+       u8 APMSK2_a5;
+
+       struct {
+               u8 HABADR :7;
+               u8 na     :1;
+       } HABADR_a6;
+
+       u8 HABDATA_a7;
+
+       struct {
+               u8 HABR   :1;
+               u8 LDHABR :1;
+               u8 APMSK  :1;
+               u8 HMSK   :1;
+               u8 LDMSK  :1;
+               u8 na     :3;
+       } HABSTAT_a8;
+
+       u8 MADRH_a9;
+       u8 MADRL_aa;
+       u8 MDATA_ab;
+
+       struct {
+#define JDEC_WAIT_AT_RAM      0x7
+#define JDEC_EEPROM_LOAD_WAIT 0x4
+               u8 JDEC   :3;
+               u8 na     :5;
+       } JDEC_ca;
+
+       struct {
+               u8 REV   :4;
+               u8 LAYER :4;
+       } REVID_e0;
+
+       struct {
+               u8 unk0   :1;
+               u8 CNTCTL :1;
+               u8 BITCNT :1;
+               u8 unk1   :1;
+               u8 RESYNC :1;
+               u8 unk2   :3;
+       } BERCTL_fa;
+
+       struct {
+               u8 CSEL0  :1;
+               u8 CLKED0 :1;
+               u8 CSEL1  :1;
+               u8 CLKED1 :1;
+               u8 CLKLEV :1;
+               u8 SPIVAR :1;
+               u8 na     :2;
+       } TUNSET_fc;
+
+       struct {
+               u8 CLK    :1;
+               u8 DATA   :1;
+               u8 CS0    :1;
+               u8 CS1    :1;
+               u8 AGCSEL :1;
+               u8 na0    :1;
+               u8 TUNSEL :1;
+               u8 na1    :1;
+       } TUNCTL_fd;
+
+       u8 TUNSEL0_fe;
+       u8 TUNSEL1_ff;
+
+} bcm3510_register_value;
+
+/* HAB commands */
+
+/* version */
+#define CMD_GET_VERSION_INFO   0x3D
+#define MSGID_GET_VERSION_INFO 0x15
+struct bcm3510_hab_cmd_get_version_info {
+       u8 microcode_version;
+       u8 script_version;
+       u8 config_version;
+       u8 demod_version;
+} PACKED;
+
+#define BCM3510_DEF_MICROCODE_VERSION 0x0E
+#define BCM3510_DEF_SCRIPT_VERSION    0x06
+#define BCM3510_DEF_CONFIG_VERSION    0x01
+#define BCM3510_DEF_DEMOD_VERSION     0xB1
+
+/* acquire */
+#define CMD_ACQUIRE            0x38
+
+#define MSGID_EXT_TUNER_ACQUIRE 0x0A
+struct bcm3510_hab_cmd_ext_acquire {
+       struct {
+               u8 MODE      :4;
+               u8 BW        :1;
+               u8 FA        :1;
+               u8 NTSCSWEEP :1;
+               u8 OFFSET    :1;
+       } PACKED ACQUIRE0; /* control_byte */
+
+       struct {
+               u8 IF_FREQ  :3;
+               u8 zero0    :1;
+               u8 SYM_RATE :3;
+               u8 zero1    :1;
+       } PACKED ACQUIRE1; /* sym_if */
+
+       u8 IF_OFFSET0;   /* IF_Offset_10hz */
+       u8 IF_OFFSET1;
+       u8 SYM_OFFSET0;  /* SymbolRateOffset */
+       u8 SYM_OFFSET1;
+       u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */
+       u8 NTSC_OFFSET1;
+} PACKED;
+
+#define MSGID_INT_TUNER_ACQUIRE 0x0B
+struct bcm3510_hab_cmd_int_acquire {
+       struct {
+               u8 MODE      :4;
+               u8 BW        :1;
+               u8 FA        :1;
+               u8 NTSCSWEEP :1;
+               u8 OFFSET    :1;
+       } PACKED ACQUIRE0; /* control_byte */
+
+       struct {
+               u8 IF_FREQ  :3;
+               u8 zero0    :1;
+               u8 SYM_RATE :3;
+               u8 zero1    :1;
+       } PACKED ACQUIRE1; /* sym_if */
+
+       u8 TUNER_FREQ0;
+       u8 TUNER_FREQ1;
+       u8 TUNER_FREQ2;
+       u8 TUNER_FREQ3;
+       u8 IF_OFFSET0;   /* IF_Offset_10hz */
+       u8 IF_OFFSET1;
+       u8 SYM_OFFSET0;  /* SymbolRateOffset */
+       u8 SYM_OFFSET1;
+       u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */
+       u8 NTSC_OFFSET1;
+} PACKED;
+
+/* modes */
+#define BCM3510_QAM16           =   0x01
+#define BCM3510_QAM32           =   0x02
+#define BCM3510_QAM64           =   0x03
+#define BCM3510_QAM128          =   0x04
+#define BCM3510_QAM256          =   0x05
+#define BCM3510_8VSB            =   0x0B
+#define BCM3510_16VSB           =   0x0D
+
+/* IF_FREQS */
+#define BCM3510_IF_TERRESTRIAL 0x0
+#define BCM3510_IF_CABLE       0x1
+#define BCM3510_IF_USE_CMD     0x7
+
+/* SYM_RATE */
+#define BCM3510_SR_8VSB        0x0 /* 5381119 s/sec */
+#define BCM3510_SR_256QAM      0x1 /* 5360537 s/sec */
+#define BCM3510_SR_16QAM       0x2 /* 5056971 s/sec */
+#define BCM3510_SR_MISC        0x3 /* 5000000 s/sec */
+#define BCM3510_SR_USE_CMD     0x7
+
+/* special symbol rate */
+#define CMD_SET_VALUE_NOT_LISTED  0x2d
+#define MSGID_SET_SYMBOL_RATE_NOT_LISTED 0x0c
+struct bcm3510_hab_cmd_set_sr_not_listed {
+       u8 HOST_SYM_RATE0;
+       u8 HOST_SYM_RATE1;
+       u8 HOST_SYM_RATE2;
+       u8 HOST_SYM_RATE3;
+} PACKED;
+
+/* special IF */
+#define MSGID_SET_IF_FREQ_NOT_LISTED 0x0d
+struct bcm3510_hab_cmd_set_if_freq_not_listed {
+       u8 HOST_IF_FREQ0;
+       u8 HOST_IF_FREQ1;
+       u8 HOST_IF_FREQ2;
+       u8 HOST_IF_FREQ3;
+} PACKED;
+
+/* auto reacquire */
+#define CMD_AUTO_PARAM       0x2a
+#define MSGID_AUTO_REACQUIRE 0x0e
+struct bcm3510_hab_cmd_auto_reacquire {
+       u8 ACQ    :1; /* on/off*/
+       u8 unused :7;
+} PACKED;
+
+#define MSGID_SET_RF_AGC_SEL 0x12
+struct bcm3510_hab_cmd_set_agc {
+       u8 LVL    :1;
+       u8 unused :6;
+       u8 SEL    :1;
+} PACKED;
+
+#define MSGID_SET_AUTO_INVERSION 0x14
+struct bcm3510_hab_cmd_auto_inversion {
+       u8 AI     :1;
+       u8 unused :7;
+} PACKED;
+
+
+/* bert control */
+#define CMD_STATE_CONTROL  0x12
+#define MSGID_BERT_CONTROL 0x0e
+#define MSGID_BERT_SET     0xfa
+struct bcm3510_hab_cmd_bert_control {
+       u8 BE     :1;
+       u8 unused :7;
+} PACKED;
+
+#define MSGID_TRI_STATE 0x2e
+struct bcm3510_hab_cmd_tri_state {
+       u8 RE :1; /* a/d ram port pins */
+       u8 PE :1; /* baud clock pin */
+       u8 AC :1; /* a/d clock pin */
+       u8 BE :1; /* baud clock pin */
+       u8 unused :4;
+} PACKED;
+
+
+/* tune */
+#define CMD_TUNE   0x38
+#define MSGID_TUNE 0x16
+struct bcm3510_hab_cmd_tune_ctrl_data_pair {
+       struct {
+#define BITS_8 0x07
+#define BITS_7 0x06
+#define BITS_6 0x05
+#define BITS_5 0x04
+#define BITS_4 0x03
+#define BITS_3 0x02
+#define BITS_2 0x01
+#define BITS_1 0x00
+               u8 size    :3;
+               u8 unk     :2;
+               u8 clk_off :1;
+               u8 cs0     :1;
+               u8 cs1     :1;
+
+       } PACKED ctrl;
+
+       u8 data;
+} PACKED;
+
+struct bcm3510_hab_cmd_tune {
+       u8 length;
+       u8 clock_width;
+       u8 misc;
+       u8 TUNCTL_state;
+
+       struct bcm3510_hab_cmd_tune_ctrl_data_pair ctl_dat[16];
+} PACKED;
+
+#define CMD_STATUS    0x38
+#define MSGID_STATUS1 0x08
+struct bcm3510_hab_cmd_status1 {
+       struct {
+               u8 EQ_MODE       :4;
+               u8 reserved      :2;
+               u8 QRE           :1; /* if QSE and the spectrum is inversed */
+               u8 QSE           :1; /* automatic spectral inversion */
+       } PACKED STATUS0;
+
+       struct {
+               u8 RECEIVER_LOCK :1;
+               u8 FEC_LOCK      :1;
+               u8 OUT_PLL_LOCK  :1;
+               u8 reserved      :5;
+       } PACKED STATUS1;
+
+       struct {
+               u8 reserved      :2;
+               u8 BW            :1;
+               u8 NTE           :1; /* NTSC filter sweep enabled */
+               u8 AQI           :1; /* currently acquiring */
+               u8 FA            :1; /* fast acquisition */
+               u8 ARI           :1; /* auto reacquire */
+               u8 TI            :1; /* programming the tuner */
+       } PACKED STATUS2;
+       u8 STATUS3;
+       u8 SNR_EST0;
+       u8 SNR_EST1;
+       u8 TUNER_FREQ0;
+       u8 TUNER_FREQ1;
+       u8 TUNER_FREQ2;
+       u8 TUNER_FREQ3;
+       u8 SYM_RATE0;
+       u8 SYM_RATE1;
+       u8 SYM_RATE2;
+       u8 SYM_RATE3;
+       u8 SYM_OFFSET0;
+       u8 SYM_OFFSET1;
+       u8 SYM_ERROR0;
+       u8 SYM_ERROR1;
+       u8 IF_FREQ0;
+       u8 IF_FREQ1;
+       u8 IF_FREQ2;
+       u8 IF_FREQ3;
+       u8 IF_OFFSET0;
+       u8 IF_OFFSET1;
+       u8 IF_ERROR0;
+       u8 IF_ERROR1;
+       u8 NTSC_FILTER0;
+       u8 NTSC_FILTER1;
+       u8 NTSC_FILTER2;
+       u8 NTSC_FILTER3;
+       u8 NTSC_OFFSET0;
+       u8 NTSC_OFFSET1;
+       u8 NTSC_ERROR0;
+       u8 NTSC_ERROR1;
+       u8 INT_AGC_LEVEL0;
+       u8 INT_AGC_LEVEL1;
+       u8 EXT_AGC_LEVEL0;
+       u8 EXT_AGC_LEVEL1;
+} PACKED;
+
+#define MSGID_STATUS2 0x14
+struct bcm3510_hab_cmd_status2 {
+       struct {
+               u8 EQ_MODE  :4;
+               u8 reserved :2;
+               u8 QRE      :1;
+               u8 QSR      :1;
+       } PACKED STATUS0;
+       struct {
+               u8 RL       :1;
+               u8 FL       :1;
+               u8 OL       :1;
+               u8 reserved :5;
+       } PACKED STATUS1;
+       u8 SYMBOL_RATE0;
+       u8 SYMBOL_RATE1;
+       u8 SYMBOL_RATE2;
+       u8 SYMBOL_RATE3;
+       u8 LDCERC0;
+       u8 LDCERC1;
+       u8 LDCERC2;
+       u8 LDCERC3;
+       u8 LDUERC0;
+       u8 LDUERC1;
+       u8 LDUERC2;
+       u8 LDUERC3;
+       u8 LDBER0;
+       u8 LDBER1;
+       u8 LDBER2;
+       u8 LDBER3;
+       struct {
+               u8 MODE_TYPE :4; /* acquire mode 0 */
+               u8 reservd   :4;
+       } MODE_TYPE;
+       u8 SNR_EST0;
+       u8 SNR_EST1;
+       u8 SIGNAL;
+} PACKED;
+
+#define CMD_SET_RF_BW_NOT_LISTED   0x3f
+#define MSGID_SET_RF_BW_NOT_LISTED 0x11
+/* TODO */
+
+#endif
index 47ab02e133d1bc1bad8c7c0a469bda739b08958d..1a4f1f7c228a1e112fc0ad1c4040c6c72dab833e 100644 (file)
@@ -73,7 +73,7 @@ u16 dib3000_seq[2][2][2] =     /* fft,gua,   inv   */
        };
 
 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de");
-MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb-frontend drivers");
+MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb frontend drivers");
 MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(dib3000_seq);
index 80687c130836f06a39d57a1362ebdea0e3eefc60..2d5475b5c0636d5c86df2baf16ac60723e10abd1 100644 (file)
@@ -32,9 +32,8 @@ struct dib3000_config
        u8 demod_address;
 
        /* PLL maintenance and the i2c address of the PLL */
-       u8 (*pll_addr)(struct dvb_frontend *fe);
-       int (*pll_init)(struct dvb_frontend *fe, u8 pll_buf[5]);
-       int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params, u8 pll_buf[5]);
+       int (*pll_init)(struct dvb_frontend *fe);
+       int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params);
 };
 
 struct dib_fe_xfer_ops
index 6f52d649e97e083b8fcd18a837526aeb5abacfec..cd434b7cf9db697370b7d46635876bd80ce58cd9 100644 (file)
@@ -48,8 +48,6 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-a
 #define deb_setf(args...) dprintk(0x04,args)
 #define deb_getf(args...) dprintk(0x08,args)
 
-static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr);
-
 static int dib3000mb_get_frontend(struct dvb_frontend* fe,
                                  struct dvb_frontend_parameters *fep);
 
@@ -61,10 +59,8 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
        fe_code_rate_t fe_cr = FEC_NONE;
        int search_state, seq;
 
-       if (tuner && state->config.pll_addr && state->config.pll_set) {
-               dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
-               state->config.pll_set(fe, fep, NULL);
-               dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
+       if (tuner && state->config.pll_set) {
+               state->config.pll_set(fe, fep);
 
                deb_setf("bandwidth: ");
                switch (ofdm->bandwidth) {
@@ -389,11 +385,8 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
 
        wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF);
 
-       if (state->config.pll_init) {
-               dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
-               state->config.pll_init(fe,NULL);
-               dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
-       }
+       if (state->config.pll_init)
+               state->config.pll_init(fe);
 
        return 0;
 }
@@ -623,7 +616,7 @@ static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
 {
        struct dib3000_state* state = fe->demodulator_priv;
 
-       *unc = rd(DIB3000MB_REG_UNC);
+       *unc = rd(DIB3000MB_REG_PACKET_ERROR_RATE);
        return 0;
 }
 
@@ -638,9 +631,6 @@ static int dib3000mb_sleep(struct dvb_frontend* fe)
 static int dib3000mb_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
 {
        tune->min_delay_ms = 800;
-       tune->step_size = 166667;
-       tune->max_drift = 166667 * 2;
-
        return 0;
 }
 
index 57e61aa5b07b0b79da7cecc720effae549e4823a..999b19047816dfc4402781557b9aea7a6f611de5 100644 (file)
@@ -294,7 +294,7 @@ static u16 dib3000mb_reg_filter_coeffs[] = {
 
 static u16 dib3000mb_filter_coeffs[] = {
         226,  160,   29,
-        979,  998,   19,
+        979,  998,   19,
          22, 1019, 1006,
        1022,   12,    6,
        1017, 1017,    3,
index 888f10a5e96b28bc469c9d14c4b265b89a527dc0..cd33705a4320b5a44ba6e8eb9158c2436e893fc4 100644 (file)
@@ -48,8 +48,6 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe,16=s
 #define deb_getf(args...) dprintk(0x08,args)
 #define deb_stat(args...) dprintk(0x10,args)
 
-static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr);
-
 static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode,
        fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth)
 {
@@ -463,10 +461,8 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
        int search_state,auto_val;
        u16 val;
 
-       if (tuner && state->config.pll_addr && state->config.pll_set) { /* initial call from dvb */
-               dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
-               state->config.pll_set(fe,fep,NULL);
-               dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
+       if (tuner && state->config.pll_set) { /* initial call from dvb */
+               state->config.pll_set(fe,fep);
 
                state->last_tuned_freq = fep->frequency;
        //      if (!scanboost) {
@@ -554,19 +550,15 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
                        dib3000mc_set_adp_cfg(state,ofdm->constellation);
                wr_foreach(dib3000mc_reg_offset,
                                dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
-
-
        }
        return 0;
 }
 
 static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
 {
-       struct dib3000_state *state;
-
+       struct dib3000_state *state = fe->demodulator_priv;
        deb_info("init start\n");
 
-       state = fe->demodulator_priv;
        state->timing_offset = 0;
        state->timing_offset_comp_done = 0;
 
@@ -649,11 +641,9 @@ static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
 
        set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
 
-/*     if (state->config->pll_init) {
-               dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
-               state->config->pll_init(fe,NULL);
-               dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
-       }*/
+       if (state->config.pll_init)
+               state->config.pll_init(fe);
+
        deb_info("init end\n");
        return 0;
 }
@@ -688,7 +678,7 @@ static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
 {
        struct dib3000_state* state = fe->demodulator_priv;
 
-       *unc = rd(DIB3000MC_REG_PACKET_ERROR_COUNT);
+       *unc = rd(DIB3000MC_REG_PACKET_ERRORS);
        return 0;
 }
 
@@ -737,10 +727,7 @@ static int dib3000mc_sleep(struct dvb_frontend* fe)
 
 static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
 {
-       tune->min_delay_ms = 2000;
-       tune->step_size = 166667;
-       tune->max_drift = 166667 * 2;
-
+       tune->min_delay_ms = 1000;
        return 0;
 }
 
index 2a3c2ce7b2aa8fbe24f7c466e742b8cc73a64320..f73b5f48e23591b83aa39102040d52c48325c4f9 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: dvb-pll.c,v 1.7 2005/02/10 11:52:02 kraxel Exp $
- *
  * descriptions + helper functions for simple dvb plls.
  *
  * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
@@ -114,6 +112,92 @@ struct dvb_pll_desc dvb_pll_unknown_1 = {
 };
 EXPORT_SYMBOL(dvb_pll_unknown_1);
 
+/* Infineon TUA6010XS
+ * used in Thomson Cable Tuner
+ */
+struct dvb_pll_desc dvb_pll_tua6010xs = {
+       .name  = "Infineon TUA6010XS",
+       .min   =  44250000,
+       .max   = 858000000,
+       .count = 3,
+       .entries = {
+               {  115750000, 36125000, 62500, 0x8e, 0x03 },
+               {  403250000, 36125000, 62500, 0x8e, 0x06 },
+               {  999999999, 36125000, 62500, 0x8e, 0x85 },
+       },
+};
+EXPORT_SYMBOL(dvb_pll_tua6010xs);
+
+/* Panasonic env57h1xd5 (some Philips PLL ?) */
+struct dvb_pll_desc dvb_pll_env57h1xd5 = {
+       .name  = "Panasonic ENV57H1XD5",
+       .min   =  44250000,
+       .max   = 858000000,
+       .count = 4,
+       .entries = {
+               {  153000000, 36291666, 166666, 0xc2, 0x41 },
+               {  470000000, 36291666, 166666, 0xc2, 0x42 },
+               {  526000000, 36291666, 166666, 0xc2, 0x84 },
+               {  999999999, 36291666, 166666, 0xc2, 0xa4 },
+       },
+};
+EXPORT_SYMBOL(dvb_pll_env57h1xd5);
+
+/* Philips TDA6650/TDA6651
+ * used in Panasonic ENV77H11D5
+ */
+static void tda665x_bw(u8 *buf, int bandwidth)
+{
+       if (bandwidth == BANDWIDTH_8_MHZ)
+               buf[3] |= 0x08;
+}
+
+struct dvb_pll_desc dvb_pll_tda665x = {
+       .name  = "Philips TDA6650/TDA6651",
+       .min   =  44250000,
+       .max   = 858000000,
+       .setbw = tda665x_bw,
+       .count = 12,
+       .entries = {
+               {   93834000, 36249333, 166667, 0xca, 0x61 /* 011 0 0 0  01 */ },
+               {  123834000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0  01 */ },
+               {  161000000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0  01 */ },
+               {  163834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0  10 */ },
+               {  253834000, 36249333, 166667, 0xca, 0x62 /* 011 0 0 0  10 */ },
+               {  383834000, 36249333, 166667, 0xca, 0xa2 /* 101 0 0 0  10 */ },
+               {  443834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0  10 */ },
+               {  444000000, 36249333, 166667, 0xca, 0xc3 /* 110 0 0 0  11 */ },
+               {  583834000, 36249333, 166667, 0xca, 0x63 /* 011 0 0 0  11 */ },
+               {  793834000, 36249333, 166667, 0xca, 0xa3 /* 101 0 0 0  11 */ },
+               {  444834000, 36249333, 166667, 0xca, 0xc3 /* 110 0 0 0  11 */ },
+               {  861000000, 36249333, 166667, 0xca, 0xe3 /* 111 0 0 0  11 */ },
+       }
+};
+EXPORT_SYMBOL(dvb_pll_tda665x);
+
+/* Infineon TUA6034
+ * used in LG TDTP E102P
+ */
+static void tua6034_bw(u8 *buf, int bandwidth)
+{
+       if (BANDWIDTH_7_MHZ != bandwidth)
+               buf[3] |= 0x08;
+}
+
+struct dvb_pll_desc dvb_pll_tua6034 = {
+       .name  = "Infineon TUA6034",
+       .min   =  44250000,
+       .max   = 858000000,
+       .count = 3,
+       .setbw = tua6034_bw,
+       .entries = {
+               {  174500000, 36166667, 62500, 0xce, 0x01 },
+               {  230000000, 36166667, 62500, 0xce, 0x02 },
+               {  999999999, 36166667, 62500, 0xce, 0x04 },
+       },
+};
+EXPORT_SYMBOL(dvb_pll_tua6034);
+
 /* ----------------------------------------------------------- */
 /* code                                                        */
 
@@ -160,9 +244,3 @@ EXPORT_SYMBOL(dvb_pll_configure);
 MODULE_DESCRIPTION("dvb pll library");
 MODULE_AUTHOR("Gerd Knorr");
 MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index c4c3c56c4a819769e650ad62199abe431bc7a27f..b796778624b61059ce427c59bbec8b3b32c6a2f8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dvb-pll.h,v 1.2 2005/02/10 11:43:41 kraxel Exp $
+ * descriptions + helper functions for simple dvb plls.
  */
 
 #ifndef __DVB_PLL_H__
@@ -17,7 +17,7 @@ struct dvb_pll_desc {
                u32 stepsize;
                u8  cb1;
                u8  cb2;
-       } entries[9];
+       } entries[12];
 };
 
 extern struct dvb_pll_desc dvb_pll_thomson_dtt7579;
@@ -26,6 +26,11 @@ extern struct dvb_pll_desc dvb_pll_thomson_dtt7610;
 extern struct dvb_pll_desc dvb_pll_lg_z201;
 extern struct dvb_pll_desc dvb_pll_unknown_1;
 
+extern struct dvb_pll_desc dvb_pll_tua6010xs;
+extern struct dvb_pll_desc dvb_pll_env57h1xd5;
+extern struct dvb_pll_desc dvb_pll_tua6034;
+extern struct dvb_pll_desc dvb_pll_tda665x;
+
 int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
                      u32 freq, int bandwidth);
 
index 6c05fddb69ab484841abefdf007e52ebc4d17bf5..1b70f8b0feb9fa1f32d10715a657edc114dc73a3 100644 (file)
@@ -7,6 +7,19 @@ menu "Video For Linux"
 
 comment "Video Adapters"
 
+config TUNER_MULTI_I2C
+       bool "Enable support for multiple I2C devices on Video Adapters (EXPERIMENTAL)"
+       depends on VIDEO_DEV && EXPERIMENTAL
+       ---help---
+         Some video adapters have more than one tuner inside. This patch
+         enables support for using more than one tuner. This is required
+         for some cards to allow tunning  both video and radio.
+         It also improves I2C autodetection for these cards.
+
+         Only few tuners currently is supporting this. More to come.
+
+         It is safe to say 'Y' here even if your card has only one I2C tuner.
+
 config VIDEO_BT848
        tristate "BT848 Video For Linux"
        depends on VIDEO_DEV && PCI && I2C
@@ -330,6 +343,7 @@ config VIDEO_CX88_DVB
        select VIDEO_BUF_DVB
        select DVB_MT352
        select DVB_OR51132
+       select DVB_CX22702
        ---help---
          This adds support for DVB/ATSC cards based on the
          Connexant 2388x chip.
index 2dc906fdfa550948caf23f528119401b7de22f9f..810e7aac0a535edeed845e2c435d3d8f5cbb9d8f 100644 (file)
@@ -7,8 +7,7 @@ bttv-objs       :=      bttv-driver.o bttv-cards.o bttv-if.o \
 zoran-objs      :=     zr36120.o zr36120_i2c.o zr36120_mem.o
 zr36067-objs   :=      zoran_procfs.o zoran_device.o \
                        zoran_driver.o zoran_card.o
-tuner-objs     :=      tuner-core.o tuner-simple.o mt20xx.o tda8290.o
-
+tuner-objs     :=      tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o
 
 obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
index 07f72f64c5f73c9776b44d1f09eac17a8c3c3e5d..9a642c7de545104019471c510f7657b0fc4ba34f 100644 (file)
@@ -6,7 +6,7 @@
   It outputs an 8-bit 4:2:2 YUV or YCrCb video signal which can be directly
   connected to bt848/bt878 GPIO pins on this purpose.
   (see: VLSI Vision Ltd. www.vvl.co.uk for camera datasheets)
-  
+
   Supported Cards:
   -  Pixelview Rev.4E: 0x8a
                GPIO 0x400000 toggles Bt832 RESET, and the chip changes to i2c 0x88 !
@@ -31,8 +31,8 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 
-#include "id.h"
-#include "audiochip.h"
+#include <media/audiochip.h>
+#include <media/id.h>
 #include "bttv.h"
 #include "bt832.h"
 
@@ -95,7 +95,7 @@ int bt832_init(struct i2c_client *i2c_client_s)
 
        buf=kmalloc(65,GFP_KERNEL);
        bt832_hexdump(i2c_client_s,buf);
-       
+
        if(buf[0x40] != 0x31) {
                printk("bt832: this i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
                kfree(buf);
@@ -135,7 +135,7 @@ int bt832_init(struct i2c_client *i2c_client_s)
        buf[1]= 0x27 & (~0x01); // Default | !skip
        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
                 printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
-       
+
         bt832_hexdump(i2c_client_s,buf);
 
 #if 0
@@ -168,8 +168,7 @@ int bt832_init(struct i2c_client *i2c_client_s)
 
 
 
-static int bt832_attach(struct i2c_adapter *adap, int addr,
-                         unsigned short flags, int kind)
+static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
 {
        struct bt832 *t;
 
@@ -184,27 +183,32 @@ static int bt832_attach(struct i2c_adapter *adap, int addr,
                 return -ENOMEM;
        memset(t,0,sizeof(*t));
        t->client = client_template;
-        t->client.data = t;
+        i2c_set_clientdata(&t->client, t);
         i2c_attach_client(&t->client);
 
        if(! bt832_init(&t->client)) {
                bt832_detach(&t->client);
                return -1;
        }
-        
+
        return 0;
 }
 
 static int bt832_probe(struct i2c_adapter *adap)
 {
+#ifdef I2C_CLASS_TV_ANALOG
        if (adap->class & I2C_CLASS_TV_ANALOG)
                return i2c_probe(adap, &addr_data, bt832_attach);
+#else
+       if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+               return i2c_probe(adap, &addr_data, bt832_attach);
+#endif
        return 0;
 }
 
 static int bt832_detach(struct i2c_client *client)
 {
-       struct bt832 *t = (struct bt832*)client->data;
+       struct bt832 *t = i2c_get_clientdata(client);
 
        printk("bt832: detach.\n");
        i2c_detach_client(client);
@@ -215,7 +219,7 @@ static int bt832_detach(struct i2c_client *client)
 static int
 bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
-       struct bt832 *t = (struct bt832*)client->data;
+       struct bt832 *t = i2c_get_clientdata(client);
 
        printk("bt832: command %x\n",cmd);
 
@@ -249,19 +253,18 @@ static struct i2c_driver driver = {
 };
 static struct i2c_client client_template =
 {
-        .name   = "bt832",
-       .flags  = I2C_CLIENT_ALLOW_USE,
-        .driver = &driver,
+       I2C_DEVNAME("bt832"),
+       .flags      = I2C_CLIENT_ALLOW_USE,
+        .driver     = &driver,
 };
 
 
-int bt832_init_module(void)
+static int __init bt832_init_module(void)
 {
-       i2c_add_driver(&driver);
-       return 0;
+       return i2c_add_driver(&driver);
 }
 
-static void bt832_cleanup_module(void)
+static void __exit bt832_cleanup_module(void)
 {
        i2c_del_driver(&driver);
 }
@@ -269,3 +272,10 @@ static void bt832_cleanup_module(void)
 module_init(bt832_init_module);
 module_exit(bt832_cleanup_module);
 
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
index 7a98c06e0e34ca55a18a3e0e47b6b4a969a437b1..9b6a8d2c96b5a37e398a13b969b213537d6c55ee 100644 (file)
@@ -1,6 +1,6 @@
 /* Bt832 CMOS Camera Video Processor (VP)
 
- The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS 
+ The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS
   color digital camera directly to video capture devices via an 8-bit,
   4:2:2 YUV or YCrCb video interface.
 
@@ -85,7 +85,7 @@
 #define BT832_DEVICE_ID                63
 # define BT832_DEVICE_ID__31           0x31 // Bt832 has ID 0x31
 
-/* STMicroelectronivcs VV5404 camera module 
+/* STMicroelectronivcs VV5404 camera module
    i2c: 0x20: sensor address
    i2c: 0xa0: eeprom for ccd defect map
  */
@@ -256,26 +256,26 @@ For the CCIR-601 standards, the sampling is based on a static orthogonal samplin
 //===========================================================================
 // Timing generator SRAM table values for CCIR601 720x480 NTSC
 //===========================================================================
-// For NTSC CCIR656 
+// For NTSC CCIR656
 BYTE BtCard::SRAMTable_NTSC[] =
 {
     // SRAM Timing Table for NTSC
-    0x0c, 0xc0, 0x00, 
-    0x00, 0x90, 0xc2, 
-    0x03, 0x10, 0x03, 
-    0x06, 0x10, 0x34, 
-    0x12, 0x12, 0x65, 
-    0x02, 0x13, 0x24, 
-    0x19, 0x00, 0x24, 
-    0x39, 0x00, 0x96, 
-    0x59, 0x08, 0x93, 
+    0x0c, 0xc0, 0x00,
+    0x00, 0x90, 0xc2,
+    0x03, 0x10, 0x03,
+    0x06, 0x10, 0x34,
+    0x12, 0x12, 0x65,
+    0x02, 0x13, 0x24,
+    0x19, 0x00, 0x24,
+    0x39, 0x00, 0x96,
+    0x59, 0x08, 0x93,
     0x83, 0x08, 0x97,
-    0x03, 0x50, 0x30, 
-    0xc0, 0x40, 0x30, 
-    0x86, 0x01, 0x01, 
-    0xa6, 0x0d, 0x62, 
-    0x03, 0x11, 0x61, 
-    0x05, 0x37, 0x30, 
+    0x03, 0x50, 0x30,
+    0xc0, 0x40, 0x30,
+    0x86, 0x01, 0x01,
+    0xa6, 0x0d, 0x62,
+    0x03, 0x11, 0x61,
+    0x05, 0x37, 0x30,
     0xac, 0x21, 0x50
 };
 
index 6334122704aecead4a200695d649c2f544522110..251092e7f19faf47224920ebdad9379166fa90c2 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    $Id: bttv-cards.c,v 1.47 2005/02/22 14:06:32 kraxel Exp $
+    $Id: bttv-cards.c,v 1.49 2005/06/10 17:20:24 mchehab Exp $
 
     bttv-cards.c
 
@@ -51,6 +51,7 @@ static void avermedia_eeprom(struct bttv *btv);
 static void osprey_eeprom(struct bttv *btv);
 static void modtec_eeprom(struct bttv *btv);
 static void init_PXC200(struct bttv *btv);
+static void init_RTV24(struct bttv *btv);
 
 static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
 static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set);
@@ -2251,6 +2252,20 @@ struct tvcard bttv_tvcards[] = {
        .no_tda7432     = 1,
        .no_tda9875     = 1,
        .muxsel_hook    = kodicom4400r_muxsel,
+},
+{
+        /* ---- card 0x85---------------------------------- */
+        /* Michael Henson <mhenson@clarityvi.com> */
+        /* Adlink RTV24 with special unlock codes */
+        .name           = "Adlink RTV24",
+        .video_inputs   = 4,
+        .audio_inputs   = 1,
+        .tuner          = 0,
+        .svhs           = 2,
+        .muxsel         = { 2, 3, 1, 0},
+        .tuner_type     = -1,
+        .pll            = PLL_28,
+
 }};
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -2636,6 +2651,10 @@ void __devinit bttv_init_card1(struct bttv *btv)
        case BTTV_AVDVBT_771:
                btv->use_i2c_hw = 1;
                break;
+        case BTTV_ADLINK_RTV24:
+                init_RTV24( btv );
+                break;
+
        }
        if (!bttv_tvcards[btv->c.type].has_dvb)
                bttv_reset_audio(btv);
@@ -2784,6 +2803,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
         }
        btv->pll.pll_current = -1;
 
+       bttv_reset_audio(btv);
+
        /* tuner configuration (from card list / autodetect / insmod option) */
        if (UNSET != bttv_tvcards[btv->c.type].tuner_type)
                if(UNSET == btv->tuner_type)
@@ -3304,6 +3325,83 @@ static void __devinit init_PXC200(struct bttv *btv)
 }
 
 
+
+/* ----------------------------------------------------------------------- */
+/*
+ *  The Adlink RTV-24 (aka Angelo) has some special initialisation to unlock
+ *  it. This apparently involves the following procedure for each 878 chip:
+ *
+ *  1) write 0x00C3FEFF to the GPIO_OUT_EN register
+ *
+ *  2)  write to GPIO_DATA
+ *      - 0x0E
+ *      - sleep 1ms
+ *      - 0x10 + 0x0E
+ *      - sleep 10ms
+ *      - 0x0E
+ *     read from GPIO_DATA into buf (uint_32)
+ *      - if ( data>>18 & 0x01 != 0) || ( buf>>19 & 0x01 != 1 )
+ *                 error. ERROR_CPLD_Check_Failed stop.
+ *
+ *  3) write to GPIO_DATA
+ *      - write 0x4400 + 0x0E
+ *      - sleep 10ms
+ *      - write 0x4410 + 0x0E
+ *      - sleep 1ms
+ *      - write 0x0E
+ *     read from GPIO_DATA into buf (uint_32)
+ *      - if ( buf>>18 & 0x01 ) || ( buf>>19 && 0x01 != 0 )
+ *                error. ERROR_CPLD_Check_Failed.
+ */
+/* ----------------------------------------------------------------------- */
+void
+init_RTV24 (struct bttv *btv)
+{
+       uint32_t dataRead = 0;
+       long watchdog_value = 0x0E;
+
+       printk (KERN_INFO
+               "bttv%d: Adlink RTV-24 initialisation in progress ...\n",
+               btv->c.nr);
+
+       btwrite (0x00c3feff, BT848_GPIO_OUT_EN);
+
+       btwrite (0 + watchdog_value, BT848_GPIO_DATA);
+       msleep (1);
+       btwrite (0x10 + watchdog_value, BT848_GPIO_DATA);
+       msleep (10);
+       btwrite (0 + watchdog_value, BT848_GPIO_DATA);
+
+       dataRead = btread (BT848_GPIO_DATA);
+
+       if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 1)) {
+               printk (KERN_INFO
+                       "bttv%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n",
+                       btv->c.nr, dataRead);
+       }
+
+       btwrite (0x4400 + watchdog_value, BT848_GPIO_DATA);
+       msleep (10);
+       btwrite (0x4410 + watchdog_value, BT848_GPIO_DATA);
+       msleep (1);
+       btwrite (watchdog_value, BT848_GPIO_DATA);
+       msleep (1);
+       dataRead = btread (BT848_GPIO_DATA);
+
+       if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 0)) {
+               printk (KERN_INFO
+                       "bttv%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n",
+                       btv->c.nr, dataRead);
+
+               return;
+       }
+
+       printk (KERN_INFO
+               "bttv%d: Adlink RTV-24 initialisation complete.\n", btv->c.nr);
+}
+
+
+
 /* ----------------------------------------------------------------------- */
 /* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports     */
 /*
index 033cc5498f234e62c456c706a8f8986766fdf209..7d62b394c5092d9269781c45b5a342bf60291b0c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    $Id: bttv-driver.c,v 1.37 2005/02/21 13:57:59 kraxel Exp $
+    $Id: bttv-driver.c,v 1.40 2005/06/16 21:38:45 nsh Exp $
 
     bttv - Bt848 frame grabber driver
 
@@ -76,6 +76,9 @@ static unsigned int whitecrush_upper = 0xCF;
 static unsigned int whitecrush_lower = 0x7F;
 static unsigned int vcr_hack    = 0;
 static unsigned int irq_iswitch = 0;
+static unsigned int uv_ratio    = 50;
+static unsigned int full_luma_range = 0;
+static unsigned int coring      = 0;
 
 /* API features (turn on/off stuff for testing) */
 static unsigned int v4l2        = 1;
@@ -106,6 +109,9 @@ module_param(adc_crush,         int, 0444);
 module_param(whitecrush_upper,  int, 0444);
 module_param(whitecrush_lower,  int, 0444);
 module_param(vcr_hack,          int, 0444);
+module_param(uv_ratio,          int, 0444);
+module_param(full_luma_range,   int, 0444);
+module_param(coring,            int, 0444);
 
 module_param_array(radio, int, NULL, 0444);
 
@@ -124,6 +130,9 @@ MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is
 MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
 MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
 MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
+MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
+MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
+MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
 
 MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
 MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
@@ -484,7 +493,10 @@ static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
 #define V4L2_CID_PRIVATE_VCR_HACK    (V4L2_CID_PRIVATE_BASE + 5)
 #define V4L2_CID_PRIVATE_WHITECRUSH_UPPER   (V4L2_CID_PRIVATE_BASE + 6)
 #define V4L2_CID_PRIVATE_WHITECRUSH_LOWER   (V4L2_CID_PRIVATE_BASE + 7)
-#define V4L2_CID_PRIVATE_LASTP1      (V4L2_CID_PRIVATE_BASE + 8)
+#define V4L2_CID_PRIVATE_UV_RATIO    (V4L2_CID_PRIVATE_BASE + 8)
+#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE    (V4L2_CID_PRIVATE_BASE + 9)
+#define V4L2_CID_PRIVATE_CORING      (V4L2_CID_PRIVATE_BASE + 10)
+#define V4L2_CID_PRIVATE_LASTP1      (V4L2_CID_PRIVATE_BASE + 11)
 
 static const struct v4l2_queryctrl no_ctl = {
        .name  = "42",
@@ -618,8 +630,32 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
                .step          = 1,
                .default_value = 0x7F,
                .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_PRIVATE_UV_RATIO,
+               .name          = "uv ratio",
+               .minimum       = 0,
+               .maximum       = 100,
+               .step          = 1,
+               .default_value = 50,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
+               .name          = "full luma range",
+               .minimum       = 0,
+               .maximum       = 1,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       },{
+               .id            = V4L2_CID_PRIVATE_CORING,
+               .name          = "coring",
+               .minimum       = 0,
+               .maximum       = 3,
+               .step          = 1,
+               .default_value = 0,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
        }
 
+
+
 };
 static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
 
@@ -833,8 +869,8 @@ static void bt848_sat(struct bttv *btv, int color)
        btv->saturation = color;
 
        /* 0-511 for the color */
-       val_u   = color >> 7;
-       val_v   = ((color>>7)*180L)/254;
+       val_u   = ((color * btv->opt_uv_ratio) / 50) >> 7;
+       val_v   = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
         hibits  = (val_u >> 7) & 2;
        hibits |= (val_v >> 8) & 1;
         btwrite(val_u & 0xff, BT848_SAT_U_LO);
@@ -1151,6 +1187,15 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
        case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
                c->value = btv->opt_whitecrush_lower;
                break;
+       case V4L2_CID_PRIVATE_UV_RATIO:
+               c->value = btv->opt_uv_ratio;
+               break;
+       case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
+               c->value = btv->opt_full_luma_range;
+               break;
+       case V4L2_CID_PRIVATE_CORING:
+               c->value = btv->opt_coring;
+               break;
        default:
                return -EINVAL;
        }
@@ -1247,6 +1292,18 @@ static int set_control(struct bttv *btv, struct v4l2_control *c)
                btv->opt_whitecrush_lower = c->value;
                btwrite(c->value, BT848_WC_DOWN);
                break;
+       case V4L2_CID_PRIVATE_UV_RATIO:
+               btv->opt_uv_ratio = c->value;
+               bt848_sat(btv, btv->saturation);
+               break;
+       case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
+               btv->opt_full_luma_range = c->value;
+               btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
+               break;
+       case V4L2_CID_PRIVATE_CORING:
+               btv->opt_coring = c->value;
+               btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
+               break;
        default:
                return -EINVAL;
        }
@@ -3117,11 +3174,6 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
                         return -EINVAL;
                memset(v,0,sizeof(*v));
                 strcpy(v->name, "Radio");
-                /* japan:          76.0 MHz -  89.9 MHz
-                   western europe: 87.5 MHz - 108.0 MHz
-                   russia:         65.0 MHz - 108.0 MHz */
-                v->rangelow=(int)(65*16);
-                v->rangehigh=(int)(108*16);
                 bttv_call_i2c_clients(btv,cmd,v);
                 return 0;
         }
@@ -3876,6 +3928,9 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        btv->opt_vcr_hack   = vcr_hack;
        btv->opt_whitecrush_upper  = whitecrush_upper;
        btv->opt_whitecrush_lower  = whitecrush_lower;
+       btv->opt_uv_ratio   = uv_ratio;
+       btv->opt_full_luma_range   = full_luma_range;
+       btv->opt_coring     = coring;
 
        /* fill struct bttv with some useful defaults */
        btv->init.btv         = btv;
index c2368bc832edc248978cb646218184da59d0b4bc..da448a5f9e9c91ea9403ce2a1dff9f9ccc533369 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    $Id: bttv-i2c.c,v 1.18 2005/02/16 12:14:10 kraxel Exp $
+    $Id: bttv-i2c.c,v 1.21 2005/06/10 17:20:24 mchehab Exp $
 
     bttv-i2c.c  --  all the i2c code is here
 
index 8322b66e09054344c97619195d86cb5dac57ec36..191eaf1714ba52294d1398f87af3c167875dcbfe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: bttv.h,v 1.17 2005/02/22 14:06:32 kraxel Exp $
+ * $Id: bttv.h,v 1.18 2005/05/24 23:41:42 nsh Exp $
  *
  *  bttv - Bt848 frame grabber driver
  *
 #define BTTV_DVICO_DVBT_LITE  0x80
 #define BTTV_TIBET_CS16  0x83
 #define BTTV_KODICOM_4400R  0x84
+#define BTTV_ADLINK_RTV24   0x85
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
index 1a9ba7e1cf519325cd7fd9371a758821df5cdba1..f3293e4a15ad3f6137a06d03120dc76d73eb68dc 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    $Id: bttvp.h,v 1.17 2005/02/16 12:14:10 kraxel Exp $
+    $Id: bttvp.h,v 1.19 2005/06/16 21:38:45 nsh Exp $
 
     bttv - Bt848 frame grabber driver
 
@@ -226,10 +226,6 @@ extern int fini_bttv_i2c(struct bttv *btv);
 #define dprintk  if (bttv_debug >= 1) printk
 #define d2printk if (bttv_debug >= 2) printk
 
-/* our devices */
-#define BTTV_MAX 16
-extern unsigned int bttv_num;
-
 #define BTTV_MAX_FBUF   0x208000
 #define VBIBUF_SIZE     (2048*VBI_MAXLINES*2)
 #define BTTV_TIMEOUT    (HZ/2) /* 0.5 seconds */
@@ -330,6 +326,9 @@ struct bttv {
        int opt_vcr_hack;
        int opt_whitecrush_upper;
        int opt_whitecrush_lower;
+       int opt_uv_ratio;
+       int opt_full_luma_range;
+       int opt_coring;
 
        /* radio data/state */
        int has_radio;
@@ -375,6 +374,10 @@ struct bttv {
        unsigned int users;
        struct bttv_fh init;
 };
+
+/* our devices */
+#define BTTV_MAX 16
+extern unsigned int bttv_num;
 extern struct bttv bttvs[BTTV_MAX];
 
 /* private ioctls */
index 46d6778b863b6e29ca14092a12dc105c0a30edf3..91f8afeded88997411eba26f28ea1280bd868487 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-blackbird.c,v 1.26 2005/03/07 15:58:05 kraxel Exp $
+ * $Id: cx88-blackbird.c,v 1.27 2005/06/03 13:31:50 mchehab Exp $
  *
  *  Support for a cx23416 mpeg encoder via cx2388x host port.
  *  "blackbird" reference design.
@@ -61,37 +61,304 @@ static LIST_HEAD(cx8802_devlist);
 
 #define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
 
-/*Firmware API commands*/
-#define IVTV_API_ENC_PING_FW 0x00000080
-#define IVTV_API_ENC_GETVER 0x000000C4
-#define IVTV_API_ENC_HALT_FW 0x000000C3
-#define IVTV_API_STD_TIMEOUT 0x00010000 /*units??*/
-//#define IVTV_API_ASSIGN_PGM_INDEX_INFO 0x000000c7
-#define IVTV_API_ASSIGN_STREAM_TYPE 0x000000b9
-#define IVTV_API_ASSIGN_OUTPUT_PORT 0x000000bb
-#define IVTV_API_ASSIGN_FRAMERATE 0x0000008f
-#define IVTV_API_ASSIGN_FRAME_SIZE 0x00000091
-#define IVTV_API_ASSIGN_ASPECT_RATIO 0x00000099
-#define IVTV_API_ASSIGN_BITRATES 0x00000095
-#define IVTV_API_ASSIGN_GOP_PROPERTIES 0x00000097
-#define IVTV_API_ASSIGN_3_2_PULLDOWN 0x000000b1
-#define IVTV_API_ASSIGN_GOP_CLOSURE 0x000000c5
-#define IVTV_API_ASSIGN_AUDIO_PROPERTIES 0x000000bd
-#define IVTV_API_ASSIGN_DNR_FILTER_MODE 0x0000009b
-#define IVTV_API_ASSIGN_DNR_FILTER_PROPS 0x0000009d
-#define IVTV_API_ASSIGN_CORING_LEVELS 0x0000009f
-#define IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE 0x000000a1
-#define IVTV_API_ASSIGN_FRAME_DROP_RATE 0x000000d0
-#define IVTV_API_ASSIGN_PLACEHOLDER 0x000000d8
-#define IVTV_API_MUTE_VIDEO 0x000000d9
-#define IVTV_API_MUTE_AUDIO 0x000000da
-#define IVTV_API_INITIALIZE_INPUT 0x000000cd
-#define IVTV_API_REFRESH_INPUT 0x000000d3
-#define IVTV_API_ASSIGN_NUM_VSYNC_LINES 0x000000d6
-#define IVTV_API_BEGIN_CAPTURE 0x00000081
-//#define IVTV_API_PAUSE_ENCODER 0x000000d2
-//#define IVTV_API_EVENT_NOTIFICATION 0x000000d5
-#define IVTV_API_END_CAPTURE 0x00000082
+/* Firmware API commands */
+/* #define IVTV_API_STD_TIMEOUT 0x00010000 // 65536, units?? */
+#define IVTV_API_STD_TIMEOUT 500
+
+#define BLACKBIRD_API_PING               0x80
+#define BLACKBIRD_API_BEGIN_CAPTURE      0x81
+enum blackbird_capture_type {
+       BLACKBIRD_MPEG_CAPTURE,
+       BLACKBIRD_RAW_CAPTURE,
+       BLACKBIRD_RAW_PASSTHRU_CAPTURE
+};
+enum blackbird_capture_bits {
+       BLACKBIRD_RAW_BITS_NONE             = 0x00,
+       BLACKBIRD_RAW_BITS_YUV_CAPTURE      = 0x01,
+       BLACKBIRD_RAW_BITS_PCM_CAPTURE      = 0x02,
+       BLACKBIRD_RAW_BITS_VBI_CAPTURE      = 0x04,
+       BLACKBIRD_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
+       BLACKBIRD_RAW_BITS_TO_HOST_CAPTURE  = 0x10
+};
+#define BLACKBIRD_API_END_CAPTURE        0x82
+enum blackbird_capture_end {
+       BLACKBIRD_END_AT_GOP, /* stop at the end of gop, generate irq */
+       BLACKBIRD_END_NOW, /* stop immediately, no irq */
+};
+#define BLACKBIRD_API_SET_AUDIO_ID       0x89
+#define BLACKBIRD_API_SET_VIDEO_ID       0x8B
+#define BLACKBIRD_API_SET_PCR_ID         0x8D
+#define BLACKBIRD_API_SET_FRAMERATE      0x8F
+enum blackbird_framerate {
+       BLACKBIRD_FRAMERATE_NTSC_30, /* NTSC: 30fps */
+       BLACKBIRD_FRAMERATE_PAL_25   /* PAL: 25fps */
+};
+#define BLACKBIRD_API_SET_RESOLUTION     0x91
+#define BLACKBIRD_API_SET_VIDEO_BITRATE  0x95
+enum blackbird_video_bitrate_type {
+       BLACKBIRD_VIDEO_VBR,
+       BLACKBIRD_VIDEO_CBR
+};
+#define BLACKBIRD_PEAK_RATE_DIVISOR 400
+enum blackbird_mux_rate {
+       BLACKBIRD_MUX_RATE_DEFAULT,
+        /* dvd mux rate: multiply by 400 to get the actual rate */
+       BLACKBIRD_MUX_RATE_DVD = 25200
+};
+#define BLACKBIRD_API_SET_GOP_STRUCTURE  0x97
+#define BLACKBIRD_API_SET_ASPECT_RATIO   0x99
+enum blackbird_aspect_ratio {
+       BLACKBIRD_ASPECT_RATIO_FORBIDDEN,
+       BLACKBIRD_ASPECT_RATIO_1_1_SQUARE,
+       BLACKBIRD_ASPECT_RATIO_4_3,
+       BLACKBIRD_ASPECT_RATIO_16_9,
+       BLACKBIRD_ASPECT_RATIO_221_100,
+       BLACKBIRD_ASPECT_RATIO_RESERVED
+};
+#define BLACKBIRD_API_SET_DNR_MODE       0x9B
+enum blackbird_dnr_bits {
+       BLACKBIRD_DNR_BITS_MANUAL,
+       BLACKBIRD_DNR_BITS_AUTO_SPATIAL,
+       BLACKBIRD_DNR_BITS_AUTO_TEMPORAL,
+       BLACKBIRD_DNR_BITS_AUTO
+};
+enum blackbird_median_filter {
+       BLACKBIRD_MEDIAN_FILTER_DISABLED,
+       BLACKBIRD_MEDIAN_FILTER_HORIZONTAL,
+       BLACKBIRD_MEDIAN_FILTER_VERTICAL,
+       BLACKBIRD_MEDIAN_FILTER_HV,
+       BLACKBIRD_MEDIAN_FILTER_DIAGONAL
+};
+#define BLACKBIRD_API_SET_MANUAL_DNR     0x9D
+#define BLACKBIRD_API_SET_DNR_MEDIAN     0x9F
+#define BLACKBIRD_API_SET_SPATIAL_FILTER 0xA1
+enum blackbird_spatial_filter_luma {
+       BLACKBIRD_SPATIAL_FILTER_LUMA_DISABLED,
+       BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
+       BLACKBIRD_SPATIAL_FILTER_LUMA_1D_VERT,
+       BLACKBIRD_SPATIAL_FILTER_LUMA_2D_HV, /* separable, default */
+       BLACKBIRD_SPATIAL_FILTER_LUMA_2D_SYMM /* symmetric non-separable */
+};
+enum blackbird_spatial_filter_chroma {
+       BLACKBIRD_SPATIAL_FILTER_CHROMA_DISABLED,
+       BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ /* default */
+};
+#define BLACKBIRD_API_SET_3_2_PULLDOWN   0xB1
+enum blackbird_pulldown {
+       BLACKBIRD_3_2_PULLDOWN_DISABLED,
+       BLACKBIRD_3_2_PULLDOWN_ENABLED
+};
+#define BLACKBIRD_API_SET_VBI_LINE_NO    0xB7
+enum blackbird_vbi_line_bits {
+       BLACKBIRD_VBI_LINE_BITS_TOP_FIELD,
+       BLACKBIRD_VBI_LINE_BITS_BOT_FIELD = (1 << 31),
+       BLACKBIRD_VBI_LINE_BITS_ALL_LINES = 0xFFFFFFFF
+};
+enum blackbird_vbi_line {
+       BLACKBIRD_VBI_LINE_DISABLED,
+       BLACKBIRD_VBI_LINE_ENABLED
+};
+enum blackbird_vbi_slicing {
+       BLACKBIRD_VBI_SLICING_NONE,
+       BLACKBIRD_VBI_SLICING_CLOSED_CAPTION
+};
+#define BLACKBIRD_API_SET_STREAM_TYPE    0xB9
+enum blackbird_stream_type {
+       BLACKBIRD_STREAM_PROGRAM,
+       BLACKBIRD_STREAM_TRANSPORT,
+       BLACKBIRD_STREAM_MPEG1,
+       BLACKBIRD_STREAM_PES_AV,
+       BLACKBIRD_STREAM_UNKNOWN4,
+       BLACKBIRD_STREAM_PES_VIDEO,
+       BLACKBIRD_STREAM_UNKNOWN6,
+       BLACKBIRD_STREAM_PES_AUDIO,
+       BLACKBIRD_STREAM_UNKNOWN8,
+       BLACKBIRD_STREAM_UNKNOWN9, /* audio/pcm ? */
+       BLACKBIRD_STREAM_DVD,
+       BLACKBIRD_STREAM_VCD,
+       BLACKBIRD_STREAM_UNKNOWN12 /* svcd/xvcd ? */
+};
+#define BLACKBIRD_API_SET_OUTPUT_PORT    0xBB
+enum blackbird_stream_port {
+       BLACKBIRD_OUTPUT_PORT_MEMORY,
+       BLACKBIRD_OUTPUT_PORT_STREAMING,
+       BLACKBIRD_OUTPUT_PORT_SERIAL
+};
+#define BLACKBIRD_API_SET_AUDIO_PARAMS   0xBD
+enum blackbird_audio_bits_sample_rate {
+       BLACKBIRD_AUDIO_BITS_44100HZ,
+       BLACKBIRD_AUDIO_BITS_48000HZ,
+       BLACKBIRD_AUDIO_BITS_32000HZ,
+       BLACKBIRD_AUDIO_BITS_RESERVED_HZ,
+};
+enum blackbird_audio_bits_encoding {
+       BLACKBIRD_AUDIO_BITS_LAYER_1 = 0x1 << 2,
+       BLACKBIRD_AUDIO_BITS_LAYER_2 = 0x2 << 2,
+};
+enum blackbird_audio_bits_bitrate_layer_1 {
+       BLACKBIRD_AUDIO_BITS_LAYER_1_FREE_FORMAT,
+       BLACKBIRD_AUDIO_BITS_LAYER_1_32  = 0x01 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_1_64  = 0x02 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_1_96  = 0x03 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_1_128 = 0x04 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_1_160 = 0x05 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_1_192 = 0x06 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_1_224 = 0x07 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_1_256 = 0x08 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_1_288 = 0x09 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_1_320 = 0x0A << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_1_352 = 0x0B << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_1_384 = 0x0C << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_1_416 = 0x0D << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_1_448 = 0x0E << 4,
+};
+enum blackbird_audio_bits_bitrate_layer_2 {
+       BLACKBIRD_AUDIO_BITS_LAYER_2_FREE_FORMAT,
+       BLACKBIRD_AUDIO_BITS_LAYER_2_32  = 0x01 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_2_48  = 0x02 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_2_56  = 0x03 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_2_64  = 0x04 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_2_80  = 0x05 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_2_96  = 0x06 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_2_112 = 0x07 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_2_128 = 0x08 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_2_160 = 0x09 << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_2_192 = 0x0A << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_2_224 = 0x0B << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_2_256 = 0x0C << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_2_320 = 0x0D << 4,
+       BLACKBIRD_AUDIO_BITS_LAYER_2_384 = 0x0E << 4,
+};
+enum blackbird_audio_bits_mode {
+       BLACKBIRD_AUDIO_BITS_STEREO,
+       BLACKBIRD_AUDIO_BITS_JOINT_STEREO = 0x1 << 8,
+       BLACKBIRD_AUDIO_BITS_DUAL         = 0x2 << 8,
+       BLACKBIRD_AUDIO_BITS_MONO         = 0x3 << 8,
+};
+enum blackbird_audio_bits_mode_extension {
+       BLACKBIRD_AUDIO_BITS_BOUND_4,
+       BLACKBIRD_AUDIO_BITS_BOUND_8  = 0x1 << 10,
+       BLACKBIRD_AUDIO_BITS_BOUND_12 = 0x2 << 10,
+       BLACKBIRD_AUDIO_BITS_BOUND_16 = 0x3 << 10,
+};
+enum blackbird_audio_bits_emphasis {
+       BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE,
+       BLACKBIRD_AUDIO_BITS_EMPHASIS_50_15     = 0x1 << 12,
+       BLACKBIRD_AUDIO_BITS_EMPHASIS_RESERVED  = 0x2 << 12,
+       BLACKBIRD_AUDIO_BITS_EMPHASIS_CCITT_J17 = 0x3 << 12,
+};
+enum blackbird_audio_bits_crc {
+       BLACKBIRD_AUDIO_BITS_CRC_OFF,
+       BLACKBIRD_AUDIO_BITS_CRC_ON = 0x1 << 14,
+};
+enum blackbird_audio_bits_copyright {
+       BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF,
+       BLACKBIRD_AUDIO_BITS_COPYRIGHT_ON = 0x1 << 15,
+};
+enum blackbird_audio_bits_original {
+       BLACKBIRD_AUDIO_BITS_COPY,
+       BLACKBIRD_AUDIO_BITS_ORIGINAL = 0x1 << 16,
+};
+#define BLACKBIRD_API_HALT               0xC3
+#define BLACKBIRD_API_GET_VERSION        0xC4
+#define BLACKBIRD_API_SET_GOP_CLOSURE    0xC5
+enum blackbird_gop_closure {
+       BLACKBIRD_GOP_CLOSURE_OFF,
+       BLACKBIRD_GOP_CLOSURE_ON,
+};
+#define BLACKBIRD_API_DATA_XFER_STATUS   0xC6
+enum blackbird_data_xfer_status {
+       BLACKBIRD_MORE_BUFFERS_FOLLOW,
+       BLACKBIRD_LAST_BUFFER,
+};
+#define BLACKBIRD_API_PROGRAM_INDEX_INFO 0xC7
+enum blackbird_picture_mask {
+       BLACKBIRD_PICTURE_MASK_NONE,
+       BLACKBIRD_PICTURE_MASK_I_FRAMES,
+       BLACKBIRD_PICTURE_MASK_I_P_FRAMES = 0x3,
+       BLACKBIRD_PICTURE_MASK_ALL_FRAMES = 0x7,
+};
+#define BLACKBIRD_API_SET_VBI_PARAMS     0xC8
+enum blackbird_vbi_mode_bits {
+       BLACKBIRD_VBI_BITS_SLICED,
+       BLACKBIRD_VBI_BITS_RAW,
+};
+enum blackbird_vbi_insertion_bits {
+       BLACKBIRD_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
+       BLACKBIRD_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
+       BLACKBIRD_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
+       BLACKBIRD_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
+       BLACKBIRD_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
+};
+#define BLACKBIRD_API_SET_DMA_BLOCK_SIZE 0xC9
+enum blackbird_dma_unit {
+       BLACKBIRD_DMA_BYTES,
+       BLACKBIRD_DMA_FRAMES,
+};
+#define BLACKBIRD_API_DMA_TRANSFER_INFO  0xCA
+#define BLACKBIRD_API_DMA_TRANSFER_STAT  0xCB
+enum blackbird_dma_transfer_status_bits {
+       BLACKBIRD_DMA_TRANSFER_BITS_DONE = 0x01,
+       BLACKBIRD_DMA_TRANSFER_BITS_ERROR = 0x04,
+       BLACKBIRD_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
+};
+#define BLACKBIRD_API_SET_DMA2HOST_ADDR  0xCC
+#define BLACKBIRD_API_INIT_VIDEO_INPUT   0xCD
+#define BLACKBIRD_API_SET_FRAMESKIP      0xD0
+#define BLACKBIRD_API_PAUSE              0xD2
+enum blackbird_pause {
+       BLACKBIRD_PAUSE_ENCODING,
+       BLACKBIRD_RESUME_ENCODING,
+};
+#define BLACKBIRD_API_REFRESH_INPUT      0xD3
+#define BLACKBIRD_API_SET_COPYRIGHT      0xD4
+enum blackbird_copyright {
+       BLACKBIRD_COPYRIGHT_OFF,
+       BLACKBIRD_COPYRIGHT_ON,
+};
+#define BLACKBIRD_API_SET_NOTIFICATION   0xD5
+enum blackbird_notification_type {
+       BLACKBIRD_NOTIFICATION_REFRESH,
+};
+enum blackbird_notification_status {
+       BLACKBIRD_NOTIFICATION_OFF,
+       BLACKBIRD_NOTIFICATION_ON,
+};
+enum blackbird_notification_mailbox {
+       BLACKBIRD_NOTIFICATION_NO_MAILBOX = -1,
+};
+#define BLACKBIRD_API_SET_CAPTURE_LINES  0xD6
+enum blackbird_field1_lines {
+       BLACKBIRD_FIELD1_SAA7114 = 0x00EF, /* 239 */
+       BLACKBIRD_FIELD1_SAA7115 = 0x00F0, /* 240 */
+       BLACKBIRD_FIELD1_MICRONAS = 0x0105, /* 261 */
+};
+enum blackbird_field2_lines {
+       BLACKBIRD_FIELD2_SAA7114 = 0x00EF, /* 239 */
+       BLACKBIRD_FIELD2_SAA7115 = 0x00F0, /* 240 */
+       BLACKBIRD_FIELD2_MICRONAS = 0x0106, /* 262 */
+};
+#define BLACKBIRD_API_SET_CUSTOM_DATA    0xD7
+enum blackbird_custom_data_type {
+       BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
+       BLACKBIRD_CUSTOM_PRIVATE_PACKET,
+};
+#define BLACKBIRD_API_MUTE_VIDEO         0xD9
+enum blackbird_mute {
+       BLACKBIRD_UNMUTE,
+       BLACKBIRD_MUTE,
+};
+enum blackbird_mute_video_mask {
+       BLACKBIRD_MUTE_VIDEO_V_MASK = 0x0000FF00,
+       BLACKBIRD_MUTE_VIDEO_U_MASK = 0x00FF0000,
+       BLACKBIRD_MUTE_VIDEO_Y_MASK = 0xFF000000,
+};
+enum blackbird_mute_video_shift {
+       BLACKBIRD_MUTE_VIDEO_V_SHIFT = 8,
+       BLACKBIRD_MUTE_VIDEO_U_SHIFT = 16,
+       BLACKBIRD_MUTE_VIDEO_Y_SHIFT = 24,
+};
+#define BLACKBIRD_API_MUTE_AUDIO         0xDA
 
 /* Registers */
 #define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/)
@@ -405,68 +672,100 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
        return 0;
 }
 
+/**
+ Settings used by the windows tv app for PVR2000:
+=================================================================================================================
+Profile | Codec | Resolution | CBR/VBR | Video Qlty   | V. Bitrate | Frmrate | Audio Codec | A. Bitrate | A. Mode
+-----------------------------------------------------------------------------------------------------------------
+MPEG-1  | MPEG1 | 352x288PAL | (CBR)   | 1000:Optimal | 2000 Kbps  | 25fps   | MPG1 Layer2 | 224kbps    | Stereo
+MPEG-2  | MPEG2 | 720x576PAL | VBR     | 600 :Good    | 4000 Kbps  | 25fps   | MPG1 Layer2 | 224kbps    | Stereo
+VCD     | MPEG1 | 352x288PAL | (CBR)   | 1000:Optimal | 1150 Kbps  | 25fps   | MPG1 Layer2 | 224kbps    | Stereo
+DVD     | MPEG2 | 720x576PAL | VBR     | 600 :Good    | 6000 Kbps  | 25fps   | MPG1 Layer2 | 224kbps    | Stereo
+DB* DVD | MPEG2 | 720x576PAL | CBR     | 600 :Good    | 6000 Kbps  | 25fps   | MPG1 Layer2 | 224kbps    | Stereo
+=================================================================================================================
+*DB: "DirectBurn"
+*/
 static void blackbird_codec_settings(struct cx8802_dev *dev)
 {
        int bitrate_mode = 1;
        int bitrate = 7500000;
        int bitrate_peak = 7500000;
+#if 1
+       bitrate_mode = BLACKBIRD_VIDEO_CBR;
+       bitrate = 4000*1024;
+       bitrate_peak = 4000*1024;
+#endif
 
        /* assign stream type */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 0); /* program stream */
-        //blackbird_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 2); /* MPEG1 stream */
-        //blackbird_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 3); /* PES A/V */
-        //blackbird_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 10); /* DVD stream */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, BLACKBIRD_STREAM_PROGRAM);
+       /* blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, BLACKBIRD_STREAM_TRANSPORT); */
 
-        /* assign output port */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_OUTPUT_PORT, 1, 0, 1); /* 1 = Host */
+       /* assign output port */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */
 
-        /* assign framerate */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAMERATE, 1, 0, 0);
+       /* assign framerate */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
 
-        /* assign frame size */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_SIZE, 2, 0,
+       /* assign frame size */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_RESOLUTION, 2, 0,
                          dev->height, dev->width);
 
-        /* assign aspect ratio */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_ASPECT_RATIO, 1, 0, 2);
+       /* assign aspect ratio */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, BLACKBIRD_ASPECT_RATIO_4_3);
 
-        /* assign bitrates */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_BITRATES, 5, 0,
+       /* assign bitrates */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 5, 0,
                         bitrate_mode,         /* mode */
                         bitrate,              /* bps */
-                        bitrate_peak / 400,   /* peak/400 */
-                        0, 0x70);             /* encoding buffer, ckennedy */
-
-        /* assign gop properties */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_GOP_PROPERTIES, 2, 0, 15, 3);
-        //blackbird_api_cmd(dev, IVTV_API_ASSIGN_GOP_PROPERTIES, 2, 0, 2, 1);
-
-        /* assign 3 2 pulldown */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_3_2_PULLDOWN, 1, 0, 0);
-
-        /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
-       blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, (2<<2) | (8<<4));
+                        bitrate_peak / BLACKBIRD_PEAK_RATE_DIVISOR,   /* peak/400 */
+                        BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/);             /* encoding buffer, ckennedy */
+
+       /* assign gop properties */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, 15, 3);
+
+       /* assign 3 2 pulldown */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, BLACKBIRD_3_2_PULLDOWN_DISABLED);
+
+       /* assign audio properties */
+       /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
+       /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, (2<<2) | (8<<4));
+          blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, 0 | (2 << 2) | (14 << 4)); */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0,
+                       BLACKBIRD_AUDIO_BITS_44100HZ |
+                       BLACKBIRD_AUDIO_BITS_LAYER_2 |
+                       BLACKBIRD_AUDIO_BITS_LAYER_2_224 |
+                       BLACKBIRD_AUDIO_BITS_STEREO |
+                       /* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
+                       BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
+                       BLACKBIRD_AUDIO_BITS_CRC_OFF |
+                       BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
+                       BLACKBIRD_AUDIO_BITS_COPY
+               );
 
        /* assign gop closure */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_GOP_CLOSURE, 1, 0, 0);
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, BLACKBIRD_GOP_CLOSURE_OFF);
 
-        /* assign audio properties */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, 0 | (2 << 2) | (14 << 4));
 
-        /* assign dnr filter mode */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_DNR_FILTER_MODE, 2, 0, 0, 0);
+       /* assign dnr filter mode */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0,
+                       BLACKBIRD_DNR_BITS_MANUAL,
+                       BLACKBIRD_MEDIAN_FILTER_DISABLED
+               );
 
-        /* assign dnr filter props*/
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_DNR_FILTER_PROPS, 2, 0, 0, 0);
+       /* assign dnr filter props*/
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0, 0, 0);
 
-        /* assign coring levels (luma_h, luma_l, chroma_h, chroma_l) */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_CORING_LEVELS, 4, 0, 0, 255, 0, 255);
+       /* assign coring levels (luma_h, luma_l, chroma_h, chroma_l) */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MEDIAN, 4, 0, 0, 255, 0, 255);
 
-       /* assign spatial filter type: luma_t: 1 = horiz_only, chroma_t: 1 = horiz_only */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE, 2, 0, 1, 1);
+       /* assign spatial filter type: luma_t: horiz_only, chroma_t: horiz_only */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_SPATIAL_FILTER, 2, 0,
+                       BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
+                       BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ
+               );
 
-        /* assign frame drop rate */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_DROP_RATE, 1, 0, 0);
+       /* assign frame drop rate */
+       /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_DROP_RATE, 1, 0, 0); */
 }
 
 static int blackbird_initialize_codec(struct cx8802_dev *dev)
@@ -476,7 +775,7 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
        int retval;
 
        dprintk(1,"Initialize codec\n");
-       retval = blackbird_api_cmd(dev, IVTV_API_ENC_PING_FW, 0, 0); /* ping */
+       retval = blackbird_api_cmd(dev, BLACKBIRD_API_PING, 0, 0); /* ping */
        if (retval < 0) {
                /* ping was not successful, reset and upload firmware */
                cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
@@ -491,13 +790,13 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
                if (dev->mailbox < 0)
                        return -1;
 
-               retval = blackbird_api_cmd(dev, IVTV_API_ENC_PING_FW, 0, 0); /* ping */
+               retval = blackbird_api_cmd(dev, BLACKBIRD_API_PING, 0, 0); /* ping */
                if (retval < 0) {
                        dprintk(0, "ERROR: Firmware ping failed!\n");
                        return -1;
                }
 
-               retval = blackbird_api_cmd(dev, IVTV_API_ENC_GETVER, 0, 1, &version);
+               retval = blackbird_api_cmd(dev, BLACKBIRD_API_GET_VERSION, 0, 1, &version);
                if (retval < 0) {
                        dprintk(0, "ERROR: Firmware get encoder version failed!\n");
                        return -1;
@@ -517,25 +816,36 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
        blackbird_codec_settings(dev);
        msleep(1);
 
-       //blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
-       blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
-       //blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180);
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+       /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
+          blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
+          blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_CAPTURE_LINES, 2, 0,
+                       BLACKBIRD_FIELD1_SAA7115,
+                       BLACKBIRD_FIELD1_SAA7115
+               );
+
+       /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_CUSTOM_DATA, 12, 0,
+                       BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
+                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
-       blackbird_api_cmd(dev, IVTV_API_INITIALIZE_INPUT, 0, 0); /* initialize the video input */
+       blackbird_api_cmd(dev, BLACKBIRD_API_INIT_VIDEO_INPUT, 0, 0); /* initialize the video input */
 
        msleep(1);
 
-        blackbird_api_cmd(dev, IVTV_API_MUTE_VIDEO, 1, 0, 0);
+       blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
        msleep(1);
-        blackbird_api_cmd(dev, IVTV_API_MUTE_AUDIO, 1, 0, 0);
+       blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
        msleep(1);
 
-       blackbird_api_cmd(dev, IVTV_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); /* start capturing to the host interface */
-       //blackbird_api_cmd(dev, IVTV_API_BEGIN_CAPTURE, 2, 0, 0, 0); /* start capturing to the host interface */
-       msleep(1);
+       /* blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); // start capturing to the host interface */
+       blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0,
+                       BLACKBIRD_MPEG_CAPTURE,
+                       BLACKBIRD_RAW_BITS_NONE
+               ); /* start capturing to the host interface */
+       msleep(10);
 
-       blackbird_api_cmd(dev, IVTV_API_REFRESH_INPUT, 0,0);
+       blackbird_api_cmd(dev, BLACKBIRD_API_REFRESH_INPUT, 0,0);
        return 0;
 }
 
@@ -709,7 +1019,12 @@ static int mpeg_release(struct inode *inode, struct file *file)
 {
        struct cx8802_fh  *fh  = file->private_data;
 
-       blackbird_api_cmd(fh->dev, IVTV_API_END_CAPTURE, 3, 0, 1, 0, 0x13);
+       /* blackbird_api_cmd(fh->dev, BLACKBIRD_API_END_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
+       blackbird_api_cmd(fh->dev, BLACKBIRD_API_END_CAPTURE, 3, 0,
+                       BLACKBIRD_END_NOW,
+                       BLACKBIRD_MPEG_CAPTURE,
+                       BLACKBIRD_RAW_BITS_NONE
+               );
 
        /* stop mpeg capture */
        if (fh->mpegq.streaming)
@@ -908,4 +1223,5 @@ module_exit(blackbird_fini);
  * Local variables:
  * c-basic-offset: 8
  * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
  */
index 367624822d7762948286681aab287a6b773895eb..b3fb04356b719cdeeab67f2939e4f6ee4a155512 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-cards.c,v 1.66 2005/03/04 09:12:23 kraxel Exp $
+ * $Id: cx88-cards.c,v 1.76 2005/06/08 01:28:09 mchehab Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * card-specific stuff.
@@ -35,6 +35,9 @@ struct cx88_board cx88_boards[] = {
        [CX88_BOARD_UNKNOWN] = {
                .name           = "UNKNOWN/GENERIC",
                .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .input          = {{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 0,
@@ -52,6 +55,9 @@ struct cx88_board cx88_boards[] = {
        [CX88_BOARD_HAUPPAUGE] = {
                .name           = "Hauppauge WinTV 34xxx models",
                .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
@@ -78,6 +84,9 @@ struct cx88_board cx88_boards[] = {
        [CX88_BOARD_GDI] = {
                .name           = "GDI Black Gold",
                .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
@@ -85,7 +94,10 @@ struct cx88_board cx88_boards[] = {
        },
        [CX88_BOARD_PIXELVIEW] = {
                .name           = "PixelView",
-               .tuner_type     = 5,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
@@ -104,7 +116,10 @@ struct cx88_board cx88_boards[] = {
        },
        [CX88_BOARD_ATI_WONDER_PRO] = {
                .name           = "ATI TV Wonder Pro",
-               .tuner_type     = 44,
+               .tuner_type     = TUNER_PHILIPS_4IN1,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT | TDA9887_INTERCARRIER,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
@@ -122,7 +137,10 @@ struct cx88_board cx88_boards[] = {
        },
         [CX88_BOARD_WINFAST2000XP_EXPERT] = {
                 .name           = "Leadtek Winfast 2000XP Expert",
-                .tuner_type     = 44,
+                .tuner_type     = TUNER_PHILIPS_4IN1,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                 .input          = {{
                         .type   = CX88_VMUX_TELEVISION,
@@ -156,7 +174,10 @@ struct cx88_board cx88_boards[] = {
         },
        [CX88_BOARD_AVERTV_303] = {
                .name           = "AverTV Studio 303 (M126)",
-               .tuner_type     = 38,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
@@ -179,7 +200,10 @@ struct cx88_board cx88_boards[] = {
                // added gpio values thanks to Michal
                // values for PAL from DScaler
                .name           = "MSI TV-@nywhere Master",
-               .tuner_type     = 33,
+               .tuner_type     = TUNER_MT2032,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
@@ -206,7 +230,10 @@ struct cx88_board cx88_boards[] = {
        },
        [CX88_BOARD_WINFAST_DV2000] = {
                 .name           = "Leadtek Winfast DV2000",
-                .tuner_type     = 38,
+                .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                 .input          = {{
                         .type   = CX88_VMUX_TELEVISION,
@@ -239,34 +266,40 @@ struct cx88_board cx88_boards[] = {
                        .gpio3  = 0x02000000,
                 },
         },
-        [CX88_BOARD_LEADTEK_PVR2000] = {
+       [CX88_BOARD_LEADTEK_PVR2000] = {
                // gpio values for PAL version from regspy by DScaler
-                .name           = "Leadtek PVR 2000",
-                .tuner_type     = 38,
+               .name           = "Leadtek PVR 2000",
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-                .input          = {{
-                        .type   = CX88_VMUX_TELEVISION,
-                        .vmux   = 0,
-                        .gpio0  = 0x0000bde6,
-                },{
-                        .type   = CX88_VMUX_COMPOSITE1,
-                        .vmux   = 1,
-                        .gpio0  = 0x0000bde6,
-                },{
-                        .type   = CX88_VMUX_SVIDEO,
-                        .vmux   = 2,
-                        .gpio0  = 0x0000bde6,
-                }},
-                .radio = {
-                        .type   = CX88_RADIO,
-                        .gpio0  = 0x0000bd62,
-                },
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x0000bde2,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x0000bde6,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x0000bde6,
+               }},
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0  = 0x0000bd62,
+               },
                .blackbird = 1,
-        },
+       },
        [CX88_BOARD_IODATA_GVVCP3PCI] = {
                .name           = "IODATA GV-VCP3/PCI",
                .tuner_type     = TUNER_ABSENT,
-               .input          = {{
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 0,
                },{
@@ -279,7 +312,10 @@ struct cx88_board cx88_boards[] = {
        },
        [CX88_BOARD_PROLINK_PLAYTVPVR] = {
                 .name           = "Prolink PlayTV PVR",
-                .tuner_type     = 43,
+                .tuner_type     = TUNER_PHILIPS_FM1236_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
@@ -301,8 +337,11 @@ struct cx88_board cx88_boards[] = {
        },
        [CX88_BOARD_ASUS_PVR_416] = {
                .name           = "ASUS PVR-416",
-               .tuner_type     = 43,
-                .tda9887_conf   = TDA9887_PRESENT,
+               .tuner_type     = TUNER_PHILIPS_FM1236_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
@@ -320,7 +359,10 @@ struct cx88_board cx88_boards[] = {
        },
        [CX88_BOARD_MSI_TVANYWHERE] = {
                .name           = "MSI TV-@nywhere",
-               .tuner_type     = 33,
+               .tuner_type     = TUNER_MT2032,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
@@ -342,6 +384,9 @@ struct cx88_board cx88_boards[] = {
         [CX88_BOARD_KWORLD_DVB_T] = {
                 .name           = "KWorld/VStream XPert DVB-T",
                .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                 .input          = {{
                         .type   = CX88_VMUX_COMPOSITE1,
                         .vmux   = 1,
@@ -358,6 +403,9 @@ struct cx88_board cx88_boards[] = {
        [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
                .name           = "DVICO FusionHDTV DVB-T1",
                .tuner_type     = TUNER_ABSENT, /* No analog tuner */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .input          = {{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
@@ -371,7 +419,10 @@ struct cx88_board cx88_boards[] = {
        },
        [CX88_BOARD_KWORLD_LTV883] = {
                .name           = "KWorld LTV883RF",
-                .tuner_type     = 48,
+               .tuner_type     = TUNER_TNF_8831BGFF,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                 .input          = {{
                         .type   = CX88_VMUX_TELEVISION,
                         .vmux   = 0,
@@ -397,6 +448,9 @@ struct cx88_board cx88_boards[] = {
        [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD] = {
                .name           = "DViCO - FusionHDTV 3 Gold",
                .tuner_type     = TUNER_MICROTUNE_4042FI5,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                /*
                   GPIO[0] resets DT3302 DTV receiver
                    0 - reset asserted
@@ -428,17 +482,14 @@ struct cx88_board cx88_boards[] = {
                        .vmux   = 2,
                        .gpio0  = 0x0f00,
                }},
-#if 0
-               .ts             = {
-                        .type   = CX88_TS,
-                        .gpio0  = 0x00000f01,   /* Hooked to tuner reset bit */
-                }
-#endif
        },
         [CX88_BOARD_HAUPPAUGE_DVB_T1] = {
-                .name           = "Hauppauge Nova-T DVB-T",
+               .name           = "Hauppauge Nova-T DVB-T",
                .tuner_type     = TUNER_ABSENT,
-                .input          = {{
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
                         .type   = CX88_VMUX_DVB,
                         .vmux   = 0,
                 }},
@@ -447,6 +498,9 @@ struct cx88_board cx88_boards[] = {
         [CX88_BOARD_CONEXANT_DVB_T1] = {
                .name           = "Conexant DVB-T reference design",
                .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                 .input          = {{
                         .type   = CX88_VMUX_DVB,
                         .vmux   = 0,
@@ -456,6 +510,9 @@ struct cx88_board cx88_boards[] = {
        [CX88_BOARD_PROVIDEO_PV259] = {
                .name           = "Provideo PV259",
                .tuner_type     = TUNER_PHILIPS_FQ1216ME,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
@@ -465,6 +522,9 @@ struct cx88_board cx88_boards[] = {
        [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = {
                .name           = "DVICO FusionHDTV DVB-T Plus",
                .tuner_type     = TUNER_ABSENT, /* No analog tuner */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .input          = {{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
@@ -479,6 +539,9 @@ struct cx88_board cx88_boards[] = {
        [CX88_BOARD_DNTV_LIVE_DVB_T] = {
                .name           = "digitalnow DNTV Live! DVB-T",
                .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .input          = {{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
@@ -495,6 +558,9 @@ struct cx88_board cx88_boards[] = {
        [CX88_BOARD_PCHDTV_HD3000] = {
                .name           = "pcHDTV HD3000 HDTV",
                .tuner_type     = TUNER_THOMSON_DTT7610,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
@@ -530,8 +596,11 @@ struct cx88_board cx88_boards[] = {
        [CX88_BOARD_HAUPPAUGE_ROSLYN] = {
                // entry added by Kaustubh D. Bhalerao <bhalerao.1@osu.edu>
                // GPIO values obtained from regspy, courtesy Sean Covel
-               .name        = "Hauppauge WinTV 28xxx (Roslyn) models",
-               .tuner_type  = UNSET,
+               .name           = "Hauppauge WinTV 28xxx (Roslyn) models",
+               .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
@@ -559,33 +628,37 @@ struct cx88_board cx88_boards[] = {
                .blackbird = 1,
        },
        [CX88_BOARD_DIGITALLOGIC_MEC] = {
-               /* params copied over from Leadtek PVR 2000 */
                .name           = "Digital-Logic MICROSPACE Entertainment Center (MEC)",
-               /* not sure yet about the tuner type */
-               .tuner_type     = 38,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
-                       .gpio0  = 0x0000bde6,
+                       .gpio0  = 0x00009d80,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
-                       .gpio0  = 0x0000bde6,
+                       .gpio0  = 0x00009d76,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-                       .gpio0  = 0x0000bde6,
+                       .gpio0  = 0x00009d76,
                }},
                .radio = {
                        .type   = CX88_RADIO,
-                       .gpio0  = 0x0000bd62,
+                       .gpio0  = 0x00009d00,
                },
                .blackbird = 1,
        },
        [CX88_BOARD_IODATA_GVBCTV7E] = {
                .name           = "IODATA GV/BCTV7E",
                .tuner_type     = TUNER_PHILIPS_FQ1286,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
@@ -601,6 +674,56 @@ struct cx88_board cx88_boards[] = {
                        .gpio1  = 0x0000e07f,
                }}
        },
+       [CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO] = {
+               .name           = "PixelView PlayTV Ultra Pro (Stereo)",
+               /* May be also TUNER_YMEC_TVF_5533MF for NTSC/M or PAL/M */
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = TUNER_TEA5767,
+               .tuner_addr     = 0xc2>>1,
+               .radio_addr     = 0xc0>>1,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0xbf61,  /* internal decoder */
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0xbf63,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0xbf63,
+               }},
+               .radio = {
+                        .type  = CX88_RADIO,
+                        .gpio0 = 0xbf60,
+                },
+       },
+        [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
+                .name           = "DViCO - FusionHDTV 3 Gold-T",
+               .tuner_type     = TUNER_THOMSON_DTT7611,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               /*  See DViCO FusionHDTV 3 Gold for GPIO documentation.  */
+                .input          = {{
+                        .type   = CX88_VMUX_TELEVISION,
+                        .vmux   = 0,
+                        .gpio0  = 0x0f0d,
+                },{
+                        .type   = CX88_VMUX_CABLE,
+                        .vmux   = 0,
+                        .gpio0  = 0x0f05,
+                },{
+                        .type   = CX88_VMUX_COMPOSITE1,
+                        .vmux   = 1,
+                        .gpio0  = 0x0f00,
+                },{
+                        .type   = CX88_VMUX_SVIDEO,
+                        .vmux   = 2,
+                        .gpio0  = 0x0f00,
+                }},
+        },
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -672,6 +795,10 @@ struct cx88_subid cx88_subids[] = {
                .subvendor = 0x18ac,
                .subdevice = 0xd810,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD,
+       },{
+               .subvendor = 0x18ac,
+               .subdevice = 0xd820,
+               .card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T,
        },{
                .subvendor = 0x18AC,
                .subdevice = 0xDB00,
@@ -935,4 +1062,5 @@ EXPORT_SYMBOL(cx88_card_setup);
  * Local variables:
  * c-basic-offset: 8
  * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
  */
index 1ff79b5a8835d0a96ecf870c1041273977f0616c..c046a23537d35ed22923e833c8ebcd7306c62213 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-core.c,v 1.24 2005/01/19 12:01:55 kraxel Exp $
+ * $Id: cx88-core.c,v 1.28 2005/06/12 04:19:19 mchehab Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * driver core
@@ -51,12 +51,15 @@ module_param(latency,int,0444);
 MODULE_PARM_DESC(latency,"pci latency timer");
 
 static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
 static unsigned int card[]  = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
 
 module_param_array(tuner, int, NULL, 0444);
+module_param_array(radio, int, NULL, 0444);
 module_param_array(card,  int, NULL, 0444);
 
 MODULE_PARM_DESC(tuner,"tuner type");
+MODULE_PARM_DESC(radio,"radio tuner type");
 MODULE_PARM_DESC(card,"card type");
 
 static unsigned int nicam = 0;
@@ -429,7 +432,7 @@ int cx88_sram_channel_setup(struct cx88_core *core,
 /* ------------------------------------------------------------------ */
 /* debug helper code                                                  */
 
-static int cx88_risc_decode(u32 risc)
+int cx88_risc_decode(u32 risc)
 {
        static char *instr[16] = {
                [ RISC_SYNC    >> 28 ] = "sync",
@@ -736,6 +739,10 @@ static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
 {
        static const unsigned int ntsc = 28636360;
        static const unsigned int pal  = 35468950;
+       static const unsigned int palm  = 28604892;
+
+       if (norm->id & V4L2_STD_PAL_M)
+               return palm;
 
        return (norm->id & V4L2_STD_625_50) ? pal : ntsc;
 }
@@ -749,6 +756,11 @@ static unsigned int inline norm_notchfilter(struct cx88_tvnorm *norm)
 
 static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
 {
+       /* Should always be Line Draw Time / (4*FSC) */
+
+       if (norm->id & V4L2_STD_PAL_M)
+               return 909;
+
        return (norm->id & V4L2_STD_625_50) ? 1135 : 910;
 }
 
@@ -1164,8 +1176,20 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci)
               "insmod option" : "autodetected");
 
        core->tuner_type = tuner[core->nr];
+       core->radio_type = radio[core->nr];
        if (UNSET == core->tuner_type)
                core->tuner_type = cx88_boards[core->board].tuner_type;
+       if (UNSET == core->radio_type)
+               core->radio_type = cx88_boards[core->board].radio_type;
+       if (!core->tuner_addr)
+               core->tuner_addr = cx88_boards[core->board].tuner_addr;
+       if (!core->radio_addr)
+               core->radio_addr = cx88_boards[core->board].radio_addr;
+
+        printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
+               core->tuner_type, core->tuner_addr<<1,
+               core->radio_type, core->radio_addr<<1);
+
        core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
 
        /* init hardware */
index 9d15d3d5a2b70c4e502bc8f94adbbbe97903afa3..1a259c3966cd748ff6d0130a0262ba02e7b1da52 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-dvb.c,v 1.31 2005/03/07 15:58:05 kraxel Exp $
+ * $Id: cx88-dvb.c,v 1.33 2005/06/12 04:19:19 mchehab Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * MPEG Transport Stream (DVB) routines
index 0725b1288f4f55761e81a37ee8e7c2a42a8f4efe..e20adefcfc6c76d233c54eb3edb29908ac9cfabc 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    $Id: cx88-i2c.c,v 1.20 2005/02/15 15:59:35 kraxel Exp $
+    $Id: cx88-i2c.c,v 1.23 2005/06/12 04:19:19 mchehab Exp $
 
     cx88-i2c.c  --  all the i2c code is here
 
@@ -91,6 +91,7 @@ static int cx8800_bit_getsda(void *data)
 
 static int attach_inform(struct i2c_client *client)
 {
+        struct tuner_addr tun_addr;
        struct cx88_core *core = i2c_get_adapdata(client->adapter);
 
        dprintk(1, "i2c attach [addr=0x%x,client=%s]\n",
@@ -98,8 +99,19 @@ static int attach_inform(struct i2c_client *client)
        if (!client->driver->command)
                return 0;
 
-       if (core->tuner_type != UNSET)
-               client->driver->command(client, TUNER_SET_TYPE, &core->tuner_type);
+        if (core->radio_type != UNSET) {
+                tun_addr.v4l2_tuner = V4L2_TUNER_RADIO;
+                tun_addr.type = core->radio_type;
+                tun_addr.addr = core->radio_addr;
+                client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_addr);
+        }
+        if (core->tuner_type != UNSET) {
+                tun_addr.v4l2_tuner = V4L2_TUNER_ANALOG_TV;
+                tun_addr.type = core->tuner_type;
+                tun_addr.addr = core->tuner_addr;
+                client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_addr);
+        }
+
        if (core->tda9887_conf)
                client->driver->command(client, TDA9887_SET_CONFIG, &core->tda9887_conf);
        return 0;
index af6ad8cdbdb7782873cdbae000678a56c63e0688..dc0dcf249aacfe63fdf01b5a08c241a06ea1785c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-input.c,v 1.9 2005/03/04 09:12:23 kraxel Exp $
+ * $Id: cx88-input.c,v 1.11 2005/05/22 20:57:56 nsh Exp $
  *
  * Device driver for GPIO attached remote control interfaces
  * on Conexant 2388x based TV/DVB cards.
@@ -235,6 +235,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        /* detect & configure */
        switch (core->board) {
        case CX88_BOARD_DNTV_LIVE_DVB_T:
+       case CX88_BOARD_KWORLD_DVB_T:
                ir_codes         = ir_codes_dntv_live_dvb_t;
                ir->gpio_addr    = MO_GP1_IO;
                ir->mask_keycode = 0x1f;
@@ -261,7 +262,15 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                ir->mask_keydown = 0x02;
                ir->polling      = 5; // ms
                break;
+       case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO:
+               ir_codes         = ir_codes_pixelview;
+               ir->gpio_addr    = MO_GP1_IO;
+               ir->mask_keycode = 0x1f;
+               ir->mask_keyup   = 0x80;
+               ir->polling      = 1; // ms
+               break;
        }
+
        if (NULL == ir_codes) {
                kfree(ir);
                return -ENODEV;
index 07aae1899e17a7cff64e0f537fb50ad07f837485..9ade2ae91e9bfef1b787d1179cbd7234e5a9eb52 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-mpeg.c,v 1.25 2005/03/07 14:18:00 kraxel Exp $
+ * $Id: cx88-mpeg.c,v 1.26 2005/06/03 13:31:51 mchehab Exp $
  *
  *  Support for the mpeg transport stream transfers
  *  PCI function #2 of the cx2388x.
@@ -55,7 +55,7 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
 {
        struct cx88_core *core = dev->core;
 
-       dprintk(1, "cx8802_start_mpegport_dma %d\n", buf->vb.width);
+       dprintk(0, "cx8802_start_dma %d\n", buf->vb.width);
 
        /* setup fifo + format */
        cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
@@ -100,18 +100,21 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
        q->count = 1;
 
        /* enable irqs */
+       dprintk( 0, "setting the interrupt mask\n" );
        cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04);
-       cx_write(MO_TS_INTMSK,  0x1f0011);
+       cx_set(MO_TS_INTMSK,  0x1f0011);
+       //cx_write(MO_TS_INTMSK,  0x0f0011);
 
        /* start dma */
-       cx_write(MO_DEV_CNTRL2, (1<<5)); /* FIXME: s/write/set/ ??? */
-       cx_write(MO_TS_DMACNTRL, 0x11);
+       cx_set(MO_DEV_CNTRL2, (1<<5));
+       cx_set(MO_TS_DMACNTRL, 0x11);
        return 0;
 }
 
 static int cx8802_stop_dma(struct cx8802_dev *dev)
 {
        struct cx88_core *core = dev->core;
+       dprintk( 0, "cx8802_stop_dma\n" );
 
        /* stop dma */
        cx_clear(MO_TS_DMACNTRL, 0x11);
@@ -131,8 +134,12 @@ static int cx8802_restart_queue(struct cx8802_dev    *dev,
        struct cx88_buffer *buf;
        struct list_head *item;
 
+       dprintk( 0, "cx8802_restart_queue\n" );
        if (list_empty(&q->active))
+       {
+               dprintk( 0, "cx8802_restart_queue: queue is empty\n" );
                return 0;
+       }
 
        buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
        dprintk(2,"restart_queue [%p/%d]: restart dma\n",
@@ -182,27 +189,32 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
        struct cx88_buffer    *prev;
        struct cx88_dmaqueue  *q    = &dev->mpegq;
 
+       dprintk( 1, "cx8802_buf_queue\n" );
        /* add jump to stopper */
        buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
        buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
 
        if (list_empty(&q->active)) {
+               dprintk( 0, "queue is empty - first active\n" );
                list_add_tail(&buf->vb.queue,&q->active);
                cx8802_start_dma(dev, q, buf);
                buf->vb.state = STATE_ACTIVE;
                buf->count    = q->count++;
                mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-               dprintk(2,"[%p/%d] %s - first active\n",
+               dprintk(0,"[%p/%d] %s - first active\n",
                        buf, buf->vb.i, __FUNCTION__);
+               //udelay(100);
 
        } else {
+               dprintk( 1, "queue is not empty - append to active\n" );
                prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);
                list_add_tail(&buf->vb.queue,&q->active);
                buf->vb.state = STATE_ACTIVE;
                buf->count    = q->count++;
                prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-               dprintk(2,"[%p/%d] %s - append to active\n",
+               dprintk( 1, "[%p/%d] %s - append to active\n",
                        buf, buf->vb.i, __FUNCTION__);
+               //udelay(100);
        }
 }
 
@@ -224,7 +236,10 @@ static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart)
                        buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
        }
        if (restart)
+       {
+               dprintk(0, "restarting queue\n" );
                cx8802_restart_queue(dev,q);
+       }
        spin_unlock_irqrestore(&dev->slock,flags);
 }
 
@@ -232,6 +247,7 @@ void cx8802_cancel_buffers(struct cx8802_dev *dev)
 {
        struct cx88_dmaqueue *q = &dev->mpegq;
 
+       dprintk( 1, "cx8802_cancel_buffers" );
        del_timer_sync(&q->timeout);
        cx8802_stop_dma(dev);
        do_cancel_buffers(dev,"cancel",0);
@@ -241,7 +257,7 @@ static void cx8802_timeout(unsigned long data)
 {
        struct cx8802_dev *dev = (struct cx8802_dev*)data;
 
-       dprintk(1, "%s\n",__FUNCTION__);
+       dprintk(0, "%s\n",__FUNCTION__);
 
        if (debug)
                cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
@@ -254,12 +270,17 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev)
        struct cx88_core *core = dev->core;
        u32 status, mask, count;
 
+       dprintk( 1, "cx8802_mpeg_irq\n" );
        status = cx_read(MO_TS_INTSTAT);
        mask   = cx_read(MO_TS_INTMSK);
        if (0 == (status & mask))
                return;
 
        cx_write(MO_TS_INTSTAT, status);
+#if 0
+       cx88_print_irqbits(core->name, "irq mpeg ",
+                       cx88_mpeg_irqs, status, mask);
+#endif
        if (debug || (status & mask & ~0xff))
                cx88_print_irqbits(core->name, "irq mpeg ",
                                   cx88_mpeg_irqs, status, mask);
@@ -273,6 +294,7 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev)
 
        /* risc1 y */
        if (status & 0x01) {
+               dprintk( 1, "wake up\n" );
                spin_lock(&dev->slock);
                count = cx_read(MO_TS_GPCNT);
                cx88_wakeup(dev->core, &dev->mpegq, count);
@@ -288,6 +310,7 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev)
 
         /* other general errors */
         if (status & 0x1f0100) {
+               dprintk( 0, "general errors: 0x%08x\n", status & 0x1f0100 );
                 spin_lock(&dev->slock);
                cx8802_stop_dma(dev);
                 cx8802_restart_queue(dev,&dev->mpegq);
@@ -295,6 +318,8 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev)
         }
 }
 
+#define MAX_IRQ_LOOP 10
+
 static irqreturn_t cx8802_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct cx8802_dev *dev = dev_id;
@@ -302,10 +327,13 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id, struct pt_regs *regs)
        u32 status;
        int loop, handled = 0;
 
-       for (loop = 0; loop < 10; loop++) {
+       for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
                status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x04);
                if (0 == status)
                        goto out;
+               dprintk( 1, "cx8802_irq\n" );
+               dprintk( 1, "    loop: %d/%d\n", loop, MAX_IRQ_LOOP );
+               dprintk( 1, "    status: %d\n", status );
                handled = 1;
                cx_write(MO_PCI_INTSTAT, status);
 
@@ -314,7 +342,8 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id, struct pt_regs *regs)
                if (status & 0x04)
                        cx8802_mpeg_irq(dev);
        };
-       if (10 == loop) {
+       if (MAX_IRQ_LOOP == loop) {
+               dprintk( 0, "clearing mask\n" );
                printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n",
                       core->name);
                cx_write(MO_PCI_INTMSK,0);
@@ -378,6 +407,7 @@ int cx8802_init_common(struct cx8802_dev *dev)
 
 void cx8802_fini_common(struct cx8802_dev *dev)
 {
+       dprintk( 2, "cx8802_fini_common\n" );
        cx8802_stop_dma(dev);
        pci_disable_device(dev->pci);
 
@@ -399,6 +429,7 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
        /* stop mpeg dma */
        spin_lock(&dev->slock);
        if (!list_empty(&dev->mpegq.active)) {
+               dprintk( 2, "suspend\n" );
                printk("%s: suspend mpeg\n", core->name);
                cx8802_stop_dma(dev);
                del_timer(&dev->mpegq.timeout);
@@ -463,4 +494,5 @@ EXPORT_SYMBOL(cx8802_resume_common);
  * Local variables:
  * c-basic-offset: 8
  * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
  */
index 8638ce57d84c435828f9c902d63804de1d9df798..63ad33f5818b38f49ca2eeed19ac670a3d83ead0 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    $Id: cx88-reg.h,v 1.6 2004/10/13 10:39:00 kraxel Exp $
+    $Id: cx88-reg.h,v 1.7 2005/06/03 13:31:51 mchehab Exp $
 
     cx88x-hw.h - CX2388x register offsets
 
 #define AUD_RATE_ADJ4            0x3205e4
 #define AUD_RATE_ADJ5            0x3205e8
 #define AUD_APB_IN_RATE_ADJ      0x3205ec
+#define AUD_I2SCNTL              0x3205ec
 #define AUD_PHASE_FIX_CTL        0x3205f0
 #define AUD_PLL_PRESCALE         0x320600
 #define AUD_PLL_DDS              0x320604
index f2a9475a2feeff551c9a269668c6d5738eb0ff56..46d78b1dc9b29993787f69994300113bc84561af 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    $Id: cx88-tvaudio.c,v 1.34 2005/03/07 16:10:51 kraxel Exp $
+    $Id: cx88-tvaudio.c,v 1.36 2005/06/05 05:53:45 mchehab Exp $
 
     cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver
 
@@ -127,7 +127,8 @@ static void set_audio_start(struct cx88_core *core,
        cx_write(AUD_VOL_CTL,       (1 << 6));
 
        //  increase level of input by 12dB
-       cx_write(AUD_AFE_12DB_EN,   0x0001);
+//     cx_write(AUD_AFE_12DB_EN,   0x0001);
+       cx_write(AUD_AFE_12DB_EN,   0x0000);
 
        // start programming
        cx_write(AUD_CTL,           0x0000);
@@ -143,9 +144,15 @@ static void set_audio_finish(struct cx88_core *core)
        u32 volume;
 
        if (cx88_boards[core->board].blackbird) {
+               // sets sound input from external adc
+               cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+               //cx_write(AUD_I2SINPUTCNTL, 0);
+               cx_write(AUD_I2SINPUTCNTL, 4);
+               cx_write(AUD_BAUDRATE, 1);
                // 'pass-thru mode': this enables the i2s output to the mpeg encoder
-               cx_set(AUD_CTL, 0x2000);
+               cx_set(AUD_CTL, EN_I2SOUT_ENABLE);
                cx_write(AUD_I2SOUTPUTCNTL, 1);
+               cx_write(AUD_I2SCNTL, 0);
                //cx_write(AUD_APB_IN_RATE_ADJ, 0);
        }
 
@@ -707,50 +714,65 @@ static void set_audio_standard_EIAJ(struct cx88_core *core)
        set_audio_finish(core);
 }
 
-static void set_audio_standard_FM(struct cx88_core *core)
+static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type deemph)
 {
-#if 0 /* FIXME */
-       switch (dev->audio_properties.FM_deemphasis)
-       {
-               case WW_FM_DEEMPH_50:
-                       //Set De-emphasis filter coefficients for 50 usec
-                       cx_write(AUD_DEEMPH0_G0, 0x0C45);
-                       cx_write(AUD_DEEMPH0_A0, 0x6262);
-                       cx_write(AUD_DEEMPH0_B0, 0x1C29);
-                       cx_write(AUD_DEEMPH0_A1, 0x3FC66);
-                       cx_write(AUD_DEEMPH0_B1, 0x399A);
-
-                       cx_write(AUD_DEEMPH1_G0, 0x0D80);
-                       cx_write(AUD_DEEMPH1_A0, 0x6262);
-                       cx_write(AUD_DEEMPH1_B0, 0x1C29);
-                       cx_write(AUD_DEEMPH1_A1, 0x3FC66);
-                       cx_write(AUD_DEEMPH1_B1, 0x399A);
+       static const struct rlist fm_deemph_50[] = {
+               { AUD_DEEMPH0_G0,       0x0C45 },
+               { AUD_DEEMPH0_A0,       0x6262 },
+               { AUD_DEEMPH0_B0,       0x1C29 },
+               { AUD_DEEMPH0_A1,       0x3FC66},
+               { AUD_DEEMPH0_B1,       0x399A },
+
+               { AUD_DEEMPH1_G0,       0x0D80 },
+               { AUD_DEEMPH1_A0,       0x6262 },
+               { AUD_DEEMPH1_B0,       0x1C29 },
+               { AUD_DEEMPH1_A1,       0x3FC66},
+               { AUD_DEEMPH1_B1,       0x399A},
+
+               { AUD_POLYPH80SCALEFAC, 0x0003},
+               { /* end of list */ },
+       };
+       static const struct rlist fm_deemph_75[] = {
+               { AUD_DEEMPH0_G0,       0x091B },
+               { AUD_DEEMPH0_A0,       0x6B68 },
+               { AUD_DEEMPH0_B0,       0x11EC },
+               { AUD_DEEMPH0_A1,       0x3FC66},
+               { AUD_DEEMPH0_B1,       0x399A },
+
+               { AUD_DEEMPH1_G0,       0x0AA0 },
+               { AUD_DEEMPH1_A0,       0x6B68 },
+               { AUD_DEEMPH1_B0,       0x11EC },
+               { AUD_DEEMPH1_A1,       0x3FC66},
+               { AUD_DEEMPH1_B1,       0x399A},
+
+               { AUD_POLYPH80SCALEFAC, 0x0003},
+               { /* end of list */ },
+       };
 
-                       break;
+       /* It is enough to leave default values? */
+       static const struct rlist fm_no_deemph[] = {
 
-               case WW_FM_DEEMPH_75:
-                       //Set De-emphasis filter coefficients for 75 usec
-                       cx_write(AUD_DEEMPH0_G0, 0x91B );
-                       cx_write(AUD_DEEMPH0_A0, 0x6B68);
-                       cx_write(AUD_DEEMPH0_B0, 0x11EC);
-                       cx_write(AUD_DEEMPH0_A1, 0x3FC66);
-                       cx_write(AUD_DEEMPH0_B1, 0x399A);
+               { AUD_POLYPH80SCALEFAC, 0x0003},
+               { /* end of list */ },
+       };
 
-                       cx_write(AUD_DEEMPH1_G0, 0xAA0 );
-                       cx_write(AUD_DEEMPH1_A0, 0x6B68);
-                       cx_write(AUD_DEEMPH1_B0, 0x11EC);
-                       cx_write(AUD_DEEMPH1_A1, 0x3FC66);
-                       cx_write(AUD_DEEMPH1_B1, 0x399A);
+       dprintk("%s (status: unknown)\n",__FUNCTION__);
+       set_audio_start(core, 0x0020, EN_FMRADIO_AUTO_STEREO);
 
+       switch (deemph)
+       {
+               case FM_NO_DEEMPH:
+                       set_audio_registers(core, fm_no_deemph);
                        break;
-       }
-#endif
 
-       dprintk("%s (status: unknown)\n",__FUNCTION__);
-       set_audio_start(core, 0x0020, EN_FMRADIO_AUTO_STEREO);
+               case FM_DEEMPH_50:
+                       set_audio_registers(core, fm_deemph_50);
+                       break;
 
-       // AB: 10/2/01: this register is not being reset appropriately on occasion.
-       cx_write(AUD_POLYPH80SCALEFAC,3);
+               case FM_DEEMPH_75:
+                       set_audio_registers(core, fm_deemph_75);
+                       break;
+       }
 
        set_audio_finish(core);
 }
@@ -778,7 +800,7 @@ void cx88_set_tvaudio(struct cx88_core *core)
                set_audio_standard_EIAJ(core);
                break;
        case WW_FM:
-               set_audio_standard_FM(core);
+               set_audio_standard_FM(core,FM_NO_DEEMPH);
                break;
        case WW_SYSTEM_L_AM:
                set_audio_standard_NICAM_L(core, 1);
@@ -1029,4 +1051,5 @@ EXPORT_SYMBOL(cx88_audio_thread);
  * Local variables:
  * c-basic-offset: 8
  * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
  */
index 0584ff476387bbc3233bda943467a4890e59172a..320d57888bbd942764df6a7059122fe909dbe5fa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-vbi.c,v 1.16 2004/12/10 12:33:39 kraxel Exp $
+ * $Id: cx88-vbi.c,v 1.17 2005/06/12 04:19:19 mchehab Exp $
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -47,8 +47,8 @@ void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
 }
 
 static int cx8800_start_vbi_dma(struct cx8800_dev    *dev,
-                               struct cx88_dmaqueue *q,
-                               struct cx88_buffer   *buf)
+                        struct cx88_dmaqueue *q,
+                        struct cx88_buffer   *buf)
 {
        struct cx88_core *core = dev->core;
 
index d1f5c92f0ce578c123a59dde9aa9234b6e51f2e8..e4ca7350df1510f4e4e3eb58f83aa2a3101a840c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-video.c,v 1.58 2005/03/07 15:58:05 kraxel Exp $
+ * $Id: cx88-video.c,v 1.63 2005/06/12 04:19:19 mchehab Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * video4linux video interface
@@ -1187,9 +1187,24 @@ static void init_controls(struct cx8800_dev *dev)
                .id    = V4L2_CID_AUDIO_VOLUME,
                .value = 0x3f,
        };
+       static struct v4l2_control hue = {
+               .id    = V4L2_CID_HUE,
+               .value = 0x80,
+       };
+       static struct v4l2_control contrast = {
+               .id    = V4L2_CID_CONTRAST,
+               .value = 0x80,
+       };
+       static struct v4l2_control brightness = {
+               .id    = V4L2_CID_BRIGHTNESS,
+               .value = 0x80,
+       };
 
        set_control(dev,&mute);
        set_control(dev,&volume);
+       set_control(dev,&hue);
+       set_control(dev,&contrast);
+       set_control(dev,&brightness);
 }
 
 /* ------------------------------------------------------------------ */
@@ -1335,6 +1350,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                        V4L2_CAP_READWRITE     |
                        V4L2_CAP_STREAMING     |
                        V4L2_CAP_VBI_CAPTURE   |
+#if 0
+                       V4L2_TUNER_CAP_LOW     |
+#endif
 #if 0
                        V4L2_CAP_VIDEO_OVERLAY |
 #endif
@@ -1696,7 +1714,11 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
                        sizeof(cap->card));
                sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
                cap->version = CX88_VERSION_CODE;
-               cap->capabilities = V4L2_CAP_TUNER;
+               cap->capabilities = V4L2_CAP_TUNER
+#if 0
+                                   | V4L2_TUNER_CAP_LOW
+#endif
+                                   ;
                return 0;
        }
        case VIDIOC_G_TUNER:
@@ -1992,6 +2014,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
 {
        struct cx8800_dev *dev;
        struct cx88_core *core;
+       struct tuner_addr tun_addr;
        int err;
 
        dev = kmalloc(sizeof(*dev),GFP_KERNEL);
@@ -2065,8 +2088,19 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
                request_module("tuner");
        if (core->tda9887_conf)
                request_module("tda9887");
-       if (core->tuner_type != UNSET)
-               cx88_call_i2c_clients(dev->core,TUNER_SET_TYPE,&core->tuner_type);
+       if (core->radio_type != UNSET) {
+               tun_addr.v4l2_tuner = V4L2_TUNER_RADIO;
+               tun_addr.type = core->radio_type;
+               tun_addr.addr = core->radio_addr;
+               cx88_call_i2c_clients(dev->core,TUNER_SET_TYPE_ADDR, &tun_addr);
+       }
+       if (core->tuner_type != UNSET) {
+               tun_addr.v4l2_tuner = V4L2_TUNER_ANALOG_TV;
+               tun_addr.type = core->tuner_type;
+               tun_addr.addr = core->tuner_addr;
+               cx88_call_i2c_clients(dev->core,TUNER_SET_TYPE_ADDR, &tun_addr);
+       }
+
        if (core->tda9887_conf)
                cx88_call_i2c_clients(dev->core,TDA9887_SET_CONFIG,&core->tda9887_conf);
 
@@ -2162,7 +2196,7 @@ static void __devexit cx8800_finidev(struct pci_dev *pci_dev)
 
 static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
 {
-        struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+       struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
        struct cx88_core *core = dev->core;
 
        /* stop video+vbi capture */
@@ -2194,7 +2228,7 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
 
 static int cx8800_resume(struct pci_dev *pci_dev)
 {
-        struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+       struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
        struct cx88_core *core = dev->core;
 
        if (dev->state.disabled) {
@@ -2230,8 +2264,8 @@ static struct pci_device_id cx8800_pci_tbl[] = {
        {
                .vendor       = 0x14f1,
                .device       = 0x8800,
-                .subvendor    = PCI_ANY_ID,
-                .subdevice    = PCI_ANY_ID,
+               .subvendor    = PCI_ANY_ID,
+               .subdevice    = PCI_ANY_ID,
        },{
                /* --- end of list --- */
        }
@@ -2239,10 +2273,10 @@ static struct pci_device_id cx8800_pci_tbl[] = {
 MODULE_DEVICE_TABLE(pci, cx8800_pci_tbl);
 
 static struct pci_driver cx8800_pci_driver = {
-        .name     = "cx8800",
-        .id_table = cx8800_pci_tbl,
-        .probe    = cx8800_initdev,
-        .remove   = __devexit_p(cx8800_finidev),
+       .name     = "cx8800",
+       .id_table = cx8800_pci_tbl,
+       .probe    = cx8800_initdev,
+       .remove   = __devexit_p(cx8800_finidev),
 
        .suspend  = cx8800_suspend,
        .resume   = cx8800_resume,
@@ -2274,4 +2308,5 @@ module_exit(cx8800_fini);
  * Local variables:
  * c-basic-offset: 8
  * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
  */
index 88eaaaba5ad8838d0cc4d8ba0291fb846b348a7e..867e988a5a93cc397685a4095cb861860dbd8e9e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88.h,v 1.56 2005/03/04 09:12:23 kraxel Exp $
+ * $Id: cx88.h,v 1.62 2005/06/12 04:19:19 mchehab Exp $
  *
  * v4l2 device driver for cx2388x based TV cards
  *
 #define SHADOW_AUD_BAL_CTL           2
 #define SHADOW_MAX                   2
 
+/* FM Radio deemphasis type */
+enum cx88_deemph_type {
+       FM_NO_DEEMPH = 0,
+       FM_DEEMPH_50,
+       FM_DEEMPH_75
+};
+
 /* ----------------------------------------------------------- */
 /* tv norms                                                    */
 
@@ -162,6 +169,8 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_HAUPPAUGE_ROSLYN        24
 #define CX88_BOARD_DIGITALLOGIC_MEC           25
 #define CX88_BOARD_IODATA_GVBCTV7E         26
+#define CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO 27
+#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T  28
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -185,6 +194,9 @@ struct cx88_input {
 struct cx88_board {
        char                    *name;
        unsigned int            tuner_type;
+       unsigned int            radio_type;
+       unsigned char           tuner_addr;
+       unsigned char           radio_addr;
        int                     tda9887_conf;
        struct cx88_input       input[8];
        struct cx88_input       radio;
@@ -255,6 +267,9 @@ struct cx88_core {
        /* config info -- analog */
        unsigned int               board;
        unsigned int               tuner_type;
+       unsigned int               radio_type;
+       unsigned char              tuner_addr;
+       unsigned char              radio_addr;
        unsigned int               tda9887_conf;
        unsigned int               has_radio;
 
@@ -471,6 +486,11 @@ extern void cx88_core_put(struct cx88_core *core,
 /* cx88-vbi.c                                                  */
 
 void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f);
+/*
+int cx8800_start_vbi_dma(struct cx8800_dev    *dev,
+                        struct cx88_dmaqueue *q,
+                        struct cx88_buffer   *buf);
+*/
 int cx8800_stop_vbi_dma(struct cx8800_dev *dev);
 int cx8800_restart_vbi_queue(struct cx8800_dev    *dev,
                             struct cx88_dmaqueue *q);
index ab6620de4b3b8318c4ad55c87a3c033dfed0a280..a565823330aaa29883f2a16f793a65b4cb7416ec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ir-kbd-gpio.c,v 1.12 2005/02/22 12:28:40 kraxel Exp $
+ * $Id: ir-kbd-gpio.c,v 1.13 2005/05/15 19:01:26 mchehab Exp $
  *
  * Copyright (c) 2003 Gerd Knorr
  * Copyright (c) 2003 Pavel Machek
@@ -114,38 +114,6 @@ static IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
        [ 0x3e ] = KEY_VOLUMEUP,    // 'volume +'
 };
 
-static IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = {
-       [  2 ] = KEY_KP0,
-       [  1 ] = KEY_KP1,
-       [ 11 ] = KEY_KP2,
-       [ 27 ] = KEY_KP3,
-       [  5 ] = KEY_KP4,
-       [  9 ] = KEY_KP5,
-       [ 21 ] = KEY_KP6,
-       [  6 ] = KEY_KP7,
-       [ 10 ] = KEY_KP8,
-       [ 18 ] = KEY_KP9,
-
-       [  3 ] = KEY_TUNER,       // TV/FM
-       [  7 ] = KEY_SEARCH,      // scan
-       [ 28 ] = KEY_ZOOM,        // full screen
-       [ 30 ] = KEY_POWER,
-       [ 23 ] = KEY_VOLUMEDOWN,
-       [ 31 ] = KEY_VOLUMEUP,
-       [ 20 ] = KEY_CHANNELDOWN,
-       [ 22 ] = KEY_CHANNELUP,
-       [ 24 ] = KEY_MUTE,
-
-       [  0 ] = KEY_LIST,        // source
-       [ 19 ] = KEY_INFO,        // loop
-       [ 16 ] = KEY_LAST,        // +100
-       [ 13 ] = KEY_CLEAR,       // reset
-       [ 12 ] = BTN_RIGHT,       // fun++
-       [  4 ] = BTN_LEFT,        // fun--
-       [ 14 ] = KEY_GOTO,        // function
-       [ 15 ] = KEY_STOP,         // freeze
-};
-
 /* Attila Kondoros <attila.kondoros@chello.hu> */
 static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
 
index 09464d624a6b40b8f4f70dd3de571a47cad314ff..b4ee9dfe6d4247e1cfcdc47ac8bcdb2082140290 100644 (file)
@@ -735,7 +735,6 @@ static int msp34xx_sleep(struct msp3400c *msp, int timeout)
 {
        DECLARE_WAITQUEUE(wait, current);
 
-again:
        add_wait_queue(&msp->wq, &wait);
        if (!kthread_should_stop()) {
                if (timeout < 0) {
@@ -751,12 +750,8 @@ again:
 #endif
                }
        }
-
+       try_to_freeze();
        remove_wait_queue(&msp->wq, &wait);
-
-       if (try_to_freeze(PF_FREEZE))
-               goto again;
-
        return msp->restart;
 }
 
@@ -1436,7 +1431,7 @@ static int msp_detach(struct i2c_client *client);
 static int msp_probe(struct i2c_adapter *adap);
 static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);
 
-static int msp_suspend(struct device * dev, pm_message_t state, u32 level);
+static int msp_suspend(struct device * dev, u32 state, u32 level);
 static int msp_resume(struct device * dev, u32 level);
 
 static void msp_wake_thread(struct i2c_client *client);
@@ -1841,7 +1836,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
        return 0;
 }
 
-static int msp_suspend(struct device * dev, pm_message_t state, u32 level)
+static int msp_suspend(struct device * dev, u32 state, u32 level)
 {
        struct i2c_client *c = container_of(dev, struct i2c_client, dev);
 
index d70a954e13aaa48d67c41adab9c6010443b6ef2c..023f33056a4f82e7f3595be4932075d0797a9f2d 100644 (file)
@@ -1,3 +1,7 @@
+/*
+ * $Id: msp3400.h,v 1.3 2005/06/12 04:19:19 mchehab Exp $
+ */
+
 #ifndef MSP3400_H
 #define MSP3400_H
 
index 95ad17b7f38e3b41a36f96d441ffcd36741f7de4..9c005cb128d7cbeb6d1327fe6845fb797791b30e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mt20xx.c,v 1.4 2005/03/04 09:24:56 kraxel Exp $
+ * $Id: mt20xx.c,v 1.5 2005/06/16 08:29:49 nsh Exp $
  *
  * i2c tv tuner chip device driver
  * controls microtune tuners, mt2032 + mt2050 at the moment.
@@ -295,8 +295,8 @@ static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
        int if2 = t->radio_if2;
 
        // per Manual for FM tuning: first if center freq. 1085 MHz
-        mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
-                          1085*1000*1000,if2,if2,if2);
+        mt2032_set_if_freq(c, freq * 1000 / 16,
+                             1085*1000*1000,if2,if2,if2);
 }
 
 // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
index 42c2b565c9fed172168652142757e729e724517f..e6d0a18833d6ddd0234f26f155c9a8db10fbc26a 100644 (file)
@@ -41,16 +41,16 @@ enum saa6752hs_videoformat {
 
 static const struct v4l2_format v4l2_format_table[] =
 {
-       [SAA6752HS_VF_D1] = {
-               .fmt = { .pix = { .width = 720, .height = 576 }, }, },
-       [SAA6752HS_VF_2_3_D1] = {
-               .fmt = { .pix = { .width = 480, .height = 576 }, }, },
-       [SAA6752HS_VF_1_2_D1] = {
-               .fmt = { .pix = { .width = 352, .height = 576 }, }, },
-       [SAA6752HS_VF_SIF] = {
-               .fmt = { .pix = { .width = 352, .height = 288 }, }, },
-       [SAA6752HS_VF_UNKNOWN] = {
-               .fmt = { .pix = { .width = 0, .height = 0 }, }, },
+       [SAA6752HS_VF_D1] =
+               { .fmt = { .pix = { .width = 720, .height = 576 }}},
+       [SAA6752HS_VF_2_3_D1] =
+               { .fmt = { .pix = { .width = 480, .height = 576 }}},
+       [SAA6752HS_VF_1_2_D1] =
+               { .fmt = { .pix = { .width = 352, .height = 576 }}},
+       [SAA6752HS_VF_SIF] =
+               { .fmt = { .pix = { .width = 352, .height = 288 }}},
+       [SAA6752HS_VF_UNKNOWN] =
+               { .fmt = { .pix = { .width = 0, .height = 0}}},
 };
 
 struct saa6752hs_state {
index c51eb7f078d3f40b33d480f93adbc30fd8868b7e..0c781e24c4466c94fff090c63cce868a7f51e13c 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: saa7134-cards.c,v 1.54 2005/03/07 12:01:51 kraxel Exp $
+ * $Id: saa7134-cards.c,v 1.58 2005/06/07 18:05:00 nsh Exp $
  *
  * device driver for philips saa7134 based TV cards
  * card-specific stuff.
@@ -165,7 +165,7 @@ struct saa7134_board saa7134_boards[] = {
                .inputs         = {{
                        .name = name_tv,
                        .vmux = 1,
-                       .amux = LINE2,
+                       .amux = TV,
                        .tv   = 1,
                },{
                        .name = name_comp1,
@@ -878,7 +878,7 @@ struct saa7134_board saa7134_boards[] = {
         },
        [SAA7134_BOARD_MANLI_MTV002] = {
                /* Ognjen Nastic <ognjen@logosoft.ba> */
-               .name           = "Manli MuchTV M-TV002",
+               .name           = "Manli MuchTV M-TV002/Behold TV 403 FM",
                .audio_clock    = 0x00200000,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .inputs         = {{
@@ -899,14 +899,10 @@ struct saa7134_board saa7134_boards[] = {
                        .name = name_radio,
                        .amux = LINE2,
                },
-               .mute = {
-                       .name = name_mute,
-                        .amux = LINE1,
-               },
        },
        [SAA7134_BOARD_MANLI_MTV001] = {
                /* Ognjen Nastic <ognjen@logosoft.ba> UNTESTED */
-               .name           = "Manli MuchTV M-TV001",
+               .name           = "Manli MuchTV M-TV001/Behold TV 401",
                .audio_clock    = 0x00200000,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .inputs         = {{
@@ -923,6 +919,10 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = LINE2,
                        .tv   = 1,
                }},
+               .mute = {
+                       .name = name_mute,
+                        .amux = LINE1,
+               },
         },
        [SAA7134_BOARD_TG3000TV] = {
                /* TransGear 3000TV */
@@ -1078,7 +1078,6 @@ struct saa7134_board saa7134_boards[] = {
                .audio_clock    = 0x00187de7,
                .tuner_type     = TUNER_PHILIPS_FM1256_IH3,
                .tda9887_conf   = TDA9887_PRESENT,
-               .gpiomask = 0x3,
                .inputs         = {{
                        .name = name_tv,
                        .vmux = 1,
@@ -1285,7 +1284,7 @@ struct saa7134_board saa7134_boards[] = {
                         .gpio =0x8000,
                 }
        },
-        [SAA7134_BOARD_AVERMEDIA_307] = {
+        [SAA7134_BOARD_AVERMEDIA_STUDIO_307] = {
                /*
                Nickolay V. Shmyrev <nshmyrev@yandex.ru>
                Lots of thanks to Andrey Zolotarev <zolotarev_andrey@mail.ru>
@@ -1323,6 +1322,35 @@ struct saa7134_board saa7134_boards[] = {
                        .gpio = 0x01,
                },
         },
+        [SAA7134_BOARD_AVERMEDIA_GO_007_FM] = {
+               .name           = "Avermedia AVerTV GO 007 FM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .gpiomask       = 0x00300003,
+//             .gpiomask       = 0x8c240003,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+                       .gpio = 0x01,
+               },{
+                       .name = name_comp1,
+                       .vmux = 0,
+                       .amux = LINE2,
+                       .gpio = 0x02,
+               },{
+                       .name = name_svideo,
+                       .vmux = 6,
+                       .amux = LINE2,
+                       .gpio = 0x02,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE1,
+                       .gpio = 0x00300001,
+               },
+        },
        [SAA7134_BOARD_AVERMEDIA_CARDBUS] = {
                /* Jon Westgate <oryn@oryn.fsck.tv> */
                .name           = "AVerMedia Cardbus TV/Radio",
@@ -1492,7 +1520,6 @@ struct saa7134_board saa7134_boards[] = {
                .audio_clock    = 0x00187de7,
                .tuner_type     = TUNER_PHILIPS_FQ1216ME,
                .tda9887_conf   = TDA9887_PRESENT,
-               .gpiomask = 0x3,
                .inputs         = {{
                        .name = name_tv,
                        .vmux = 1,
@@ -1546,7 +1573,82 @@ struct saa7134_board saa7134_boards[] = {
 //                     .gpio = 0x4000,
                }},
        },
-};
+        [SAA7134_BOARD_AVERMEDIA_307] = {
+               /*
+                 Davydov Vladimir <vladimir@iqmedia.com>
+               */
+               .name           = "Avermedia AVerTV 307",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FQ1216ME,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 0,
+                       .amux = LINE1,
+               },{
+                       .name = name_comp2,
+                       .vmux = 3,
+                       .amux = LINE1,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               }},
+        },
+       [SAA7134_BOARD_ADS_INSTANT_TV] = {
+                .name           = "ADS Tech Instant TV (saa7135)",
+               .audio_clock    = 0x00187de7,
+                .tuner_type     = TUNER_PHILIPS_TDA8290,
+                .inputs         = {{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = TV,
+                        .tv   = 1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 3,
+                        .amux = LINE2,
+                },{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE2,
+                }},
+       },
+       [SAA7134_BOARD_KWORLD_VSTREAM_XPERT] = {
+               .name           = "Kworld/Tevion V-Stream Xpert TV PVR7134",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_PAL_I,
+               .gpiomask       = 0x0700,
+               .inputs = {{
+                       .name   = name_tv,
+                       .vmux   = 1,
+                       .amux   = TV,
+                       .tv     = 1,
+                       .gpio   = 0x000,
+               },{
+                       .name   = name_comp1,
+                       .vmux   = 3,
+                       .amux   = LINE1,
+                       .gpio   = 0x200,                //gpio by DScaler
+               },{
+                       .name   = name_svideo,
+                       .vmux   = 0,
+                       .amux   = LINE1,
+                       .gpio   = 0x200,
+               }},
+               .radio = {
+                       .name   = name_radio,
+                       .amux   = LINE1,
+                       .gpio   = 0x100,
+               },
+       },
+ };
+
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
 
 /* ------------------------------------------------------------------ */
@@ -1663,7 +1765,7 @@ struct pci_device_id saa7134_pci_tbl[] = {
                 .driver_data  = SAA7134_BOARD_ASUSTeK_TVFM7134,
        },{
                 .vendor       = PCI_VENDOR_ID_PHILIPS,
-                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7135,
                 .subvendor    = PCI_VENDOR_ID_ASUSTEK,
                 .subdevice    = 0x4845,
                 .driver_data  = SAA7135_BOARD_ASUSTeK_TVFM7135,
@@ -1824,6 +1926,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
                .subdevice    = 0x9715,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_307,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+               .subdevice    = 0xa70a,
                .driver_data  = SAA7134_BOARD_AVERMEDIA_307,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -1844,6 +1952,26 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x5168,
                .subdevice    = 0x0306,
                .driver_data  = SAA7134_BOARD_FLYDVBTDUO,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+               .subdevice    = 0xf31f,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_GO_007_FM,
+
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7135,
+               .subvendor    = 0x1421,
+               .subdevice    = 0x0350,         /* PCI version */
+               .driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
+
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7135,
+               .subvendor    = 0x1421,
+               .subdevice    = 0x0370,         /* cardbus version */
+               .driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
 
        },{
                /* --- boards without eeprom + subsystem ID --- */
@@ -1954,20 +2082,23 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                dev->has_remote = 1;
                board_flyvideo(dev);
                break;
-       case SAA7134_BOARD_FLYTVPLATINUM_FM:
+        case SAA7134_BOARD_FLYTVPLATINUM_FM:
        case SAA7134_BOARD_CINERGY400:
        case SAA7134_BOARD_CINERGY600:
        case SAA7134_BOARD_CINERGY600_MK3:
        case SAA7134_BOARD_ECS_TVP3XP:
        case SAA7134_BOARD_ECS_TVP3XP_4CB5:
        case SAA7134_BOARD_MD2819:
+       case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
        case SAA7134_BOARD_AVERMEDIA_305:
+       case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
        case SAA7134_BOARD_AVERMEDIA_307:
+       case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
 //     case SAA7134_BOARD_SABRENT_SBTTVFM:  /* not finished yet */
        case SAA7134_BOARD_VIDEOMATE_TV_PVR:
-               dev->has_remote = 1;
-               break;
+       case SAA7134_BOARD_MANLI_MTV001:
+       case SAA7134_BOARD_MANLI_MTV002:
        case SAA7134_BOARD_AVACSSMARTTV:
                dev->has_remote = 1;
                break;
index d506cafba8ffe55ca74e7d897d4ec358bb146b7f..f61ed1849a2a276d2f7c51d8b6e546b5d4ad81b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-core.c,v 1.28 2005/02/22 09:56:29 kraxel Exp $
+ * $Id: saa7134-core.c,v 1.30 2005/05/22 19:23:39 nsh Exp $
  *
  * device driver for philips saa7134 based TV cards
  * driver core
@@ -316,7 +316,7 @@ unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
 
 int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt)
 {
-        u32          *cpu;
+        __le32       *cpu;
         dma_addr_t   dma_addr;
 
        cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr);
@@ -332,7 +332,7 @@ int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
                          struct scatterlist *list, unsigned int length,
                          unsigned int startpage)
 {
-       u32           *ptr;
+       __le32        *ptr;
        unsigned int  i,p;
 
        BUG_ON(NULL == pt || NULL == pt->cpu);
@@ -340,7 +340,7 @@ int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
        ptr = pt->cpu + startpage;
        for (i = 0; i < length; i++, list++)
                for (p = 0; p * 4096 < list->length; p++, ptr++)
-                       *ptr = sg_dma_address(list) - list->offset;
+                       *ptr = cpu_to_le32(sg_dma_address(list) - list->offset);
        return 0;
 }
 
index c2873ae029f95224f721fd22bc57b17e77c6abd5..aa8e2cf62d5596f7f29c0e3ef4854a4d73278fe9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-dvb.c,v 1.12 2005/02/18 12:28:29 kraxel Exp $
+ * $Id: saa7134-dvb.c,v 1.13 2005/06/12 04:19:19 mchehab Exp $
  *
  * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
  *
index fa1357336907cd6df71614e39f61d133b8428607..c85348d0239fda3119b1852ee7777153d97cb6fe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-empress.c,v 1.10 2005/02/03 10:24:33 kraxel Exp $
+ * $Id: saa7134-empress.c,v 1.11 2005/05/22 19:23:39 nsh Exp $
  *
  * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
  *
index 702bb63d98133b7ce0ec6aac9832deab1264d540..b6f002e8421dfcfb4e60d87839f8b0ff132d5874 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-i2c.c,v 1.10 2005/01/24 17:37:23 kraxel Exp $
+ * $Id: saa7134-i2c.c,v 1.11 2005/06/12 01:36:14 mchehab Exp $
  *
  * device driver for philips saa7134 based TV cards
  * i2c interface support
index ca50cf531f20948aed62c3524a53c6ca968997ac..aba2b9de60def3c43c702355b443018b5a0dabf0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-input.c,v 1.16 2004/12/10 12:33:39 kraxel Exp $
+ * $Id: saa7134-input.c,v 1.19 2005/06/07 18:02:26 nsh Exp $
  *
  * handle saa7134 IR remotes via linux kernel input layer.
  *
@@ -308,6 +308,102 @@ static IR_KEYTAB_TYPE videomate_tv_pvr_codes[IR_KEYTAB_SIZE] = {
        [ 32 ] = KEY_LANGUAGE,
        [ 33 ] = KEY_SLEEP,
 };
+
+/* Michael Tokarev <mjt@tls.msk.ru>
+   http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
+   keytable is used by MANLI MTV00[12] and BeholdTV 40[13] at
+   least, and probably other cards too.
+   The "ascii-art picture" below (in comments, first row
+   is the keycode in hex, and subsequent row(s) shows
+   the button labels (several variants when appropriate)
+   helps to descide which keycodes to assign to the buttons.
+ */
+static IR_KEYTAB_TYPE manli_codes[IR_KEYTAB_SIZE] = {
+
+       /*  0x1c            0x12  *
+        * FUNCTION         POWER *
+        *   FM              (|)  *
+        *                        */
+       [ 0x1c ] = KEY_RADIO,   /*XXX*/
+       [ 0x12 ] = KEY_POWER,
+
+       /*  0x01    0x02    0x03  *
+        *   1       2       3    *
+        *                        *
+        *  0x04    0x05    0x06  *
+        *   4       5       6    *
+        *                        *
+        *  0x07    0x08    0x09  *
+        *   7       8       9    *
+        *                        */
+       [ 0x01 ] = KEY_KP1,
+       [ 0x02 ] = KEY_KP2,
+       [ 0x03 ] = KEY_KP3,
+       [ 0x04 ] = KEY_KP4,
+       [ 0x05 ] = KEY_KP5,
+       [ 0x06 ] = KEY_KP6,
+       [ 0x07 ] = KEY_KP7,
+       [ 0x08 ] = KEY_KP8,
+       [ 0x09 ] = KEY_KP9,
+
+       /*  0x0a    0x00    0x17  *
+        * RECALL    0      +100  *
+        *                  PLUS  *
+        *                        */
+       [ 0x0a ] = KEY_AGAIN,   /*XXX KEY_REWIND? */
+       [ 0x00 ] = KEY_KP0,
+       [ 0x17 ] = KEY_DIGITS,  /*XXX*/
+
+       /*  0x14            0x10  *
+        *  MENU            INFO  *
+        *  OSD                   */
+       [ 0x14 ] = KEY_MENU,
+       [ 0x10 ] = KEY_INFO,
+
+       /*          0x0b          *
+        *           Up           *
+        *                        *
+        *  0x18    0x16    0x0c  *
+        *  Left     Ok     Right *
+        *                        *
+        *         0x015          *
+        *         Down           *
+        *                        */
+       [ 0x0b ] = KEY_UP,      /*XXX KEY_SCROLLUP? */
+       [ 0x18 ] = KEY_LEFT,    /*XXX KEY_BACK? */
+       [ 0x16 ] = KEY_OK,      /*XXX KEY_SELECT? KEY_ENTER? */
+       [ 0x0c ] = KEY_RIGHT,   /*XXX KEY_FORWARD? */
+       [ 0x15 ] = KEY_DOWN,    /*XXX KEY_SCROLLDOWN? */
+
+       /*  0x11            0x0d  *
+        *  TV/AV           MODE  *
+        *  SOURCE         STEREO *
+        *                        */
+       [ 0x11 ] = KEY_TV,      /*XXX*/
+       [ 0x0d ] = KEY_MODE,    /*XXX there's no KEY_STEREO */
+
+       /*  0x0f    0x1b    0x1a  *
+        *  AUDIO   Vol+    Chan+ *
+        *        TIMESHIFT???    *
+        *                        *
+        *  0x0e    0x1f    0x1e  *
+        *  SLEEP   Vol-    Chan- *
+        *                        */
+       [ 0x0f ] = KEY_AUDIO,
+       [ 0x1b ] = KEY_VOLUMEUP,
+       [ 0x1a ] = KEY_CHANNELUP,
+       [ 0x0e ] = KEY_SLEEP,   /*XXX maybe KEY_PAUSE */
+       [ 0x1f ] = KEY_VOLUMEDOWN,
+       [ 0x1e ] = KEY_CHANNELDOWN,
+
+       /*         0x13     0x19  *
+        *         MUTE   SNAPSHOT*
+        *                        */
+       [ 0x13 ] = KEY_MUTE,
+       [ 0x19 ] = KEY_RECORD,  /*XXX*/
+
+       // 0x1d unused ?
+};
 /* ---------------------------------------------------------------------- */
 
 static int build_key(struct saa7134_dev *dev)
@@ -379,7 +475,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        switch (dev->board) {
        case SAA7134_BOARD_FLYVIDEO2000:
        case SAA7134_BOARD_FLYVIDEO3000:
-       case SAA7134_BOARD_FLYTVPLATINUM_FM:
+        case SAA7134_BOARD_FLYTVPLATINUM_FM:
                ir_codes     = flyvideo_codes;
                mask_keycode = 0xEC00000;
                mask_keydown = 0x0040000;
@@ -405,8 +501,12 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                polling      = 50; // ms
                break;
        case SAA7134_BOARD_MD2819:
+       case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
        case SAA7134_BOARD_AVERMEDIA_305:
        case SAA7134_BOARD_AVERMEDIA_307:
+       case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+       case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+       case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
                ir_codes     = md2819_codes;
                mask_keycode = 0x0007C8;
                mask_keydown = 0x000010;
@@ -415,6 +515,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
                saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
                break;
+       case SAA7134_BOARD_MANLI_MTV001:
+       case SAA7134_BOARD_MANLI_MTV002:
+               ir_codes     = manli_codes;
+               mask_keycode = 0x001f00;
+               mask_keyup   = 0x004000;
+               mask_keydown = 0x002000;
+               polling      = 50; // ms
+               break;
        case SAA7134_BOARD_VIDEOMATE_TV_PVR:
                ir_codes     = videomate_tv_pvr_codes;
                mask_keycode = 0x00003F;
index 6b6a643bf1cda8fb087a4c07d2234ab723251627..81732904623fa8e460f1fb6b92817c493f2b202e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-oss.c,v 1.13 2004/12/10 12:33:39 kraxel Exp $
+ * $Id: saa7134-oss.c,v 1.14 2005/05/18 22:45:16 hhackmann Exp $
  *
  * device driver for philips saa7134 based TV cards
  * oss dsp interface
@@ -49,7 +49,6 @@ MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)");
 
 static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
 {
-       blksize &= ~0xff;
        if (blksize < 0x100)
                blksize = 0x100;
        if (blksize > 0x10000)
@@ -57,8 +56,6 @@ static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
 
        if (blocks < 2)
                blocks = 2;
-        while ((blksize * blocks) & ~PAGE_MASK)
-               blocks++;
        if ((blksize * blocks) > 1024*1024)
                blocks = 1024*1024 / blksize;
 
@@ -79,7 +76,7 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
                BUG();
        videobuf_dma_init(&dev->oss.dma);
        err = videobuf_dma_init_kernel(&dev->oss.dma, PCI_DMA_FROMDEVICE,
-                                      dev->oss.bufsize >> PAGE_SHIFT);
+                                      (dev->oss.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
        if (0 != err)
                return err;
        return 0;
@@ -163,10 +160,11 @@ static int dsp_rec_start(struct saa7134_dev *dev)
                        fmt |= 0x04;
                fmt |= (TV == dev->oss.input) ? 0xc0 : 0x80;
 
-               saa_writeb(SAA7134_NUM_SAMPLES0, (dev->oss.blksize & 0x0000ff));
-               saa_writeb(SAA7134_NUM_SAMPLES1, (dev->oss.blksize & 0x00ff00) >>  8);
-               saa_writeb(SAA7134_NUM_SAMPLES2, (dev->oss.blksize & 0xff0000) >> 16);
+               saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->oss.blksize - 1) & 0x0000ff));
+               saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->oss.blksize - 1) & 0x00ff00) >>  8);
+               saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->oss.blksize - 1) & 0xff0000) >> 16);
                saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
+
                break;
        case PCI_DEVICE_ID_PHILIPS_SAA7133:
        case PCI_DEVICE_ID_PHILIPS_SAA7135:
@@ -817,7 +815,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
                        reg = SAA7134_RS_BA1(6);
        } else {
                /* even */
-               if (0 == (dev->oss.dma_blk & 0x00))
+               if (1 == (dev->oss.dma_blk & 0x01))
                        reg = SAA7134_RS_BA2(6);
        }
        if (0 == reg) {
index ecac13c006d513b61ba6350f2cd04723fcfb9fef..3617e7f7a4108aef491fdd50414ac6e07f1225eb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-tvaudio.c,v 1.22 2005/01/07 13:11:19 kraxel Exp $
+ * $Id: saa7134-tvaudio.c,v 1.25 2005/06/07 19:00:38 nsh Exp $
  *
  * device driver for philips saa7134 based TV cards
  * tv audio decoder (fm stereo, nicam, ...)
@@ -181,7 +181,8 @@ static void tvaudio_init(struct saa7134_dev *dev)
        saa_writeb(SAA7134_AUDIO_CLOCK0,      clock        & 0xff);
        saa_writeb(SAA7134_AUDIO_CLOCK1,     (clock >>  8) & 0xff);
        saa_writeb(SAA7134_AUDIO_CLOCK2,     (clock >> 16) & 0xff);
-       saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x01);
+       // frame locked audio was reported not to be reliable
+       saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x02);
 
        saa_writeb(SAA7134_NICAM_ERROR_LOW,  0x14);
        saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50);
@@ -250,6 +251,11 @@ static void mute_input_7134(struct saa7134_dev *dev)
        saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, ausel);
        saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, ics);
        saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, ocs);
+       // for oss, we need to change the clock configuration
+       if (in->amux == TV)
+               saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, 0x00);
+       else
+               saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, 0x01);
 
        /* switch gpio-connected external audio mux */
        if (0 == card(dev).gpiomask)
@@ -439,16 +445,15 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au
                nicam = saa_readb(SAA7134_NICAM_STATUS);
                dprintk("getstereo: nicam=0x%x\n",nicam);
                switch (nicam & 0x0b) {
+               case 0x08:
+                       retval = V4L2_TUNER_SUB_MONO;
+                       break;
                case 0x09:
                        retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
                        break;
                case 0x0a:
                        retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
                        break;
-               case 0x08:
-               default:
-                       retval = V4L2_TUNER_SUB_MONO;
-                       break;
                }
                break;
        }
@@ -572,14 +577,14 @@ static int tvaudio_thread(void *data)
                } else if (0 != dev->last_carrier) {
                        /* no carrier -- try last detected one as fallback */
                        carrier = dev->last_carrier;
-                       printk(KERN_WARNING "%s/audio: audio carrier scan failed, "
+                       dprintk(KERN_WARNING "%s/audio: audio carrier scan failed, "
                               "using %d.%03d MHz [last detected]\n",
                               dev->name, carrier/1000, carrier%1000);
 
                } else {
                        /* no carrier + no fallback -- use default */
                        carrier = default_carrier;
-                       printk(KERN_WARNING "%s/audio: audio carrier scan failed, "
+                       dprintk(KERN_WARNING "%s/audio: audio carrier scan failed, "
                               "using %d.%03d MHz [default]\n",
                               dev->name, carrier/1000, carrier%1000);
                }
index 86954cc7c3776d2e6a69bf2ace01ead6f76243e7..3c33c591cc8554c9f555c02927ae3389cc203027 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-vbi.c,v 1.6 2004/12/10 12:33:39 kraxel Exp $
+ * $Id: saa7134-vbi.c,v 1.7 2005/05/24 23:13:06 nsh Exp $
  *
  * device driver for philips saa7134 based TV cards
  * video4linux video interface
@@ -60,10 +60,10 @@ static void task_init(struct saa7134_dev *dev, struct saa7134_buf *buf,
        saa_writeb(SAA7134_VBI_H_START2(task), norm->h_start     >> 8);
        saa_writeb(SAA7134_VBI_H_STOP1(task),  norm->h_stop      &  0xff);
        saa_writeb(SAA7134_VBI_H_STOP2(task),  norm->h_stop      >> 8);
-       saa_writeb(SAA7134_VBI_V_START1(task), norm->vbi_v_start &  0xff);
-       saa_writeb(SAA7134_VBI_V_START2(task), norm->vbi_v_start >> 8);
-       saa_writeb(SAA7134_VBI_V_STOP1(task),  norm->vbi_v_stop  &  0xff);
-       saa_writeb(SAA7134_VBI_V_STOP2(task),  norm->vbi_v_stop  >> 8);
+       saa_writeb(SAA7134_VBI_V_START1(task), norm->vbi_v_start_0 &  0xff);
+       saa_writeb(SAA7134_VBI_V_START2(task), norm->vbi_v_start_0 >> 8);
+       saa_writeb(SAA7134_VBI_V_STOP1(task),  norm->vbi_v_stop_0  &  0xff);
+       saa_writeb(SAA7134_VBI_V_STOP2(task),  norm->vbi_v_stop_0  >> 8);
 
        saa_writeb(SAA7134_VBI_H_SCALE_INC1(task),        VBI_SCALE & 0xff);
        saa_writeb(SAA7134_VBI_H_SCALE_INC2(task),        VBI_SCALE >> 8);
@@ -127,7 +127,7 @@ static int buffer_prepare(struct videobuf_queue *q,
        unsigned int lines, llength, size;
        int err;
 
-       lines   = norm->vbi_v_stop - norm->vbi_v_start +1;
+       lines   = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1;
        if (lines > VBI_LINE_COUNT)
                lines = VBI_LINE_COUNT;
 #if 1
@@ -177,7 +177,7 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
        struct saa7134_dev *dev = fh->dev;
        int llength,lines;
 
-       lines   = dev->tvnorm->vbi_v_stop - dev->tvnorm->vbi_v_start +1;
+       lines   = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 +1;
 #if 1
        llength = VBI_LINE_LENGTH;
 #else
index 5d66060026ff5b460b57ae2d45ac43b54abb3456..c0a2ee520531cd27e007dcafaa67534f01413b22 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-video.c,v 1.28 2005/02/15 15:59:35 kraxel Exp $
+ * $Id: saa7134-video.c,v 1.30 2005/06/07 19:00:38 nsh Exp $
  *
  * device driver for philips saa7134 based TV cards
  * video4linux video interface
@@ -31,8 +31,6 @@
 #include "saa7134-reg.h"
 #include "saa7134.h"
 
-#define V4L2_I2C_CLIENTS 1
-
 /* ------------------------------------------------------------------ */
 
 static unsigned int video_debug   = 0;
@@ -158,18 +156,20 @@ static struct saa7134_format formats[] = {
                .h_stop        = 719,   \
                .video_v_start = 24,    \
                .video_v_stop  = 311,   \
-               .vbi_v_start   = 7,     \
-               .vbi_v_stop    = 22,    \
+               .vbi_v_start_0 = 7,     \
+               .vbi_v_stop_0  = 22,    \
+               .vbi_v_start_1 = 319,   \
                .src_timing    = 4
 
 #define NORM_525_60                    \
                .h_start       = 0,     \
                .h_stop        = 703,   \
-               .video_v_start = 22,    \
-               .video_v_stop  = 22+239, \
-               .vbi_v_start   = 10, /* FIXME */ \
-               .vbi_v_stop    = 21, /* FIXME */ \
-               .src_timing    = 1
+               .video_v_start = 23,    \
+               .video_v_stop  = 262,   \
+               .vbi_v_start_0 = 10,    \
+               .vbi_v_stop_0  = 21,    \
+               .vbi_v_start_1 = 273,   \
+               .src_timing    = 7
 
 static struct saa7134_tvnorm tvnorms[] = {
        {
@@ -274,11 +274,12 @@ static struct saa7134_tvnorm tvnorms[] = {
 
                .h_start       = 0,
                .h_stop        = 719,
-               .video_v_start = 22,
-               .video_v_stop  = 22+239,
-               .vbi_v_start   = 10, /* FIXME */
-               .vbi_v_stop    = 21, /* FIXME */
-               .src_timing    = 1,
+               .video_v_start = 23,
+               .video_v_stop  = 262,
+               .vbi_v_start_0 = 10,
+               .vbi_v_stop_0  = 21,
+               .vbi_v_start_1 = 273,
+               .src_timing    = 7,
 
                .sync_control  = 0x18,
                .luma_control  = 0x40,
@@ -335,8 +336,8 @@ static const struct v4l2_queryctrl video_ctrls[] = {
                .default_value = 0,
                .type          = V4L2_CTRL_TYPE_INTEGER,
        },{
-               .id            = V4L2_CID_VFLIP,
-               .name          = "vertical flip",
+               .id            = V4L2_CID_HFLIP,
+               .name          = "Mirror",
                .minimum       = 0,
                .maximum       = 1,
                .type          = V4L2_CTRL_TYPE_BOOLEAN,
@@ -482,7 +483,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
        dev->crop_bounds.width   = norm->h_stop - norm->h_start +1;
        dev->crop_defrect.width  = norm->h_stop - norm->h_start +1;
 
-       dev->crop_bounds.top     = (norm->vbi_v_stop+1)*2;
+       dev->crop_bounds.top     = (norm->vbi_v_stop_0+1)*2;
        dev->crop_defrect.top    = norm->video_v_start*2;
        dev->crop_bounds.height  = ((norm->id & V4L2_STD_525_60) ? 524 : 624)
                - dev->crop_bounds.top;
@@ -521,22 +522,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
        saa_writeb(SAA7134_RAW_DATA_GAIN,         0x40);
        saa_writeb(SAA7134_RAW_DATA_OFFSET,       0x80);
 
-#ifdef V4L2_I2C_CLIENTS
        saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id);
-#else
-       {
-               /* pass down info to the i2c chips (v4l1) */
-               struct video_channel c;
-               memset(&c,0,sizeof(c));
-               c.channel = dev->ctl_input;
-               c.norm = VIDEO_MODE_PAL;
-               if (norm->id & V4L2_STD_NTSC)
-                       c.norm = VIDEO_MODE_NTSC;
-               if (norm->id & V4L2_STD_SECAM)
-                       c.norm = VIDEO_MODE_SECAM;
-               saa7134_i2c_call_clients(dev,VIDIOCSCHAN,&c);
-       }
-#endif
 }
 
 static void video_mux(struct saa7134_dev *dev, int input)
@@ -1064,7 +1050,7 @@ static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
        case V4L2_CID_PRIVATE_INVERT:
                c->value = dev->ctl_invert;
                break;
-       case V4L2_CID_VFLIP:
+       case V4L2_CID_HFLIP:
                c->value = dev->ctl_mirror;
                break;
        case V4L2_CID_PRIVATE_Y_EVEN:
@@ -1139,7 +1125,7 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
                saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
                           dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
                break;
-       case V4L2_CID_VFLIP:
+       case V4L2_CID_HFLIP:
                dev->ctl_mirror = c->value;
                restart_overlay = 1;
                break;
@@ -1407,9 +1393,9 @@ static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
        f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */;
        f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
        f->fmt.vbi.offset = 64 * 4;
-       f->fmt.vbi.start[0] = norm->vbi_v_start;
-       f->fmt.vbi.count[0] = norm->vbi_v_stop - norm->vbi_v_start +1;
-       f->fmt.vbi.start[1] = norm->video_v_stop + norm->vbi_v_start +1;
+       f->fmt.vbi.start[0] = norm->vbi_v_start_0;
+       f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1;
+       f->fmt.vbi.start[1] = norm->vbi_v_start_1;
        f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
        f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */
 
@@ -1880,11 +1866,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                        return -EINVAL;
                down(&dev->lock);
                dev->ctl_freq = f->frequency;
-#ifdef V4L2_I2C_CLIENTS
+
                saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);
-#else
-               saa7134_i2c_call_clients(dev,VIDIOCSFREQ,&dev->ctl_freq);
-#endif
+
                saa7134_tvaudio_do_scan(dev);
                up(&dev->lock);
                return 0;
@@ -2139,16 +2123,19 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
                 t->rangelow  = (int)(65*16);
                 t->rangehigh = (int)(108*16);
 
-#ifdef V4L2_I2C_CLIENTS
-               saa7134_i2c_call_clients(dev,VIDIOC_G_TUNER,t);
-#else
-               {
-                       struct video_tuner vt;
-                       memset(&vt,0,sizeof(vt));
-                       saa7134_i2c_call_clients(dev,VIDIOCGTUNER,&vt);
-                       t->signal = vt.signal;
-               }
-#endif
+               saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+
+               return 0;
+       }
+       case VIDIOC_S_TUNER:
+       {
+               struct v4l2_tuner *t = arg;
+
+               if (0 != t->index)
+                       return -EINVAL;
+
+               saa7134_i2c_call_clients(dev,VIDIOC_S_TUNER,t);
+
                return 0;
        }
        case VIDIOC_ENUMINPUT:
@@ -2182,7 +2169,6 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
                return 0;
        }
        case VIDIOC_S_AUDIO:
-       case VIDIOC_S_TUNER:
        case VIDIOC_S_INPUT:
        case VIDIOC_S_STD:
                return 0;
index ac90a985323608ff20fc95383d2fe040e3825118..d6b1c0d4d0f9e2801c66ac04c7ddd7e1e3c079ac 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134.h,v 1.38 2005/03/07 12:01:51 kraxel Exp $
+ * $Id: saa7134.h,v 1.41 2005/06/07 18:02:26 nsh Exp $
  *
  * v4l2 device driver for philips saa7134 based TV cards
  *
@@ -21,7 +21,7 @@
  */
 
 #include <linux/version.h>
-#define SAA7134_VERSION_CODE KERNEL_VERSION(0,2,12)
+#define SAA7134_VERSION_CODE KERNEL_VERSION(0,2,13)
 
 #include <linux/pci.h>
 #include <linux/i2c.h>
@@ -91,9 +91,10 @@ struct saa7134_tvnorm {
        unsigned int  h_stop;
        unsigned int  video_v_start;
        unsigned int  video_v_stop;
-       unsigned int  vbi_v_start;
-       unsigned int  vbi_v_stop;
+       unsigned int  vbi_v_start_0;
+       unsigned int  vbi_v_stop_0;
        unsigned int  src_timing;
+       unsigned int  vbi_v_start_1;
 };
 
 struct saa7134_tvaudio {
@@ -167,7 +168,7 @@ struct saa7134_format {
 #define SAA7134_BOARD_SABRENT_SBTTVFM  42
 #define SAA7134_BOARD_ZOLID_XPERT_TV7134 43
 #define SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE 44
-#define SAA7134_BOARD_AVERMEDIA_307    45
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_307    45
 #define SAA7134_BOARD_AVERMEDIA_CARDBUS 46
 #define SAA7134_BOARD_CINERGY400_CARDBUS 47
 #define SAA7134_BOARD_CINERGY600_MK3   48
@@ -178,6 +179,10 @@ struct saa7134_format {
 #define SAA7135_BOARD_ASUSTeK_TVFM7135 53
 #define SAA7134_BOARD_FLYTVPLATINUM_FM 54
 #define SAA7134_BOARD_FLYDVBTDUO 55
+#define SAA7134_BOARD_AVERMEDIA_307    56
+#define SAA7134_BOARD_AVERMEDIA_GO_007_FM 57
+#define SAA7134_BOARD_ADS_INSTANT_TV 58
+#define SAA7134_BOARD_KWORLD_VSTREAM_XPERT 59
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -241,7 +246,7 @@ struct saa7134_dma;
 /* saa7134 page table */
 struct saa7134_pgtable {
        unsigned int               size;
-       u32                        *cpu;
+       __le32                     *cpu;
        dma_addr_t                 dma;
 };
 
index b27cc348d95ce40f3076150868c25e14415c220d..f59d4601cc6311118f10774445173f7ec69d6c29 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: tda8290.c,v 1.7 2005/03/07 12:01:51 kraxel Exp $
+ * $Id: tda8290.c,v 1.11 2005/06/18 06:09:06 nsh Exp $
  *
  * i2c tv tuner chip device driver
  * controls the philips tda8290+75 tuner chip combo.
@@ -69,7 +69,7 @@ static __u8 get_freq_entry( struct freq_entry* table, __u16 freq)
 static unsigned char i2c_enable_bridge[2] =    { 0x21, 0xC0 };
 static unsigned char i2c_disable_bridge[2] =   { 0x21, 0x80 };
 static unsigned char i2c_init_tda8275[14] =    { 0x00, 0x00, 0x00, 0x00,
-                                                 0x7C, 0x04, 0xA3, 0x3F,
+                                                 0xfC, 0x04, 0xA3, 0x3F,
                                                  0x2A, 0x04, 0xFF, 0x00,
                                                  0x00, 0x40 };
 static unsigned char i2c_set_VS[2] =           { 0x30, 0x6F };
@@ -138,16 +138,24 @@ static int tda8290_tune(struct i2c_client *c)
 
 static void set_frequency(struct tuner *t, u16 ifc)
 {
-       u32 N = (((t->freq<<3)+ifc)&0x3fffc);
+       u32 freq;
+       u32 N;
 
-       N = N >> get_freq_entry(div_table, t->freq);
+       if (t->mode == V4L2_TUNER_RADIO)
+               freq = t->freq / 1000;
+       else
+               freq = t->freq;
+
+       N = (((freq<<3)+ifc)&0x3fffc);
+
+       N = N >> get_freq_entry(div_table, freq);
        t->i2c_set_freq[0] = 0;
        t->i2c_set_freq[1] = (unsigned char)(N>>8);
        t->i2c_set_freq[2] = (unsigned char) N;
        t->i2c_set_freq[3] = 0x40;
        t->i2c_set_freq[4] = 0x52;
-       t->i2c_set_freq[5] = get_freq_entry(band_table, t->freq);
-       t->i2c_set_freq[6] = get_freq_entry(agc_table,  t->freq);
+       t->i2c_set_freq[5] = get_freq_entry(band_table, freq);
+       t->i2c_set_freq[6] = get_freq_entry(agc_table,  freq);
        t->i2c_set_freq[7] = 0x8f;
 }
 
index 7e6e6dd966a2f0de9aa00002c87edbed158bce36..ee35562f4d1a1e4aa682cf23223f2a0071436641 100644 (file)
@@ -53,6 +53,7 @@ struct tda9887 {
        unsigned int       config;
        unsigned int       pinnacle_id;
        unsigned int       using_v4l2;
+       unsigned int       radio_mode;
 };
 
 struct tvnorm {
@@ -212,12 +213,22 @@ static struct tvnorm tvnorms[] = {
        }
 };
 
-static struct tvnorm radio = {
-       .name = "radio",
+static struct tvnorm radio_stereo = {
+       .name = "Radio Stereo",
+       .b    = ( cFmRadio       |
+                 cQSS           ),
+       .c    = ( cDeemphasisOFF |
+                 cAudioGain6 ),
+       .e    = ( cAudioIF_5_5   |
+                 cRadioIF_38_90 ),
+};
+
+static struct tvnorm radio_mono = {
+       .name = "Radio Mono",
        .b    = ( cFmRadio       |
                  cQSS           ),
        .c    = ( cDeemphasisON  |
-                 cDeemphasis50  ),
+                 cDeemphasis50),
        .e    = ( cAudioIF_5_5   |
                  cRadioIF_38_90 ),
 };
@@ -354,7 +365,10 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf)
        int i;
 
        if (t->radio) {
-               norm = &radio;
+               if (t->radio_mode == V4L2_TUNER_MODE_MONO)
+                       norm = &radio_mono;
+               else
+                       norm = &radio_stereo;
        } else {
                for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
                        if (tvnorms[i].std & t->std) {
@@ -545,8 +559,10 @@ static int tda9887_configure(struct tda9887 *t)
 
        memset(buf,0,sizeof(buf));
        tda9887_set_tvnorm(t,buf);
+
        buf[1] |= cOutputPort1Inactive;
        buf[1] |= cOutputPort2Inactive;
+
        if (UNSET != t->pinnacle_id) {
                tda9887_set_pinnacle(t,buf);
        }
@@ -592,11 +608,14 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
         if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
                 return -ENOMEM;
        memset(t,0,sizeof(*t));
+
        t->client      = client_template;
        t->std         = 0;
        t->pinnacle_id = UNSET;
-        i2c_set_clientdata(&t->client, t);
-        i2c_attach_client(&t->client);
+       t->radio_mode = V4L2_TUNER_MODE_STEREO;
+
+       i2c_set_clientdata(&t->client, t);
+       i2c_attach_client(&t->client);
 
        return 0;
 }
@@ -733,6 +752,16 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
                }
                break;
        }
+       case VIDIOC_S_TUNER:
+       {
+               struct v4l2_tuner* tuner = arg;
+
+               if (t->radio) {
+                       t->radio_mode = tuner->audmode;
+                       tda9887_configure (t);
+               }
+               break;
+       }
        default:
                /* nothing */
                break;
@@ -740,7 +769,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
        return 0;
 }
 
-static int tda9887_suspend(struct device * dev, pm_message_t state, u32 level)
+static int tda9887_suspend(struct device * dev, u32 state, u32 level)
 {
        dprintk("tda9887: suspend\n");
        return 0;
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
new file mode 100644 (file)
index 0000000..a29f08f
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview
+ * I2C address is allways 0xC0.
+ *
+ * $Id: tea5767.c,v 1.11 2005/06/21 15:40:33 mchehab Exp $
+ *
+ * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br)
+ * This code is placed under the terms of the GNU General Public License
+ *
+ * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa
+ * from their contributions on DScaler.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <media/tuner.h>
+
+/* Declared at tuner-core.c */
+extern unsigned int tuner_debug;
+
+#define PREFIX "TEA5767 "
+
+/*****************************************************************************/
+
+/******************************
+ * Write mode register values *
+ ******************************/
+
+/* First register */
+#define TEA5767_MUTE           0x80 /* Mutes output */
+#define TEA5767_SEARCH         0x40 /* Activates station search */
+/* Bits 0-5 for divider MSB */
+
+/* Second register */
+/* Bits 0-7 for divider LSB */
+
+/* Third register */
+
+/* Station search from botton to up */
+#define TEA5767_SEARCH_UP      0x80
+
+/* Searches with ADC output = 10 */
+#define TEA5767_SRCH_HIGH_LVL  0x60
+
+/* Searches with ADC output = 10 */
+#define TEA5767_SRCH_MID_LVL   0x40
+
+/* Searches with ADC output = 5 */
+#define TEA5767_SRCH_LOW_LVL   0x20
+
+/* if on, div=4*(Frf+Fif)/Fref otherwise, div=4*(Frf-Fif)/Freq) */
+#define TEA5767_HIGH_LO_INJECT 0x10
+
+/* Disable stereo */
+#define TEA5767_MONO           0x08
+
+/* Disable right channel and turns to mono */
+#define TEA5767_MUTE_RIGHT     0x04
+
+/* Disable left channel and turns to mono */
+#define TEA5767_MUTE_LEFT      0x02
+
+#define TEA5767_PORT1_HIGH     0x01
+
+/* Forth register */
+#define TEA5767_PORT2_HIGH     0x80
+/* Chips stops working. Only I2C bus remains on */
+#define TEA5767_STDBY          0x40
+
+/* Japan freq (76-108 MHz. If disabled, 87.5-108 MHz */
+#define TEA5767_JAPAN_BAND     0x20
+
+/* Unselected means 32.768 KHz freq as reference. Otherwise Xtal at 13 MHz */
+#define TEA5767_XTAL_32768     0x10
+
+/* Cuts weak signals */
+#define TEA5767_SOFT_MUTE      0x08
+
+/* Activates high cut control */
+#define TEA5767_HIGH_CUT_CTRL  0x04
+
+/* Activates stereo noise control */
+#define TEA5767_ST_NOISE_CTL   0x02
+
+/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */
+#define TEA5767_SRCH_IND       0x01
+
+/* Fiveth register */
+
+/* By activating, it will use Xtal at 13 MHz as reference for divider */
+#define TEA5767_PLLREF_ENABLE  0x80
+
+/* By activating, deemphasis=50, or else, deemphasis of 50us */
+#define TEA5767_DEEMPH_75      0X40
+
+/*****************************
+ * Read mode register values *
+ *****************************/
+
+/* First register */
+#define TEA5767_READY_FLAG_MASK        0x80
+#define TEA5767_BAND_LIMIT_MASK        0X40
+/* Bits 0-5 for divider MSB after search or preset */
+
+/* Second register */
+/* Bits 0-7 for divider LSB after search or preset */
+
+/* Third register */
+#define TEA5767_STEREO_MASK    0x80
+#define TEA5767_IF_CNTR_MASK   0x7f
+
+/* Four register */
+#define TEA5767_ADC_LEVEL_MASK 0xf0
+
+/* should be 0 */
+#define TEA5767_CHIP_ID_MASK   0x0f
+
+/* Fiveth register */
+/* Reserved for future extensions */
+#define TEA5767_RESERVED_MASK  0xff
+
+/*****************************************************************************/
+
+static void set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+
+       tuner_warn("This tuner doesn't support TV freq.\n");
+}
+
+static void tea5767_status_dump(unsigned char *buffer)
+{
+       unsigned int div, frq;
+
+       if (TEA5767_READY_FLAG_MASK & buffer[0])
+               printk(PREFIX "Ready Flag ON\n");
+       else
+               printk(PREFIX "Ready Flag OFF\n");
+
+       if (TEA5767_BAND_LIMIT_MASK & buffer[0])
+               printk(PREFIX "Tuner at band limit\n");
+       else
+               printk(PREFIX "Tuner not at band limit\n");
+
+       div=((buffer[0]&0x3f)<<8) | buffer[1];
+
+       switch (TEA5767_HIGH_LO_32768) {
+       case TEA5767_HIGH_LO_13MHz:
+               frq = 1000*(div*50-700-225)/4; /* Freq in KHz */
+               break;
+       case TEA5767_LOW_LO_13MHz:
+               frq = 1000*(div*50+700+225)/4; /* Freq in KHz */
+               break;
+       case TEA5767_LOW_LO_32768:
+               frq = 1000*(div*32768/1000+700+225)/4; /* Freq in KHz */
+               break;
+       case TEA5767_HIGH_LO_32768:
+       default:
+               frq = 1000*(div*32768/1000-700-225)/4; /* Freq in KHz */
+               break;
+       }
+        buffer[0] = (div>>8) & 0x3f;
+        buffer[1] = div      & 0xff;
+
+       printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n",
+                                               frq/1000,frq%1000,div);
+
+       if (TEA5767_STEREO_MASK & buffer[2])
+               printk(PREFIX "Stereo\n");
+       else
+               printk(PREFIX "Mono\n");
+
+       printk(PREFIX "IF Counter = %d\n",buffer[2] & TEA5767_IF_CNTR_MASK);
+
+       printk(PREFIX "ADC Level = %d\n",(buffer[3] & TEA5767_ADC_LEVEL_MASK)>>4);
+
+       printk(PREFIX "Chip ID = %d\n",(buffer[3] & TEA5767_CHIP_ID_MASK));
+
+       printk(PREFIX "Reserved = 0x%02x\n",(buffer[4] & TEA5767_RESERVED_MASK));
+}
+
+/* Freq should be specifyed at 62.5 Hz */
+static void set_radio_freq(struct i2c_client *c, unsigned int frq)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+        unsigned char buffer[5];
+       unsigned div;
+       int rc;
+
+       if ( tuner_debug )
+               printk(PREFIX "radio freq counter %d\n",frq);
+
+       /* Rounds freq to next decimal value - for 62.5 KHz step */
+       /* frq = 20*(frq/16)+radio_frq[frq%16]; */
+
+       buffer[2] = TEA5767_PORT1_HIGH;
+       buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND;
+       buffer[4]=0;
+
+       if (t->audmode == V4L2_TUNER_MODE_MONO) {
+               tuner_dbg("TEA5767 set to mono\n");
+               buffer[2] |= TEA5767_MONO;
+       } else
+               tuner_dbg("TEA5767 set to stereo\n");
+
+       switch (t->type) {
+       case TEA5767_HIGH_LO_13MHz:
+               tuner_dbg("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n");
+               buffer[2] |= TEA5767_HIGH_LO_INJECT;
+               buffer[4] |= TEA5767_PLLREF_ENABLE;
+               div = (frq*4/16+700+225+25)/50;
+               break;
+       case TEA5767_LOW_LO_13MHz:
+               tuner_dbg("TEA5767 radio LOW LO inject xtal @ 13 MHz\n");
+
+               buffer[4] |= TEA5767_PLLREF_ENABLE;
+               div = (frq*4/16-700-225+25)/50;
+               break;
+       case TEA5767_LOW_LO_32768:
+               tuner_dbg("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n");
+               buffer[3] |= TEA5767_XTAL_32768;
+               /* const 700=4000*175 Khz - to adjust freq to right value */
+               div = (1000*(frq*4/16-700-225)+16384)>>15;
+               break;
+       case TEA5767_HIGH_LO_32768:
+       default:
+               tuner_dbg("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n");
+
+               buffer[2] |= TEA5767_HIGH_LO_INJECT;
+               buffer[3] |= TEA5767_XTAL_32768;
+               div = (1000*(frq*4/16+700+225)+16384)>>15;
+               break;
+       }
+        buffer[0] = (div>>8) & 0x3f;
+        buffer[1] = div      & 0xff;
+
+       if ( tuner_debug )
+               tea5767_status_dump(buffer);
+
+        if (5 != (rc = i2c_master_send(c,buffer,5)))
+               tuner_warn("i2c i/o error: rc == %d (should be 5)\n",rc);
+}
+
+static int tea5767_signal(struct i2c_client *c)
+{
+       unsigned char buffer[5];
+       int rc;
+       struct tuner *t = i2c_get_clientdata(c);
+
+       memset(buffer,0,sizeof(buffer));
+        if (5 != (rc = i2c_master_recv(c,buffer,5)))
+                tuner_warn ( "i2c i/o error: rc == %d (should be 5)\n",rc);
+
+       return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) <<(13-4));
+}
+
+static int tea5767_stereo(struct i2c_client *c)
+{
+       unsigned char buffer[5];
+       int rc;
+       struct tuner *t = i2c_get_clientdata(c);
+
+       memset(buffer,0,sizeof(buffer));
+        if (5 != (rc = i2c_master_recv(c,buffer,5)))
+                tuner_warn ( "i2c i/o error: rc == %d (should be 5)\n",rc);
+
+       rc = buffer[2] & TEA5767_STEREO_MASK;
+
+       if ( tuner_debug )
+               tuner_dbg("TEA5767 radio ST GET = %02x\n", rc);
+
+       return ( (buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO: 0);
+}
+
+int tea_detection(struct i2c_client *c)
+{
+       unsigned char buffer[5]= { 0xff, 0xff, 0xff, 0xff, 0xff };
+       int rc;
+       struct tuner *t = i2c_get_clientdata(c);
+
+        if (5 != (rc = i2c_master_recv(c,buffer,5))) {
+                tuner_warn ( "it is not a TEA5767. Received %i chars.\n",rc );
+               return EINVAL;
+       }
+
+       /* If all bytes are the same then it's a TV tuner and not a tea5767 chip. */
+       if (buffer[0] == buffer[1] &&  buffer[0] == buffer[2] &&
+           buffer[0] == buffer[3] &&  buffer[0] == buffer[4]) {
+                tuner_warn ( "All bytes are equal. It is not a TEA5767\n" );
+               return EINVAL;
+       }
+
+       /*  Status bytes:
+        *  Byte 4: bit 3:1 : CI (Chip Identification) == 0
+        *          bit 0   : internally set to 0
+        *  Byte 5: bit 7:0 : == 0
+        */
+
+       if (!((buffer[3] & 0x0f) == 0x00) && (buffer[4] == 0x00)) {
+                tuner_warn ( "Chip ID is not zero. It is not a TEA5767\n" );
+               return EINVAL;
+       }
+       tuner_warn ( "TEA5767 detected.\n" );
+       return 0;
+}
+
+int tea5767_tuner_init(struct i2c_client *c)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+
+       if (tea_detection(c)==EINVAL) return EINVAL;
+
+        tuner_info("type set to %d (%s)\n",
+                   t->type, TEA5767_TUNER_NAME);
+        strlcpy(c->name, TEA5767_TUNER_NAME, sizeof(c->name));
+
+       t->tv_freq    = set_tv_freq;
+       t->radio_freq = set_radio_freq;
+       t->has_signal = tea5767_signal;
+       t->is_stereo  = tea5767_stereo;
+
+       return (0);
+}
index 81882ddab859dd52c3db6ecfbfeac5c228b6a97f..6f6bf4a633fc7449a774031a158b431163ba91c5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: tuner-core.c,v 1.5 2005/02/15 15:59:35 kraxel Exp $
+ * $Id: tuner-core.c,v 1.29 2005/06/21 15:40:33 mchehab Exp $
  *
  * i2c tv tuner chip device driver
  * core core, i.e. kernel interfaces, registering and so on
 #include <media/tuner.h>
 #include <media/audiochip.h>
 
+/*
+ * comment line bellow to return to old behavor, where only one I2C device is supported
+ */
+
 #define UNSET (-1U)
 
 /* standard i2c insmod options */
@@ -53,13 +57,14 @@ MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
 MODULE_LICENSE("GPL");
 
 static int this_adap;
+static unsigned short first_tuner, tv_tuner, radio_tuner;
 
 static struct i2c_driver driver;
 static struct i2c_client client_template;
 
 /* ---------------------------------------------------------------------- */
 
-// Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz
+/* Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz */
 static void set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
@@ -73,13 +78,8 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
                return;
        }
        if (freq < tv_range[0]*16 || freq > tv_range[1]*16) {
-               /* FIXME: better do that chip-specific, but
-                  right now we don't have that in the config
-                  struct and this way is still better than no
-                  check at all */
-               tuner_info("TV freq (%d.%02d) out of range (%d-%d)\n",
-                          freq/16,freq%16*100/16,tv_range[0],tv_range[1]);
-               return;
+                       tuner_info("TV freq (%d.%02d) out of range (%d-%d)\n",
+                                  freq/16,freq%16*100/16,tv_range[0],tv_range[1]);
        }
        t->tv_freq(c,freq);
 }
@@ -96,13 +96,18 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
                tuner_info("no radio tuning for this one, sorry.\n");
                return;
        }
-       if (freq < radio_range[0]*16 || freq > radio_range[1]*16) {
+       if (freq >= radio_range[0]*16000 && freq <= radio_range[1]*16000) {
+               if (tuner_debug)
+                       tuner_info("radio freq step 62.5Hz (%d.%06d)\n",
+                                           freq/16000,freq%16000*1000/16);
+               t->radio_freq(c,freq);
+        } else {
                tuner_info("radio freq (%d.%02d) out of range (%d-%d)\n",
-                          freq/16,freq%16*100/16,
-                          radio_range[0],radio_range[1]);
-               return;
+                           freq/16,freq%16*100/16,
+                           radio_range[0],radio_range[1]);
        }
-       t->radio_freq(c,freq);
+
+       return;
 }
 
 static void set_freq(struct i2c_client *c, unsigned long freq)
@@ -128,9 +133,10 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
 static void set_type(struct i2c_client *c, unsigned int type)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       unsigned char buffer[4];
 
        /* sanity check */
-       if (type == UNSET  ||  type == TUNER_ABSENT)
+       if (type == UNSET || type == TUNER_ABSENT)
                return;
        if (type >= tuner_count)
                return;
@@ -140,11 +146,12 @@ static void set_type(struct i2c_client *c, unsigned int type)
                t->type = type;
                return;
        }
-       if (t->initialized)
-               /* run only once */
+       if ((t->initialized) && (t->type == type))
+               /* run only once except type change  Hac 04/05*/
                return;
 
        t->initialized = 1;
+
        t->type = type;
        switch (t->type) {
        case TUNER_MT2032:
@@ -153,10 +160,71 @@ static void set_type(struct i2c_client *c, unsigned int type)
        case TUNER_PHILIPS_TDA8290:
                tda8290_init(c);
                break;
+       case TUNER_TEA5767:
+               if (tea5767_tuner_init(c)==EINVAL) t->type=TUNER_ABSENT;
+               break;
+       case TUNER_PHILIPS_FMD1216ME_MK3:
+               buffer[0] = 0x0b;
+               buffer[1] = 0xdc;
+               buffer[2] = 0x9c;
+               buffer[3] = 0x60;
+               i2c_master_send(c,buffer,4);
+               mdelay(1);
+               buffer[2] = 0x86;
+               buffer[3] = 0x54;
+               i2c_master_send(c,buffer,4);
+               default_tuner_init(c);
+               break;
        default:
+               /* TEA5767 autodetection code */
+                       if (tea5767_tuner_init(c)!=EINVAL) {
+                               t->type = TUNER_TEA5767;
+                               if (first_tuner == 0x60)
+                                       first_tuner++;
+                               break;
+                       }
+
                default_tuner_init(c);
                break;
        }
+       tuner_dbg ("I2C addr 0x%02x with type %d\n",c->addr<<1,type);
+}
+
+#define CHECK_ADDR(tp,cmd,tun) if (client->addr!=tp) { \
+                         return 0; } else if (tuner_debug) \
+                         tuner_info ("Cmd %s accepted to "tun"\n",cmd);
+#define CHECK_MODE(cmd)        if (t->mode == V4L2_TUNER_RADIO) { \
+                       CHECK_ADDR(radio_tuner,cmd,"radio") } else \
+                       { CHECK_ADDR(tv_tuner,cmd,"TV"); }
+
+static void set_addr(struct i2c_client *c, struct tuner_addr *tun_addr)
+{
+       /* ADDR_UNSET defaults to first available tuner */
+       if ( tun_addr->addr == ADDR_UNSET ) {
+               if (first_tuner != c->addr)
+                       return;
+               switch (tun_addr->v4l2_tuner) {
+               case V4L2_TUNER_RADIO:
+                       radio_tuner=c->addr;
+                       break;
+               default:
+                       tv_tuner=c->addr;
+                       break;
+               }
+       } else {
+               /* Sets tuner to its configured value */
+               switch (tun_addr->v4l2_tuner) {
+               case V4L2_TUNER_RADIO:
+                       radio_tuner=tun_addr->addr;
+                       if ( tun_addr->addr == c->addr ) set_type(c,tun_addr->type);
+                       return;
+               default:
+                       tv_tuner=tun_addr->addr;
+                       if ( tun_addr->addr == c->addr ) set_type(c,tun_addr->type);
+                       return;
+               }
+       }
+       set_type(c,tun_addr->type);
 }
 
 static char pal[] = "-";
@@ -197,8 +265,12 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
 {
        struct tuner *t;
 
-       if (this_adap > 0)
-               return -1;
+       /* by default, first I2C card is both tv and radio tuner */
+       if (this_adap == 0) {
+               first_tuner = addr;
+               tv_tuner = addr;
+               radio_tuner = addr;
+       }
        this_adap++;
 
         client_template.adapter = adap;
@@ -211,11 +283,13 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
         memcpy(&t->i2c,&client_template,sizeof(struct i2c_client));
        i2c_set_clientdata(&t->i2c, t);
        t->type       = UNSET;
-       t->radio_if2  = 10700*1000; // 10.7MHz - FM radio
+       t->radio_if2  = 10700*1000; /* 10.7MHz - FM radio */
+       t->audmode    = V4L2_TUNER_MODE_STEREO;
 
         i2c_attach_client(&t->i2c);
        tuner_info("chip found @ 0x%x (%s)\n",
                   addr << 1, adap->name);
+
        set_type(&t->i2c, t->type);
        return 0;
 }
@@ -228,6 +302,10 @@ static int tuner_probe(struct i2c_adapter *adap)
        }
        this_adap = 0;
 
+       first_tuner = 0;
+       tv_tuner = 0;
+       radio_tuner = 0;
+
        if (adap->class & I2C_CLASS_TV_ANALOG)
                return i2c_probe(adap, &addr_data, tuner_attach);
        return 0;
@@ -236,8 +314,14 @@ static int tuner_probe(struct i2c_adapter *adap)
 static int tuner_detach(struct i2c_client *client)
 {
        struct tuner *t = i2c_get_clientdata(client);
+       int err;
+
+       err=i2c_detach_client(&t->i2c);
+       if (err) {
+               tuner_warn ("Client deregistration failed, client not detached.\n");
+               return err;
+       }
 
-       i2c_detach_client(&t->i2c);
        kfree(t);
        return 0;
 }
@@ -256,18 +340,23 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
         unsigned int *iarg = (int*)arg;
 
         switch (cmd) {
-
        /* --- configuration --- */
        case TUNER_SET_TYPE:
                set_type(client,*iarg);
                break;
+       case TUNER_SET_TYPE_ADDR:
+               set_addr(client,(struct tuner_addr *)arg);
+               break;
        case AUDC_SET_RADIO:
+               t->mode = V4L2_TUNER_RADIO;
+               CHECK_ADDR(tv_tuner,"AUDC_SET_RADIO","TV");
+
                if (V4L2_TUNER_RADIO != t->mode) {
                        set_tv_freq(client,400 * 16);
-                       t->mode = V4L2_TUNER_RADIO;
                }
                break;
        case AUDC_CONFIG_PINNACLE:
+               CHECK_ADDR(tv_tuner,"AUDC_CONFIG_PINNACLE","TV");
                switch (*iarg) {
                case 2:
                        tuner_dbg("pinnacle pal\n");
@@ -278,8 +367,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        t->radio_if2 = 41300 * 1000;
                        break;
                }
-                break;
-
+               break;
        /* --- v4l ioctls --- */
        /* take care: bttv does userspace copying, we'll get a
           kernel pointer here... */
@@ -297,6 +385,8 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
                CHECK_V4L2;
                t->mode = V4L2_TUNER_ANALOG_TV;
+               CHECK_ADDR(tv_tuner,"VIDIOCSCHAN","TV");
+
                if (vc->norm < ARRAY_SIZE(map))
                        t->std = map[vc->norm];
                tuner_fixup_std(t);
@@ -308,6 +398,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
        {
                unsigned long *v = arg;
 
+               CHECK_MODE("VIDIOCSFREQ");
                CHECK_V4L2;
                set_freq(client,*v);
                return 0;
@@ -316,15 +407,34 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
        {
                struct video_tuner *vt = arg;
 
+               CHECK_ADDR(radio_tuner,"VIDIOCGTUNER","radio");
                CHECK_V4L2;
-               if (V4L2_TUNER_RADIO == t->mode  &&  t->has_signal)
-                       vt->signal = t->has_signal(client);
+               if (V4L2_TUNER_RADIO == t->mode) {
+                       if (t->has_signal)
+                               vt->signal = t->has_signal(client);
+                       if (t->is_stereo) {
+                               if (t->is_stereo(client))
+                                       vt->flags |= VIDEO_TUNER_STEREO_ON;
+                               else
+                                       vt->flags &= ~VIDEO_TUNER_STEREO_ON;
+                       }
+                       vt->flags |= V4L2_TUNER_CAP_LOW; /* Allow freqs at 62.5 Hz */
+
+                       vt->rangelow = radio_range[0] * 16000;
+                       vt->rangehigh = radio_range[1] * 16000;
+
+               } else {
+                       vt->rangelow = tv_range[0] * 16;
+                       vt->rangehigh = tv_range[1] * 16;
+               }
+
                return 0;
        }
        case VIDIOCGAUDIO:
        {
                struct video_audio *va = arg;
 
+               CHECK_ADDR(radio_tuner,"VIDIOCGAUDIO","radio");
                CHECK_V4L2;
                if (V4L2_TUNER_RADIO == t->mode  &&  t->is_stereo)
                        va->mode = t->is_stereo(client)
@@ -339,6 +449,8 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
                SWITCH_V4L2;
                t->mode = V4L2_TUNER_ANALOG_TV;
+               CHECK_ADDR(tv_tuner,"VIDIOC_S_STD","TV");
+
                t->std = *id;
                tuner_fixup_std(t);
                if (t->freq)
@@ -349,6 +461,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
        {
                struct v4l2_frequency *f = arg;
 
+               CHECK_MODE("VIDIOC_S_FREQUENCY");
                SWITCH_V4L2;
                if (V4L2_TUNER_RADIO == f->type &&
                    V4L2_TUNER_RADIO != t->mode)
@@ -361,6 +474,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
        {
                struct v4l2_frequency *f = arg;
 
+               CHECK_MODE("VIDIOC_G_FREQUENCY");
                SWITCH_V4L2;
                f->type = t->mode;
                f->frequency = t->freq;
@@ -370,14 +484,55 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
        {
                struct v4l2_tuner *tuner = arg;
 
+               CHECK_MODE("VIDIOC_G_TUNER");
                SWITCH_V4L2;
-               if (V4L2_TUNER_RADIO == t->mode  &&  t->has_signal)
-                       tuner->signal = t->has_signal(client);
-               tuner->rangelow = tv_range[0] * 16;
-               tuner->rangehigh = tv_range[1] * 16;
+               if (V4L2_TUNER_RADIO == t->mode) {
+                       if (t->has_signal)
+                               tuner -> signal = t->has_signal(client);
+                       if (t->is_stereo) {
+                               if (t->is_stereo(client)) {
+                                       tuner -> rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+                               } else {
+                                       tuner -> rxsubchans = V4L2_TUNER_SUB_MONO;
+                               }
+                       }
+                       tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+                       tuner->audmode = t->audmode;
+
+                       tuner->rangelow = radio_range[0] * 16000;
+                       tuner->rangehigh = radio_range[1] * 16000;
+               } else {
+                       tuner->rangelow = tv_range[0] * 16;
+                       tuner->rangehigh = tv_range[1] * 16;
+               }
                break;
        }
+       case VIDIOC_S_TUNER: /* Allow changing radio range and audio mode */
+       {
+               struct v4l2_tuner *tuner = arg;
+
+               CHECK_ADDR(radio_tuner,"VIDIOC_S_TUNER","radio");
+               SWITCH_V4L2;
+
+               /* To switch the audio mode, applications initialize the
+                  index and audmode fields and the reserved array and
+                  call the VIDIOC_S_TUNER ioctl. */
+               /* rxsubchannels: V4L2_TUNER_MODE_MONO, V4L2_TUNER_MODE_STEREO,
+                  V4L2_TUNER_MODE_LANG1, V4L2_TUNER_MODE_LANG2,
+                  V4L2_TUNER_MODE_SAP */
+
+               if (tuner->audmode == V4L2_TUNER_MODE_MONO)
+                       t->audmode = V4L2_TUNER_MODE_MONO;
+               else
+                       t->audmode = V4L2_TUNER_MODE_STEREO;
+
+               set_radio_freq(client, t->freq);
+               break;
+       }
+       case TDA9887_SET_CONFIG: /* Nothing to do on tuner-core */
+               break;
        default:
+               tuner_dbg ("Unimplemented IOCTL 0x%08x called to tuner.\n", cmd);
                /* nothing */
                break;
        }
@@ -385,7 +540,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
        return 0;
 }
 
-static int tuner_suspend(struct device * dev, pm_message_t state, u32 level)
+static int tuner_suspend(struct device * dev, u32 state, u32 level)
 {
        struct i2c_client *c = container_of(dev, struct i2c_client, dev);
        struct tuner *t = i2c_get_clientdata(c);
index 48c6ceff1dc265c39799ec15120c42e59c024735..c39ed6226ee090c9f1c80051763246142242b659 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: tuner-simple.c,v 1.10 2005/03/08 08:38:00 kraxel Exp $
+ * $Id: tuner-simple.c,v 1.31 2005/06/21 16:02:25 mkrufky Exp $
  *
  * i2c tv tuner chip device driver
  * controls all those simple 4-control-bytes style tuners.
@@ -207,12 +207,29 @@ static struct tunertype tuners[] = {
        { "LG PAL (TAPE series)", LGINNOTEK, PAL,
           16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623},
 
-        { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL,
-          16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 },
-        { "Philips FQ1236A MK4", Philips, NTSC,
-          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
-
+       { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL,
+         16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 },
+       { "Philips FQ1236A MK4", Philips, NTSC,
+         16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
+
+       /* Should work for TVF8531MF, TVF8831MF, TVF8731MF */
+       { "Ymec TVision TVF-8531MF", Philips, NTSC,
+         16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
+       { "Ymec TVision TVF-5533MF", Philips, NTSC,
+         16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732},
+       { "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC,
+         16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
+       /* Should work for TNF9533-D/IF, TNF9533-B/DF */
+       { "Tena TNF9533-D/IF", Philips, PAL,
+          16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623},
+
+       /* This entry is for TEA5767 FM radio only chip used on several boards w/TV tuner */
+       { TEA5767_TUNER_NAME, Philips, RADIO,
+          -1, -1, 0, 0, 0, TEA5767_LOW_LO_32768,0},
+       { "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL,
+         16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 },
 };
+
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
 
 /* ---------------------------------------------------------------------- */
@@ -223,6 +240,7 @@ static int tuner_getstatus(struct i2c_client *c)
 
        if (1 != i2c_master_recv(c,&byte,1))
                return 0;
+
        return byte;
 }
 
@@ -231,17 +249,33 @@ static int tuner_getstatus(struct i2c_client *c)
 #define TUNER_MODE      0x38
 #define TUNER_AFC       0x07
 
-#define TUNER_STEREO    0x10 /* radio mode */
-#define TUNER_SIGNAL    0x07 /* radio mode */
+#define TUNER_STEREO       0x10 /* radio mode */
+#define TUNER_STEREO_MK3   0x04 /* radio mode */
+#define TUNER_SIGNAL       0x07 /* radio mode */
 
 static int tuner_signal(struct i2c_client *c)
 {
-       return (tuner_getstatus(c) & TUNER_SIGNAL)<<13;
+       return (tuner_getstatus(c) & TUNER_SIGNAL) << 13;
 }
 
 static int tuner_stereo(struct i2c_client *c)
 {
-       return (tuner_getstatus (c) & TUNER_STEREO);
+       int stereo, status;
+       struct tuner *t = i2c_get_clientdata(c);
+
+       status = tuner_getstatus (c);
+
+       switch (t->type) {
+               case TUNER_PHILIPS_FM1216ME_MK3:
+               case TUNER_PHILIPS_FM1236_MK3:
+               case TUNER_PHILIPS_FM1256_IH3:
+                       stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
+                       break;
+               default:
+                       stereo = status & TUNER_STEREO;
+       }
+
+       return stereo;
 }
 
 #if 0 /* unused */
@@ -420,16 +454,24 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
        int rc;
 
        tun=&tuners[t->type];
-       div = freq + (int)(16*10.7);
+       div = (freq / 1000) + (int)(16*10.7);
        buffer[2] = tun->config;
 
        switch (t->type) {
+       case TUNER_TENA_9533_DI:
+       case TUNER_YMEC_TVF_5533MF:
+               /*These values are empirically determinated */
+               div = (freq * 122) / 16000 - 20;
+               buffer[2] = 0x88; /* could be also 0x80 */
+               buffer[3] = 0x19; /* could be also 0x10, 0x18, 0x99 */
+               break;
        case TUNER_PHILIPS_FM1216ME_MK3:
        case TUNER_PHILIPS_FM1236_MK3:
+       case TUNER_PHILIPS_FMD1216ME_MK3:
                buffer[3] = 0x19;
                break;
        case TUNER_PHILIPS_FM1256_IH3:
-               div = (20 * freq)/16 + 333 * 2;
+               div = (20 * freq) / 16000 + 333 * 2;
                buffer[2] = 0x80;
                buffer[3] = 0x19;
                break;
@@ -462,6 +504,7 @@ int default_tuner_init(struct i2c_client *c)
        t->radio_freq = default_set_radio_freq;
        t->has_signal = tuner_signal;
        t->is_stereo  = tuner_stereo;
+
        return 0;
 }
 
index 41b635e0d3c6a5b6d758e1b7254acd8995b0baeb..9a493bea76d87ea3d37abe1037dcbad84685fa24 100644 (file)
@@ -285,7 +285,6 @@ static int chip_thread(void *data)
                        schedule();
                }
                remove_wait_queue(&chip->wq, &wait);
-               try_to_freeze(PF_FREEZE);
                if (chip->done || signal_pending(current))
                        break;
                dprintk("%s: thread wakeup\n", i2c_clientname(&chip->c));
@@ -1237,17 +1236,17 @@ static int ta8874z_checkit(struct CHIPSTATE *chip)
 /* audio chip descriptions - struct CHIPDESC                              */
 
 /* insmod options to enable/disable individual audio chips */
-int tda8425  = 1;
-int tda9840  = 1;
-int tda9850  = 1;
-int tda9855  = 1;
-int tda9873  = 1;
-int tda9874a = 1;
-int tea6300  = 0;  // address clash with msp34xx
-int tea6320  = 0;  // address clash with msp34xx
-int tea6420  = 1;
-int pic16c54 = 1;
-int ta8874z  = 0;  // address clash with tda9840
+static int tda8425  = 1;
+static int tda9840  = 1;
+static int tda9850  = 1;
+static int tda9855  = 1;
+static int tda9873  = 1;
+static int tda9874a = 1;
+static int tea6300  = 0;  // address clash with msp34xx
+static int tea6320  = 0;  // address clash with msp34xx
+static int tea6420  = 1;
+static int pic16c54 = 1;
+static int ta8874z  = 0;  // address clash with tda9840
 
 module_param(tda8425, int, 0444);
 module_param(tda9840, int, 0444);
index 3d216973798c6755353d6f8d17aa31f1b112c54c..0f03c25489f19d0944822506de7608c87053c5f0 100644 (file)
@@ -75,7 +75,7 @@ hauppauge_tuner_fmt[] =
        { 0x00000007, "PAL(B/G)" },
        { 0x00001000, "NTSC(M)" },
        { 0x00000010, "PAL(I)" },
-       { 0x00400000, "SECAM(L/L�)" },
+       { 0x00400000, "SECAM(L/L´)" },
        { 0x00000e00, "PAL(D/K)" },
        { 0x03000000, "ATSC Digital" },
 };
index eafd7061b310327c5dbfd401aceae302fe5309a6..51b99cdbf29e8bc9447dc65eea4b53d7f230e2ae 100644 (file)
@@ -1,3 +1,7 @@
+/*
+ * $Id: tvmixer.c,v 1.8 2005/06/12 04:19:19 mchehab Exp $
+ */
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
index b0d4bcb027d085e00ade287f0cf80e3b71449fcc..70ecbdb80277f58512342b81de6351333a5f71d6 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * $Id: v4l1-compat.c,v 1.9 2005/06/12 04:19:19 mchehab Exp $
+ *
  *     Video for Linux Two
  *     Backward Compatibility Layer
  *
  *
  */
 
-#ifndef __KERNEL__
-#define __KERNEL__
-#endif
-
 #include <linux/config.h>
 
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -787,12 +786,15 @@ v4l_compat_translate_ioctl(struct inode         *inode,
                    !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED))
                        aud->step = qctrl2.step;
                aud->mode = 0;
+
+               memset(&tun2,0,sizeof(tun2));
                err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
                if (err < 0) {
                        dprintk("VIDIOCGAUDIO / VIDIOC_G_TUNER: %d\n",err);
                        err = 0;
                        break;
                }
+
                if (tun2.rxsubchans & V4L2_TUNER_SUB_LANG2)
                        aud->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
                else if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO)
index 5f870075b55e595df3e8384d0812279092ed3259..15f5bb4869638a78a1dcc94f1196d251d350e361 100644 (file)
@@ -62,8 +62,7 @@ static int videobuf_dvb_thread(void *data)
                        break;
                if (kthread_should_stop())
                        break;
-               if (current->flags & PF_FREEZE)
-                       refrigerator(PF_FREEZE);
+               try_to_freeze();
 
                /* feed buffer data to demux */
                if (buf->state == STATE_DONE)
index d8d65397e06e668be27cebf001e6681ddfd253c4..353deb25e3978bb300865be18affdbb455545e4a 100644 (file)
@@ -364,9 +364,7 @@ static struct pci_driver mptfc_driver = {
        .id_table       = mptfc_pci_table,
        .probe          = mptfc_probe,
        .remove         = __devexit_p(mptscsih_remove),
-       .driver         = {
-               .shutdown = mptscsih_shutdown,
-        },
+       .shutdown       = mptscsih_shutdown,
 #ifdef CONFIG_PM
        .suspend        = mptscsih_suspend,
        .resume         = mptscsih_resume,
index a0078ae5b9b84587a0d8ed0de8f78f71755d5fc6..4f973a49be4c125e8634dcd29db4ec5649ecc520 100644 (file)
@@ -170,7 +170,7 @@ static void mptscsih_fillbuf(char *buffer, int size, int index, int width);
 #endif
 
 void           mptscsih_remove(struct pci_dev *);
-void           mptscsih_shutdown(struct device *);
+void           mptscsih_shutdown(struct pci_dev *);
 #ifdef CONFIG_PM
 int            mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
 int            mptscsih_resume(struct pci_dev *pdev);
@@ -988,7 +988,7 @@ mptscsih_remove(struct pci_dev *pdev)
 #endif
 #endif
 
-       mptscsih_shutdown(&pdev->dev);
+       mptscsih_shutdown(pdev);
 
        sz1=0;
 
@@ -1026,9 +1026,9 @@ mptscsih_remove(struct pci_dev *pdev)
  *
  */
 void
-mptscsih_shutdown(struct device * dev)
+mptscsih_shutdown(struct pci_dev *pdev)
 {
-       MPT_ADAPTER             *ioc = pci_get_drvdata(to_pci_dev(dev));
+       MPT_ADAPTER             *ioc = pci_get_drvdata(pdev);
        struct Scsi_Host        *host = ioc->sh;
        MPT_SCSI_HOST           *hd;
 
@@ -1054,7 +1054,7 @@ mptscsih_shutdown(struct device * dev)
 int
 mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
 {
-       mptscsih_shutdown(&pdev->dev);
+       mptscsih_shutdown(pdev);
        return mpt_suspend(pdev,state);
 }
 
index d73aec33e16a35ee3bac0b3109d8a6ae4739b706..5ea89bf0df199862e26c1398f006818b852ea66d 100644 (file)
@@ -82,7 +82,7 @@
 #endif
 
 extern void mptscsih_remove(struct pci_dev *);
-extern void mptscsih_shutdown(struct device *);
+extern void mptscsih_shutdown(struct pci_dev *);
 #ifdef CONFIG_PM
 extern int mptscsih_suspend(struct pci_dev *pdev, u32 state);
 extern int mptscsih_resume(struct pci_dev *pdev);
index 5f9a61b85b3b6c3b0c65c1f0581f21fe09769b22..e0c0ee5bc9662386e73c79af9ceded98d9623a72 100644 (file)
@@ -419,9 +419,7 @@ static struct pci_driver mptspi_driver = {
        .id_table       = mptspi_pci_table,
        .probe          = mptspi_probe,
        .remove         = __devexit_p(mptscsih_remove),
-       .driver         = {
-               .shutdown = mptscsih_shutdown,
-        },
+       .shutdown       = mptscsih_shutdown,
 #ifdef CONFIG_PM
        .suspend        = mptscsih_suspend,
        .resume         = mptscsih_resume,
index 8d132b0d6b1218d3dfc2360d54e4c631675e28e3..06e8eb19a05c5df2fab8386cd9a68a8ab242e394 100644 (file)
@@ -24,10 +24,28 @@ config I2O
 
          If unsure, say N.
 
+config I2O_EXT_ADAPTEC
+       bool "Enable Adaptec extensions"
+       depends on I2O
+       default y
+       ---help---
+         Say Y for support of raidutils for Adaptec I2O controllers. You also
+         have to say Y to "I2O Configuration support", "I2O SCSI OSM" below
+         and to "SCSI generic support" under "SCSI device configuration".
+
+config I2O_EXT_ADAPTEC_DMA64
+       bool "Enable 64-bit DMA"
+       depends on I2O_EXT_ADAPTEC && ( 64BIT || HIGHMEM64G )
+       default y
+       ---help---
+         Say Y for support of 64-bit DMA transfer mode on Adaptec I2O
+         controllers.
+         Note: You need at least firmware version 3709.
+
 config I2O_CONFIG
        tristate "I2O Configuration support"
-       depends on PCI && I2O
-       help
+       depends on I2O
+       ---help---
          Say Y for support of the configuration interface for the I2O adapters.
          If you have a RAID controller from Adaptec and you want to use the
          raidutils to manage your RAID array, you have to say Y here.
@@ -35,10 +53,28 @@ config I2O_CONFIG
          To compile this support as a module, choose M here: the
          module will be called i2o_config.
 
+config I2O_CONFIG_OLD_IOCTL
+       bool "Enable ioctls (OBSOLETE)"
+       depends on I2O_CONFIG
+       default y
+       ---help---
+         Enables old ioctls.
+
+config I2O_BUS
+       tristate "I2O Bus Adapter OSM"
+       depends on I2O
+       ---help---
+         Include support for the I2O Bus Adapter OSM. The Bus Adapter OSM
+         provides access to the busses on the I2O controller. The main purpose
+         is to rescan the bus to find new devices.
+
+         To compile this support as a module, choose M here: the
+         module will be called i2o_bus.
+
 config I2O_BLOCK
        tristate "I2O Block OSM"
        depends on I2O
-       help
+       ---help---
          Include support for the I2O Block OSM. The Block OSM presents disk
          and other structured block devices to the operating system. If you
          are using an RAID controller, you could access the array only by
@@ -51,7 +87,7 @@ config I2O_BLOCK
 config I2O_SCSI
        tristate "I2O SCSI OSM"
        depends on I2O && SCSI
-       help
+       ---help---
          Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel
          I2O controller. You can use both the SCSI and Block OSM together if
          you wish. To access a RAID array, you must use the Block OSM driver.
@@ -63,7 +99,7 @@ config I2O_SCSI
 config I2O_PROC
        tristate "I2O /proc support"
        depends on I2O
-       help
+       ---help---
          If you say Y here and to "/proc file system support", you will be
          able to read I2O related information from the virtual directory
          /proc/i2o.
index aabc6cdc3fcec4025a9dfd0b19dd58731dcf232e..2c2e39aa1efaf04d8747018369089bc44a0c3b8a 100644 (file)
@@ -6,8 +6,11 @@
 #
 
 i2o_core-y             += iop.o driver.o device.o debug.o pci.o exec-osm.o
+i2o_bus-y              += bus-osm.o
+i2o_config-y           += config-osm.o
 obj-$(CONFIG_I2O)      += i2o_core.o
 obj-$(CONFIG_I2O_CONFIG)+= i2o_config.o
+obj-$(CONFIG_I2O_BUS)  += i2o_bus.o
 obj-$(CONFIG_I2O_BLOCK)        += i2o_block.o
 obj-$(CONFIG_I2O_SCSI) += i2o_scsi.o
 obj-$(CONFIG_I2O_PROC) += i2o_proc.o
diff --git a/drivers/message/i2o/bus-osm.c b/drivers/message/i2o/bus-osm.c
new file mode 100644 (file)
index 0000000..151b228
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ *     Bus Adapter OSM
+ *
+ *     Copyright (C) 2005      Markus Lidel <Markus.Lidel@shadowconnect.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.
+ *
+ *     Fixes/additions:
+ *             Markus Lidel <Markus.Lidel@shadowconnect.com>
+ *                     initial version.
+ */
+
+#include <linux/module.h>
+#include <linux/i2o.h>
+
+#define OSM_NAME       "bus-osm"
+#define OSM_VERSION    "$Rev$"
+#define OSM_DESCRIPTION        "I2O Bus Adapter OSM"
+
+static struct i2o_driver i2o_bus_driver;
+
+/* Bus OSM class handling definition */
+static struct i2o_class_id i2o_bus_class_id[] = {
+       {I2O_CLASS_BUS_ADAPTER},
+       {I2O_CLASS_END}
+};
+
+/**
+ *     i2o_bus_scan - Scan the bus for new devices
+ *     @dev: I2O device of the bus, which should be scanned
+ *
+ *     Scans the bus dev for new / removed devices. After the scan a new LCT
+ *     will be fetched automatically.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static int i2o_bus_scan(struct i2o_device *dev)
+{
+       struct i2o_message __iomem *msg;
+       u32 m;
+
+       m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET);
+       if (m == I2O_QUEUE_EMPTY)
+               return -ETIMEDOUT;
+
+       writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
+       writel(I2O_CMD_BUS_SCAN << 24 | HOST_TID << 12 | dev->lct_data.tid,
+              &msg->u.head[1]);
+
+       return i2o_msg_post_wait(dev->iop, m, 60);
+};
+
+/**
+ *     i2o_bus_store_scan - Scan the I2O Bus Adapter
+ *     @d: device which should be scanned
+ *
+ *     Returns count.
+ */
+static ssize_t i2o_bus_store_scan(struct device *d, struct device_attribute *attr, const char *buf,
+                                 size_t count)
+{
+       struct i2o_device *i2o_dev = to_i2o_device(d);
+       int rc;
+
+       if ((rc = i2o_bus_scan(i2o_dev)))
+               osm_warn("bus scan failed %d\n", rc);
+
+       return count;
+}
+
+/* Bus Adapter OSM device attributes */
+static DEVICE_ATTR(scan, S_IWUSR, NULL, i2o_bus_store_scan);
+
+/**
+ *     i2o_bus_probe - verify if dev is a I2O Bus Adapter device and install it
+ *     @dev: device to verify if it is a I2O Bus Adapter device
+ *
+ *     Because we want all Bus Adapters always return 0.
+ *
+ *     Returns 0.
+ */
+static int i2o_bus_probe(struct device *dev)
+{
+       struct i2o_device *i2o_dev = to_i2o_device(get_device(dev));
+
+       device_create_file(dev, &dev_attr_scan);
+
+       osm_info("device added (TID: %03x)\n", i2o_dev->lct_data.tid);
+
+       return 0;
+};
+
+/**
+ *     i2o_bus_remove - remove the I2O Bus Adapter device from the system again
+ *     @dev: I2O Bus Adapter device which should be removed
+ *
+ *     Always returns 0.
+ */
+static int i2o_bus_remove(struct device *dev)
+{
+       struct i2o_device *i2o_dev = to_i2o_device(dev);
+
+       device_remove_file(dev, &dev_attr_scan);
+
+       put_device(dev);
+
+       osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid);
+
+       return 0;
+};
+
+/* Bus Adapter OSM driver struct */
+static struct i2o_driver i2o_bus_driver = {
+       .name = OSM_NAME,
+       .classes = i2o_bus_class_id,
+       .driver = {
+                  .probe = i2o_bus_probe,
+                  .remove = i2o_bus_remove,
+                  },
+};
+
+/**
+ *     i2o_bus_init - Bus Adapter OSM initialization function
+ *
+ *     Only register the Bus Adapter OSM in the I2O core.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_bus_init(void)
+{
+       int rc;
+
+       printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+       /* Register Bus Adapter OSM into I2O core */
+       rc = i2o_driver_register(&i2o_bus_driver);
+       if (rc) {
+               osm_err("Could not register Bus Adapter OSM\n");
+               return rc;
+       }
+
+       return 0;
+};
+
+/**
+ *     i2o_bus_exit - Bus Adapter OSM exit function
+ *
+ *     Unregisters Bus Adapter OSM from I2O core.
+ */
+static void __exit i2o_bus_exit(void)
+{
+       i2o_driver_unregister(&i2o_bus_driver);
+};
+
+MODULE_AUTHOR("Markus Lidel <Markus.Lidel@shadowconnect.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+module_init(i2o_bus_init);
+module_exit(i2o_bus_exit);
diff --git a/drivers/message/i2o/config-osm.c b/drivers/message/i2o/config-osm.c
new file mode 100644 (file)
index 0000000..d026760
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+ *     Configuration OSM
+ *
+ *     Copyright (C) 2005      Markus Lidel <Markus.Lidel@shadowconnect.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.
+ *
+ *     Fixes/additions:
+ *             Markus Lidel <Markus.Lidel@shadowconnect.com>
+ *                     initial version.
+ */
+
+#include <linux/module.h>
+#include <linux/i2o.h>
+#include <linux/namei.h>
+
+#include <asm/uaccess.h>
+
+#define OSM_NAME       "config-osm"
+#define OSM_VERSION    "1.248"
+#define OSM_DESCRIPTION        "I2O Configuration OSM"
+
+/* access mode user rw */
+#define S_IWRSR (S_IRUSR | S_IWUSR)
+
+static struct i2o_driver i2o_config_driver;
+
+/* Special file operations for sysfs */
+struct fops_attribute {
+       struct bin_attribute bin;
+       struct file_operations fops;
+};
+
+/**
+ *     sysfs_read_dummy
+ */
+static ssize_t sysfs_read_dummy(struct kobject *kobj, char *buf, loff_t offset,
+                               size_t count)
+{
+       return 0;
+};
+
+/**
+ *     sysfs_write_dummy
+ */
+static ssize_t sysfs_write_dummy(struct kobject *kobj, char *buf, loff_t offset,
+                                size_t count)
+{
+       return 0;
+};
+
+/**
+ *     sysfs_create_fops_file - Creates attribute with special file operations
+ *     @kobj: kobject which should contains the attribute
+ *     @attr: attributes which should be used to create file
+ *
+ *     First creates attribute @attr in kobject @kobj. If it is the first time
+ *     this function is called, merge old fops from sysfs with new one and
+ *     write it back. Afterwords the new fops will be set for the created
+ *     attribute.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static int sysfs_create_fops_file(struct kobject *kobj,
+                                 struct fops_attribute *attr)
+{
+       struct file_operations tmp, *fops;
+       struct dentry *d;
+       struct qstr qstr;
+       int rc;
+
+       fops = &attr->fops;
+
+       if (fops->read)
+               attr->bin.read = sysfs_read_dummy;
+
+       if (fops->write)
+               attr->bin.write = sysfs_write_dummy;
+
+       if ((rc = sysfs_create_bin_file(kobj, &attr->bin)))
+               return rc;
+
+       qstr.name = attr->bin.attr.name;
+       qstr.len = strlen(qstr.name);
+       qstr.hash = full_name_hash(qstr.name, qstr.len);
+
+       if ((d = lookup_hash(&qstr, kobj->dentry))) {
+               if (!fops->owner) {
+                       memcpy(&tmp, d->d_inode->i_fop, sizeof(tmp));
+                       if (fops->read)
+                               tmp.read = fops->read;
+                       if (fops->write)
+                               tmp.write = fops->write;
+                       memcpy(fops, &tmp, sizeof(tmp));
+               }
+
+               d->d_inode->i_fop = fops;
+       } else
+               sysfs_remove_bin_file(kobj, &attr->bin);
+
+       return -ENOENT;
+};
+
+/**
+ *     sysfs_remove_fops_file - Remove attribute with special file operations
+ *     @kobj: kobject which contains the attribute
+ *     @attr: attributes which are used to create file
+ *
+ *     Only wrapper arround sysfs_remove_bin_file()
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static inline int sysfs_remove_fops_file(struct kobject *kobj,
+                                        struct fops_attribute *attr)
+{
+       return sysfs_remove_bin_file(kobj, &attr->bin);
+};
+
+/**
+ *     i2o_config_read_hrt - Returns the HRT of the controller
+ *     @kob: kernel object handle
+ *     @buf: buffer into which the HRT should be copied
+ *     @off: file offset
+ *     @count: number of bytes to read
+ *
+ *     Put @count bytes starting at @off into @buf from the HRT of the I2O
+ *     controller corresponding to @kobj.
+ *
+ *     Returns number of bytes copied into buffer.
+ */
+static ssize_t i2o_config_read_hrt(struct kobject *kobj, char *buf,
+                                  loff_t offset, size_t count)
+{
+       struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop;
+       i2o_hrt *hrt = c->hrt.virt;
+
+       u32 size = (hrt->num_entries * hrt->entry_len + 2) * 4;
+
+       if (offset > size)
+               return 0;
+
+       if (offset + count > size)
+               count = size - offset;
+
+       memcpy(buf, (u8 *) hrt + offset, count);
+
+       return count;
+};
+
+/**
+ *     i2o_config_read_lct - Returns the LCT of the controller
+ *     @kob: kernel object handle
+ *     @buf: buffer into which the LCT should be copied
+ *     @off: file offset
+ *     @count: number of bytes to read
+ *
+ *     Put @count bytes starting at @off into @buf from the LCT of the I2O
+ *     controller corresponding to @kobj.
+ *
+ *     Returns number of bytes copied into buffer.
+ */
+static ssize_t i2o_config_read_lct(struct kobject *kobj, char *buf,
+                                  loff_t offset, size_t count)
+{
+       struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop;
+       u32 size = c->lct->table_size * 4;
+
+       if (offset > size)
+               return 0;
+
+       if (offset + count > size)
+               count = size - offset;
+
+       memcpy(buf, (u8 *) c->lct + offset, count);
+
+       return count;
+};
+
+#define I2O_CONFIG_SW_ATTR(_name,_mode,_type,_swid) \
+static ssize_t i2o_config_##_name##_read(struct file *file, char __user *buf, size_t count, loff_t * offset) { \
+       return i2o_config_sw_read(file, buf, count, offset, _type, _swid); \
+};\
+\
+static ssize_t i2o_config_##_name##_write(struct file *file, const char __user *buf, size_t count, loff_t * offset) { \
+       return i2o_config_sw_write(file, buf, count, offset, _type, _swid); \
+}; \
+\
+static struct fops_attribute i2o_config_attr_##_name = { \
+       .bin = { .attr = { .name = __stringify(_name), .mode = _mode, \
+                          .owner = THIS_MODULE }, \
+                .size = 0, }, \
+       .fops = { .write = i2o_config_##_name##_write, \
+                 .read = i2o_config_##_name##_read} \
+};
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+
+/**
+ *     i2o_config_dpt_reagion - Converts type and id to flash region
+ *     @swtype: type of software module reading
+ *     @swid: id of software which should be read
+ *
+ *     Converts type and id from I2O spec to the matching region for DPT /
+ *     Adaptec controllers.
+ *
+ *     Returns region which match type and id or -1 on error.
+ */
+static u32 i2o_config_dpt_region(u8 swtype, u8 swid)
+{
+       switch (swtype) {
+       case I2O_SOFTWARE_MODULE_IRTOS:
+               /*
+                * content: operation firmware
+                * region size:
+                *      0xbc000 for 2554, 3754, 2564, 3757
+                *      0x170000 for 2865
+                *      0x17c000 for 3966
+                */
+               if (!swid)
+                       return 0;
+
+               break;
+
+       case I2O_SOFTWARE_MODULE_IOP_PRIVATE:
+               /*
+                * content: BIOS and SMOR
+                * BIOS size: first 0x8000 bytes
+                * region size:
+                *      0x40000 for 2554, 3754, 2564, 3757
+                *      0x80000 for 2865, 3966
+                */
+               if (!swid)
+                       return 1;
+
+               break;
+
+       case I2O_SOFTWARE_MODULE_IOP_CONFIG:
+               switch (swid) {
+               case 0:
+                       /*
+                        * content: NVRAM defaults
+                        * region size: 0x2000 bytes
+                        */
+                       return 2;
+               case 1:
+                       /*
+                        * content: serial number
+                        * region size: 0x2000 bytes
+                        */
+                       return 3;
+               }
+               break;
+       }
+
+       return -1;
+};
+
+#endif
+
+/**
+ *     i2o_config_sw_read - Read a software module from controller
+ *     @file: file pointer
+ *     @buf: buffer into which the data should be copied
+ *     @count: number of bytes to read
+ *     @off: file offset
+ *     @swtype: type of software module reading
+ *     @swid: id of software which should be read
+ *
+ *     Transfers @count bytes at offset @offset from IOP into buffer using
+ *     type @swtype and id @swid as described in I2O spec.
+ *
+ *     Returns number of bytes copied into buffer or error code on failure.
+ */
+static ssize_t i2o_config_sw_read(struct file *file, char __user * buf,
+                                 size_t count, loff_t * offset, u8 swtype,
+                                 u32 swid)
+{
+       struct sysfs_dirent *sd = file->f_dentry->d_parent->d_fsdata;
+       struct kobject *kobj = sd->s_element;
+       struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop;
+       u32 m, function = I2O_CMD_SW_UPLOAD;
+       struct i2o_dma buffer;
+       struct i2o_message __iomem *msg;
+       u32 __iomem *mptr;
+       int rc, status;
+
+       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+       if (m == I2O_QUEUE_EMPTY)
+               return -EBUSY;
+
+       mptr = &msg->body[3];
+
+       if ((rc = i2o_dma_alloc(&c->pdev->dev, &buffer, count, GFP_KERNEL))) {
+               i2o_msg_nop(c, m);
+               return rc;
+       }
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+       if (c->adaptec) {
+               mptr = &msg->body[4];
+               function = I2O_CMD_PRIVATE;
+
+               writel(TEN_WORD_MSG_SIZE | SGL_OFFSET_8, &msg->u.head[0]);
+
+               writel(I2O_VENDOR_DPT << 16 | I2O_DPT_FLASH_READ,
+                      &msg->body[0]);
+               writel(i2o_config_dpt_region(swtype, swid), &msg->body[1]);
+               writel(*offset, &msg->body[2]);
+               writel(count, &msg->body[3]);
+       } else
+#endif
+               writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]);
+
+       writel(0xD0000000 | count, mptr++);
+       writel(buffer.phys, mptr);
+
+       writel(function << 24 | HOST_TID << 12 | ADAPTER_TID, &msg->u.head[1]);
+       writel(i2o_config_driver.context, &msg->u.head[2]);
+       writel(0, &msg->u.head[3]);
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+       if (!c->adaptec)
+#endif
+       {
+               writel((u32) swtype << 16 | (u32) 1 << 8, &msg->body[0]);
+               writel(0, &msg->body[1]);
+               writel(swid, &msg->body[2]);
+       }
+
+       status = i2o_msg_post_wait_mem(c, m, 60, &buffer);
+
+       if (status == I2O_POST_WAIT_OK) {
+               if (!(rc = copy_to_user(buf, buffer.virt, count))) {
+                       rc = count;
+                       *offset += count;
+               }
+       } else
+               rc = -EIO;
+
+       if (status != -ETIMEDOUT)
+               i2o_dma_free(&c->pdev->dev, &buffer);
+
+       return rc;
+};
+
+/**
+ *     i2o_config_sw_write - Write a software module to controller
+ *     @file: file pointer
+ *     @buf: buffer into which the data should be copied
+ *     @count: number of bytes to read
+ *     @off: file offset
+ *     @swtype: type of software module writing
+ *     @swid: id of software which should be written
+ *
+ *     Transfers @count bytes at offset @offset from buffer to IOP using
+ *     type @swtype and id @swid as described in I2O spec.
+ *
+ *     Returns number of bytes copied from buffer or error code on failure.
+ */
+static ssize_t i2o_config_sw_write(struct file *file, const char __user * buf,
+                                  size_t count, loff_t * offset, u8 swtype,
+                                  u32 swid)
+{
+       struct sysfs_dirent *sd = file->f_dentry->d_parent->d_fsdata;
+       struct kobject *kobj = sd->s_element;
+       struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop;
+       u32 m, function = I2O_CMD_SW_DOWNLOAD;
+       struct i2o_dma buffer;
+       struct i2o_message __iomem *msg;
+       u32 __iomem *mptr;
+       int rc, status;
+
+       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+       if (m == I2O_QUEUE_EMPTY)
+               return -EBUSY;
+
+       mptr = &msg->body[3];
+
+       if ((rc = i2o_dma_alloc(&c->pdev->dev, &buffer, count, GFP_KERNEL)))
+               goto nop_msg;
+
+       if ((rc = copy_from_user(buffer.virt, buf, count)))
+               goto free_buffer;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+       if (c->adaptec) {
+               mptr = &msg->body[4];
+               function = I2O_CMD_PRIVATE;
+
+               writel(TEN_WORD_MSG_SIZE | SGL_OFFSET_8, &msg->u.head[0]);
+
+               writel(I2O_VENDOR_DPT << 16 | I2O_DPT_FLASH_WRITE,
+                      &msg->body[0]);
+               writel(i2o_config_dpt_region(swtype, swid), &msg->body[1]);
+               writel(*offset, &msg->body[2]);
+               writel(count, &msg->body[3]);
+       } else
+#endif
+               writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]);
+
+       writel(0xD4000000 | count, mptr++);
+       writel(buffer.phys, mptr);
+
+       writel(function << 24 | HOST_TID << 12 | ADAPTER_TID, &msg->u.head[1]);
+       writel(i2o_config_driver.context, &msg->u.head[2]);
+       writel(0, &msg->u.head[3]);
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+       if (!c->adaptec)
+#endif
+       {
+               writel((u32) swtype << 16 | (u32) 1 << 8, &msg->body[0]);
+               writel(0, &msg->body[1]);
+               writel(swid, &msg->body[2]);
+       }
+
+       status = i2o_msg_post_wait_mem(c, m, 60, &buffer);
+
+       if (status != -ETIMEDOUT)
+               i2o_dma_free(&c->pdev->dev, &buffer);
+
+       if (status != I2O_POST_WAIT_OK)
+               return -EIO;
+
+       *offset += count;
+
+       return count;
+
+      free_buffer:
+       i2o_dma_free(&c->pdev->dev, &buffer);
+
+      nop_msg:
+       i2o_msg_nop(c, m);
+
+       return rc;
+};
+
+/* attribute for HRT in sysfs */
+static struct bin_attribute i2o_config_hrt_attr = {
+       .attr = {
+                .name = "hrt",
+                .mode = S_IRUGO,
+                .owner = THIS_MODULE},
+       .size = 0,
+       .read = i2o_config_read_hrt
+};
+
+/* attribute for LCT in sysfs */
+static struct bin_attribute i2o_config_lct_attr = {
+       .attr = {
+                .name = "lct",
+                .mode = S_IRUGO,
+                .owner = THIS_MODULE},
+       .size = 0,
+       .read = i2o_config_read_lct
+};
+
+/* IRTOS firmware access */
+I2O_CONFIG_SW_ATTR(irtos, S_IWRSR, I2O_SOFTWARE_MODULE_IRTOS, 0);
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+
+/*
+ * attribute for BIOS / SMOR, nvram and serial number access on DPT / Adaptec
+ * controllers
+ */
+I2O_CONFIG_SW_ATTR(bios, S_IWRSR, I2O_SOFTWARE_MODULE_IOP_PRIVATE, 0);
+I2O_CONFIG_SW_ATTR(nvram, S_IWRSR, I2O_SOFTWARE_MODULE_IOP_CONFIG, 0);
+I2O_CONFIG_SW_ATTR(serial, S_IWRSR, I2O_SOFTWARE_MODULE_IOP_CONFIG, 1);
+
+#endif
+
+/**
+ *     i2o_config_notify_controller_add - Notify of added controller
+ *     @c: the controller which was added
+ *
+ *     If a I2O controller is added, we catch the notification to add sysfs
+ *     entries.
+ */
+static void i2o_config_notify_controller_add(struct i2o_controller *c)
+{
+       struct kobject *kobj = &c->exec->device.kobj;
+
+       sysfs_create_bin_file(kobj, &i2o_config_hrt_attr);
+       sysfs_create_bin_file(kobj, &i2o_config_lct_attr);
+
+       sysfs_create_fops_file(kobj, &i2o_config_attr_irtos);
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+       if (c->adaptec) {
+               sysfs_create_fops_file(kobj, &i2o_config_attr_bios);
+               sysfs_create_fops_file(kobj, &i2o_config_attr_nvram);
+               sysfs_create_fops_file(kobj, &i2o_config_attr_serial);
+       }
+#endif
+};
+
+/**
+ *     i2o_config_notify_controller_remove - Notify of removed controller
+ *     @c: the controller which was removed
+ *
+ *     If a I2O controller is removed, we catch the notification to remove the
+ *     sysfs entries.
+ */
+static void i2o_config_notify_controller_remove(struct i2o_controller *c)
+{
+       struct kobject *kobj = &c->exec->device.kobj;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+       if (c->adaptec) {
+               sysfs_remove_fops_file(kobj, &i2o_config_attr_serial);
+               sysfs_remove_fops_file(kobj, &i2o_config_attr_nvram);
+               sysfs_remove_fops_file(kobj, &i2o_config_attr_bios);
+       }
+#endif
+       sysfs_remove_fops_file(kobj, &i2o_config_attr_irtos);
+
+       sysfs_remove_bin_file(kobj, &i2o_config_lct_attr);
+       sysfs_remove_bin_file(kobj, &i2o_config_hrt_attr);
+};
+
+/* Config OSM driver struct */
+static struct i2o_driver i2o_config_driver = {
+       .name = OSM_NAME,
+       .notify_controller_add = i2o_config_notify_controller_add,
+       .notify_controller_remove = i2o_config_notify_controller_remove
+};
+
+#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
+#include "i2o_config.c"
+#endif
+
+/**
+ *     i2o_config_init - Configuration OSM initialization function
+ *
+ *     Registers Configuration OSM in the I2O core and if old ioctl's are
+ *     compiled in initialize them.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_config_init(void)
+{
+       printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+       if (i2o_driver_register(&i2o_config_driver)) {
+               osm_err("handler register failed.\n");
+               return -EBUSY;
+       }
+#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
+       if (i2o_config_old_init())
+               i2o_driver_unregister(&i2o_config_driver);
+#endif
+
+       return 0;
+}
+
+/**
+ *     i2o_config_exit - Configuration OSM exit function
+ *
+ *     If old ioctl's are compiled in exit remove them and unregisters
+ *     Configuration OSM from I2O core.
+ */
+static void i2o_config_exit(void)
+{
+#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
+       i2o_config_old_exit();
+#endif
+
+       i2o_driver_unregister(&i2o_config_driver);
+}
+
+MODULE_AUTHOR("Markus Lidel <Markus.Lidel@shadowconnect.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+module_init(i2o_config_init);
+module_exit(i2o_config_exit);
diff --git a/drivers/message/i2o/core.h b/drivers/message/i2o/core.h
new file mode 100644 (file)
index 0000000..c5bcfd7
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *     I2O core internal declarations
+ *
+ *     Copyright (C) 2005      Markus Lidel <Markus.Lidel@shadowconnect.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.
+ *
+ *     Fixes/additions:
+ *             Markus Lidel <Markus.Lidel@shadowconnect.com>
+ *                     initial version.
+ */
+
+/* Exec-OSM */
+extern struct bus_type i2o_bus_type;
+
+extern struct i2o_driver i2o_exec_driver;
+extern int i2o_exec_lct_get(struct i2o_controller *);
+
+extern int __init i2o_exec_init(void);
+extern void __exit i2o_exec_exit(void);
+
+/* driver */
+extern int i2o_driver_dispatch(struct i2o_controller *, u32);
+
+extern int __init i2o_driver_init(void);
+extern void __exit i2o_driver_exit(void);
+
+/* PCI */
+extern int __init i2o_pci_init(void);
+extern void __exit i2o_pci_exit(void);
+
+/* device */
+extern void i2o_device_remove(struct i2o_device *);
+extern int i2o_device_parse_lct(struct i2o_controller *);
+
+extern int i2o_device_init(void);
+extern void i2o_device_exit(void);
+
+/* IOP */
+extern struct i2o_controller *i2o_iop_alloc(void);
+extern void i2o_iop_free(struct i2o_controller *);
+
+extern int i2o_iop_add(struct i2o_controller *);
+extern void i2o_iop_remove(struct i2o_controller *);
+
+/* config */
+extern int i2o_parm_issue(struct i2o_device *, int, void *, int, void *, int);
+
+/* control registers relative to c->base */
+#define I2O_IRQ_STATUS 0x30
+#define I2O_IRQ_MASK   0x34
+#define I2O_IN_PORT    0x40
+#define I2O_OUT_PORT   0x44
+
+#define I2O_IRQ_OUTBOUND_POST  0x00000008
index 2a5d478fc60e15c03680bc9f35e444efd775fbd5..018ca887ca8561e9f5f81b5e113587206fb3eb5b 100644 (file)
@@ -4,8 +4,6 @@
 #include <linux/pci.h>
 #include <linux/i2o.h>
 
-extern struct i2o_driver **i2o_drivers;
-extern unsigned int i2o_max_drivers;
 static void i2o_report_util_cmd(u8 cmd);
 static void i2o_report_exec_cmd(u8 cmd);
 static void i2o_report_fail_status(u8 req_status, u32 * msg);
@@ -23,7 +21,6 @@ void i2o_report_status(const char *severity, const char *str,
        u8 cmd = (msg[1] >> 24) & 0xFF;
        u8 req_status = (msg[4] >> 24) & 0xFF;
        u16 detailed_status = msg[4] & 0xFFFF;
-       //struct i2o_driver *h = i2o_drivers[msg[2] & (i2o_max_drivers-1)];
 
        if (cmd == I2O_CMD_UTIL_EVT_REGISTER)
                return;         // No status in this reply
index eb907e87bc7b7d2fb24550a3386ddeafb56012db..21f16ba3ac38a5f77477daa4eb9e5109e049b6d7 100644 (file)
@@ -16,9 +16,7 @@
 #include <linux/module.h>
 #include <linux/i2o.h>
 #include <linux/delay.h>
-
-/* Exec OSM functions */
-extern struct bus_type i2o_bus_type;
+#include "core.h"
 
 /**
  *     i2o_device_issue_claim - claim or release a device
@@ -282,8 +280,7 @@ int i2o_device_parse_lct(struct i2o_controller *c)
 
        down(&c->lct_lock);
 
-       if (c->lct)
-               kfree(c->lct);
+       kfree(c->lct);
 
        lct = c->dlct.virt;
 
@@ -294,12 +291,12 @@ int i2o_device_parse_lct(struct i2o_controller *c)
        }
 
        if (lct->table_size * 4 > c->dlct.len) {
-               memcpy_fromio(c->lct, c->dlct.virt, c->dlct.len);
+               memcpy(c->lct, c->dlct.virt, c->dlct.len);
                up(&c->lct_lock);
                return -EAGAIN;
        }
 
-       memcpy_fromio(c->lct, c->dlct.virt, lct->table_size * 4);
+       memcpy(c->lct, c->dlct.virt, lct->table_size * 4);
 
        lct = c->lct;
 
@@ -354,7 +351,7 @@ static ssize_t i2o_device_class_show_class_id(struct class_device *cd,
 {
        struct i2o_device *dev = to_i2o_device(cd->dev);
 
-       sprintf(buf, "%03x\n", dev->lct_data.class_id);
+       sprintf(buf, "0x%03x\n", dev->lct_data.class_id);
        return strlen(buf) + 1;
 };
 
@@ -369,7 +366,7 @@ static ssize_t i2o_device_class_show_tid(struct class_device *cd, char *buf)
 {
        struct i2o_device *dev = to_i2o_device(cd->dev);
 
-       sprintf(buf, "%03x\n", dev->lct_data.tid);
+       sprintf(buf, "0x%03x\n", dev->lct_data.tid);
        return strlen(buf) + 1;
 };
 
@@ -401,25 +398,27 @@ static int i2o_device_class_add(struct class_device *cd)
 
        /* create user entries for this device */
        tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid);
-       if (tmp)
+       if (tmp && (tmp != i2o_dev))
                sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj,
                                  "user");
 
        /* create user entries refering to this device */
        list_for_each_entry(tmp, &c->devices, list)
-           if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
+           if ((tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
+               && (tmp != i2o_dev))
                sysfs_create_link(&tmp->device.kobj,
                                  &i2o_dev->device.kobj, "user");
 
        /* create parent entries for this device */
        tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid);
-       if (tmp)
+       if (tmp && (tmp != i2o_dev))
                sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj,
                                  "parent");
 
        /* create parent entries refering to this device */
        list_for_each_entry(tmp, &c->devices, list)
-           if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
+           if ((tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
+               && (tmp != i2o_dev))
                sysfs_create_link(&tmp->device.kobj,
                                  &i2o_dev->device.kobj, "parent");
 
@@ -444,9 +443,8 @@ static struct class_interface i2o_device_class_interface = {
  *     Note that the minimum sized reslist is 8 bytes and contains
  *     ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
  */
-
 int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist,
-                  int oplen, void *reslist, int reslen)
+                         int oplen, void *reslist, int reslen)
 {
        struct i2o_message __iomem *msg;
        u32 m;
@@ -489,7 +487,7 @@ int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist,
        if (rc == -ETIMEDOUT)
                return rc;
 
-       memcpy_fromio(reslist, res.virt, res.len);
+       memcpy(reslist, res.virt, res.len);
        i2o_dma_free(dev, &res);
 
        /* Query failed */
@@ -531,17 +529,23 @@ int i2o_parm_field_get(struct i2o_device *i2o_dev, int group, int field,
                       void *buf, int buflen)
 {
        u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
-       u8 resblk[8 + buflen];  /* 8 bytes for header */
+       u8 *resblk;             /* 8 bytes for header */
        int size;
 
        if (field == -1)        /* whole group */
                opblk[4] = -1;
 
+       resblk = kmalloc(buflen + 8, GFP_KERNEL | GFP_ATOMIC);
+       if (!resblk)
+               return -ENOMEM;
+
        size = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
-                             sizeof(opblk), resblk, sizeof(resblk));
+                             sizeof(opblk), resblk, buflen + 8);
 
        memcpy(buf, resblk + 8, buflen);        /* cut off header */
 
+       kfree(resblk);
+
        if (size > buflen)
                return buflen;
 
index 91f4edbb2a27ddc4a60c80ffae84da17629d0345..739bfdef0c6d04b5d96a70aa333d276a8874bf6d 100644 (file)
 #include <linux/module.h>
 #include <linux/rwsem.h>
 #include <linux/i2o.h>
+#include "core.h"
+
+#define OSM_NAME       "i2o"
 
 /* max_drivers - Maximum I2O drivers (OSMs) which could be registered */
-unsigned int i2o_max_drivers = I2O_MAX_DRIVERS;
+static unsigned int i2o_max_drivers = I2O_MAX_DRIVERS;
 module_param_named(max_drivers, i2o_max_drivers, uint, 0);
 MODULE_PARM_DESC(max_drivers, "maximum number of OSM's to support");
 
@@ -76,17 +79,16 @@ int i2o_driver_register(struct i2o_driver *drv)
        int rc = 0;
        unsigned long flags;
 
-       pr_debug("i2o: Register driver %s\n", drv->name);
+       osm_debug("Register driver %s\n", drv->name);
 
        if (drv->event) {
                drv->event_queue = create_workqueue(drv->name);
                if (!drv->event_queue) {
-                       printk(KERN_ERR "i2o: Could not initialize event queue "
-                              "for driver %s\n", drv->name);
+                       osm_err("Could not initialize event queue for driver "
+                               "%s\n", drv->name);
                        return -EFAULT;
                }
-               pr_debug("i2o: Event queue initialized for driver %s\n",
-                        drv->name);
+               osm_debug("Event queue initialized for driver %s\n", drv->name);
        } else
                drv->event_queue = NULL;
 
@@ -97,8 +99,8 @@ int i2o_driver_register(struct i2o_driver *drv)
 
        for (i = 0; i2o_drivers[i]; i++)
                if (i >= i2o_max_drivers) {
-                       printk(KERN_ERR "i2o: too many drivers registered, "
-                              "increase max_drivers\n");
+                       osm_err("too many drivers registered, increase "
+                               "max_drivers\n");
                        spin_unlock_irqrestore(&i2o_drivers_lock, flags);
                        return -EFAULT;
                }
@@ -108,18 +110,16 @@ int i2o_driver_register(struct i2o_driver *drv)
 
        spin_unlock_irqrestore(&i2o_drivers_lock, flags);
 
-       pr_debug("i2o: driver %s gets context id %d\n", drv->name,
-                drv->context);
+       osm_debug("driver %s gets context id %d\n", drv->name, drv->context);
 
        list_for_each_entry(c, &i2o_controllers, list) {
                struct i2o_device *i2o_dev;
 
                i2o_driver_notify_controller_add(drv, c);
                list_for_each_entry(i2o_dev, &c->devices, list)
-                       i2o_driver_notify_device_add(drv, i2o_dev);
+                   i2o_driver_notify_device_add(drv, i2o_dev);
        }
 
-
        rc = driver_register(&drv->driver);
        if (rc)
                destroy_workqueue(drv->event_queue);
@@ -139,7 +139,7 @@ void i2o_driver_unregister(struct i2o_driver *drv)
        struct i2o_controller *c;
        unsigned long flags;
 
-       pr_debug("i2o: unregister driver %s\n", drv->name);
+       osm_debug("unregister driver %s\n", drv->name);
 
        driver_unregister(&drv->driver);
 
@@ -159,7 +159,7 @@ void i2o_driver_unregister(struct i2o_driver *drv)
        if (drv->event_queue) {
                destroy_workqueue(drv->event_queue);
                drv->event_queue = NULL;
-               pr_debug("i2o: event queue removed for %s\n", drv->name);
+               osm_debug("event queue removed for %s\n", drv->name);
        }
 };
 
@@ -176,68 +176,70 @@ void i2o_driver_unregister(struct i2o_driver *drv)
  *     on success and if the message should be flushed afterwords. Returns
  *     negative error code on failure (the message will be flushed too).
  */
-int i2o_driver_dispatch(struct i2o_controller *c, u32 m,
-                       struct i2o_message __iomem *msg)
+int i2o_driver_dispatch(struct i2o_controller *c, u32 m)
 {
        struct i2o_driver *drv;
-       u32 context = readl(&msg->u.s.icntxt);
+       struct i2o_message *msg = i2o_msg_out_to_virt(c, m);
+       u32 context = le32_to_cpu(msg->u.s.icntxt);
+       unsigned long flags;
 
-       if (likely(context < i2o_max_drivers)) {
-               spin_lock(&i2o_drivers_lock);
-               drv = i2o_drivers[context];
-               spin_unlock(&i2o_drivers_lock);
+       if (unlikely(context >= i2o_max_drivers)) {
+               osm_warn("%s: Spurious reply to unknown driver %d\n", c->name,
+                        context);
+               return -EIO;
+       }
 
-               if (unlikely(!drv)) {
-                       printk(KERN_WARNING "%s: Spurious reply to unknown "
-                              "driver %d\n", c->name, context);
-                       return -EIO;
-               }
+       spin_lock_irqsave(&i2o_drivers_lock, flags);
+       drv = i2o_drivers[context];
+       spin_unlock_irqrestore(&i2o_drivers_lock, flags);
 
-               if ((readl(&msg->u.head[1]) >> 24) == I2O_CMD_UTIL_EVT_REGISTER) {
-                       struct i2o_device *dev, *tmp;
-                       struct i2o_event *evt;
-                       u16 size;
-                       u16 tid;
+       if (unlikely(!drv)) {
+               osm_warn("%s: Spurious reply to unknown driver %d\n", c->name,
+                        context);
+               return -EIO;
+       }
 
-                       tid = readl(&msg->u.head[1]) & 0x1fff;
+       if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_UTIL_EVT_REGISTER) {
+               struct i2o_device *dev, *tmp;
+               struct i2o_event *evt;
+               u16 size;
+               u16 tid = le32_to_cpu(msg->u.head[1]) & 0xfff;
 
-                       pr_debug("%s: event received from device %d\n", c->name,
-                                tid);
+               osm_debug("event received from device %d\n", tid);
 
-                       /* cut of header from message size (in 32-bit words) */
-                       size = (readl(&msg->u.head[0]) >> 16) - 5;
+               if (!drv->event)
+                       return -EIO;
 
-                       evt = kmalloc(size * 4 + sizeof(*evt), GFP_ATOMIC);
-                       if (!evt)
-                               return -ENOMEM;
-                       memset(evt, 0, size * 4 + sizeof(*evt));
+               /* cut of header from message size (in 32-bit words) */
+               size = (le32_to_cpu(msg->u.head[0]) >> 16) - 5;
 
-                       evt->size = size;
-                       memcpy_fromio(&evt->tcntxt, &msg->u.s.tcntxt,
-                                     (size + 2) * 4);
+               evt = kmalloc(size * 4 + sizeof(*evt), GFP_ATOMIC | __GFP_ZERO);
+               if (!evt)
+                       return -ENOMEM;
 
-                       list_for_each_entry_safe(dev, tmp, &c->devices, list)
-                           if (dev->lct_data.tid == tid) {
-                               evt->i2o_dev = dev;
-                               break;
-                       }
+               evt->size = size;
+               evt->tcntxt = le32_to_cpu(msg->u.s.tcntxt);
+               evt->event_indicator = le32_to_cpu(msg->body[0]);
+               memcpy(&evt->tcntxt, &msg->u.s.tcntxt, size * 4);
 
-                       INIT_WORK(&evt->work, (void (*)(void *))drv->event,
-                                 evt);
-                       queue_work(drv->event_queue, &evt->work);
-                       return 1;
+               list_for_each_entry_safe(dev, tmp, &c->devices, list)
+                   if (dev->lct_data.tid == tid) {
+                       evt->i2o_dev = dev;
+                       break;
                }
 
-               if (likely(drv->reply))
-                       return drv->reply(c, m, msg);
-               else
-                       pr_debug("%s: Reply to driver %s, but no reply function"
-                                " defined!\n", c->name, drv->name);
+               INIT_WORK(&evt->work, (void (*)(void *))drv->event, evt);
+               queue_work(drv->event_queue, &evt->work);
+               return 1;
+       }
+
+       if (unlikely(!drv->reply)) {
+               osm_debug("%s: Reply to driver %s, but no reply function"
+                         " defined!\n", c->name, drv->name);
                return -EIO;
-       } else
-               printk(KERN_WARNING "%s: Spurious reply to unknown driver "
-                      "%d\n", c->name, readl(&msg->u.s.icntxt));
-       return -EIO;
+       }
+
+       return drv->reply(c, m, msg);
 }
 
 /**
@@ -334,11 +336,11 @@ int __init i2o_driver_init(void)
        if ((i2o_max_drivers < 2) || (i2o_max_drivers > 64) ||
            ((i2o_max_drivers ^ (i2o_max_drivers - 1)) !=
             (2 * i2o_max_drivers - 1))) {
-               printk(KERN_WARNING "i2o: max_drivers set to %d, but must be "
-                      ">=2 and <= 64 and a power of 2\n", i2o_max_drivers);
+               osm_warn("max_drivers set to %d, but must be >=2 and <= 64 and "
+                        "a power of 2\n", i2o_max_drivers);
                i2o_max_drivers = I2O_MAX_DRIVERS;
        }
-       printk(KERN_INFO "i2o: max drivers = %d\n", i2o_max_drivers);
+       osm_info("max drivers = %d\n", i2o_max_drivers);
 
        i2o_drivers =
            kmalloc(i2o_max_drivers * sizeof(*i2o_drivers), GFP_KERNEL);
index 79c1cbfb8f44a7dd0cc381206637525769420deb..bda2c62648bac566529ccdbdd32f82bc33f1d7ca 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 #include <linux/i2o.h>
 #include <linux/delay.h>
+#include "core.h"
 
 #define OSM_NAME "exec-osm"
 
@@ -37,9 +38,6 @@ struct i2o_driver i2o_exec_driver;
 
 static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind);
 
-/* Module internal functions from other sources */
-extern int i2o_device_parse_lct(struct i2o_controller *);
-
 /* global wait list for POST WAIT */
 static LIST_HEAD(i2o_exec_wait_list);
 
@@ -50,7 +48,7 @@ struct i2o_exec_wait {
        u32 tcntxt;             /* transaction context from reply */
        int complete;           /* 1 if reply received otherwise 0 */
        u32 m;                  /* message id */
-       struct i2o_message __iomem *msg;        /* pointer to the reply message */
+       struct i2o_message *msg;        /* pointer to the reply message */
        struct list_head list;  /* node in global wait list */
 };
 
@@ -108,7 +106,8 @@ static void i2o_exec_wait_free(struct i2o_exec_wait *wait)
  *     buffer must not be freed. Instead the event completion will free them
  *     for you. In all other cases the buffer are your problem.
  *
- *     Returns 0 on success or negative error code on failure.
+ *     Returns 0 on success, negative error code on timeout or positive error
+ *     code from reply.
  */
 int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
                          timeout, struct i2o_dma *dma)
@@ -116,7 +115,7 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
        DECLARE_WAIT_QUEUE_HEAD(wq);
        struct i2o_exec_wait *wait;
        static u32 tcntxt = 0x80000000;
-       struct i2o_message __iomem *msg = c->in_queue.virt + m;
+       struct i2o_message __iomem *msg = i2o_msg_in_to_virt(c, m);
        int rc = 0;
 
        wait = i2o_exec_wait_alloc();
@@ -153,7 +152,7 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
                list_add(&wait->list, &i2o_exec_wait_list);
 
                wait_event_interruptible_timeout(wq, wait->complete,
-                       timeout * HZ);
+                                                timeout * HZ);
 
                wait->wq = NULL;
        }
@@ -161,8 +160,7 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
        barrier();
 
        if (wait->complete) {
-               if (readl(&wait->msg->body[0]) >> 24)
-                       rc = readl(&wait->msg->body[0]) & 0xff;
+               rc = le32_to_cpu(wait->msg->body[0]) >> 24;
                i2o_flush_reply(c, wait->m);
                i2o_exec_wait_free(wait);
        } else {
@@ -187,6 +185,7 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
  *     @c: I2O controller which answers
  *     @m: message id
  *     @msg: pointer to the I2O reply message
+ *     @context: transaction context of request
  *
  *     This function is called in interrupt context only. If the reply reached
  *     before the timeout, the i2o_exec_wait struct is filled with the message
@@ -201,16 +200,12 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
  *     message must also be given back to the controller.
  */
 static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
-                                     struct i2o_message __iomem *msg)
+                                     struct i2o_message *msg, u32 context)
 {
        struct i2o_exec_wait *wait, *tmp;
-       static spinlock_t lock;
+       unsigned long flags;
+       static spinlock_t lock = SPIN_LOCK_UNLOCKED;
        int rc = 1;
-       u32 context;
-
-       spin_lock_init(&lock);
-
-       context = readl(&msg->u.s.tcntxt);
 
        /*
         * We need to search through the i2o_exec_wait_list to see if the given
@@ -219,11 +214,13 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
         * already expired. Not much we can do about that except log it for
         * debug purposes, increase timeout, and recompile.
         */
-       spin_lock(&lock);
+       spin_lock_irqsave(&lock, flags);
        list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) {
                if (wait->tcntxt == context) {
                        list_del(&wait->list);
 
+                       spin_unlock_irqrestore(&lock, flags);
+
                        wait->m = m;
                        wait->msg = msg;
                        wait->complete = 1;
@@ -245,20 +242,62 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
                                rc = -1;
                        }
 
-                       spin_unlock(&lock);
-
                        return rc;
                }
        }
 
-       spin_unlock(&lock);
+       spin_unlock_irqrestore(&lock, flags);
 
-       pr_debug("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name,
+       osm_warn("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name,
                 context);
 
        return -1;
 };
 
+/**
+ *     i2o_exec_show_vendor_id - Displays Vendor ID of controller
+ *     @d: device of which the Vendor ID should be displayed
+ *     @buf: buffer into which the Vendor ID should be printed
+ *
+ *     Returns number of bytes printed into buffer.
+ */
+static ssize_t i2o_exec_show_vendor_id(struct device *d, struct device_attribute *attr, char *buf)
+{
+       struct i2o_device *dev = to_i2o_device(d);
+       u16 id;
+
+       if (i2o_parm_field_get(dev, 0x0000, 0, &id, 2)) {
+               sprintf(buf, "0x%04x", id);
+               return strlen(buf) + 1;
+       }
+
+       return 0;
+};
+
+/**
+ *     i2o_exec_show_product_id - Displays Product ID of controller
+ *     @d: device of which the Product ID should be displayed
+ *     @buf: buffer into which the Product ID should be printed
+ *
+ *     Returns number of bytes printed into buffer.
+ */
+static ssize_t i2o_exec_show_product_id(struct device *d, struct device_attribute *attr, char *buf)
+{
+       struct i2o_device *dev = to_i2o_device(d);
+       u16 id;
+
+       if (i2o_parm_field_get(dev, 0x0000, 1, &id, 2)) {
+               sprintf(buf, "0x%04x", id);
+               return strlen(buf) + 1;
+       }
+
+       return 0;
+};
+
+/* Exec-OSM device attributes */
+static DEVICE_ATTR(vendor_id, S_IRUGO, i2o_exec_show_vendor_id, NULL);
+static DEVICE_ATTR(product_id, S_IRUGO, i2o_exec_show_product_id, NULL);
+
 /**
  *     i2o_exec_probe - Called if a new I2O device (executive class) appears
  *     @dev: I2O device which should be probed
@@ -271,10 +310,16 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
 static int i2o_exec_probe(struct device *dev)
 {
        struct i2o_device *i2o_dev = to_i2o_device(dev);
+       struct i2o_controller *c = i2o_dev->iop;
 
        i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
 
-       i2o_dev->iop->exec = i2o_dev;
+       c->exec = i2o_dev;
+
+       i2o_exec_lct_notify(c, c->lct->change_ind + 1);
+
+       device_create_file(dev, &dev_attr_vendor_id);
+       device_create_file(dev, &dev_attr_product_id);
 
        return 0;
 };
@@ -289,6 +334,9 @@ static int i2o_exec_probe(struct device *dev)
  */
 static int i2o_exec_remove(struct device *dev)
 {
+       device_remove_file(dev, &dev_attr_product_id);
+       device_remove_file(dev, &dev_attr_vendor_id);
+
        i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
 
        return 0;
@@ -300,12 +348,16 @@ static int i2o_exec_remove(struct device *dev)
  *
  *     This function handles asynchronus LCT NOTIFY replies. It parses the
  *     new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY
- *     again.
+ *     again, otherwise send LCT NOTIFY to get informed on next LCT change.
  */
 static void i2o_exec_lct_modified(struct i2o_controller *c)
 {
-       if (i2o_device_parse_lct(c) == -EAGAIN)
-               i2o_exec_lct_notify(c, 0);
+       u32 change_ind = 0;
+
+       if (i2o_device_parse_lct(c) != -EAGAIN)
+               change_ind = c->lct->change_ind + 1;
+
+       i2o_exec_lct_notify(c, change_ind);
 };
 
 /**
@@ -325,8 +377,14 @@ static void i2o_exec_lct_modified(struct i2o_controller *c)
 static int i2o_exec_reply(struct i2o_controller *c, u32 m,
                          struct i2o_message *msg)
 {
-       if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) {   // Fail bit is set
-               struct i2o_message __iomem *pmsg;       /* preserved message */
+       u32 context;
+
+       if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) {
+               /*
+                * If Fail bit is set we must take the transaction context of
+                * the preserved message to find the right request again.
+                */
+               struct i2o_message __iomem *pmsg;
                u32 pm;
 
                pm = le32_to_cpu(msg->body[3]);
@@ -335,15 +393,15 @@ static int i2o_exec_reply(struct i2o_controller *c, u32 m,
 
                i2o_report_status(KERN_INFO, "i2o_core", msg);
 
-               /* Release the preserved msg by resubmitting it as a NOP */
-               i2o_msg_nop(c, pm);
+               context = readl(&pmsg->u.s.tcntxt);
 
-               /* If reply to i2o_post_wait failed, return causes a timeout */
-               return -1;
-       }
+               /* Release the preserved msg */
+               i2o_msg_nop(c, pm);
+       } else
+               context = le32_to_cpu(msg->u.s.tcntxt);
 
-       if (le32_to_cpu(msg->u.s.tcntxt) & 0x80000000)
-               return i2o_msg_post_wait_complete(c, m, msg);
+       if (context & 0x80000000)
+               return i2o_msg_post_wait_complete(c, m, msg, context);
 
        if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) {
                struct work_struct *work;
@@ -381,8 +439,9 @@ static int i2o_exec_reply(struct i2o_controller *c, u32 m,
  */
 static void i2o_exec_event(struct i2o_event *evt)
 {
-       osm_info("Event received from device: %d\n",
-                evt->i2o_dev->lct_data.tid);
+       if (likely(evt->i2o_dev))
+               osm_debug("Event received from device: %d\n",
+                         evt->i2o_dev->lct_data.tid);
        kfree(evt);
 };
 
index 4830b775906104d718b882c720a3ea1d306b96f3..f283b5bafdd3945c2cc087a3f3d20dc2efdf0898 100644 (file)
@@ -62,7 +62,7 @@
 #include "i2o_block.h"
 
 #define OSM_NAME       "block-osm"
-#define OSM_VERSION    "$Rev$"
+#define OSM_VERSION    "1.287"
 #define OSM_DESCRIPTION        "I2O Block Device OSM"
 
 static struct i2o_driver i2o_block_driver;
@@ -104,7 +104,8 @@ static int i2o_block_remove(struct device *dev)
        struct i2o_device *i2o_dev = to_i2o_device(dev);
        struct i2o_block_device *i2o_blk_dev = dev_get_drvdata(dev);
 
-       osm_info("Device removed %s\n", i2o_blk_dev->gd->disk_name);
+       osm_info("device removed (TID: %03x): %s\n", i2o_dev->lct_data.tid,
+                i2o_blk_dev->gd->disk_name);
 
        i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0);
 
@@ -145,6 +146,29 @@ static int i2o_block_device_flush(struct i2o_device *dev)
        return i2o_msg_post_wait(dev->iop, m, 60);
 };
 
+/**
+ *     i2o_block_issue_flush - device-flush interface for block-layer
+ *     @queue: the request queue of the device which should be flushed
+ *     @disk: gendisk
+ *     @error_sector: error offset
+ *
+ *     Helper function to provide flush functionality to block-layer.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+
+static int i2o_block_issue_flush(request_queue_t * queue, struct gendisk *disk,
+                                sector_t * error_sector)
+{
+       struct i2o_block_device *i2o_blk_dev = queue->queuedata;
+       int rc = -ENODEV;
+
+       if (likely(i2o_blk_dev))
+               rc = i2o_block_device_flush(i2o_blk_dev->i2o_dev);
+
+       return rc;
+}
+
 /**
  *     i2o_block_device_mount - Mount (load) the media of device dev
  *     @dev: I2O device which should receive the mount request
@@ -298,28 +322,31 @@ static inline void i2o_block_request_free(struct i2o_block_request *ireq)
 
 /**
  *     i2o_block_sglist_alloc - Allocate the SG list and map it
+ *     @c: I2O controller to which the request belongs
  *     @ireq: I2O block request
  *
- *     Builds the SG list and map it into to be accessable by the controller.
+ *     Builds the SG list and map it to be accessable by the controller.
  *
- *     Returns the number of elements in the SG list or 0 on failure.
+ *     Returns 0 on failure or 1 on success.
  */
-static inline int i2o_block_sglist_alloc(struct i2o_block_request *ireq)
+static inline int i2o_block_sglist_alloc(struct i2o_controller *c,
+                                        struct i2o_block_request *ireq,
+                                        u32 __iomem ** mptr)
 {
-       struct device *dev = &ireq->i2o_blk_dev->i2o_dev->iop->pdev->dev;
        int nents;
+       enum dma_data_direction direction;
 
+       ireq->dev = &c->pdev->dev;
        nents = blk_rq_map_sg(ireq->req->q, ireq->req, ireq->sg_table);
 
        if (rq_data_dir(ireq->req) == READ)
-               ireq->sg_dma_direction = PCI_DMA_FROMDEVICE;
+               direction = PCI_DMA_FROMDEVICE;
        else
-               ireq->sg_dma_direction = PCI_DMA_TODEVICE;
+               direction = PCI_DMA_TODEVICE;
 
-       ireq->sg_nents = dma_map_sg(dev, ireq->sg_table, nents,
-                                   ireq->sg_dma_direction);
+       ireq->sg_nents = nents;
 
-       return ireq->sg_nents;
+       return i2o_dma_map_sg(c, ireq->sg_table, nents, direction, mptr);
 };
 
 /**
@@ -330,10 +357,14 @@ static inline int i2o_block_sglist_alloc(struct i2o_block_request *ireq)
  */
 static inline void i2o_block_sglist_free(struct i2o_block_request *ireq)
 {
-       struct device *dev = &ireq->i2o_blk_dev->i2o_dev->iop->pdev->dev;
+       enum dma_data_direction direction;
 
-       dma_unmap_sg(dev, ireq->sg_table, ireq->sg_nents,
-                    ireq->sg_dma_direction);
+       if (rq_data_dir(ireq->req) == READ)
+               direction = PCI_DMA_FROMDEVICE;
+       else
+               direction = PCI_DMA_TODEVICE;
+
+       dma_unmap_sg(ireq->dev, ireq->sg_table, ireq->sg_nents, direction);
 };
 
 /**
@@ -351,6 +382,11 @@ static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req)
        struct i2o_block_device *i2o_blk_dev = q->queuedata;
        struct i2o_block_request *ireq;
 
+       if (unlikely(!i2o_blk_dev)) {
+               osm_err("block device already removed\n");
+               return BLKPREP_KILL;
+       }
+
        /* request is already processed by us, so return */
        if (req->flags & REQ_SPECIAL) {
                osm_debug("REQ_SPECIAL already set!\n");
@@ -400,71 +436,65 @@ static void i2o_block_delayed_request_fn(void *delayed_request)
 };
 
 /**
- *     i2o_block_reply - Block OSM reply handler.
- *     @c: I2O controller from which the message arrives
- *     @m: message id of reply
- *     qmsg: the actuall I2O message reply
+ *     i2o_block_end_request - Post-processing of completed commands
+ *     @req: request which should be completed
+ *     @uptodate: 1 for success, 0 for I/O error, < 0 for specific error
+ *     @nr_bytes: number of bytes to complete
  *
- *     This function gets all the message replies.
+ *     Mark the request as complete. The lock must not be held when entering.
  *
  */
-static int i2o_block_reply(struct i2o_controller *c, u32 m,
-                          struct i2o_message *msg)
+static void i2o_block_end_request(struct request *req, int uptodate,
+                                 int nr_bytes)
 {
-       struct i2o_block_request *ireq;
-       struct request *req;
-       struct i2o_block_device *dev;
-       struct request_queue *q;
-       u8 st;
+       struct i2o_block_request *ireq = req->special;
+       struct i2o_block_device *dev = ireq->i2o_blk_dev;
+       request_queue_t *q = req->q;
        unsigned long flags;
 
-       /* FAILed message */
-       if (unlikely(le32_to_cpu(msg->u.head[0]) & (1 << 13))) {
-               struct i2o_message *pmsg;
-               u32 pm;
+       if (end_that_request_chunk(req, uptodate, nr_bytes)) {
+               int leftover = (req->hard_nr_sectors << KERNEL_SECTOR_SHIFT);
 
-               /*
-                * FAILed message from controller
-                * We increment the error count and abort it
-                *
-                * In theory this will never happen.  The I2O block class
-                * specification states that block devices never return
-                * FAILs but instead use the REQ status field...but
-                * better be on the safe side since no one really follows
-                * the spec to the book :)
-                */
-               pm = le32_to_cpu(msg->body[3]);
-               pmsg = i2o_msg_in_to_virt(c, pm);
+               if (blk_pc_request(req))
+                       leftover = req->data_len;
 
-               req = i2o_cntxt_list_get(c, le32_to_cpu(pmsg->u.s.tcntxt));
-               if (unlikely(!req)) {
-                       osm_err("NULL reply received!\n");
-                       return -1;
-               }
+               if (end_io_error(uptodate))
+                       end_that_request_chunk(req, 0, leftover);
+       }
 
-               ireq = req->special;
-               dev = ireq->i2o_blk_dev;
-               q = dev->gd->queue;
+       add_disk_randomness(req->rq_disk);
 
-               req->errors++;
-
-               spin_lock_irqsave(q->queue_lock, flags);
+       spin_lock_irqsave(q->queue_lock, flags);
 
-               while (end_that_request_chunk(req, !req->errors,
-                                             le32_to_cpu(pmsg->body[1]))) ;
-               end_that_request_last(req);
+       end_that_request_last(req);
 
+       if (likely(dev)) {
                dev->open_queue_depth--;
                list_del(&ireq->queue);
-               blk_start_queue(q);
+       }
 
-               spin_unlock_irqrestore(q->queue_lock, flags);
+       blk_start_queue(q);
 
-               /* Now flush the message by making it a NOP */
-               i2o_msg_nop(c, pm);
+       spin_unlock_irqrestore(q->queue_lock, flags);
 
-               return -1;
-       }
+       i2o_block_sglist_free(ireq);
+       i2o_block_request_free(ireq);
+};
+
+/**
+ *     i2o_block_reply - Block OSM reply handler.
+ *     @c: I2O controller from which the message arrives
+ *     @m: message id of reply
+ *     qmsg: the actuall I2O message reply
+ *
+ *     This function gets all the message replies.
+ *
+ */
+static int i2o_block_reply(struct i2o_controller *c, u32 m,
+                          struct i2o_message *msg)
+{
+       struct request *req;
+       int uptodate = 1;
 
        req = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
        if (unlikely(!req)) {
@@ -472,61 +502,13 @@ static int i2o_block_reply(struct i2o_controller *c, u32 m,
                return -1;
        }
 
-       ireq = req->special;
-       dev = ireq->i2o_blk_dev;
-       q = dev->gd->queue;
-
-       if (unlikely(!dev->i2o_dev)) {
-               /*
-                * This is HACK, but Intel Integrated RAID allows user
-                * to delete a volume that is claimed, locked, and in use
-                * by the OS. We have to check for a reply from a
-                * non-existent device and flag it as an error or the system
-                * goes kaput...
-                */
-               req->errors++;
-               osm_warn("Data transfer to deleted device!\n");
-               spin_lock_irqsave(q->queue_lock, flags);
-               while (end_that_request_chunk
-                      (req, !req->errors, le32_to_cpu(msg->body[1]))) ;
-               end_that_request_last(req);
-
-               dev->open_queue_depth--;
-               list_del(&ireq->queue);
-               blk_start_queue(q);
-
-               spin_unlock_irqrestore(q->queue_lock, flags);
-               return -1;
-       }
-
        /*
         *      Lets see what is cooking. We stuffed the
         *      request in the context.
         */
 
-       st = le32_to_cpu(msg->body[0]) >> 24;
-
-       if (st != 0) {
-               int err;
-               char *bsa_errors[] = {
-                       "Success",
-                       "Media Error",
-                       "Failure communicating to device",
-                       "Device Failure",
-                       "Device is not ready",
-                       "Media not present",
-                       "Media is locked by another user",
-                       "Media has failed",
-                       "Failure communicating to device",
-                       "Device bus failure",
-                       "Device is locked by another user",
-                       "Device is write protected",
-                       "Device has reset",
-                       "Volume has changed, waiting for acknowledgement"
-               };
-
-               err = le32_to_cpu(msg->body[0]) & 0xffff;
-
+       if ((le32_to_cpu(msg->body[0]) >> 24) != 0) {
+               u32 status = le32_to_cpu(msg->body[0]);
                /*
                 *      Device not ready means two things. One is that the
                 *      the thing went offline (but not a removal media)
@@ -539,40 +521,23 @@ static int i2o_block_reply(struct i2o_controller *c, u32 m,
                 *      Don't stick a supertrak100 into cache aggressive modes
                 */
 
-               osm_err("block-osm: /dev/%s error: %s", dev->gd->disk_name,
-                       bsa_errors[le32_to_cpu(msg->body[0]) & 0xffff]);
-               if (le32_to_cpu(msg->body[0]) & 0x00ff0000)
-                       printk(KERN_ERR " - DDM attempted %d retries",
-                              (le32_to_cpu(msg->body[0]) >> 16) & 0x00ff);
-               printk(KERN_ERR ".\n");
-               req->errors++;
-       } else
-               req->errors = 0;
+               osm_err("TID %03x error status: 0x%02x, detailed status: "
+                       "0x%04x\n", (le32_to_cpu(msg->u.head[1]) >> 12 & 0xfff),
+                       status >> 24, status & 0xffff);
 
-       if (!end_that_request_chunk
-           (req, !req->errors, le32_to_cpu(msg->body[1]))) {
-               add_disk_randomness(req->rq_disk);
-               spin_lock_irqsave(q->queue_lock, flags);
-
-               end_that_request_last(req);
+               req->errors++;
 
-               dev->open_queue_depth--;
-               list_del(&ireq->queue);
-               blk_start_queue(q);
+               uptodate = 0;
+       }
 
-               spin_unlock_irqrestore(q->queue_lock, flags);
-
-               i2o_block_sglist_free(ireq);
-               i2o_block_request_free(ireq);
-       } else
-               osm_err("still remaining chunks\n");
+       i2o_block_end_request(req, uptodate, le32_to_cpu(msg->body[1]));
 
        return 1;
 };
 
 static void i2o_block_event(struct i2o_event *evt)
 {
-       osm_info("block-osm: event received\n");
+       osm_debug("event received\n");
        kfree(evt);
 };
 
@@ -778,18 +743,25 @@ static int i2o_block_media_changed(struct gendisk *disk)
 static int i2o_block_transfer(struct request *req)
 {
        struct i2o_block_device *dev = req->rq_disk->private_data;
-       struct i2o_controller *c = dev->i2o_dev->iop;
+       struct i2o_controller *c;
        int tid = dev->i2o_dev->lct_data.tid;
        struct i2o_message __iomem *msg;
-       void __iomem *mptr;
+       u32 __iomem *mptr;
        struct i2o_block_request *ireq = req->special;
-       struct scatterlist *sg;
-       int sgnum;
-       int i;
        u32 m;
        u32 tcntxt;
-       u32 sg_flags;
+       u32 sgl_offset = SGL_OFFSET_8;
+       u32 ctl_flags = 0x00000000;
        int rc;
+       u32 cmd;
+
+       if (unlikely(!dev->i2o_dev)) {
+               osm_err("transfer to removed drive\n");
+               rc = -ENODEV;
+               goto exit;
+       }
+
+       c = dev->i2o_dev->iop;
 
        m = i2o_msg_get(c, &msg);
        if (m == I2O_QUEUE_EMPTY) {
@@ -803,82 +775,109 @@ static int i2o_block_transfer(struct request *req)
                goto nop_msg;
        }
 
-       if ((sgnum = i2o_block_sglist_alloc(ireq)) <= 0) {
-               rc = -ENOMEM;
-               goto context_remove;
-       }
-
-       /* Build the message based on the request. */
        writel(i2o_block_driver.context, &msg->u.s.icntxt);
        writel(tcntxt, &msg->u.s.tcntxt);
-       writel(req->nr_sectors << 9, &msg->body[1]);
-
-       writel((((u64) req->sector) << 9) & 0xffffffff, &msg->body[2]);
-       writel(req->sector >> 23, &msg->body[3]);
 
-       mptr = &msg->body[4];
-
-       sg = ireq->sg_table;
+       mptr = &msg->body[0];
 
        if (rq_data_dir(req) == READ) {
-               writel(I2O_CMD_BLOCK_READ << 24 | HOST_TID << 12 | tid,
-                      &msg->u.head[1]);
-               sg_flags = 0x10000000;
+               cmd = I2O_CMD_BLOCK_READ << 24;
+
                switch (dev->rcache) {
-               case CACHE_NULL:
-                       writel(0, &msg->body[0]);
-                       break;
                case CACHE_PREFETCH:
-                       writel(0x201F0008, &msg->body[0]);
+                       ctl_flags = 0x201F0008;
                        break;
+
                case CACHE_SMARTFETCH:
                        if (req->nr_sectors > 16)
-                               writel(0x201F0008, &msg->body[0]);
+                               ctl_flags = 0x201F0008;
                        else
-                               writel(0x001F0000, &msg->body[0]);
+                               ctl_flags = 0x001F0000;
+                       break;
+
+               default:
                        break;
                }
        } else {
-               writel(I2O_CMD_BLOCK_WRITE << 24 | HOST_TID << 12 | tid,
-                      &msg->u.head[1]);
-               sg_flags = 0x14000000;
+               cmd = I2O_CMD_BLOCK_WRITE << 24;
+
                switch (dev->wcache) {
-               case CACHE_NULL:
-                       writel(0, &msg->body[0]);
-                       break;
                case CACHE_WRITETHROUGH:
-                       writel(0x001F0008, &msg->body[0]);
+                       ctl_flags = 0x001F0008;
                        break;
                case CACHE_WRITEBACK:
-                       writel(0x001F0010, &msg->body[0]);
+                       ctl_flags = 0x001F0010;
                        break;
                case CACHE_SMARTBACK:
                        if (req->nr_sectors > 16)
-                               writel(0x001F0004, &msg->body[0]);
+                               ctl_flags = 0x001F0004;
                        else
-                               writel(0x001F0010, &msg->body[0]);
+                               ctl_flags = 0x001F0010;
                        break;
                case CACHE_SMARTTHROUGH:
                        if (req->nr_sectors > 16)
-                               writel(0x001F0004, &msg->body[0]);
+                               ctl_flags = 0x001F0004;
                        else
-                               writel(0x001F0010, &msg->body[0]);
+                               ctl_flags = 0x001F0010;
+               default:
+                       break;
+               }
+       }
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+       if (c->adaptec) {
+               u8 cmd[10];
+               u32 scsi_flags;
+               u16 hwsec = queue_hardsect_size(req->q) >> KERNEL_SECTOR_SHIFT;
+
+               memset(cmd, 0, 10);
+
+               sgl_offset = SGL_OFFSET_12;
+
+               writel(I2O_CMD_PRIVATE << 24 | HOST_TID << 12 | tid,
+                      &msg->u.head[1]);
+
+               writel(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC, mptr++);
+               writel(tid, mptr++);
+
+               /*
+                * ENABLE_DISCONNECT
+                * SIMPLE_TAG
+                * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
+                */
+               if (rq_data_dir(req) == READ) {
+                       cmd[0] = 0x28;
+                       scsi_flags = 0x60a0000a;
+               } else {
+                       cmd[0] = 0x2A;
+                       scsi_flags = 0xa0a0000a;
                }
+
+               writel(scsi_flags, mptr++);
+
+               *((u32 *) & cmd[2]) = cpu_to_be32(req->sector * hwsec);
+               *((u16 *) & cmd[7]) = cpu_to_be16(req->nr_sectors * hwsec);
+
+               memcpy_toio(mptr, cmd, 10);
+               mptr += 4;
+               writel(req->nr_sectors << KERNEL_SECTOR_SHIFT, mptr++);
+       } else
+#endif
+       {
+               writel(cmd | HOST_TID << 12 | tid, &msg->u.head[1]);
+               writel(ctl_flags, mptr++);
+               writel(req->nr_sectors << KERNEL_SECTOR_SHIFT, mptr++);
+               writel((u32) (req->sector << KERNEL_SECTOR_SHIFT), mptr++);
+               writel(req->sector >> (32 - KERNEL_SECTOR_SHIFT), mptr++);
        }
 
-       for (i = sgnum; i > 0; i--) {
-               if (i == 1)
-                       sg_flags |= 0x80000000;
-               writel(sg_flags | sg_dma_len(sg), mptr);
-               writel(sg_dma_address(sg), mptr + 4);
-               mptr += 8;
-               sg++;
+       if (!i2o_block_sglist_alloc(c, ireq, &mptr)) {
+               rc = -ENOMEM;
+               goto context_remove;
        }
 
-       writel(I2O_MESSAGE_SIZE
-              (((unsigned long)mptr -
-                (unsigned long)&msg->u.head[0]) >> 2) | SGL_OFFSET_8,
-              &msg->u.head[0]);
+       writel(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) |
+              sgl_offset, &msg->u.head[0]);
 
        list_add_tail(&ireq->queue, &dev->open_queue);
        dev->open_queue_depth++;
@@ -921,11 +920,13 @@ static void i2o_block_request_fn(struct request_queue *q)
 
                        queue_depth = ireq->i2o_blk_dev->open_queue_depth;
 
-                       if (queue_depth < I2O_BLOCK_MAX_OPEN_REQUESTS)
+                       if (queue_depth < I2O_BLOCK_MAX_OPEN_REQUESTS) {
                                if (!i2o_block_transfer(req)) {
                                        blkdev_dequeue_request(req);
                                        continue;
-                               }
+                               } else
+                                       osm_info("transfer error\n");
+                       }
 
                        if (queue_depth)
                                break;
@@ -939,7 +940,6 @@ static void i2o_block_request_fn(struct request_queue *q)
                        INIT_WORK(&dreq->work, i2o_block_delayed_request_fn,
                                  dreq);
 
-                       osm_info("transfer error\n");
                        if (!queue_delayed_work(i2o_block_driver.event_queue,
                                                &dreq->work,
                                                I2O_BLOCK_RETRY_TIME))
@@ -1008,6 +1008,7 @@ static struct i2o_block_device *i2o_block_device_alloc(void)
        }
 
        blk_queue_prep_rq(queue, i2o_block_prep_req_fn);
+       blk_queue_issue_flush_fn(queue, i2o_block_issue_flush);
 
        gd->major = I2O_MAJOR;
        gd->queue = queue;
@@ -1040,17 +1041,27 @@ static struct i2o_block_device *i2o_block_device_alloc(void)
 static int i2o_block_probe(struct device *dev)
 {
        struct i2o_device *i2o_dev = to_i2o_device(dev);
-       struct i2o_block_device *i2o_blk_dev;
        struct i2o_controller *c = i2o_dev->iop;
+       struct i2o_block_device *i2o_blk_dev;
        struct gendisk *gd;
        struct request_queue *queue;
        static int unit = 0;
        int rc;
        u64 size;
        u32 blocksize;
-       u16 power;
        u32 flags, status;
-       int segments;
+       u16 body_size = 4;
+       unsigned short max_sectors;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+       if (c->adaptec)
+               body_size = 8;
+#endif
+
+       if (c->limit_sectors)
+               max_sectors = I2O_MAX_SECTORS_LIMITED;
+       else
+               max_sectors = I2O_MAX_SECTORS;
 
        /* skip devices which are used by IOP */
        if (i2o_dev->lct_data.user_tid != 0xfff) {
@@ -1058,8 +1069,6 @@ static int i2o_block_probe(struct device *dev)
                return -ENODEV;
        }
 
-       osm_info("New device detected (TID: %03x)\n", i2o_dev->lct_data.tid);
-
        if (i2o_device_claim(i2o_dev)) {
                osm_warn("Unable to claim device. Installation aborted\n");
                rc = -EFAULT;
@@ -1087,50 +1096,44 @@ static int i2o_block_probe(struct device *dev)
        queue = gd->queue;
        queue->queuedata = i2o_blk_dev;
 
-       blk_queue_max_phys_segments(queue, I2O_MAX_SEGMENTS);
-       blk_queue_max_sectors(queue, I2O_MAX_SECTORS);
-
-       if (c->short_req)
-               segments = 8;
-       else {
-               i2o_status_block *sb;
+       blk_queue_max_phys_segments(queue, I2O_MAX_PHYS_SEGMENTS);
+       blk_queue_max_sectors(queue, max_sectors);
+       blk_queue_max_hw_segments(queue, i2o_sg_tablesize(c, body_size));
 
-               sb = c->status_block.virt;
-
-               segments = (sb->inbound_frame_size -
-                           sizeof(struct i2o_message) / 4 - 4) / 2;
-       }
-
-       blk_queue_max_hw_segments(queue, segments);
-
-       osm_debug("max sectors = %d\n", I2O_MAX_SECTORS);
-       osm_debug("phys segments = %d\n", I2O_MAX_SEGMENTS);
-       osm_debug("hw segments = %d\n", segments);
+       osm_debug("max sectors = %d\n", queue->max_phys_segments);
+       osm_debug("phys segments = %d\n", queue->max_sectors);
+       osm_debug("max hw segments = %d\n", queue->max_hw_segments);
 
        /*
         *      Ask for the current media data. If that isn't supported
         *      then we ask for the device capacity data
         */
-       if (i2o_parm_field_get(i2o_dev, 0x0004, 1, &blocksize, 4) != 0
-           || i2o_parm_field_get(i2o_dev, 0x0004, 0, &size, 8) != 0) {
-               i2o_parm_field_get(i2o_dev, 0x0000, 3, &blocksize, 4);
-               i2o_parm_field_get(i2o_dev, 0x0000, 4, &size, 8);
-       }
-       osm_debug("blocksize = %d\n", blocksize);
+       if (i2o_parm_field_get(i2o_dev, 0x0004, 1, &blocksize, 4) ||
+           i2o_parm_field_get(i2o_dev, 0x0000, 3, &blocksize, 4)) {
+               blk_queue_hardsect_size(queue, blocksize);
+       } else
+               osm_warn("unable to get blocksize of %s\n", gd->disk_name);
 
-       if (i2o_parm_field_get(i2o_dev, 0x0000, 2, &power, 2))
-               power = 0;
+       if (i2o_parm_field_get(i2o_dev, 0x0004, 0, &size, 8) ||
+           i2o_parm_field_get(i2o_dev, 0x0000, 4, &size, 8)) {
+               set_capacity(gd, size >> KERNEL_SECTOR_SHIFT);
+       } else
+               osm_warn("could not get size of %s\n", gd->disk_name);
+
+       if (!i2o_parm_field_get(i2o_dev, 0x0000, 2, &i2o_blk_dev->power, 2))
+               i2o_blk_dev->power = 0;
        i2o_parm_field_get(i2o_dev, 0x0000, 5, &flags, 4);
        i2o_parm_field_get(i2o_dev, 0x0000, 6, &status, 4);
 
-       set_capacity(gd, size >> 9);
-
        i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0xffffffff);
 
        add_disk(gd);
 
        unit++;
 
+       osm_info("device added (TID: %03x): %s\n", i2o_dev->lct_data.tid,
+                i2o_blk_dev->gd->disk_name);
+
        return 0;
 
       claim_release:
@@ -1178,7 +1181,7 @@ static int __init i2o_block_init(void)
                goto exit;
        }
 
-       i2o_blk_req_pool.pool = mempool_create(I2O_REQ_MEMPOOL_SIZE,
+       i2o_blk_req_pool.pool = mempool_create(I2O_BLOCK_REQ_MEMPOOL_SIZE,
                                               mempool_alloc_slab,
                                               mempool_free_slab,
                                               i2o_blk_req_pool.slab);
index ddd9a15679c0f42ec937db36d5f86391b961901d..4fdaa5bda4125d57b7591bd89f9e9054fc47ddcb 100644 (file)
 #define I2O_BLOCK_RETRY_TIME HZ/4
 #define I2O_BLOCK_MAX_OPEN_REQUESTS 50
 
+/* request queue sizes */
+#define I2O_BLOCK_REQ_MEMPOOL_SIZE             32
+
+#define KERNEL_SECTOR_SHIFT 9
+#define KERNEL_SECTOR_SIZE (1 << KERNEL_SECTOR_SHIFT)
+
 /* I2O Block OSM mempool struct */
 struct i2o_block_mempool {
-       kmem_cache_t    *slab;
-       mempool_t       *pool;
+       kmem_cache_t *slab;
+       mempool_t *pool;
 };
 
 /* I2O Block device descriptor */
 struct i2o_block_device {
        struct i2o_device *i2o_dev;     /* pointer to I2O device */
        struct gendisk *gd;
-       spinlock_t lock;                /* queue lock */
+       spinlock_t lock;        /* queue lock */
        struct list_head open_queue;    /* list of transfered, but unfinished
                                           requests */
        unsigned int open_queue_depth;  /* number of requests in the queue */
 
-       int rcache;                     /* read cache flags */
-       int wcache;                     /* write cache flags */
+       int rcache;             /* read cache flags */
+       int wcache;             /* write cache flags */
        int flags;
-       int power;                      /* power state */
-       int media_change_flag;          /* media changed flag */
+       u16 power;              /* power state */
+       int media_change_flag;  /* media changed flag */
 };
 
 /* I2O Block device request */
-struct i2o_block_request
-{
+struct i2o_block_request {
        struct list_head queue;
-       struct request *req;            /* corresponding request */
+       struct request *req;    /* corresponding request */
        struct i2o_block_device *i2o_blk_dev;   /* I2O block device */
-       int sg_dma_direction;           /* direction of DMA buffer read/write */
-       int sg_nents;                   /* number of SG elements */
-       struct scatterlist sg_table[I2O_MAX_SEGMENTS]; /* SG table */
+       struct device *dev;     /* device used for DMA */
+       int sg_nents;           /* number of SG elements */
+       struct scatterlist sg_table[I2O_MAX_PHYS_SEGMENTS];     /* SG table */
 };
 
 /* I2O Block device delayed request */
-struct i2o_block_delayed_request
-{
+struct i2o_block_delayed_request {
        struct work_struct work;
        struct request_queue *queue;
 };
index 1fb5cdf67f8fa82e6245586bdf151da6a26d60a7..3c3a7abebb1bef7969a8737f1861055fbcd7c3e6 100644 (file)
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/i2o.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
 #include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <linux/spinlock.h>
 #include <linux/smp_lock.h>
-#include <linux/ioctl32.h>
 #include <linux/compat.h>
-#include <linux/syscalls.h>
 
 #include <asm/uaccess.h>
-#include <asm/io.h>
 
-#define OSM_NAME       "config-osm"
-#define OSM_VERSION    "$Rev$"
-#define OSM_DESCRIPTION        "I2O Configuration OSM"
+#include "core.h"
 
-extern int i2o_parm_issue(struct i2o_device *, int, void *, int, void *, int);
+#define SG_TABLESIZE           30
 
 static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
                         unsigned long arg);
@@ -80,15 +66,6 @@ struct i2o_cfg_info {
 static struct i2o_cfg_info *open_files = NULL;
 static ulong i2o_cfg_info_id = 0;
 
-/*
- *     Each of these describes an i2o message handler. They are
- *     multiplexed by the i2o_core code
- */
-
-static struct i2o_driver i2o_config_driver = {
-       .name = OSM_NAME
-};
-
 static int i2o_cfg_getiops(unsigned long arg)
 {
        struct i2o_controller *c;
@@ -391,9 +368,9 @@ static int i2o_cfg_swul(unsigned long arg)
 
        i2o_dma_free(&c->pdev->dev, &buffer);
 
-return_ret:
+      return_ret:
        return ret;
-return_fault:
+      return_fault:
        ret = -EFAULT;
        goto return_ret;
 };
@@ -540,8 +517,10 @@ static int i2o_cfg_evt_get(unsigned long arg, struct file *fp)
        return 0;
 }
 
+#ifdef CONFIG_I2O_EXT_ADAPTEC
 #ifdef CONFIG_COMPAT
-static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long arg)
+static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
+                             unsigned long arg)
 {
        struct i2o_cmd_passthru32 __user *cmd;
        struct i2o_controller *c;
@@ -555,6 +534,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
        u32 sg_offset = 0;
        u32 sg_count = 0;
        u32 i = 0;
+       u32 sg_index = 0;
        i2o_status_block *sb;
        struct i2o_message *msg;
        u32 m;
@@ -634,8 +614,8 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
                if (sg_count > SG_TABLESIZE) {
                        printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n",
                               c->name, sg_count);
-                       kfree(reply);
-                       return -EINVAL;
+                       rcode = -EINVAL;
+                       goto cleanup;
                }
 
                for (i = 0; i < sg_count; i++) {
@@ -651,7 +631,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
                                goto cleanup;
                        }
                        sg_size = sg[i].flag_count & 0xffffff;
-                       p = &(sg_list[i]);
+                       p = &(sg_list[sg_index++]);
                        /* Allocate memory for the transfer */
                        if (i2o_dma_alloc
                            (&c->pdev->dev, p, sg_size,
@@ -660,20 +640,21 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
                                       "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                       c->name, sg_size, i, sg_count);
                                rcode = -ENOMEM;
-                               goto cleanup;
+                               goto sg_list_cleanup;
                        }
                        /* Copy in the user's SG buffer if necessary */
                        if (sg[i].
                            flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) {
                                // TODO 64bit fix
                                if (copy_from_user
-                                   (p->virt, (void __user *)(unsigned long)sg[i].addr_bus,
-                                    sg_size)) {
+                                   (p->virt,
+                                    (void __user *)(unsigned long)sg[i].
+                                    addr_bus, sg_size)) {
                                        printk(KERN_DEBUG
                                               "%s: Could not copy SG buf %d FROM user\n",
                                               c->name, i);
                                        rcode = -EFAULT;
-                                       goto cleanup;
+                                       goto sg_list_cleanup;
                                }
                        }
                        //TODO 64bit fix
@@ -683,10 +664,10 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
 
        rcode = i2o_msg_post_wait(c, m, 60);
        if (rcode)
-               goto cleanup;
+               goto sg_list_cleanup;
 
        if (sg_offset) {
-               u32 msg[128];
+               u32 msg[I2O_OUTBOUND_MSG_FRAME_SIZE];
                /* Copy back the Scatter Gather buffers back to user space */
                u32 j;
                // TODO 64bit fix
@@ -694,18 +675,18 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
                int sg_size;
 
                // re-acquire the original message to handle correctly the sg copy operation
-               memset(&msg, 0, MSG_FRAME_SIZE * 4);
+               memset(&msg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);
                // get user msg size in u32s
                if (get_user(size, &user_msg[0])) {
                        rcode = -EFAULT;
-                       goto cleanup;
+                       goto sg_list_cleanup;
                }
                size = size >> 16;
                size *= 4;
                /* Copy in the user's I2O command */
                if (copy_from_user(msg, user_msg, size)) {
                        rcode = -EFAULT;
-                       goto cleanup;
+                       goto sg_list_cleanup;
                }
                sg_count =
                    (size - sg_offset * 4) / sizeof(struct sg_simple_element);
@@ -727,7 +708,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
                                               c->name, sg_list[j].virt,
                                               sg[j].addr_bus);
                                        rcode = -EFAULT;
-                                       goto cleanup;
+                                       goto sg_list_cleanup;
                                }
                        }
                }
@@ -741,6 +722,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
                               "%s: Could not copy message context FROM user\n",
                               c->name);
                        rcode = -EFAULT;
+                       goto sg_list_cleanup;
                }
                if (copy_to_user(user_reply, reply, reply_size)) {
                        printk(KERN_WARNING
@@ -749,16 +731,21 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
                }
        }
 
+      sg_list_cleanup:
+       for (i = 0; i < sg_index; i++)
+               i2o_dma_free(&c->pdev->dev, &sg_list[i]);
+
       cleanup:
        kfree(reply);
        return rcode;
 }
 
-static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd,
+                                unsigned long arg)
 {
        int ret;
-       lock_kernel();          
-       switch (cmd) { 
+       lock_kernel();
+       switch (cmd) {
        case I2OGETIOPS:
                ret = i2o_cfg_ioctl(NULL, file, cmd, arg);
                break;
@@ -862,8 +849,8 @@ static int i2o_cfg_passthru(unsigned long arg)
                if (sg_count > SG_TABLESIZE) {
                        printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n",
                               c->name, sg_count);
-                       kfree(reply);
-                       return -EINVAL;
+                       rcode = -EINVAL;
+                       goto cleanup;
                }
 
                for (i = 0; i < sg_count; i++) {
@@ -875,7 +862,7 @@ static int i2o_cfg_passthru(unsigned long arg)
                                       "%s:Bad SG element %d - not simple (%x)\n",
                                       c->name, i, sg[i].flag_count);
                                rcode = -EINVAL;
-                               goto cleanup;
+                               goto sg_list_cleanup;
                        }
                        sg_size = sg[i].flag_count & 0xffffff;
                        /* Allocate memory for the transfer */
@@ -885,7 +872,7 @@ static int i2o_cfg_passthru(unsigned long arg)
                                       "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                       c->name, sg_size, i, sg_count);
                                rcode = -ENOMEM;
-                               goto cleanup;
+                               goto sg_list_cleanup;
                        }
                        sg_list[sg_index++] = p;        // sglist indexed with input frame, not our internal frame.
                        /* Copy in the user's SG buffer if necessary */
@@ -899,7 +886,7 @@ static int i2o_cfg_passthru(unsigned long arg)
                                               "%s: Could not copy SG buf %d FROM user\n",
                                               c->name, i);
                                        rcode = -EFAULT;
-                                       goto cleanup;
+                                       goto sg_list_cleanup;
                                }
                        }
                        //TODO 64bit fix
@@ -909,7 +896,7 @@ static int i2o_cfg_passthru(unsigned long arg)
 
        rcode = i2o_msg_post_wait(c, m, 60);
        if (rcode)
-               goto cleanup;
+               goto sg_list_cleanup;
 
        if (sg_offset) {
                u32 msg[128];
@@ -920,18 +907,18 @@ static int i2o_cfg_passthru(unsigned long arg)
                int sg_size;
 
                // re-acquire the original message to handle correctly the sg copy operation
-               memset(&msg, 0, MSG_FRAME_SIZE * 4);
+               memset(&msg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);
                // get user msg size in u32s
                if (get_user(size, &user_msg[0])) {
                        rcode = -EFAULT;
-                       goto cleanup;
+                       goto sg_list_cleanup;
                }
                size = size >> 16;
                size *= 4;
                /* Copy in the user's I2O command */
                if (copy_from_user(msg, user_msg, size)) {
                        rcode = -EFAULT;
-                       goto cleanup;
+                       goto sg_list_cleanup;
                }
                sg_count =
                    (size - sg_offset * 4) / sizeof(struct sg_simple_element);
@@ -953,7 +940,7 @@ static int i2o_cfg_passthru(unsigned long arg)
                                               c->name, sg_list[j],
                                               sg[j].addr_bus);
                                        rcode = -EFAULT;
-                                       goto cleanup;
+                                       goto sg_list_cleanup;
                                }
                        }
                }
@@ -975,10 +962,15 @@ static int i2o_cfg_passthru(unsigned long arg)
                }
        }
 
+      sg_list_cleanup:
+       for (i = 0; i < sg_index; i++)
+               kfree(sg_list[i]);
+
       cleanup:
        kfree(reply);
        return rcode;
 }
+#endif
 
 /*
  * IOCTL Handler
@@ -1033,9 +1025,11 @@ static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
                ret = i2o_cfg_evt_get(arg, fp);
                break;
 
+#ifdef CONFIG_I2O_EXT_ADAPTEC
        case I2OPASSTHRU:
                ret = i2o_cfg_passthru(arg);
                break;
+#endif
 
        default:
                osm_debug("unknown ioctl called!\n");
@@ -1137,37 +1131,21 @@ static struct miscdevice i2o_miscdev = {
        &config_fops
 };
 
-static int __init i2o_config_init(void)
+static int __init i2o_config_old_init(void)
 {
-       printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
-
        spin_lock_init(&i2o_config_lock);
 
        if (misc_register(&i2o_miscdev) < 0) {
                osm_err("can't register device.\n");
                return -EBUSY;
        }
-       /*
-        *      Install our handler
-        */
-       if (i2o_driver_register(&i2o_config_driver)) {
-               osm_err("handler register failed.\n");
-               misc_deregister(&i2o_miscdev);
-               return -EBUSY;
-       }
+
        return 0;
 }
 
-static void i2o_config_exit(void)
+static void i2o_config_old_exit(void)
 {
        misc_deregister(&i2o_miscdev);
-       i2o_driver_unregister(&i2o_config_driver);
 }
 
 MODULE_AUTHOR("Red Hat Software");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(OSM_DESCRIPTION);
-MODULE_VERSION(OSM_VERSION);
-
-module_init(i2o_config_init);
-module_exit(i2o_config_exit);
index b176d0eeff7f05934874a22fea6081c0752fb30d..d559a1758363bd2ee49ed5ac4baeae7eb6f93c8c 100644 (file)
@@ -28,7 +28,7 @@
  */
 
 #define OSM_NAME       "proc-osm"
-#define OSM_VERSION    "$Rev$"
+#define OSM_VERSION    "1.145"
 #define OSM_DESCRIPTION        "I2O ProcFS OSM"
 
 #define I2O_MAX_MODULES 4
@@ -228,7 +228,7 @@ static const char *i2o_get_class_name(int class)
        case I2O_CLASS_FLOPPY_DEVICE:
                idx = 12;
                break;
-       case I2O_CLASS_BUS_ADAPTER_PORT:
+       case I2O_CLASS_BUS_ADAPTER:
                idx = 13;
                break;
        case I2O_CLASS_PEER_TRANSPORT_AGENT:
@@ -490,7 +490,7 @@ static int i2o_seq_show_lct(struct seq_file *seq, void *v)
                                seq_printf(seq, ", Unknown Device Type");
                        break;
 
-               case I2O_CLASS_BUS_ADAPTER_PORT:
+               case I2O_CLASS_BUS_ADAPTER:
                        if (lct->lct_entry[i].sub_class < BUS_TABLE_SIZE)
                                seq_printf(seq, ", %s",
                                           bus_ports[lct->lct_entry[i].
index 43f5875e0be54b821e980b1421fbe09c4b511f1e..9f1744c3933b8b258b61128d83577e6a188c11bd 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/pci.h>
 #include <linux/blkdev.h>
 #include <linux/i2o.h>
+#include <linux/scatterlist.h>
 
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_request.h>
+#include <scsi/sg.h>
+#include <scsi/sg_request.h>
 
 #define OSM_NAME       "scsi-osm"
-#define OSM_VERSION    "$Rev$"
+#define OSM_VERSION    "1.282"
 #define OSM_DESCRIPTION        "I2O SCSI Peripheral OSM"
 
 static struct i2o_driver i2o_scsi_driver;
 
-static int i2o_scsi_max_id = 16;
-static int i2o_scsi_max_lun = 8;
+static unsigned int i2o_scsi_max_id = 16;
+static unsigned int i2o_scsi_max_lun = 255;
 
 struct i2o_scsi_host {
        struct Scsi_Host *scsi_host;    /* pointer to the SCSI host */
        struct i2o_controller *iop;     /* pointer to the I2O controller */
+       unsigned int lun;       /* lun's used for block devices */
        struct i2o_device *channel[0];  /* channel->i2o_dev mapping table */
 };
 
@@ -99,11 +104,17 @@ static struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c)
        u8 type;
        int i;
        size_t size;
-       i2o_status_block *sb;
+       u16 body_size = 6;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+       if (c->adaptec)
+               body_size = 8;
+#endif
 
        list_for_each_entry(i2o_dev, &c->devices, list)
-           if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER_PORT) {
-               if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) || (type == 1))    /* SCSI bus */
+           if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
+               if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
+                   && (type == 0x01))  /* SCSI bus */
                        max_channel++;
        }
 
@@ -125,20 +136,18 @@ static struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c)
        scsi_host->max_id = i2o_scsi_max_id;
        scsi_host->max_lun = i2o_scsi_max_lun;
        scsi_host->this_id = c->unit;
-
-       sb = c->status_block.virt;
-
-       scsi_host->sg_tablesize = (sb->inbound_frame_size -
-                                  sizeof(struct i2o_message) / 4 - 6) / 2;
+       scsi_host->sg_tablesize = i2o_sg_tablesize(c, body_size);
 
        i2o_shost = (struct i2o_scsi_host *)scsi_host->hostdata;
        i2o_shost->scsi_host = scsi_host;
        i2o_shost->iop = c;
+       i2o_shost->lun = 1;
 
        i = 0;
        list_for_each_entry(i2o_dev, &c->devices, list)
-           if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER_PORT) {
-               if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) || (type == 1))    /* only SCSI bus */
+           if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
+               if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
+                   && (type == 0x01))  /* only SCSI bus */
                        i2o_shost->channel[i++] = i2o_dev;
 
                if (i >= max_channel)
@@ -178,10 +187,13 @@ static int i2o_scsi_remove(struct device *dev)
        struct i2o_scsi_host *i2o_shost;
        struct scsi_device *scsi_dev;
 
+       osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid);
+
        i2o_shost = i2o_scsi_get_host(c);
 
        shost_for_each_device(scsi_dev, i2o_shost->scsi_host)
            if (scsi_dev->hostdata == i2o_dev) {
+               sysfs_remove_link(&i2o_dev->device.kobj, "scsi");
                scsi_remove_device(scsi_dev);
                scsi_device_put(scsi_dev);
                break;
@@ -207,8 +219,8 @@ static int i2o_scsi_probe(struct device *dev)
        struct Scsi_Host *scsi_host;
        struct i2o_device *parent;
        struct scsi_device *scsi_dev;
-       u32 id;
-       u64 lun;
+       u32 id = -1;
+       u64 lun = -1;
        int channel = -1;
        int i;
 
@@ -218,8 +230,56 @@ static int i2o_scsi_probe(struct device *dev)
 
        scsi_host = i2o_shost->scsi_host;
 
-       if (i2o_parm_field_get(i2o_dev, 0, 3, &id, 4) < 0)
+       switch (i2o_dev->lct_data.class_id) {
+       case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+       case I2O_CLASS_EXECUTIVE:
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+               if (c->adaptec) {
+                       u8 type;
+                       struct i2o_device *d = i2o_shost->channel[0];
+
+                       if (i2o_parm_field_get(d, 0x0000, 0, &type, 1)
+                           && (type == 0x01))  /* SCSI bus */
+                               if (i2o_parm_field_get(d, 0x0200, 4, &id, 4)) {
+                                       channel = 0;
+                                       if (i2o_dev->lct_data.class_id ==
+                                           I2O_CLASS_RANDOM_BLOCK_STORAGE)
+                                               lun = i2o_shost->lun++;
+                                       else
+                                               lun = 0;
+                               }
+               }
+#endif
+               break;
+
+       case I2O_CLASS_SCSI_PERIPHERAL:
+               if (i2o_parm_field_get(i2o_dev, 0x0000, 3, &id, 4) < 0)
+                       return -EFAULT;
+
+               if (i2o_parm_field_get(i2o_dev, 0x0000, 4, &lun, 8) < 0)
+                       return -EFAULT;
+
+               parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid);
+               if (!parent) {
+                       osm_warn("can not find parent of device %03x\n",
+                                i2o_dev->lct_data.tid);
+                       return -EFAULT;
+               }
+
+               for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++)
+                       if (i2o_shost->channel[i] == parent)
+                               channel = i;
+               break;
+
+       default:
                return -EFAULT;
+       }
+
+       if (channel == -1) {
+               osm_warn("can not find channel of device %03x\n",
+                        i2o_dev->lct_data.tid);
+               return -EFAULT;
+       }
 
        if (id >= scsi_host->max_id) {
                osm_warn("SCSI device id (%d) >= max_id of I2O host (%d)", id,
@@ -227,42 +287,26 @@ static int i2o_scsi_probe(struct device *dev)
                return -EFAULT;
        }
 
-       if (i2o_parm_field_get(i2o_dev, 0, 4, &lun, 8) < 0)
-               return -EFAULT;
        if (lun >= scsi_host->max_lun) {
                osm_warn("SCSI device id (%d) >= max_lun of I2O host (%d)",
                         (unsigned int)lun, scsi_host->max_lun);
                return -EFAULT;
        }
 
-       parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid);
-       if (!parent) {
-               osm_warn("can not find parent of device %03x\n",
-                        i2o_dev->lct_data.tid);
-               return -EFAULT;
-       }
-
-       for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++)
-               if (i2o_shost->channel[i] == parent)
-                       channel = i;
-
-       if (channel == -1) {
-               osm_warn("can not find channel of device %03x\n",
-                        i2o_dev->lct_data.tid);
-               return -EFAULT;
-       }
-
        scsi_dev =
            __scsi_add_device(i2o_shost->scsi_host, channel, id, lun, i2o_dev);
 
-       if (!scsi_dev) {
+       if (IS_ERR(scsi_dev)) {
                osm_warn("can not add SCSI device %03x\n",
                         i2o_dev->lct_data.tid);
-               return -EFAULT;
+               return PTR_ERR(scsi_dev);
        }
 
-       osm_debug("added new SCSI device %03x (cannel: %d, id: %d, lun: %d)\n",
-                 i2o_dev->lct_data.tid, channel, id, (unsigned int)lun);
+       sysfs_create_link(&i2o_dev->device.kobj, &scsi_dev->sdev_gendev.kobj,
+                         "scsi");
+
+       osm_info("device added (TID: %03x) channel: %d, id: %d, lun: %d\n",
+                i2o_dev->lct_data.tid, channel, id, (unsigned int)lun);
 
        return 0;
 };
@@ -293,162 +337,89 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m,
                          struct i2o_message *msg)
 {
        struct scsi_cmnd *cmd;
+       u32 error;
        struct device *dev;
-       u8 as, ds, st;
 
        cmd = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
-
-       if (msg->u.head[0] & (1 << 13)) {
-               struct i2o_message __iomem *pmsg;       /* preserved message */
-               u32 pm;
-               int err = DID_ERROR;
-
-               pm = le32_to_cpu(msg->body[3]);
-
-               pmsg = i2o_msg_in_to_virt(c, pm);
-
-               osm_err("IOP fail.\n");
-               osm_err("From %d To %d Cmd %d.\n",
-                       (msg->u.head[1] >> 12) & 0xFFF,
-                       msg->u.head[1] & 0xFFF, msg->u.head[1] >> 24);
-               osm_err("Failure Code %d.\n", msg->body[0] >> 24);
-               if (msg->body[0] & (1 << 16))
-                       osm_err("Format error.\n");
-               if (msg->body[0] & (1 << 17))
-                       osm_err("Path error.\n");
-               if (msg->body[0] & (1 << 18))
-                       osm_err("Path State.\n");
-               if (msg->body[0] & (1 << 18))
-               {
-                       osm_err("Congestion.\n");
-                       err = DID_BUS_BUSY;
-               }
-
-               osm_debug("Failing message is %p.\n", pmsg);
-
-               cmd = i2o_cntxt_list_get(c, readl(&pmsg->u.s.tcntxt));
-               if (!cmd)
-                       return 1;
-
-               cmd->result = err << 16;
-               cmd->scsi_done(cmd);
-
-               /* Now flush the message by making it a NOP */
-               i2o_msg_nop(c, pm);
-
-               return 1;
+       if (unlikely(!cmd)) {
+               osm_err("NULL reply received!\n");
+               return -1;
        }
 
        /*
         *      Low byte is device status, next is adapter status,
         *      (then one byte reserved), then request status.
         */
-       ds = (u8) le32_to_cpu(msg->body[0]);
-       as = (u8) (le32_to_cpu(msg->body[0]) >> 8);
-       st = (u8) (le32_to_cpu(msg->body[0]) >> 24);
+       error = le32_to_cpu(msg->body[0]);
+
+       osm_debug("Completed %ld\n", cmd->serial_number);
 
+       cmd->result = error & 0xff;
        /*
-        *      Is this a control request coming back - eg an abort ?
+        * if DeviceStatus is not SCSI_SUCCESS copy over the sense data and let
+        * the SCSI layer handle the error
         */
+       if (cmd->result)
+               memcpy(cmd->sense_buffer, &msg->body[3],
+                      min(sizeof(cmd->sense_buffer), (size_t) 40));
 
-       if (!cmd) {
-               if (st)
-                       osm_warn("SCSI abort: %08X", le32_to_cpu(msg->body[0]));
-               osm_info("SCSI abort completed.\n");
-               return -EFAULT;
-       }
+       /* only output error code if AdapterStatus is not HBA_SUCCESS */
+       if ((error >> 8) & 0xff)
+               osm_err("SCSI error %08x\n", error);
 
-       osm_debug("Completed %ld\n", cmd->serial_number);
+       dev = &c->pdev->dev;
+       if (cmd->use_sg)
+               dma_unmap_sg(dev, cmd->request_buffer, cmd->use_sg,
+                            cmd->sc_data_direction);
+       else if (cmd->SCp.dma_handle)
+               dma_unmap_single(dev, cmd->SCp.dma_handle, cmd->request_bufflen,
+                                cmd->sc_data_direction);
 
-       if (st) {
-               u32 count, error;
-               /* An error has occurred */
-
-               switch (st) {
-               case 0x06:
-                       count = le32_to_cpu(msg->body[1]);
-                       if (count < cmd->underflow) {
-                               int i;
-
-                               osm_err("SCSI underflow 0x%08X 0x%08X\n", count,
-                                       cmd->underflow);
-                               osm_debug("Cmd: ");
-                               for (i = 0; i < 15; i++)
-                                       pr_debug("%02X ", cmd->cmnd[i]);
-                               pr_debug(".\n");
-                               cmd->result = (DID_ERROR << 16);
-                       }
-                       break;
+       cmd->scsi_done(cmd);
 
-               default:
-                       error = le32_to_cpu(msg->body[0]);
-
-                       osm_err("SCSI error %08x\n", error);
-
-                       if ((error & 0xff) == 0x02 /*CHECK_CONDITION */ ) {
-                               int i;
-                               u32 len = sizeof(cmd->sense_buffer);
-                               len = (len > 40) ? 40 : len;
-                               // Copy over the sense data
-                               memcpy(cmd->sense_buffer, (void *)&msg->body[3],
-                                      len);
-                               for (i = 0; i <= len; i++)
-                                       osm_info("%02x\n",
-                                                cmd->sense_buffer[i]);
-                               if (cmd->sense_buffer[0] == 0x70
-                                   && cmd->sense_buffer[2] == DATA_PROTECT) {
-                                       /* This is to handle an array failed */
-                                       cmd->result = (DID_TIME_OUT << 16);
-                                       printk(KERN_WARNING "%s: SCSI Data "
-                                              "Protect-Device (%d,%d,%d) "
-                                              "hba_status=0x%x, dev_status="
-                                              "0x%x, cmd=0x%x\n", c->name,
-                                              (u32) cmd->device->channel,
-                                              (u32) cmd->device->id,
-                                              (u32) cmd->device->lun,
-                                              (error >> 8) & 0xff,
-                                              error & 0xff, cmd->cmnd[0]);
-                               } else
-                                       cmd->result = (DID_ERROR << 16);
-
-                               break;
-                       }
-
-                       switch (as) {
-                       case 0x0E:
-                               /* SCSI Reset */
-                               cmd->result = DID_RESET << 16;
-                               break;
-
-                       case 0x0F:
-                               cmd->result = DID_PARITY << 16;
-                               break;
-
-                       default:
-                               cmd->result = DID_ERROR << 16;
-                               break;
-                       }
+       return 1;
+};
 
-                       break;
-               }
+/**
+ *     i2o_scsi_notify_device_add - Retrieve notifications of added devices
+ *     @i2o_dev: the I2O device which was added
+ *
+ *     If a I2O device is added we catch the notification, because I2O classes
+ *     other then SCSI peripheral will not be received through
+ *     i2o_scsi_probe().
+ */
+static void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev)
+{
+       switch (i2o_dev->lct_data.class_id) {
+       case I2O_CLASS_EXECUTIVE:
+       case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+               i2o_scsi_probe(&i2o_dev->device);
+               break;
 
-               cmd->scsi_done(cmd);
-               return 1;
+       default:
+               break;
        }
+};
 
-       cmd->result = DID_OK << 16 | ds;
-
-       cmd->scsi_done(cmd);
-
-       dev = &c->pdev->dev;
-       if (cmd->use_sg)
-               dma_unmap_sg(dev, (struct scatterlist *)cmd->buffer,
-                            cmd->use_sg, cmd->sc_data_direction);
-       else if (cmd->request_bufflen)
-               dma_unmap_single(dev, (dma_addr_t) ((long)cmd->SCp.ptr),
-                                cmd->request_bufflen, cmd->sc_data_direction);
+/**
+ *     i2o_scsi_notify_device_remove - Retrieve notifications of removed
+ *                                     devices
+ *     @i2o_dev: the I2O device which was removed
+ *
+ *     If a I2O device is removed, we catch the notification to remove the
+ *     corresponding SCSI device.
+ */
+static void i2o_scsi_notify_device_remove(struct i2o_device *i2o_dev)
+{
+       switch (i2o_dev->lct_data.class_id) {
+       case I2O_CLASS_EXECUTIVE:
+       case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+               i2o_scsi_remove(&i2o_dev->device);
+               break;
 
-       return 1;
+       default:
+               break;
+       }
 };
 
 /**
@@ -501,7 +472,7 @@ static void i2o_scsi_notify_controller_remove(struct i2o_controller *c)
 
        scsi_remove_host(i2o_shost->scsi_host);
        scsi_host_put(i2o_shost->scsi_host);
-       pr_info("I2O SCSI host removed\n");
+       osm_debug("I2O SCSI host removed\n");
 };
 
 /* SCSI OSM driver struct */
@@ -509,6 +480,8 @@ static struct i2o_driver i2o_scsi_driver = {
        .name = OSM_NAME,
        .reply = i2o_scsi_reply,
        .classes = i2o_scsi_class_id,
+       .notify_device_add = i2o_scsi_notify_device_add,
+       .notify_device_remove = i2o_scsi_notify_device_remove,
        .notify_controller_add = i2o_scsi_notify_controller_add,
        .notify_controller_remove = i2o_scsi_notify_controller_remove,
        .driver = {
@@ -535,26 +508,26 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
                                 void (*done) (struct scsi_cmnd *))
 {
        struct i2o_controller *c;
-       struct Scsi_Host *host;
        struct i2o_device *i2o_dev;
-       struct device *dev;
        int tid;
        struct i2o_message __iomem *msg;
        u32 m;
-       u32 scsi_flags, sg_flags;
+       /*
+        * ENABLE_DISCONNECT
+        * SIMPLE_TAG
+        * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
+        */
+       u32 scsi_flags = 0x20a00000;
+       u32 sgl_offset;
        u32 __iomem *mptr;
-       u32 __iomem *lenptr;
-       u32 len, reqlen;
-       int i;
+       u32 cmd = I2O_CMD_SCSI_EXEC << 24;
+       int rc = 0;
 
        /*
         *      Do the incoming paperwork
         */
-
        i2o_dev = SCpnt->device->hostdata;
-       host = SCpnt->device->host;
        c = i2o_dev->iop;
-       dev = &c->pdev->dev;
 
        SCpnt->scsi_done = done;
 
@@ -562,7 +535,7 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
                osm_warn("no I2O device in request\n");
                SCpnt->result = DID_NO_CONNECT << 16;
                done(SCpnt);
-               return 0;
+               goto exit;
        }
 
        tid = i2o_dev->lct_data.tid;
@@ -570,45 +543,86 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
        osm_debug("qcmd: Tid = %03x\n", tid);
        osm_debug("Real scsi messages.\n");
 
-       /*
-        *      Obtain an I2O message. If there are none free then
-        *      throw it back to the scsi layer
-        */
-
-       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
-       if (m == I2O_QUEUE_EMPTY)
-               return SCSI_MLQUEUE_HOST_BUSY;
-
        /*
         *      Put together a scsi execscb message
         */
-
-       len = SCpnt->request_bufflen;
-
        switch (SCpnt->sc_data_direction) {
        case PCI_DMA_NONE:
-               scsi_flags = 0x00000000;        // DATA NO XFER
-               sg_flags = 0x00000000;
+               /* DATA NO XFER */
+               sgl_offset = SGL_OFFSET_0;
                break;
 
        case PCI_DMA_TODEVICE:
-               scsi_flags = 0x80000000;        // DATA OUT (iop-->dev)
-               sg_flags = 0x14000000;
+               /* DATA OUT (iop-->dev) */
+               scsi_flags |= 0x80000000;
+               sgl_offset = SGL_OFFSET_10;
                break;
 
        case PCI_DMA_FROMDEVICE:
-               scsi_flags = 0x40000000;        // DATA IN  (iop<--dev)
-               sg_flags = 0x10000000;
+               /* DATA IN  (iop<--dev) */
+               scsi_flags |= 0x40000000;
+               sgl_offset = SGL_OFFSET_10;
                break;
 
        default:
                /* Unknown - kill the command */
                SCpnt->result = DID_NO_CONNECT << 16;
                done(SCpnt);
-               return 0;
+               goto exit;
        }
 
-       writel(I2O_CMD_SCSI_EXEC << 24 | HOST_TID << 12 | tid, &msg->u.head[1]);
+       /*
+        *      Obtain an I2O message. If there are none free then
+        *      throw it back to the scsi layer
+        */
+
+       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+       if (m == I2O_QUEUE_EMPTY) {
+               rc = SCSI_MLQUEUE_HOST_BUSY;
+               goto exit;
+       }
+
+       mptr = &msg->body[0];
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+       if (c->adaptec) {
+               u32 adpt_flags = 0;
+
+               if (SCpnt->sc_request && SCpnt->sc_request->upper_private_data) {
+                       i2o_sg_io_hdr_t __user *usr_ptr =
+                           ((Sg_request *) (SCpnt->sc_request->
+                                            upper_private_data))->header.
+                           usr_ptr;
+
+                       if (usr_ptr)
+                               get_user(adpt_flags, &usr_ptr->flags);
+               }
+
+               switch (i2o_dev->lct_data.class_id) {
+               case I2O_CLASS_EXECUTIVE:
+               case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+                       /* interpret flag has to be set for executive */
+                       adpt_flags ^= I2O_DPT_SG_FLAG_INTERPRET;
+                       break;
+
+               default:
+                       break;
+               }
+
+               /*
+                * for Adaptec controllers we use the PRIVATE command, because
+                * the normal SCSI EXEC doesn't support all SCSI commands on
+                * all controllers (for example READ CAPACITY).
+                */
+               if (sgl_offset == SGL_OFFSET_10)
+                       sgl_offset = SGL_OFFSET_12;
+               cmd = I2O_CMD_PRIVATE << 24;
+               writel(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC, mptr++);
+               writel(adpt_flags | tid, mptr++);
+       }
+#endif
+
+       writel(cmd | HOST_TID << 12 | tid, &msg->u.head[1]);
        writel(i2o_scsi_driver.context, &msg->u.s.icntxt);
 
        /* We want the SCSI control block back */
@@ -626,7 +640,7 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
         */
 
        /* Attach tags to the devices */
-       /*
+       /* FIXME: implement
           if(SCpnt->device->tagged_supported) {
           if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
           scsi_flags |= 0x01000000;
@@ -635,67 +649,35 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
           }
         */
 
-       /* Direction, disconnect ok, tag, CDBLen */
-       writel(scsi_flags | 0x20200000 | SCpnt->cmd_len, &msg->body[0]);
-
-       mptr = &msg->body[1];
+       writel(scsi_flags | SCpnt->cmd_len, mptr++);
 
        /* Write SCSI command into the message - always 16 byte block */
        memcpy_toio(mptr, SCpnt->cmnd, 16);
        mptr += 4;
-       lenptr = mptr++;        /* Remember me - fill in when we know */
-
-       reqlen = 12;            // SINGLE SGE
-
-       /* Now fill in the SGList and command */
-       if (SCpnt->use_sg) {
-               struct scatterlist *sg;
-               int sg_count;
-
-               sg = SCpnt->request_buffer;
-               len = 0;
-
-               sg_count = dma_map_sg(dev, sg, SCpnt->use_sg,
-                                     SCpnt->sc_data_direction);
 
-               if (unlikely(sg_count <= 0))
-                       return -ENOMEM;
-
-               for (i = SCpnt->use_sg; i > 0; i--) {
-                       if (i == 1)
-                               sg_flags |= 0xC0000000;
-                       writel(sg_flags | sg_dma_len(sg), mptr++);
-                       writel(sg_dma_address(sg), mptr++);
-                       len += sg_dma_len(sg);
-                       sg++;
+       if (sgl_offset != SGL_OFFSET_0) {
+               /* write size of data addressed by SGL */
+               writel(SCpnt->request_bufflen, mptr++);
+
+               /* Now fill in the SGList and command */
+               if (SCpnt->use_sg) {
+                       if (!i2o_dma_map_sg(c, SCpnt->request_buffer,
+                                           SCpnt->use_sg,
+                                           SCpnt->sc_data_direction, &mptr))
+                               goto nomem;
+               } else {
+                       SCpnt->SCp.dma_handle =
+                           i2o_dma_map_single(c, SCpnt->request_buffer,
+                                              SCpnt->request_bufflen,
+                                              SCpnt->sc_data_direction, &mptr);
+                       if (dma_mapping_error(SCpnt->SCp.dma_handle))
+                               goto nomem;
                }
-
-               reqlen = mptr - &msg->u.head[0];
-               writel(len, lenptr);
-       } else {
-               len = SCpnt->request_bufflen;
-
-               writel(len, lenptr);
-
-               if (len > 0) {
-                       dma_addr_t dma_addr;
-
-                       dma_addr = dma_map_single(dev, SCpnt->request_buffer,
-                                                 SCpnt->request_bufflen,
-                                                 SCpnt->sc_data_direction);
-                       if (!dma_addr)
-                               return -ENOMEM;
-
-                       SCpnt->SCp.ptr = (void *)(unsigned long)dma_addr;
-                       sg_flags |= 0xC0000000;
-                       writel(sg_flags | SCpnt->request_bufflen, mptr++);
-                       writel(dma_addr, mptr++);
-               } else
-                       reqlen = 9;
        }
 
        /* Stick the headers on */
-       writel(reqlen << 16 | SGL_OFFSET_10, &msg->u.head[0]);
+       writel(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) | sgl_offset,
+              &msg->u.head[0]);
 
        /* Queue the message */
        i2o_msg_post(c, m);
@@ -703,6 +685,13 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
        osm_debug("Issued %ld\n", SCpnt->serial_number);
 
        return 0;
+
+      nomem:
+       rc = -ENOMEM;
+       i2o_msg_nop(c, m);
+
+      exit:
+       return rc;
 };
 
 /**
index 50c8cedf7a2db58fd670b851849a646579f72ab1..42f8b810d6e57f8545a61ccfc2e0019a68cd3ddb 100644 (file)
 #include <linux/module.h>
 #include <linux/i2o.h>
 #include <linux/delay.h>
+#include "core.h"
 
-#define OSM_VERSION    "$Rev$"
+#define OSM_NAME       "i2o"
+#define OSM_VERSION    "1.288"
 #define OSM_DESCRIPTION        "I2O subsystem"
 
 /* global I2O controller list */
@@ -43,20 +45,6 @@ static struct i2o_dma i2o_systab;
 
 static int i2o_hrt_get(struct i2o_controller *c);
 
-/* Module internal functions from other sources */
-extern struct i2o_driver i2o_exec_driver;
-extern int i2o_exec_lct_get(struct i2o_controller *);
-extern void i2o_device_remove(struct i2o_device *);
-
-extern int __init i2o_driver_init(void);
-extern void __exit i2o_driver_exit(void);
-extern int __init i2o_exec_init(void);
-extern void __exit i2o_exec_exit(void);
-extern int __init i2o_pci_init(void);
-extern void __exit i2o_pci_exit(void);
-extern int i2o_device_init(void);
-extern void i2o_device_exit(void);
-
 /**
  *     i2o_msg_nop - Returns a message which is not used
  *     @c: I2O controller from which the message was created
@@ -68,7 +56,7 @@ extern void i2o_device_exit(void);
  */
 void i2o_msg_nop(struct i2o_controller *c, u32 m)
 {
-       struct i2o_message __iomem *msg = c->in_queue.virt + m;
+       struct i2o_message __iomem *msg = i2o_msg_in_to_virt(c, m);
 
        writel(THREE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
        writel(I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | ADAPTER_TID,
@@ -92,16 +80,16 @@ void i2o_msg_nop(struct i2o_controller *c, u32 m)
  *     address from the read port (see the i2o spec). If no message is
  *     available returns I2O_QUEUE_EMPTY and msg is leaved untouched.
  */
-u32 i2o_msg_get_wait(struct i2o_controller *c, struct i2o_message __iomem **msg,
-                    int wait)
+u32 i2o_msg_get_wait(struct i2o_controller *c,
+                    struct i2o_message __iomem ** msg, int wait)
 {
        unsigned long timeout = jiffies + wait * HZ;
        u32 m;
 
        while ((m = i2o_msg_get(c, msg)) == I2O_QUEUE_EMPTY) {
                if (time_after(jiffies, timeout)) {
-                       pr_debug("%s: Timeout waiting for message frame.\n",
-                                c->name);
+                       osm_debug("%s: Timeout waiting for message frame.\n",
+                                 c->name);
                        return I2O_QUEUE_EMPTY;
                }
                set_current_state(TASK_UNINTERRUPTIBLE);
@@ -129,13 +117,13 @@ u32 i2o_cntxt_list_add(struct i2o_controller * c, void *ptr)
        unsigned long flags;
 
        if (!ptr)
-               printk(KERN_ERR "%s: couldn't add NULL pointer to context list!"
-                      "\n", c->name);
+               osm_err("%s: couldn't add NULL pointer to context list!\n",
+                       c->name);
 
        entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
        if (!entry) {
-               printk(KERN_ERR "%s: Could not allocate memory for context "
-                      "list element\n", c->name);
+               osm_err("%s: Could not allocate memory for context list element"
+                       "\n", c->name);
                return 0;
        }
 
@@ -154,7 +142,7 @@ u32 i2o_cntxt_list_add(struct i2o_controller * c, void *ptr)
 
        spin_unlock_irqrestore(&c->context_list_lock, flags);
 
-       pr_debug("%s: Add context to list %p -> %d\n", c->name, ptr, context);
+       osm_debug("%s: Add context to list %p -> %d\n", c->name, ptr, context);
 
        return entry->context;
 };
@@ -186,11 +174,11 @@ u32 i2o_cntxt_list_remove(struct i2o_controller * c, void *ptr)
        spin_unlock_irqrestore(&c->context_list_lock, flags);
 
        if (!context)
-               printk(KERN_WARNING "%s: Could not remove nonexistent ptr "
-                      "%p\n", c->name, ptr);
+               osm_warn("%s: Could not remove nonexistent ptr %p\n", c->name,
+                        ptr);
 
-       pr_debug("%s: remove ptr from context list %d -> %p\n", c->name,
-                context, ptr);
+       osm_debug("%s: remove ptr from context list %d -> %p\n", c->name,
+                 context, ptr);
 
        return context;
 };
@@ -220,11 +208,10 @@ void *i2o_cntxt_list_get(struct i2o_controller *c, u32 context)
        spin_unlock_irqrestore(&c->context_list_lock, flags);
 
        if (!ptr)
-               printk(KERN_WARNING "%s: context id %d not found\n", c->name,
-                      context);
+               osm_warn("%s: context id %d not found\n", c->name, context);
 
-       pr_debug("%s: get ptr from context list %d -> %p\n", c->name, context,
-                ptr);
+       osm_debug("%s: get ptr from context list %d -> %p\n", c->name, context,
+                 ptr);
 
        return ptr;
 };
@@ -252,11 +239,11 @@ u32 i2o_cntxt_list_get_ptr(struct i2o_controller * c, void *ptr)
        spin_unlock_irqrestore(&c->context_list_lock, flags);
 
        if (!context)
-               printk(KERN_WARNING "%s: Could not find nonexistent ptr "
-                      "%p\n", c->name, ptr);
+               osm_warn("%s: Could not find nonexistent ptr %p\n", c->name,
+                        ptr);
 
-       pr_debug("%s: get context id from context list %p -> %d\n", c->name,
-                ptr, context);
+       osm_debug("%s: get context id from context list %p -> %d\n", c->name,
+                 ptr, context);
 
        return context;
 };
@@ -336,10 +323,9 @@ static int i2o_iop_quiesce(struct i2o_controller *c)
 
        /* Long timeout needed for quiesce if lots of devices */
        if ((rc = i2o_msg_post_wait(c, m, 240)))
-               printk(KERN_INFO "%s: Unable to quiesce (status=%#x).\n",
-                      c->name, -rc);
+               osm_info("%s: Unable to quiesce (status=%#x).\n", c->name, -rc);
        else
-               pr_debug("%s: Quiesced.\n", c->name);
+               osm_debug("%s: Quiesced.\n", c->name);
 
        i2o_status_get(c);      // Entered READY state
 
@@ -377,10 +363,9 @@ static int i2o_iop_enable(struct i2o_controller *c)
 
        /* How long of a timeout do we need? */
        if ((rc = i2o_msg_post_wait(c, m, 240)))
-               printk(KERN_ERR "%s: Could not enable (status=%#x).\n",
-                      c->name, -rc);
+               osm_err("%s: Could not enable (status=%#x).\n", c->name, -rc);
        else
-               pr_debug("%s: Enabled.\n", c->name);
+               osm_debug("%s: Enabled.\n", c->name);
 
        i2o_status_get(c);      // entered OPERATIONAL state
 
@@ -444,19 +429,77 @@ static int i2o_iop_clear(struct i2o_controller *c)
               &msg->u.head[1]);
 
        if ((rc = i2o_msg_post_wait(c, m, 30)))
-               printk(KERN_INFO "%s: Unable to clear (status=%#x).\n",
-                      c->name, -rc);
+               osm_info("%s: Unable to clear (status=%#x).\n", c->name, -rc);
        else
-               pr_debug("%s: Cleared.\n", c->name);
+               osm_debug("%s: Cleared.\n", c->name);
 
        /* Enable all IOPs */
        i2o_iop_enable_all();
 
-       i2o_status_get(c);
-
        return rc;
 }
 
+/**
+ *     i2o_iop_init_outbound_queue - setup the outbound message queue
+ *     @c: I2O controller
+ *
+ *     Clear and (re)initialize IOP's outbound queue and post the message
+ *     frames to the IOP.
+ *
+ *     Returns 0 on success or a negative errno code on failure.
+ */
+static int i2o_iop_init_outbound_queue(struct i2o_controller *c)
+{
+       volatile u8 *status = c->status.virt;
+       u32 m;
+       struct i2o_message __iomem *msg;
+       ulong timeout;
+       int i;
+
+       osm_debug("%s: Initializing Outbound Queue...\n", c->name);
+
+       memset(c->status.virt, 0, 4);
+
+       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+       if (m == I2O_QUEUE_EMPTY)
+               return -ETIMEDOUT;
+
+       writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]);
+       writel(I2O_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 | ADAPTER_TID,
+              &msg->u.head[1]);
+       writel(i2o_exec_driver.context, &msg->u.s.icntxt);
+       writel(0x00000000, &msg->u.s.tcntxt);
+       writel(PAGE_SIZE, &msg->body[0]);
+       /* Outbound msg frame size in words and Initcode */
+       writel(I2O_OUTBOUND_MSG_FRAME_SIZE << 16 | 0x80, &msg->body[1]);
+       writel(0xd0000004, &msg->body[2]);
+       writel(i2o_dma_low(c->status.phys), &msg->body[3]);
+       writel(i2o_dma_high(c->status.phys), &msg->body[4]);
+
+       i2o_msg_post(c, m);
+
+       timeout = jiffies + I2O_TIMEOUT_INIT_OUTBOUND_QUEUE * HZ;
+       while (*status <= I2O_CMD_IN_PROGRESS) {
+               if (time_after(jiffies, timeout)) {
+                       osm_warn("%s: Timeout Initializing\n", c->name);
+                       return -ETIMEDOUT;
+               }
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(1);
+       }
+
+       m = c->out_queue.phys;
+
+       /* Post frames */
+       for (i = 0; i < I2O_MAX_OUTBOUND_MSG_FRAMES; i++) {
+               i2o_flush_reply(c, m);
+               udelay(1);      /* Promise */
+               m += I2O_OUTBOUND_MSG_FRAME_SIZE * sizeof(u32);
+       }
+
+       return 0;
+}
+
 /**
  *     i2o_iop_reset - reset an I2O controller
  *     @c: controller to reset
@@ -468,20 +511,20 @@ static int i2o_iop_clear(struct i2o_controller *c)
  */
 static int i2o_iop_reset(struct i2o_controller *c)
 {
-       u8 *status = c->status.virt;
+       volatile u8 *status = c->status.virt;
        struct i2o_message __iomem *msg;
        u32 m;
        unsigned long timeout;
        i2o_status_block *sb = c->status_block.virt;
        int rc = 0;
 
-       pr_debug("%s: Resetting controller\n", c->name);
+       osm_debug("%s: Resetting controller\n", c->name);
 
        m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
        if (m == I2O_QUEUE_EMPTY)
                return -ETIMEDOUT;
 
-       memset(status, 0, 8);
+       memset(c->status_block.virt, 0, 8);
 
        /* Quiesce all IOPs first */
        i2o_iop_quiesce_all();
@@ -493,49 +536,43 @@ static int i2o_iop_reset(struct i2o_controller *c)
        writel(0, &msg->u.s.tcntxt);    //FIXME: use reasonable transaction context
        writel(0, &msg->body[0]);
        writel(0, &msg->body[1]);
-       writel(i2o_ptr_low((void *)c->status.phys), &msg->body[2]);
-       writel(i2o_ptr_high((void *)c->status.phys), &msg->body[3]);
+       writel(i2o_dma_low(c->status.phys), &msg->body[2]);
+       writel(i2o_dma_high(c->status.phys), &msg->body[3]);
 
        i2o_msg_post(c, m);
 
        /* Wait for a reply */
        timeout = jiffies + I2O_TIMEOUT_RESET * HZ;
        while (!*status) {
-               if (time_after(jiffies, timeout)) {
-                       printk(KERN_ERR "%s: IOP reset timeout.\n", c->name);
-                       rc = -ETIMEDOUT;
-                       goto exit;
-               }
-
-               /* Promise bug */
-               if (status[1] || status[4]) {
-                       *status = 0;
+               if (time_after(jiffies, timeout))
                        break;
-               }
 
                set_current_state(TASK_UNINTERRUPTIBLE);
                schedule_timeout(1);
-
-               rmb();
        }
 
-       if (*status == I2O_CMD_IN_PROGRESS) {
+       switch (*status) {
+       case I2O_CMD_REJECTED:
+               osm_warn("%s: IOP reset rejected\n", c->name);
+               rc = -EPERM;
+               break;
+
+       case I2O_CMD_IN_PROGRESS:
                /*
                 * Once the reset is sent, the IOP goes into the INIT state
-                * which is indeterminate.  We need to wait until the IOP
-                * has rebooted before we can let the system talk to
-                * it. We read the inbound Free_List until a message is
-                * available. If we can't read one in the given ammount of
-                * time, we assume the IOP could not reboot properly.
+                * which is indeterminate. We need to wait until the IOP has
+                * rebooted before we can let the system talk to it. We read
+                * the inbound Free_List until a message is available. If we
+                * can't read one in the given ammount of time, we assume the
+                * IOP could not reboot properly.
                 */
-               pr_debug("%s: Reset in progress, waiting for reboot...\n",
-                        c->name);
+               osm_debug("%s: Reset in progress, waiting for reboot...\n",
+                         c->name);
 
                m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_RESET);
                while (m == I2O_QUEUE_EMPTY) {
                        if (time_after(jiffies, timeout)) {
-                               printk(KERN_ERR "%s: IOP reset timeout.\n",
-                                      c->name);
+                               osm_err("%s: IOP reset timeout.\n", c->name);
                                rc = -ETIMEDOUT;
                                goto exit;
                        }
@@ -545,19 +582,26 @@ static int i2o_iop_reset(struct i2o_controller *c)
                        m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_RESET);
                }
                i2o_msg_nop(c, m);
-       }
 
-       /* from here all quiesce commands are safe */
-       c->no_quiesce = 0;
+               /* from here all quiesce commands are safe */
+               c->no_quiesce = 0;
 
-       /* If IopReset was rejected or didn't perform reset, try IopClear */
-       i2o_status_get(c);
-       if (*status == I2O_CMD_REJECTED || sb->iop_state != ADAPTER_STATE_RESET) {
-               printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",
-                      c->name);
-               i2o_iop_clear(c);
-       } else
-               pr_debug("%s: Reset completed.\n", c->name);
+               /* verify if controller is in state RESET */
+               i2o_status_get(c);
+
+               if (!c->promise && (sb->iop_state != ADAPTER_STATE_RESET))
+                       osm_warn("%s: reset completed, but adapter not in RESET"
+                                " state.\n", c->name);
+               else
+                       osm_debug("%s: reset completed.\n", c->name);
+
+               break;
+
+       default:
+               osm_err("%s: IOP reset timeout.\n", c->name);
+               rc = -ETIMEDOUT;
+               break;
+       }
 
       exit:
        /* Enable all IOPs */
@@ -566,88 +610,6 @@ static int i2o_iop_reset(struct i2o_controller *c)
        return rc;
 };
 
-/**
- *     i2o_iop_init_outbound_queue - setup the outbound message queue
- *     @c: I2O controller
- *
- *     Clear and (re)initialize IOP's outbound queue and post the message
- *     frames to the IOP.
- *
- *     Returns 0 on success or a negative errno code on failure.
- */
-static int i2o_iop_init_outbound_queue(struct i2o_controller *c)
-{
-       u8 *status = c->status.virt;
-       u32 m;
-       struct i2o_message __iomem *msg;
-       ulong timeout;
-       int i;
-
-       pr_debug("%s: Initializing Outbound Queue...\n", c->name);
-
-       memset(status, 0, 4);
-
-       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
-       if (m == I2O_QUEUE_EMPTY)
-               return -ETIMEDOUT;
-
-       writel(EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6, &msg->u.head[0]);
-       writel(I2O_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 | ADAPTER_TID,
-              &msg->u.head[1]);
-       writel(i2o_exec_driver.context, &msg->u.s.icntxt);
-       writel(0x0106, &msg->u.s.tcntxt);       /* FIXME: why 0x0106, maybe in
-                                                  Spec? */
-       writel(PAGE_SIZE, &msg->body[0]);
-       writel(MSG_FRAME_SIZE << 16 | 0x80, &msg->body[1]);     /* Outbound msg frame
-                                                                  size in words and Initcode */
-       writel(0xd0000004, &msg->body[2]);
-       writel(i2o_ptr_low((void *)c->status.phys), &msg->body[3]);
-       writel(i2o_ptr_high((void *)c->status.phys), &msg->body[4]);
-
-       i2o_msg_post(c, m);
-
-       timeout = jiffies + I2O_TIMEOUT_INIT_OUTBOUND_QUEUE * HZ;
-       while (*status <= I2O_CMD_IN_PROGRESS) {
-               if (time_after(jiffies, timeout)) {
-                       printk(KERN_WARNING "%s: Timeout Initializing\n",
-                              c->name);
-                       return -ETIMEDOUT;
-               }
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(1);
-
-               rmb();
-       }
-
-       m = c->out_queue.phys;
-
-       /* Post frames */
-       for (i = 0; i < NMBR_MSG_FRAMES; i++) {
-               i2o_flush_reply(c, m);
-               udelay(1);      /* Promise */
-               m += MSG_FRAME_SIZE * 4;
-       }
-
-       return 0;
-}
-
-/**
- *     i2o_iop_send_nop - send a core NOP message
- *     @c: controller
- *
- *     Send a no-operation message with a reply set to cause no
- *     action either. Needed for bringing up promise controllers.
- */
-static int i2o_iop_send_nop(struct i2o_controller *c)
-{
-       struct i2o_message __iomem *msg;
-       u32 m = i2o_msg_get_wait(c, &msg, HZ);
-       if (m == I2O_QUEUE_EMPTY)
-               return -ETIMEDOUT;
-       i2o_msg_nop(c, m);
-       return 0;
-}
-
 /**
  *     i2o_iop_activate - Bring controller up to HOLD
  *     @c: controller
@@ -659,78 +621,62 @@ static int i2o_iop_send_nop(struct i2o_controller *c)
  */
 static int i2o_iop_activate(struct i2o_controller *c)
 {
-       struct pci_dev *i960 = NULL;
        i2o_status_block *sb = c->status_block.virt;
        int rc;
-
-       if (c->promise) {
-               /* Beat up the hardware first of all */
-               i960 =
-                   pci_find_slot(c->pdev->bus->number,
-                                 PCI_DEVFN(PCI_SLOT(c->pdev->devfn), 0));
-               if (i960)
-                       pci_write_config_word(i960, 0x42, 0);
-
-               /* Follow this sequence precisely or the controller
-                  ceases to perform useful functions until reboot */
-               if ((rc = i2o_iop_send_nop(c)))
-                       return rc;
-
-               if ((rc = i2o_iop_reset(c)))
-                       return rc;
-       }
+       int state;
 
        /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */
        /* In READY state, Get status */
 
        rc = i2o_status_get(c);
        if (rc) {
-               printk(KERN_INFO "%s: Unable to obtain status, "
-                      "attempting a reset.\n", c->name);
-               if (i2o_iop_reset(c))
+               osm_info("%s: Unable to obtain status, attempting a reset.\n",
+                        c->name);
+               rc = i2o_iop_reset(c);
+               if (rc)
                        return rc;
        }
 
        if (sb->i2o_version > I2OVER15) {
-               printk(KERN_ERR "%s: Not running version 1.5 of the I2O "
-                      "Specification.\n", c->name);
+               osm_err("%s: Not running version 1.5 of the I2O Specification."
+                       "\n", c->name);
                return -ENODEV;
        }
 
        switch (sb->iop_state) {
        case ADAPTER_STATE_FAULTED:
-               printk(KERN_CRIT "%s: hardware fault\n", c->name);
-               return -ENODEV;
+               osm_err("%s: hardware fault\n", c->name);
+               return -EFAULT;
 
        case ADAPTER_STATE_READY:
        case ADAPTER_STATE_OPERATIONAL:
        case ADAPTER_STATE_HOLD:
        case ADAPTER_STATE_FAILED:
-               pr_debug("%s: already running, trying to reset...\n", c->name);
-               if (i2o_iop_reset(c))
-                       return -ENODEV;
+               osm_debug("%s: already running, trying to reset...\n", c->name);
+               rc = i2o_iop_reset(c);
+               if (rc)
+                       return rc;
        }
 
+       /* preserve state */
+       state = sb->iop_state;
+
        rc = i2o_iop_init_outbound_queue(c);
        if (rc)
                return rc;
 
-       if (c->promise) {
-               if ((rc = i2o_iop_send_nop(c)))
-                       return rc;
+       /* if adapter was not in RESET state clear now */
+       if (state != ADAPTER_STATE_RESET)
+               i2o_iop_clear(c);
 
-               if ((rc = i2o_status_get(c)))
-                       return rc;
+       i2o_status_get(c);
 
-               if (i960)
-                       pci_write_config_word(i960, 0x42, 0x3FF);
+       if (sb->iop_state != ADAPTER_STATE_HOLD) {
+               osm_err("%s: failed to bring IOP into HOLD state\n", c->name);
+               return -EIO;
        }
 
-       /* In HOLD state */
-
-       rc = i2o_hrt_get(c);
-
-       return rc;
+       return i2o_hrt_get(c);
 };
 
 /**
@@ -756,20 +702,18 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
                res->flags = IORESOURCE_MEM;
                res->start = 0;
                res->end = 0;
-               printk(KERN_INFO "%s: requires private memory resources.\n",
-                      c->name);
+               osm_info("%s: requires private memory resources.\n", c->name);
                root = pci_find_parent_resource(c->pdev, res);
                if (root == NULL)
-                       printk(KERN_WARNING "%s: Can't find parent resource!\n",
-                              c->name);
+                       osm_warn("%s: Can't find parent resource!\n", c->name);
                if (root && allocate_resource(root, res, sb->desired_mem_size, sb->desired_mem_size, sb->desired_mem_size, 1 << 20,     /* Unspecified, so use 1Mb and play safe */
                                              NULL, NULL) >= 0) {
                        c->mem_alloc = 1;
                        sb->current_mem_size = 1 + res->end - res->start;
                        sb->current_mem_base = res->start;
-                       printk(KERN_INFO "%s: allocated %ld bytes of PCI memory"
-                              " at 0x%08lX.\n", c->name,
-                              1 + res->end - res->start, res->start);
+                       osm_info("%s: allocated %ld bytes of PCI memory at "
+                                "0x%08lX.\n", c->name,
+                                1 + res->end - res->start, res->start);
                }
        }
 
@@ -779,20 +723,18 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
                res->flags = IORESOURCE_IO;
                res->start = 0;
                res->end = 0;
-               printk(KERN_INFO "%s: requires private memory resources.\n",
-                      c->name);
+               osm_info("%s: requires private memory resources.\n", c->name);
                root = pci_find_parent_resource(c->pdev, res);
                if (root == NULL)
-                       printk(KERN_WARNING "%s: Can't find parent resource!\n",
-                              c->name);
+                       osm_warn("%s: Can't find parent resource!\n", c->name);
                if (root && allocate_resource(root, res, sb->desired_io_size, sb->desired_io_size, sb->desired_io_size, 1 << 20,        /* Unspecified, so use 1Mb and play safe */
                                              NULL, NULL) >= 0) {
                        c->io_alloc = 1;
                        sb->current_io_size = 1 + res->end - res->start;
                        sb->current_mem_base = res->start;
-                       printk(KERN_INFO "%s: allocated %ld bytes of PCI I/O at"
-                              " 0x%08lX.\n", c->name,
-                              1 + res->end - res->start, res->start);
+                       osm_info("%s: allocated %ld bytes of PCI I/O at 0x%08lX"
+                                ".\n", c->name, 1 + res->end - res->start,
+                                res->start);
                }
        }
 
@@ -836,10 +778,10 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
                         PCI_DMA_TODEVICE);
 
        if (rc < 0)
-               printk(KERN_ERR "%s: Unable to set SysTab (status=%#x).\n",
-                      c->name, -rc);
+               osm_err("%s: Unable to set SysTab (status=%#x).\n", c->name,
+                       -rc);
        else
-               pr_debug("%s: SysTab set.\n", c->name);
+               osm_debug("%s: SysTab set.\n", c->name);
 
        i2o_status_get(c);      // Entered READY state
 
@@ -863,7 +805,7 @@ static int i2o_iop_online(struct i2o_controller *c)
                return rc;
 
        /* In READY state */
-       pr_debug("%s: Attempting to enable...\n", c->name);
+       osm_debug("%s: Attempting to enable...\n", c->name);
        rc = i2o_iop_enable(c);
        if (rc)
                return rc;
@@ -882,7 +824,7 @@ void i2o_iop_remove(struct i2o_controller *c)
 {
        struct i2o_device *dev, *tmp;
 
-       pr_debug("%s: deleting controller\n", c->name);
+       osm_debug("%s: deleting controller\n", c->name);
 
        i2o_driver_notify_controller_remove_all(c);
 
@@ -891,8 +833,12 @@ void i2o_iop_remove(struct i2o_controller *c)
        list_for_each_entry_safe(dev, tmp, &c->devices, list)
            i2o_device_remove(dev);
 
+       device_del(&c->device);
+
        /* Ask the IOP to switch to RESET state */
        i2o_iop_reset(c);
+
+       put_device(&c->device);
 }
 
 /**
@@ -927,8 +873,7 @@ static int i2o_systab_build(void)
 
        systab = i2o_systab.virt = kmalloc(i2o_systab.len, GFP_KERNEL);
        if (!systab) {
-               printk(KERN_ERR "i2o: unable to allocate memory for System "
-                      "Table\n");
+               osm_err("unable to allocate memory for System Table\n");
                return -ENOMEM;
        }
        memset(systab, 0, i2o_systab.len);
@@ -940,8 +885,8 @@ static int i2o_systab_build(void)
                i2o_status_block *sb;
 
                if (count >= num_controllers) {
-                       printk(KERN_ERR "i2o: controller added while building "
-                              "system table\n");
+                       osm_err("controller added while building system table"
+                               "\n");
                        break;
                }
 
@@ -955,9 +900,8 @@ static int i2o_systab_build(void)
                 * it is techninically not part of the I2O subsystem...
                 */
                if (unlikely(i2o_status_get(c))) {
-                       printk(KERN_ERR "%s: Deleting b/c could not get status"
-                              " while attempting to build system table\n",
-                              c->name);
+                       osm_err("%s: Deleting b/c could not get status while "
+                               "attempting to build system table\n", c->name);
                        i2o_iop_remove(c);
                        continue;       // try the next one
                }
@@ -971,8 +915,10 @@ static int i2o_systab_build(void)
                systab->iops[count].frame_size = sb->inbound_frame_size;
                systab->iops[count].last_changed = change_ind;
                systab->iops[count].iop_capabilities = sb->iop_capabilities;
-               systab->iops[count].inbound_low = i2o_ptr_low(c->post_port);
-               systab->iops[count].inbound_high = i2o_ptr_high(c->post_port);
+               systab->iops[count].inbound_low =
+                   i2o_dma_low(c->base.phys + I2O_IN_PORT);
+               systab->iops[count].inbound_high =
+                   i2o_dma_high(c->base.phys + I2O_IN_PORT);
 
                count++;
        }
@@ -1010,11 +956,11 @@ int i2o_status_get(struct i2o_controller *c)
 {
        struct i2o_message __iomem *msg;
        u32 m;
-       u8 *status_block;
+       volatile u8 *status_block;
        unsigned long timeout;
 
        status_block = (u8 *) c->status_block.virt;
-       memset(status_block, 0, sizeof(i2o_status_block));
+       memset(c->status_block.virt, 0, sizeof(i2o_status_block));
 
        m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
        if (m == I2O_QUEUE_EMPTY)
@@ -1027,8 +973,8 @@ int i2o_status_get(struct i2o_controller *c)
        writel(0, &msg->u.s.tcntxt);    // FIXME: use resonable transaction context
        writel(0, &msg->body[0]);
        writel(0, &msg->body[1]);
-       writel(i2o_ptr_low((void *)c->status_block.phys), &msg->body[2]);
-       writel(i2o_ptr_high((void *)c->status_block.phys), &msg->body[3]);
+       writel(i2o_dma_low(c->status_block.phys), &msg->body[2]);
+       writel(i2o_dma_high(c->status_block.phys), &msg->body[3]);
        writel(sizeof(i2o_status_block), &msg->body[4]);        /* always 88 bytes */
 
        i2o_msg_post(c, m);
@@ -1037,14 +983,12 @@ int i2o_status_get(struct i2o_controller *c)
        timeout = jiffies + I2O_TIMEOUT_STATUS_GET * HZ;
        while (status_block[87] != 0xFF) {
                if (time_after(jiffies, timeout)) {
-                       printk(KERN_ERR "%s: Get status timeout.\n", c->name);
+                       osm_err("%s: Get status timeout.\n", c->name);
                        return -ETIMEDOUT;
                }
 
                set_current_state(TASK_UNINTERRUPTIBLE);
                schedule_timeout(1);
-
-               rmb();
        }
 
 #ifdef DEBUG
@@ -1088,8 +1032,8 @@ static int i2o_hrt_get(struct i2o_controller *c)
                rc = i2o_msg_post_wait_mem(c, m, 20, &c->hrt);
 
                if (rc < 0) {
-                       printk(KERN_ERR "%s: Unable to get HRT (status=%#x)\n",
-                              c->name, -rc);
+                       osm_err("%s: Unable to get HRT (status=%#x)\n", c->name,
+                               -rc);
                        return rc;
                }
 
@@ -1103,12 +1047,40 @@ static int i2o_hrt_get(struct i2o_controller *c)
                        return i2o_parse_hrt(c);
        }
 
-       printk(KERN_ERR "%s: Unable to get HRT after %d tries, giving up\n",
-              c->name, I2O_HRT_GET_TRIES);
+       osm_err("%s: Unable to get HRT after %d tries, giving up\n", c->name,
+               I2O_HRT_GET_TRIES);
 
        return -EBUSY;
 }
 
+/**
+ *     i2o_iop_free - Free the i2o_controller struct
+ *     @c: I2O controller to free
+ */
+void i2o_iop_free(struct i2o_controller *c)
+{
+       kfree(c);
+};
+
+/**
+ *     i2o_iop_release - release the memory for a I2O controller
+ *     @dev: I2O controller which should be released
+ *
+ *     Release the allocated memory. This function is called if refcount of
+ *     device reaches 0 automatically.
+ */
+static void i2o_iop_release(struct device *dev)
+{
+       struct i2o_controller *c = to_i2o_controller(dev);
+
+       i2o_iop_free(c);
+};
+
+/* I2O controller class */
+static struct class i2o_controller_class = {
+       .name = "i2o_controller",
+};
+
 /**
  *     i2o_iop_alloc - Allocate and initialize a i2o_controller struct
  *
@@ -1125,8 +1097,8 @@ struct i2o_controller *i2o_iop_alloc(void)
 
        c = kmalloc(sizeof(*c), GFP_KERNEL);
        if (!c) {
-               printk(KERN_ERR "i2o: Insufficient memory to allocate a I2O "
-                      "controller.\n");
+               osm_err("i2o: Insufficient memory to allocate a I2O controller."
+                       "\n");
                return ERR_PTR(-ENOMEM);
        }
        memset(c, 0, sizeof(*c));
@@ -1137,6 +1109,16 @@ struct i2o_controller *i2o_iop_alloc(void)
        c->unit = unit++;
        sprintf(c->name, "iop%d", c->unit);
 
+       device_initialize(&c->device);
+       class_device_initialize(&c->classdev);
+
+       c->device.release = &i2o_iop_release;
+       c->classdev.class = &i2o_controller_class;
+       c->classdev.dev = &c->device;
+
+       snprintf(c->device.bus_id, BUS_ID_SIZE, "iop%d", c->unit);
+       snprintf(c->classdev.class_id, BUS_ID_SIZE, "iop%d", c->unit);
+
 #if BITS_PER_LONG == 64
        spin_lock_init(&c->context_list_lock);
        atomic_set(&c->context_list_counter, 0);
@@ -1146,15 +1128,6 @@ struct i2o_controller *i2o_iop_alloc(void)
        return c;
 };
 
-/**
- *     i2o_iop_free - Free the i2o_controller struct
- *     @c: I2O controller to free
- */
-void i2o_iop_free(struct i2o_controller *c)
-{
-       kfree(c);
-};
-
 /**
  *     i2o_iop_add - Initialize the I2O controller and add him to the I2O core
  *     @c: controller
@@ -1168,45 +1141,58 @@ int i2o_iop_add(struct i2o_controller *c)
 {
        int rc;
 
-       printk(KERN_INFO "%s: Activating I2O controller...\n", c->name);
-       printk(KERN_INFO "%s: This may take a few minutes if there are many "
-              "devices\n", c->name);
+       if ((rc = device_add(&c->device))) {
+               osm_err("%s: could not add controller\n", c->name);
+               goto iop_reset;
+       }
 
-       if ((rc = i2o_iop_activate(c))) {
-               printk(KERN_ERR "%s: could not activate controller\n",
-                      c->name);
-               i2o_iop_reset(c);
-               return rc;
+       if ((rc = class_device_add(&c->classdev))) {
+               osm_err("%s: could not add controller class\n", c->name);
+               goto device_del;
        }
 
-       pr_debug("%s: building sys table...\n", c->name);
+       osm_info("%s: Activating I2O controller...\n", c->name);
+       osm_info("%s: This may take a few minutes if there are many devices\n",
+                c->name);
 
-       if ((rc = i2o_systab_build())) {
-               i2o_iop_reset(c);
-               return rc;
+       if ((rc = i2o_iop_activate(c))) {
+               osm_err("%s: could not activate controller\n", c->name);
+               goto class_del;
        }
 
-       pr_debug("%s: online controller...\n", c->name);
+       osm_debug("%s: building sys table...\n", c->name);
 
-       if ((rc = i2o_iop_online(c))) {
-               i2o_iop_reset(c);
-               return rc;
-       }
+       if ((rc = i2o_systab_build()))
+               goto class_del;
 
-       pr_debug("%s: getting LCT...\n", c->name);
+       osm_debug("%s: online controller...\n", c->name);
 
-       if ((rc = i2o_exec_lct_get(c))) {
-               i2o_iop_reset(c);
-               return rc;
-       }
+       if ((rc = i2o_iop_online(c)))
+               goto class_del;
+
+       osm_debug("%s: getting LCT...\n", c->name);
+
+       if ((rc = i2o_exec_lct_get(c)))
+               goto class_del;
 
        list_add(&c->list, &i2o_controllers);
 
        i2o_driver_notify_controller_add_all(c);
 
-       printk(KERN_INFO "%s: Controller added\n", c->name);
+       osm_info("%s: Controller added\n", c->name);
 
        return 0;
+
+      class_del:
+       class_device_del(&c->classdev);
+
+      device_del:
+       device_del(&c->device);
+
+      iop_reset:
+       i2o_iop_reset(c);
+
+       return rc;
 };
 
 /**
@@ -1264,16 +1250,18 @@ static int __init i2o_iop_init(void)
        if (rc)
                goto exit;
 
-       rc = i2o_driver_init();
-       if (rc)
+       if ((rc = class_register(&i2o_controller_class))) {
+               osm_err("can't register class i2o_controller\n");
                goto device_exit;
+       }
 
-       rc = i2o_exec_init();
-       if (rc)
+       if ((rc = i2o_driver_init()))
+               goto class_exit;
+
+       if ((rc = i2o_exec_init()))
                goto driver_exit;
 
-       rc = i2o_pci_init();
-       if (rc < 0)
+       if ((rc = i2o_pci_init()))
                goto exec_exit;
 
        return 0;
@@ -1284,6 +1272,9 @@ static int __init i2o_iop_init(void)
       driver_exit:
        i2o_driver_exit();
 
+      class_exit:
+       class_unregister(&i2o_controller_class);
+
       device_exit:
        i2o_device_exit();
 
@@ -1301,6 +1292,7 @@ static void __exit i2o_iop_exit(void)
        i2o_pci_exit();
        i2o_exec_exit();
        i2o_driver_exit();
+       class_unregister(&i2o_controller_class);
        i2o_device_exit();
 };
 
index e772752f056d3330a805d6da25294be9ef11093f..7a60fd7be8ad4aa3f334a1885e3eaa439305b26a 100644 (file)
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/i2o.h>
-
-#ifdef CONFIG_MTRR
-#include <asm/mtrr.h>
-#endif                         // CONFIG_MTRR
-
-/* Module internal functions from other sources */
-extern struct i2o_controller *i2o_iop_alloc(void);
-extern void i2o_iop_free(struct i2o_controller *);
-
-extern int i2o_iop_add(struct i2o_controller *);
-extern void i2o_iop_remove(struct i2o_controller *);
-
-extern int i2o_driver_dispatch(struct i2o_controller *, u32,
-                              struct i2o_message *);
+#include "core.h"
 
 /* PCI device id table for all I2O controllers */
 static struct pci_device_id __devinitdata i2o_pci_ids[] = {
        {PCI_DEVICE_CLASS(PCI_CLASS_INTELLIGENT_I2O << 8, 0xffff00)},
        {PCI_DEVICE(PCI_VENDOR_ID_DPT, 0xa511)},
+       {.vendor = PCI_VENDOR_ID_INTEL,.device = 0x1962,
+        .subvendor = PCI_VENDOR_ID_PROMISE,.subdevice = PCI_ANY_ID},
        {0}
 };
 
-/**
- *     i2o_dma_realloc - Realloc DMA memory
- *     @dev: struct device pointer to the PCI device of the I2O controller
- *     @addr: pointer to a i2o_dma struct DMA buffer
- *     @len: new length of memory
- *     @gfp_mask: GFP mask
- *
- *     If there was something allocated in the addr, free it first. If len > 0
- *     than try to allocate it and write the addresses back to the addr
- *     structure. If len == 0 set the virtual address to NULL.
- *
- *     Returns the 0 on success or negative error code on failure.
- */
-int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr, size_t len,
-                   unsigned int gfp_mask)
-{
-       i2o_dma_free(dev, addr);
-
-       if (len)
-               return i2o_dma_alloc(dev, addr, len, gfp_mask);
-
-       return 0;
-};
-
 /**
  *     i2o_pci_free - Frees the DMA memory for the I2O controller
  *     @c: I2O controller to free
@@ -91,19 +56,11 @@ static void i2o_pci_free(struct i2o_controller *c)
 
        i2o_dma_free(dev, &c->out_queue);
        i2o_dma_free(dev, &c->status_block);
-       if (c->lct)
-               kfree(c->lct);
+       kfree(c->lct);
        i2o_dma_free(dev, &c->dlct);
        i2o_dma_free(dev, &c->hrt);
        i2o_dma_free(dev, &c->status);
 
-#ifdef CONFIG_MTRR
-       if (c->mtrr_reg0 >= 0)
-               mtrr_del(c->mtrr_reg0, 0, 0);
-       if (c->mtrr_reg1 >= 0)
-               mtrr_del(c->mtrr_reg1, 0, 0);
-#endif
-
        if (c->raptor && c->in_queue.virt)
                iounmap(c->in_queue.virt);
 
@@ -178,14 +135,15 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
                       c->name, (unsigned long)c->base.phys,
                       (unsigned long)c->base.len);
 
-       c->base.virt = ioremap(c->base.phys, c->base.len);
+       c->base.virt = ioremap_nocache(c->base.phys, c->base.len);
        if (!c->base.virt) {
                printk(KERN_ERR "%s: Unable to map controller.\n", c->name);
                return -ENOMEM;
        }
 
        if (c->raptor) {
-               c->in_queue.virt = ioremap(c->in_queue.phys, c->in_queue.len);
+               c->in_queue.virt =
+                   ioremap_nocache(c->in_queue.phys, c->in_queue.len);
                if (!c->in_queue.virt) {
                        printk(KERN_ERR "%s: Unable to map controller.\n",
                               c->name);
@@ -195,43 +153,10 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
        } else
                c->in_queue = c->base;
 
-       c->irq_mask = c->base.virt + 0x34;
-       c->post_port = c->base.virt + 0x40;
-       c->reply_port = c->base.virt + 0x44;
-
-#ifdef CONFIG_MTRR
-       /* Enable Write Combining MTRR for IOP's memory region */
-       c->mtrr_reg0 = mtrr_add(c->in_queue.phys, c->in_queue.len,
-                               MTRR_TYPE_WRCOMB, 1);
-       c->mtrr_reg1 = -1;
-
-       if (c->mtrr_reg0 < 0)
-               printk(KERN_WARNING "%s: could not enable write combining "
-                      "MTRR\n", c->name);
-       else
-               printk(KERN_INFO "%s: using write combining MTRR\n", c->name);
-
-       /*
-        * If it is an INTEL i960 I/O processor then set the first 64K to
-        * Uncacheable since the region contains the messaging unit which
-        * shouldn't be cached.
-        */
-       if ((pdev->vendor == PCI_VENDOR_ID_INTEL ||
-            pdev->vendor == PCI_VENDOR_ID_DPT) && !c->raptor) {
-               printk(KERN_INFO "%s: MTRR workaround for Intel i960 processor"
-                      "\n", c->name);
-               c->mtrr_reg1 = mtrr_add(c->base.phys, 0x10000,
-                                       MTRR_TYPE_UNCACHABLE, 1);
-
-               if (c->mtrr_reg1 < 0) {
-                       printk(KERN_WARNING "%s: Error in setting "
-                              "MTRR_TYPE_UNCACHABLE\n", c->name);
-                       mtrr_del(c->mtrr_reg0, c->in_queue.phys,
-                                c->in_queue.len);
-                       c->mtrr_reg0 = -1;
-               }
-       }
-#endif
+       c->irq_status = c->base.virt + I2O_IRQ_STATUS;
+       c->irq_mask = c->base.virt + I2O_IRQ_MASK;
+       c->in_port = c->base.virt + I2O_IN_PORT;
+       c->out_port = c->base.virt + I2O_OUT_PORT;
 
        if (i2o_dma_alloc(dev, &c->status, 8, GFP_KERNEL)) {
                i2o_pci_free(c);
@@ -254,7 +179,10 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
                return -ENOMEM;
        }
 
-       if (i2o_dma_alloc(dev, &c->out_queue, MSG_POOL_SIZE, GFP_KERNEL)) {
+       if (i2o_dma_alloc
+           (dev, &c->out_queue,
+            I2O_MAX_OUTBOUND_MSG_FRAMES * I2O_OUTBOUND_MSG_FRAME_SIZE *
+            sizeof(u32), GFP_KERNEL)) {
                i2o_pci_free(c);
                return -ENOMEM;
        }
@@ -276,51 +204,30 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
 static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r)
 {
        struct i2o_controller *c = dev_id;
-       struct device *dev = &c->pdev->dev;
-       struct i2o_message *m;
-       u32 mv;
-
-       /*
-        * Old 960 steppings had a bug in the I2O unit that caused
-        * the queue to appear empty when it wasn't.
-        */
-       mv = I2O_REPLY_READ32(c);
-       if (mv == I2O_QUEUE_EMPTY) {
-               mv = I2O_REPLY_READ32(c);
-               if (unlikely(mv == I2O_QUEUE_EMPTY)) {
-                       return IRQ_NONE;
-               } else
-                       pr_debug("%s: 960 bug detected\n", c->name);
-       }
-
-       while (mv != I2O_QUEUE_EMPTY) {
-               /*
-                * Map the message from the page frame map to kernel virtual.
-                * Because bus_to_virt is deprecated, we have calculate the
-                * location by ourself!
-                */
-               m = i2o_msg_out_to_virt(c, mv);
-
-               /*
-                *      Ensure this message is seen coherently but cachably by
-                *      the processor
-                */
-               dma_sync_single_for_cpu(dev, mv, MSG_FRAME_SIZE * 4,
-                                       PCI_DMA_FROMDEVICE);
+       u32 m;
+       irqreturn_t rc = IRQ_NONE;
+
+       while (readl(c->irq_status) & I2O_IRQ_OUTBOUND_POST) {
+               m = readl(c->out_port);
+               if (m == I2O_QUEUE_EMPTY) {
+                       /*
+                        * Old 960 steppings had a bug in the I2O unit that
+                        * caused the queue to appear empty when it wasn't.
+                        */
+                       m = readl(c->out_port);
+                       if (unlikely(m == I2O_QUEUE_EMPTY))
+                               break;
+               }
 
                /* dispatch it */
-               if (i2o_driver_dispatch(c, mv, m))
+               if (i2o_driver_dispatch(c, m))
                        /* flush it if result != 0 */
-                       i2o_flush_reply(c, mv);
+                       i2o_flush_reply(c, m);
 
-               /*
-                * That 960 bug again...
-                */
-               mv = I2O_REPLY_READ32(c);
-               if (mv == I2O_QUEUE_EMPTY)
-                       mv = I2O_REPLY_READ32(c);
+               rc = IRQ_HANDLED;
        }
-       return IRQ_HANDLED;
+
+       return rc;
 }
 
 /**
@@ -336,7 +243,7 @@ static int i2o_pci_irq_enable(struct i2o_controller *c)
        struct pci_dev *pdev = c->pdev;
        int rc;
 
-       I2O_IRQ_WRITE32(c, 0xffffffff);
+       writel(0xffffffff, c->irq_mask);
 
        if (pdev->irq) {
                rc = request_irq(pdev->irq, i2o_pci_interrupt, SA_SHIRQ,
@@ -348,7 +255,7 @@ static int i2o_pci_irq_enable(struct i2o_controller *c)
                }
        }
 
-       I2O_IRQ_WRITE32(c, 0x00000000);
+       writel(0x00000000, c->irq_mask);
 
        printk(KERN_INFO "%s: Installed at IRQ %d\n", c->name, pdev->irq);
 
@@ -363,7 +270,7 @@ static int i2o_pci_irq_enable(struct i2o_controller *c)
  */
 static void i2o_pci_irq_disable(struct i2o_controller *c)
 {
-       I2O_IRQ_WRITE32(c, 0xffffffff);
+       writel(0xffffffff, c->irq_mask);
 
        if (c->pdev->irq > 0)
                free_irq(c->pdev->irq, c);
@@ -385,28 +292,25 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
 {
        struct i2o_controller *c;
        int rc;
+       struct pci_dev *i960 = NULL;
 
        printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
 
        if ((pdev->class & 0xff) > 1) {
-               printk(KERN_WARNING "i2o: I2O controller found but does not "
-                      "support I2O 1.5 (skipping).\n");
+               printk(KERN_WARNING "i2o: %s does not support I2O 1.5 "
+                      "(skipping).\n", pci_name(pdev));
                return -ENODEV;
        }
 
        if ((rc = pci_enable_device(pdev))) {
-               printk(KERN_WARNING "i2o: I2O controller found but could not be"
-                      " enabled.\n");
+               printk(KERN_WARNING "i2o: couldn't enable device %s\n",
+                      pci_name(pdev));
                return rc;
        }
 
-       printk(KERN_INFO "i2o: I2O controller found on bus %d at %d.\n",
-              pdev->bus->number, pdev->devfn);
-
        if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
-               printk(KERN_WARNING "i2o: I2O controller on bus %d at %d: No "
-                      "suitable DMA available!\n", pdev->bus->number,
-                      pdev->devfn);
+               printk(KERN_WARNING "i2o: no suitable DMA found for %s\n",
+                      pci_name(pdev));
                rc = -ENODEV;
                goto disable;
        }
@@ -415,14 +319,16 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
 
        c = i2o_iop_alloc();
        if (IS_ERR(c)) {
-               printk(KERN_ERR "i2o: memory for I2O controller could not be "
-                      "allocated\n");
+               printk(KERN_ERR "i2o: couldn't allocate memory for %s\n",
+                      pci_name(pdev));
                rc = PTR_ERR(c);
                goto disable;
-       }
+       } else
+               printk(KERN_INFO "%s: controller found (%s)\n", c->name,
+                      pci_name(pdev));
 
        c->pdev = pdev;
-       c->device = pdev->dev;
+       c->device.parent = get_device(&pdev->dev);
 
        /* Cards that fall apart if you hit them with large I/O loads... */
        if (pdev->vendor == PCI_VENDOR_ID_NCR && pdev->device == 0x0630) {
@@ -432,16 +338,48 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
        }
 
        if (pdev->subsystem_vendor == PCI_VENDOR_ID_PROMISE) {
+               /*
+                * Expose the ship behind i960 for initialization, or it will
+                * failed
+                */
+               i960 =
+                   pci_find_slot(c->pdev->bus->number,
+                                 PCI_DEVFN(PCI_SLOT(c->pdev->devfn), 0));
+
+               if (i960)
+                       pci_write_config_word(i960, 0x42, 0);
+
                c->promise = 1;
-               printk(KERN_INFO "%s: Promise workarounds activated.\n",
-                      c->name);
+               c->limit_sectors = 1;
        }
 
+       if (pdev->subsystem_vendor == PCI_VENDOR_ID_DPT)
+               c->adaptec = 1;
+
        /* Cards that go bananas if you quiesce them before you reset them. */
        if (pdev->vendor == PCI_VENDOR_ID_DPT) {
                c->no_quiesce = 1;
                if (pdev->device == 0xa511)
                        c->raptor = 1;
+
+               if (pdev->subsystem_device == 0xc05a) {
+                       c->limit_sectors = 1;
+                       printk(KERN_INFO
+                              "%s: limit sectors per request to %d\n", c->name,
+                              I2O_MAX_SECTORS_LIMITED);
+               }
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+               if (sizeof(dma_addr_t) > 4) {
+                       if (pci_set_dma_mask(pdev, DMA_64BIT_MASK))
+                               printk(KERN_INFO "%s: 64-bit DMA unavailable\n",
+                                      c->name);
+                       else {
+                               c->pae_support = 1;
+                               printk(KERN_INFO "%s: using 64-bit DMA\n",
+                                      c->name);
+                       }
+               }
+#endif
        }
 
        if ((rc = i2o_pci_alloc(c))) {
@@ -459,6 +397,11 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
        if ((rc = i2o_iop_add(c)))
                goto uninstall;
 
+       get_device(&c->device);
+
+       if (i960)
+               pci_write_config_word(i960, 0x42, 0x03ff);
+
        return 0;
 
       uninstall:
@@ -469,6 +412,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
 
       free_controller:
        i2o_iop_free(c);
+       put_device(c->device.parent);
 
       disable:
        pci_disable_device(pdev);
@@ -492,15 +436,17 @@ static void __devexit i2o_pci_remove(struct pci_dev *pdev)
        i2o_pci_irq_disable(c);
        i2o_pci_free(c);
 
+       pci_disable_device(pdev);
+
        printk(KERN_INFO "%s: Controller removed.\n", c->name);
 
-       i2o_iop_free(c);
-       pci_disable_device(pdev);
+       put_device(c->device.parent);
+       put_device(&c->device);
 };
 
 /* PCI driver for I2O controller */
 static struct pci_driver i2o_pci_driver = {
-       .name = "I2O controller",
+       .name = "PCI_I2O",
        .id_table = i2o_pci_ids,
        .probe = i2o_pci_probe,
        .remove = __devexit_p(i2o_pci_remove),
@@ -523,6 +469,4 @@ void __exit i2o_pci_exit(void)
 {
        pci_unregister_driver(&i2o_pci_driver);
 };
-
-EXPORT_SYMBOL(i2o_dma_realloc);
 MODULE_DEVICE_TABLE(pci, i2o_pci_ids);
index 8480057eadb494da50bc1c1f428c80b3c6bfc795..2bea2e0b06f26819d3526c1c2c2d9e6e8c34c13b 100644 (file)
@@ -607,6 +607,16 @@ config MTD_PCMCIA
          cards are usually around 4-16MiB in size. This does not include
          Compact Flash cards which are treated as IDE devices.
 
+config MTD_PCMCIA_ANONYMOUS
+       bool "Use PCMCIA MTD drivers for anonymous PCMCIA cards"
+       depends on MTD_PCMCIA
+       default N
+       help
+         If this option is enabled, PCMCIA cards which do not report
+         anything about themselves are assumed to be MTD cards.
+
+         If unsure, say N.
+
 config MTD_UCLINUX
        tristate "Generic uClinux RAM/ROM filesystem support"
        depends on MTD_PARTITIONS && !MMU
index e37b4c1976e57f72c946366cb543bea453a235d1..c2655a817e3d7099e9ced9a44de5710a8449471e 100644 (file)
@@ -818,6 +818,32 @@ static dev_link_t *pcmciamtd_attach(void)
        return link;
 }
 
+static struct pcmcia_device_id pcmciamtd_ids[] = {
+       PCMCIA_DEVICE_FUNC_ID(1),
+       PCMCIA_DEVICE_PROD_ID123("IO DATA", "PCS-2M", "2MB SRAM", 0x547e66dc, 0x1fed36cd, 0x36eadd21),
+       PCMCIA_DEVICE_PROD_ID12("IBM", "2MB SRAM", 0xb569a6e5, 0x36eadd21),
+       PCMCIA_DEVICE_PROD_ID12("IBM", "4MB FLASH", 0xb569a6e5, 0x8bc54d2a),
+       PCMCIA_DEVICE_PROD_ID12("IBM", "8MB FLASH", 0xb569a6e5, 0x6df1be3e),
+       PCMCIA_DEVICE_PROD_ID12("Intel", "S2E20SW", 0x816cc815, 0xd14c9dcf),
+       PCMCIA_DEVICE_PROD_ID12("Intel", "S2E8 SW", 0x816cc815, 0xa2d7dedb),
+       PCMCIA_DEVICE_PROD_ID12("intel", "SERIES2-02 ", 0x40ade711, 0x145cea5c),
+       PCMCIA_DEVICE_PROD_ID12("intel", "SERIES2-04 ", 0x40ade711, 0x42064dda),
+       PCMCIA_DEVICE_PROD_ID12("intel", "SERIES2-20 ", 0x40ade711, 0x25ee5cb0),
+       PCMCIA_DEVICE_PROD_ID12("intel", "VALUE SERIES 100 ", 0x40ade711, 0xdf8506d8),
+       PCMCIA_DEVICE_PROD_ID12("KINGMAX TECHNOLOGY INC.", "SRAM 256K Bytes", 0x54d0c69c, 0xad12c29c),
+       PCMCIA_DEVICE_PROD_ID12("Maxtor", "MAXFL MobileMax Flash Memory Card", 0xb68968c8, 0x2dfb47b0),
+       PCMCIA_DEVICE_PROD_ID12("SEIKO EPSON", "WWB101EN20", 0xf9876baf, 0xad0b207b),
+       PCMCIA_DEVICE_PROD_ID12("SEIKO EPSON", "WWB513EN20", 0xf9876baf, 0xe8d884ad),
+       PCMCIA_DEVICE_PROD_ID12("Starfish, Inc.", "REX-3000", 0x05ddca47, 0xe7d67bca),
+       PCMCIA_DEVICE_PROD_ID12("Starfish, Inc.", "REX-4100", 0x05ddca47, 0x7bc32944),
+       /* the following was commented out in pcmcia-cs-3.2.7 */
+       /* PCMCIA_DEVICE_PROD_ID12("RATOC Systems,Inc.", "SmartMedia ADAPTER PC Card", 0xf4a2fefe, 0x5885b2ae), */
+#ifdef CONFIG_MTD_PCMCIA_ANONYMOUS
+       { .match_flags = PCMCIA_DEV_ID_MATCH_ANONYMOUS, },
+#endif
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, pcmciamtd_ids);
 
 static struct pcmcia_driver pcmciamtd_driver = {
        .drv            = {
@@ -825,7 +851,8 @@ static struct pcmcia_driver pcmciamtd_driver = {
        },
        .attach         = pcmciamtd_attach,
        .detach         = pcmciamtd_detach,
-       .owner          = THIS_MODULE
+       .owner          = THIS_MODULE,
+       .id_table       = pcmciamtd_ids,
 };
 
 
index 29dfd47f41d2b4ff10275a135cae7ef604eff17e..5c5eebdb69146e5fb83f86ff6870f796d5e95933 100644 (file)
@@ -171,12 +171,7 @@ struct net_device * __init el2_probe(int unit)
        err = do_el2_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -356,6 +351,10 @@ el2_probe1(struct net_device *dev, int ioaddr)
     dev->poll_controller = ei_poll;
 #endif
 
+    retval = register_netdev(dev);
+    if (retval)
+       goto out1;
+
     if (dev->mem_start)
        printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n",
                dev->name, ei_status.name, (wordlength+1)<<3,
@@ -715,11 +714,8 @@ init_module(void)
                dev->base_addr = io[this_dev];
                dev->mem_end = xcvr[this_dev];  /* low 4bits = xcvr sel. */
                if (do_el2_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_el2[found++] = dev;
-                               continue;
-                       }
-                       cleanup_card(dev);
+                       dev_el2[found++] = dev;
+                       continue;
                }
                free_netdev(dev);
                printk(KERN_WARNING "3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]);
index 76fa8cc2408597cf23a922db3e2b89ef1ac17839..ad17f17e8e7a0511d9475fb3eb60d648b4cfc51a 100644 (file)
@@ -1317,8 +1317,7 @@ static int __init elp_sense(struct net_device *dev)
        if (orig_HSR & DIR) {
                /* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */
                outb(0, dev->base_addr + PORT_CONTROL);
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(30*HZ/100);
+               msleep(300);
                if (inb_status(addr) & DIR) {
                        if (elp_debug > 0)
                                printk(notfound_msg, 2);
@@ -1327,8 +1326,7 @@ static int __init elp_sense(struct net_device *dev)
        } else {
                /* If HCR.DIR is down, we pull it up. HSR.DIR should follow. */
                outb(DIR, dev->base_addr + PORT_CONTROL);
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(30*HZ/100);
+               msleep(300);
                if (!(inb_status(addr) & DIR)) {
                        if (elp_debug > 0)
                                printk(notfound_msg, 3);
index e843109d4f62dc06a42c7c940c41fd22ebaef166..977935a3d898d00fcfb6a2c12e297f6a7a49cc83 100644 (file)
@@ -217,6 +217,7 @@ static void el3_poll_controller(struct net_device *dev);
 static struct eisa_device_id el3_eisa_ids[] = {
                { "TCM5092" },
                { "TCM5093" },
+               { "TCM5095" },
                { "" }
 };
 
index c4cf4fcd13444eedec8e5693b69d84b782d70e1f..91d1c4c24d9b9616799fa3cc7c171ad51f139e76 100644 (file)
@@ -365,7 +365,7 @@ static int nopnp;
 #endif /* __ISAPNP__ */
 
 static struct net_device *corkscrew_scan(int unit);
-static void corkscrew_setup(struct net_device *dev, int ioaddr,
+static int corkscrew_setup(struct net_device *dev, int ioaddr,
                            struct pnp_dev *idev, int card_number);
 static int corkscrew_open(struct net_device *dev);
 static void corkscrew_timer(unsigned long arg);
@@ -539,10 +539,9 @@ static struct net_device *corkscrew_scan(int unit)
                        printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
                                inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
                        /* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */
-                       corkscrew_setup(dev, ioaddr, idev, cards_found++);
                        SET_NETDEV_DEV(dev, &idev->dev);
                        pnp_cards++;
-                       err = register_netdev(dev);
+                       err = corkscrew_setup(dev, ioaddr, idev, cards_found++);
                        if (!err)
                                return dev;
                        cleanup_card(dev);
@@ -558,8 +557,7 @@ no_pnp:
 
                printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
                     inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
-               corkscrew_setup(dev, ioaddr, NULL, cards_found++);
-               err = register_netdev(dev);
+               err = corkscrew_setup(dev, ioaddr, NULL, cards_found++);
                if (!err)
                        return dev;
                cleanup_card(dev);
@@ -568,7 +566,7 @@ no_pnp:
        return NULL;
 }
 
-static void corkscrew_setup(struct net_device *dev, int ioaddr,
+static int corkscrew_setup(struct net_device *dev, int ioaddr,
                            struct pnp_dev *idev, int card_number)
 {
        struct corkscrew_private *vp = netdev_priv(dev);
@@ -691,6 +689,8 @@ static void corkscrew_setup(struct net_device *dev, int ioaddr,
        dev->get_stats = &corkscrew_get_stats;
        dev->set_multicast_list = &set_rx_mode;
        dev->ethtool_ops = &netdev_ethtool_ops;
+
+       return register_netdev(dev);
 }
 \f
 
@@ -822,7 +822,7 @@ static int corkscrew_open(struct net_device *dev)
                                break;  /* Bad news!  */
                        skb->dev = dev; /* Mark as being used by this device. */
                        skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
-                       vp->rx_ring[i].addr = isa_virt_to_bus(skb->tail);
+                       vp->rx_ring[i].addr = isa_virt_to_bus(skb->data);
                }
                vp->rx_ring[i - 1].next = isa_virt_to_bus(&vp->rx_ring[0]);     /* Wrap the ring. */
                outl(isa_virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
@@ -1406,7 +1406,7 @@ static int boomerang_rx(struct net_device *dev)
                                break;  /* Bad news!  */
                        skb->dev = dev; /* Mark as being used by this device. */
                        skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
-                       vp->rx_ring[entry].addr = isa_virt_to_bus(skb->tail);
+                       vp->rx_ring[entry].addr = isa_virt_to_bus(skb->data);
                        vp->rx_skbuff[entry] = skb;
                }
                vp->rx_ring[entry].status = 0;  /* Clear complete bit. */
index 8f6b2fa13e283665c9ad9744f52f912e08f0b6b5..9e1fe2e0478c3e783492e435c276e00f2d3935f1 100644 (file)
@@ -572,6 +572,10 @@ static int __init do_elmc_probe(struct net_device *dev)
         dev->flags&=~IFF_MULTICAST;     /* Multicast doesn't work */
 #endif
 
+       retval = register_netdev(dev);
+       if (retval)
+               goto err_out;
+
        return 0;
 err_out:
        mca_set_adapter_procfn(slot, NULL, NULL);
@@ -600,12 +604,7 @@ struct net_device * __init elmc_probe(int unit)
        err = do_elmc_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -1275,6 +1274,7 @@ module_param_array(irq, int, NULL, 0);
 module_param_array(io, int, NULL, 0);
 MODULE_PARM_DESC(io, "EtherLink/MC I/O base address(es)");
 MODULE_PARM_DESC(irq, "EtherLink/MC IRQ number(s)");
+MODULE_LICENSE("GPL");
 
 int init_module(void)
 {
@@ -1288,12 +1288,9 @@ int init_module(void)
                dev->irq=irq[this_dev];
                dev->base_addr=io[this_dev];
                if (do_elmc_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_elmc[this_dev] = dev;
-                               found++;
-                               continue;
-                       }
-                       cleanup_card(dev);
+                       dev_elmc[this_dev] = dev;
+                       found++;
+                       continue;
                }
                free_netdev(dev);
                if (io[this_dev]==0)
index 80ec9aa575bb5df228428afb5d84ae42c3407c35..07746b95fd83754cb3875bdea4ebe9b545bbcf6c 100644 (file)
@@ -1802,7 +1802,7 @@ vortex_open(struct net_device *dev)
                                break;                  /* Bad news!  */
                        skb->dev = dev;                 /* Mark as being used by this device. */
                        skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
-                       vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
+                       vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
                }
                if (i != RX_RING_SIZE) {
                        int j;
@@ -2632,7 +2632,7 @@ boomerang_rx(struct net_device *dev)
                                pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
                                /* 'skb_put()' points to the start of sk_buff data area. */
                                memcpy(skb_put(skb, pkt_len),
-                                          vp->rx_skbuff[entry]->tail,
+                                          vp->rx_skbuff[entry]->data,
                                           pkt_len);
                                pci_dma_sync_single_for_device(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
                                vp->rx_copy++;
@@ -2678,7 +2678,7 @@ boomerang_rx(struct net_device *dev)
                        }
                        skb->dev = dev;                 /* Mark as being used by this device. */
                        skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
-                       vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
+                       vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
                        vp->rx_skbuff[entry] = skb;
                }
                vp->rx_ring[entry].status = 0;  /* Clear complete bit. */
index 72cdf19e1be1fd6358c39718ea534e73e5531b87..7b293f01c9ed1309b67d0523c18191e91c5fc1ba 100644 (file)
@@ -61,6 +61,7 @@
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/delay.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
@@ -595,7 +596,7 @@ rx_status_loop:
 
                mapping =
                cp->rx_skb[rx_tail].mapping =
-                       pci_map_single(cp->pdev, new_skb->tail,
+                       pci_map_single(cp->pdev, new_skb->data,
                                       buflen, PCI_DMA_FROMDEVICE);
                cp->rx_skb[rx_tail].skb = new_skb;
 
@@ -1100,7 +1101,7 @@ static int cp_refill_rx (struct cp_private *cp)
                skb_reserve(skb, RX_OFFSET);
 
                cp->rx_skb[i].mapping = pci_map_single(cp->pdev,
-                       skb->tail, cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+                       skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
                cp->rx_skb[i].skb = skb;
 
                cp->rx_ring[i].opts2 = 0;
@@ -1515,22 +1516,22 @@ static void cp_get_ethtool_stats (struct net_device *dev,
                                  struct ethtool_stats *estats, u64 *tmp_stats)
 {
        struct cp_private *cp = netdev_priv(dev);
-       unsigned int work = 100;
        int i;
 
+       memset(cp->nic_stats, 0, sizeof(struct cp_dma_stats));
+
        /* begin NIC statistics dump */
        cpw32(StatsAddr + 4, (cp->nic_stats_dma >> 16) >> 16);
        cpw32(StatsAddr, (cp->nic_stats_dma & 0xffffffff) | DumpStats);
        cpr32(StatsAddr);
 
-       while (work-- > 0) {
+       for (i = 0; i < 1000; i++) {
                if ((cpr32(StatsAddr) & DumpStats) == 0)
                        break;
-               cpu_relax();
+               udelay(10);
        }
-
-       if (cpr32(StatsAddr) & DumpStats)
-               return /* -EIO */;
+       cpw32(StatsAddr, 0);
+       cpw32(StatsAddr + 4, 0);
 
        i = 0;
        tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_ok);
@@ -1732,19 +1733,19 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
        /* Configure DMA attributes. */
        if ((sizeof(dma_addr_t) > 4) &&
-           !pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL) &&
-           !pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
+           !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) &&
+           !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
                pci_using_dac = 1;
        } else {
                pci_using_dac = 0;
 
-               rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+               rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
                if (rc) {
                        printk(KERN_ERR PFX "No usable DMA configuration, "
                               "aborting.\n");
                        goto err_out_res;
                }
-               rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL);
+               rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
                if (rc) {
                        printk(KERN_ERR PFX "No usable consistent DMA configuration, "
                               "aborting.\n");
index 047202c4d9a8b23bd150eae38654c211485f3ccf..5a4a08a7c9518da338ce6f0fcea40bfad4b36d8b 100644 (file)
@@ -1606,7 +1606,7 @@ static int rtl8139_thread (void *data)
                do {
                        timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout);
                        /* make swsusp happy with our thread */
-                       try_to_freeze(PF_FREEZE);
+                       try_to_freeze();
                } while (!signal_pending (current) && (timeout > 0));
 
                if (signal_pending (current)) {
index 65f97b1dc581838012a68dca1002012f74bbab14..13b745b39667710b33308b4c8f4d770758fec599 100644 (file)
@@ -546,11 +546,11 @@ static inline void init_rx_bufs(struct net_device *dev)
                rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1));
                rbd->b_addr = WSWAPrbd(virt_to_bus(rbd));
                rbd->skb = skb;
-               rbd->v_data = skb->tail;
-               rbd->b_data = WSWAPchar(virt_to_bus(skb->tail));
+               rbd->v_data = skb->data;
+               rbd->b_data = WSWAPchar(virt_to_bus(skb->data));
                rbd->size = PKT_BUF_SZ;
 #ifdef __mc68000__
-               cache_clear(virt_to_phys(skb->tail), PKT_BUF_SZ);
+               cache_clear(virt_to_phys(skb->data), PKT_BUF_SZ);
 #endif
        }
        lp->rbd_head = lp->rbds;
@@ -816,10 +816,10 @@ static inline int i596_rx(struct net_device *dev)
                                rx_in_place = 1;
                                rbd->skb = newskb;
                                newskb->dev = dev;
-                               rbd->v_data = newskb->tail;
-                               rbd->b_data = WSWAPchar(virt_to_bus(newskb->tail));
+                               rbd->v_data = newskb->data;
+                               rbd->b_data = WSWAPchar(virt_to_bus(newskb->data));
 #ifdef __mc68000__
-                               cache_clear(virt_to_phys(newskb->tail), PKT_BUF_SZ);
+                               cache_clear(virt_to_phys(newskb->data), PKT_BUF_SZ);
 #endif
                        }
                        else
@@ -840,7 +840,7 @@ memory_squeeze:
                                skb->protocol=eth_type_trans(skb,dev);
                                skb->len = pkt_len;
 #ifdef __mc68000__
-                               cache_clear(virt_to_phys(rbd->skb->tail),
+                               cache_clear(virt_to_phys(rbd->skb->data),
                                                pkt_len);
 #endif
                                netif_rx(skb);
index fa9f76c953ddaf930ca929f05c1d3702bf4088c7..2b55687f6ee9d678a468f7a1ffdb632a5b865694 100644 (file)
@@ -1320,7 +1320,7 @@ config FORCEDETH
 
 config CS89x0
        tristate "CS89x0 support"
-       depends on NET_PCI && (ISA || ARCH_IXDP2X01)
+       depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105
        ---help---
          Support for CS89x0 chipset based Ethernet cards. If you have a
          network (Ethernet) card of this type, say Y and read the
@@ -1488,14 +1488,14 @@ config 8139CP
          will be called 8139cp.  This is recommended.
 
 config 8139TOO
-       tristate "RealTek RTL-8139 PCI Fast Ethernet Adapter support"
+       tristate "RealTek RTL-8129/8130/8139 PCI Fast Ethernet Adapter support"
        depends on NET_PCI && PCI
        select CRC32
        select MII
        ---help---
          This is a driver for the Fast Ethernet PCI network cards based on
-         the RTL8139 chips. If you have one of those, say Y and read
-         the Ethernet-HOWTO <http://www.tldp.org/docs.html#howto>.
+         the RTL 8129/8130/8139 chips. If you have one of those, say Y and
+         read the Ethernet-HOWTO <http://www.tldp.org/docs.html#howto>.
 
          To compile this driver as a module, choose M here: the module
          will be called 8139too.  This is recommended.
index 24fba36b5c1d8b8f3020df32ff43e87817222423..91791ba3776930bb8354ad691680ac00e0882b85 100644 (file)
@@ -146,12 +146,7 @@ struct net_device * __init ac3200_probe(int unit)
        err = do_ac3200_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -273,7 +268,14 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
        dev->poll_controller = ei_poll;
 #endif
        NS8390_init(dev, 0);
+
+       retval = register_netdev(dev);
+       if (retval)
+               goto out2;
        return 0;
+out2:
+       if (ei_status.reg0)
+               iounmap((void *)dev->mem_start);
 out1:
        free_irq(dev->irq, dev);
 out:
@@ -392,11 +394,8 @@ init_module(void)
                dev->base_addr = io[this_dev];
                dev->mem_start = mem[this_dev];         /* Currently ignored by driver */
                if (do_ac3200_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_ac32[found++] = dev;
-                               continue;
-                       }
-                       cleanup_card(dev);
+                       dev_ac32[found++] = dev;
+                       continue;
                }
                free_netdev(dev);
                printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]);
index 6eea3a8accb72757b43759fd10910317013d3729..dbecc6bf78519ce09088cad0e0b48d96200a8c07 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -1167,9 +1168,9 @@ static int __devinit ace_init(struct net_device *dev)
        /*
         * Configure DMA attributes.
         */
-       if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
+       if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
                ap->pci_using_dac = 1;
-       } else if (!pci_set_dma_mask(pdev, 0xffffffffULL)) {
+       } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
                ap->pci_using_dac = 0;
        } else {
                ecode = -ENODEV;
index b7dd7260cafbf137656a3f50059a7136b55ec661..8618012df06aabc6610297191c80242769bb37c3 100755 (executable)
@@ -87,6 +87,7 @@ Revision History:
 #include <linux/if_vlan.h>
 #include <linux/ctype.h>       
 #include <linux/crc32.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -2006,12 +2007,11 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
        }
 
        /* Initialize DMA */
-       if(!pci_dma_supported(pdev, 0xffffffff)){
+       if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) < 0) {
                printk(KERN_ERR "amd8111e: DMA not supported,"
                        "exiting.\n");
-               goto  err_free_reg;
-       } else
-               pdev->dma_mask = 0xffffffff;
+               goto err_free_reg;
+       }
        
        reg_addr = pci_resource_start(pdev, 0);
        reg_len = pci_resource_len(pdev, 0);
index 2e28c201dcc01722a4d39db05c16de45f0f2129f..942a2819576c2efe229c6c6cb71fc4a9c9d79b4f 100644 (file)
@@ -68,7 +68,6 @@ struct etherh_priv {
        void __iomem    *dma_base;
        unsigned int    id;
        void __iomem    *ctrl_port;
-       void __iomem    *base;
        unsigned char   ctrl;
        u32             supported;
 };
@@ -178,7 +177,7 @@ etherh_setif(struct net_device *dev)
        switch (etherh_priv(dev)->id) {
        case PROD_I3_ETHERLAN600:
        case PROD_I3_ETHERLAN600A:
-               addr = etherh_priv(dev)->base + EN0_RCNTHI;
+               addr = (void *)dev->base_addr + EN0_RCNTHI;
 
                switch (dev->if_port) {
                case IF_PORT_10BASE2:
@@ -219,7 +218,7 @@ etherh_getifstat(struct net_device *dev)
        switch (etherh_priv(dev)->id) {
        case PROD_I3_ETHERLAN600:
        case PROD_I3_ETHERLAN600A:
-               addr = etherh_priv(dev)->base + EN0_RCNTHI;
+               addr = (void *)dev->base_addr + EN0_RCNTHI;
                switch (dev->if_port) {
                case IF_PORT_10BASE2:
                        stat = 1;
@@ -282,7 +281,7 @@ static void
 etherh_reset(struct net_device *dev)
 {
        struct ei_device *ei_local = netdev_priv(dev);
-       void __iomem *addr = etherh_priv(dev)->base;
+       void __iomem *addr = (void *)dev->base_addr;
 
        writeb(E8390_NODMA+E8390_PAGE0+E8390_STOP, addr);
 
@@ -328,7 +327,7 @@ etherh_block_output (struct net_device *dev, int count, const unsigned char *buf
 
        ei_local->dmaing = 1;
 
-       addr = etherh_priv(dev)->base;
+       addr = (void *)dev->base_addr;
        dma_base = etherh_priv(dev)->dma_base;
 
        count = (count + 1) & ~1;
@@ -388,7 +387,7 @@ etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int
 
        ei_local->dmaing = 1;
 
-       addr = etherh_priv(dev)->base;
+       addr = (void *)dev->base_addr;
        dma_base = etherh_priv(dev)->dma_base;
 
        buf = skb->data;
@@ -428,7 +427,7 @@ etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_p
 
        ei_local->dmaing = 1;
 
-       addr = etherh_priv(dev)->base;
+       addr = (void *)dev->base_addr;
        dma_base = etherh_priv(dev)->dma_base;
 
        writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
@@ -697,8 +696,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
                eh->ctrl_port = eh->ioc_fast;
        }
 
-       eh->base = eh->memc + data->ns8390_offset;
-       dev->base_addr = (unsigned long)eh->base;
+       dev->base_addr = (unsigned long)eh->memc + data->ns8390_offset;
        eh->dma_base = eh->memc + data->dataport_offset;
        eh->ctrl_port += data->ctrlport_offset;
 
index b8ab2b6355ebfac9f7a96f72d3757d01db1c7f7b..e613cc289749d6a89ee595eb24b8285a95b41163 100644 (file)
        only is it difficult to detect, it also moves around in I/O space in
        response to inb()s from other device probes!
 */
-/*
-       99/03/03  Allied Telesis RE1000 Plus support by T.Hagawa
-       99/12/30        port to 2.3.35 by K.Takai
-*/
 
 #include <linux/config.h>
 #include <linux/errno.h>
index 3fe8ba992c38b32b8fd5b55e8f503e6231afbfaf..f1bd45e3da31cd0ea482fd0db6995ae319977415 100644 (file)
@@ -1285,6 +1285,9 @@ static int b44_open(struct net_device *dev)
        b44_init_hw(bp);
        bp->flags |= B44_FLAG_INIT_COMPLETE;
 
+       netif_carrier_off(dev);
+       b44_check_phy(bp);
+
        spin_unlock_irq(&bp->lock);
 
        init_timer(&bp->timer);
index 6233c4ffb80513ba74facb3662ff792134c72df8..a2e8dda5afac6b30aa0a608f521789415fb637ea 100644 (file)
@@ -2346,7 +2346,6 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
 {
        struct slave *slave, *start_at;
        struct bonding *bond = dev->priv;
-       struct ethhdr *data = (struct ethhdr *)skb->data;
        int slave_agg_no;
        int slaves_in_agg;
        int agg_id;
@@ -2377,7 +2376,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
                goto out;
        }
 
-       slave_agg_no = (data->h_dest[5]^bond->dev->dev_addr[5]) % slaves_in_agg;
+       slave_agg_no = bond->xmit_hash_policy(skb, dev, slaves_in_agg);
 
        bond_for_each_slave(bond, slave, i) {
                struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
index 269a5e407349e90e3c9c7f681979eea9732c5c17..2c930da90a854d957f881cff3b3032ce0b1ff921 100644 (file)
  *        Solution is to move call to dev_remove_pack outside of the
  *        spinlock.
  *        Set version to 2.6.1.
- *
+ * 2005/06/05 - Jay Vosburgh <fubar@us.ibm.com>
+ *     - Support for generating gratuitous ARPs in active-backup mode.
+ *       Includes support for VLAN tagging all bonding-generated ARPs
+ *       as needed.  Set version to 2.6.2.
+ * 2005/06/08 - Jason Gabler <jygabler at lbl dot gov>
+ *     - alternate hashing policy support for mode 2
+ *       * Added kernel parameter "xmit_hash_policy" to allow the selection
+ *         of different hashing policies for mode 2.  The original mode 2
+ *         policy is the default, now found in xmit_hash_policy_layer2().
+ *       * Added xmit_hash_policy_layer34()
+ *     - Modified by Jay Vosburgh <fubar@us.ibm.com> to also support mode 4.
+ *       Set version to 2.6.3.
  */
 
 //#define BONDING_DEBUG 1
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
+#include <net/ip.h>
 #include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
 #include <linux/if_bonding.h>
+#include <net/route.h>
 #include "bonding.h"
 #include "bond_3ad.h"
 #include "bond_alb.h"
@@ -537,6 +552,7 @@ static int use_carrier      = 1;
 static char *mode      = NULL;
 static char *primary   = NULL;
 static char *lacp_rate = NULL;
+static char *xmit_hash_policy = NULL;
 static int arp_interval = BOND_LINK_ARP_INTERV;
 static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
 
@@ -556,6 +572,8 @@ module_param(primary, charp, 0);
 MODULE_PARM_DESC(primary, "Primary network device to use");
 module_param(lacp_rate, charp, 0);
 MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner (slow/fast)");
+module_param(xmit_hash_policy, charp, 0);
+MODULE_PARM_DESC(xmit_hash_policy, "XOR hashing method : 0 for layer 2 (default), 1 for layer 3+4");
 module_param(arp_interval, int, 0);
 MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
 module_param_array(arp_ip_target, charp, NULL, 0);
@@ -574,8 +592,8 @@ static struct proc_dir_entry *bond_proc_dir = NULL;
 
 static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;
 static int arp_ip_count        = 0;
-static u32 my_ip       = 0;
 static int bond_mode   = BOND_MODE_ROUNDROBIN;
+static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2;
 static int lacp_fast   = 0;
 static int app_abi_ver = 0;
 static int orig_app_abi_ver = -1; /* This is used to save the first ABI version
@@ -585,7 +603,6 @@ static int orig_app_abi_ver = -1; /* This is used to save the first ABI version
                                   * command comes from an application using
                                   * another ABI version.
                                   */
-
 struct bond_parm_tbl {
        char *modename;
        int mode;
@@ -608,9 +625,16 @@ static struct bond_parm_tbl bond_mode_tbl[] = {
 {      NULL,                   -1},
 };
 
+static struct bond_parm_tbl xmit_hashtype_tbl[] = {
+{      "layer2",               BOND_XMIT_POLICY_LAYER2},
+{      "layer3+4",             BOND_XMIT_POLICY_LAYER34},
+{      NULL,                   -1},
+};
+
 /*-------------------------- Forward declarations ---------------------------*/
 
-static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode);
+static inline void bond_set_mode_ops(struct bonding *bond, int mode);
+static void bond_send_gratuitous_arp(struct bonding *bond);
 
 /*---------------------------- General routines -----------------------------*/
 
@@ -659,6 +683,7 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id)
 
        INIT_LIST_HEAD(&vlan->vlan_list);
        vlan->vlan_id = vlan_id;
+       vlan->vlan_ip = 0;
 
        write_lock_bh(&bond->lock);
 
@@ -1468,16 +1493,6 @@ static void bond_change_active_slave(struct bonding *bond, struct slave *new_act
                }
        }
 
-       if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
-               if (old_active) {
-                       bond_set_slave_inactive_flags(old_active);
-               }
-
-               if (new_active) {
-                       bond_set_slave_active_flags(new_active);
-               }
-       }
-
        if (USES_PRIMARY(bond->params.mode)) {
                bond_mc_swap(bond, new_active, old_active);
        }
@@ -1488,6 +1503,17 @@ static void bond_change_active_slave(struct bonding *bond, struct slave *new_act
        } else {
                bond->curr_active_slave = new_active;
        }
+
+       if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
+               if (old_active) {
+                       bond_set_slave_inactive_flags(old_active);
+               }
+
+               if (new_active) {
+                       bond_set_slave_active_flags(new_active);
+               }
+               bond_send_gratuitous_arp(bond);
+       }
 }
 
 /**
@@ -2694,15 +2720,180 @@ out:
        read_unlock(&bond->lock);
 }
 
+
+static u32 bond_glean_dev_ip(struct net_device *dev)
+{
+       struct in_device *idev;
+       struct in_ifaddr *ifa;
+       u32 addr = 0;
+
+       if (!dev)
+               return 0;
+
+       rcu_read_lock();
+       idev = __in_dev_get(dev);
+       if (!idev)
+               goto out;
+
+       ifa = idev->ifa_list;
+       if (!ifa)
+               goto out;
+
+       addr = ifa->ifa_local;
+out:
+       rcu_read_unlock();
+       return addr;
+}
+
+static int bond_has_ip(struct bonding *bond)
+{
+       struct vlan_entry *vlan, *vlan_next;
+
+       if (bond->master_ip)
+               return 1;
+
+       if (list_empty(&bond->vlan_list))
+               return 0;
+
+       list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
+                                vlan_list) {
+               if (vlan->vlan_ip)
+                       return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * We go to the (large) trouble of VLAN tagging ARP frames because
+ * switches in VLAN mode (especially if ports are configured as
+ * "native" to a VLAN) might not pass non-tagged frames.
+ */
+static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32 dest_ip, u32 src_ip, unsigned short vlan_id)
+{
+       struct sk_buff *skb;
+
+       dprintk("arp %d on slave %s: dst %x src %x vid %d\n", arp_op,
+              slave_dev->name, dest_ip, src_ip, vlan_id);
+              
+       skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip,
+                        NULL, slave_dev->dev_addr, NULL);
+
+       if (!skb) {
+               printk(KERN_ERR DRV_NAME ": ARP packet allocation failed\n");
+               return;
+       }
+       if (vlan_id) {
+               skb = vlan_put_tag(skb, vlan_id);
+               if (!skb) {
+                       printk(KERN_ERR DRV_NAME ": failed to insert VLAN tag\n");
+                       return;
+               }
+       }
+       arp_xmit(skb);
+}
+
+
 static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
 {
-       int i;
+       int i, vlan_id, rv;
        u32 *targets = bond->params.arp_targets;
+       struct vlan_entry *vlan, *vlan_next;
+       struct net_device *vlan_dev;
+       struct flowi fl;
+       struct rtable *rt;
 
        for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
-               arp_send(ARPOP_REQUEST, ETH_P_ARP, targets[i], slave->dev,
-                        my_ip, NULL, slave->dev->dev_addr,
-                        NULL);
+               dprintk("basa: target %x\n", targets[i]);
+               if (list_empty(&bond->vlan_list)) {
+                       dprintk("basa: empty vlan: arp_send\n");
+                       bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
+                                     bond->master_ip, 0);
+                       continue;
+               }
+
+               /*
+                * If VLANs are configured, we do a route lookup to
+                * determine which VLAN interface would be used, so we
+                * can tag the ARP with the proper VLAN tag.
+                */
+               memset(&fl, 0, sizeof(fl));
+               fl.fl4_dst = targets[i];
+               fl.fl4_tos = RTO_ONLINK;
+
+               rv = ip_route_output_key(&rt, &fl);
+               if (rv) {
+                       if (net_ratelimit()) {
+                               printk(KERN_WARNING DRV_NAME
+                            ": %s: no route to arp_ip_target %u.%u.%u.%u\n",
+                                      bond->dev->name, NIPQUAD(fl.fl4_dst));
+                       }
+                       continue;
+               }
+
+               /*
+                * This target is not on a VLAN
+                */
+               if (rt->u.dst.dev == bond->dev) {
+                       dprintk("basa: rtdev == bond->dev: arp_send\n");
+                       bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
+                                     bond->master_ip, 0);
+                       continue;
+               }
+
+               vlan_id = 0;
+               list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
+                                        vlan_list) {
+                       vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id];
+                       if (vlan_dev == rt->u.dst.dev) {
+                               vlan_id = vlan->vlan_id;
+                               dprintk("basa: vlan match on %s %d\n",
+                                      vlan_dev->name, vlan_id);
+                               break;
+                       }
+               }
+
+               if (vlan_id) {
+                       bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
+                                     vlan->vlan_ip, vlan_id);
+                       continue;
+               }
+
+               if (net_ratelimit()) {
+                       printk(KERN_WARNING DRV_NAME
+              ": %s: no path to arp_ip_target %u.%u.%u.%u via rt.dev %s\n",
+                              bond->dev->name, NIPQUAD(fl.fl4_dst),
+                              rt->u.dst.dev ? rt->u.dst.dev->name : "NULL");
+               }
+       }
+}
+
+/*
+ * Kick out a gratuitous ARP for an IP on the bonding master plus one
+ * for each VLAN above us.
+ */
+static void bond_send_gratuitous_arp(struct bonding *bond)
+{
+       struct slave *slave = bond->curr_active_slave;
+       struct vlan_entry *vlan;
+       struct net_device *vlan_dev;
+
+       dprintk("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name,
+                               slave ? slave->dev->name : "NULL");
+       if (!slave)
+               return;
+
+       if (bond->master_ip) {
+               bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip,
+                                 bond->master_ip, 0);
+       }
+
+       list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
+               vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id];
+               if (vlan->vlan_ip) {
+                       bond_arp_send(slave->dev, ARPOP_REPLY, vlan->vlan_ip,
+                                     vlan->vlan_ip, vlan->vlan_id);
+               }
        }
 }
 
@@ -2781,7 +2972,7 @@ static void bond_loadbalance_arp_mon(struct net_device *bond_dev)
                         */
                        if (((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) ||
                            (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) &&
-                            my_ip)) {
+                            bond_has_ip(bond))) {
 
                                slave->link  = BOND_LINK_DOWN;
                                slave->state = BOND_STATE_BACKUP;
@@ -2920,7 +3111,7 @@ static void bond_activebackup_arp_mon(struct net_device *bond_dev)
                        if ((slave != bond->curr_active_slave) &&
                            (!bond->current_arp_slave) &&
                            (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) &&
-                            my_ip)) {
+                            bond_has_ip(bond))) {
                                /* a backup slave has gone down; three times
                                 * the delta allows the current slave to be
                                 * taken out before the backup slave.
@@ -2966,8 +3157,8 @@ static void bond_activebackup_arp_mon(struct net_device *bond_dev)
                 * if it is up and needs to take over as the curr_active_slave
                 */
                if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) ||
-                    (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) &&
-                     my_ip)) &&
+           (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) &&
+            bond_has_ip(bond))) &&
                    ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) {
 
                        slave->link  = BOND_LINK_DOWN;
@@ -3019,7 +3210,7 @@ static void bond_activebackup_arp_mon(struct net_device *bond_dev)
                /* the current slave must tx an arp to ensure backup slaves
                 * rx traffic
                 */
-               if (slave && my_ip) {
+               if (slave && bond_has_ip(bond)) {
                        bond_arp_send_all(bond, slave);
                }
        }
@@ -3471,10 +3662,67 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v
        return NOTIFY_DONE;
 }
 
+/*
+ * bond_inetaddr_event: handle inetaddr notifier chain events.
+ *
+ * We keep track of device IPs primarily to use as source addresses in
+ * ARP monitor probes (rather than spewing out broadcasts all the time).
+ *
+ * We track one IP for the main device (if it has one), plus one per VLAN.
+ */
+static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+       struct in_ifaddr *ifa = ptr;
+       struct net_device *vlan_dev, *event_dev = ifa->ifa_dev->dev;
+       struct bonding *bond, *bond_next;
+       struct vlan_entry *vlan, *vlan_next;
+
+       list_for_each_entry_safe(bond, bond_next, &bond_dev_list, bond_list) {
+               if (bond->dev == event_dev) {
+                       switch (event) {
+                       case NETDEV_UP:
+                               bond->master_ip = ifa->ifa_local;
+                               return NOTIFY_OK;
+                       case NETDEV_DOWN:
+                               bond->master_ip = bond_glean_dev_ip(bond->dev);
+                               return NOTIFY_OK;
+                       default:
+                               return NOTIFY_DONE;
+                       }
+               }
+
+               if (list_empty(&bond->vlan_list))
+                       continue;
+
+               list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
+                                        vlan_list) {
+                       vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id];
+                       if (vlan_dev == event_dev) {
+                               switch (event) {
+                               case NETDEV_UP:
+                                       vlan->vlan_ip = ifa->ifa_local;
+                                       return NOTIFY_OK;
+                               case NETDEV_DOWN:
+                                       vlan->vlan_ip =
+                                               bond_glean_dev_ip(vlan_dev);
+                                       return NOTIFY_OK;
+                               default:
+                                       return NOTIFY_DONE;
+                               }
+                       }
+               }
+       }
+       return NOTIFY_DONE;
+}
+
 static struct notifier_block bond_netdev_notifier = {
        .notifier_call = bond_netdev_event,
 };
 
+static struct notifier_block bond_inetaddr_notifier = {
+       .notifier_call = bond_inetaddr_event,
+};
+
 /*-------------------------- Packet type handling ---------------------------*/
 
 /* register to receive lacpdus on a bond */
@@ -3496,6 +3744,46 @@ static void bond_unregister_lacpdu(struct bonding *bond)
        dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type));
 }
 
+/*---------------------------- Hashing Policies -----------------------------*/
+
+/*
+ * Hash for the the output device based upon layer 3 and layer 4 data. If
+ * the packet is a frag or not TCP or UDP, just use layer 3 data.  If it is
+ * altogether not IP, mimic bond_xmit_hash_policy_l2()
+ */
+static int bond_xmit_hash_policy_l34(struct sk_buff *skb,
+                                   struct net_device *bond_dev, int count)
+{
+       struct ethhdr *data = (struct ethhdr *)skb->data;
+       struct iphdr *iph = skb->nh.iph;
+       u16 *layer4hdr = (u16 *)((u32 *)iph + iph->ihl);
+       int layer4_xor = 0;
+
+       if (skb->protocol == __constant_htons(ETH_P_IP)) {
+               if (!(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) &&
+                   (iph->protocol == IPPROTO_TCP ||
+                    iph->protocol == IPPROTO_UDP)) {
+                       layer4_xor = htons((*layer4hdr ^ *(layer4hdr + 1)));
+               }
+               return (layer4_xor ^
+                       ((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count;
+
+       }
+
+       return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count;
+}
+
+/*
+ * Hash for the output device based upon layer 2 data
+ */
+static int bond_xmit_hash_policy_l2(struct sk_buff *skb,
+                                  struct net_device *bond_dev, int count)
+{
+       struct ethhdr *data = (struct ethhdr *)skb->data;
+
+       return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count;
+}
+
 /*-------------------------- Device entry points ----------------------------*/
 
 static int bond_open(struct net_device *bond_dev)
@@ -4060,17 +4348,6 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
        struct bonding *bond = bond_dev->priv;
        int res = 1;
 
-       /* if we are sending arp packets, try to at least
-          identify our own ip address */
-       if (bond->params.arp_interval && !my_ip &&
-               (skb->protocol == __constant_htons(ETH_P_ARP))) {
-               char *the_ip = (char *)skb->data +
-                               sizeof(struct ethhdr) +
-                               sizeof(struct arphdr) +
-                               ETH_ALEN;
-               memcpy(&my_ip, the_ip, 4);
-       }
-
        read_lock(&bond->lock);
        read_lock(&bond->curr_slave_lock);
 
@@ -4093,14 +4370,13 @@ out:
 }
 
 /*
- * in XOR mode, we determine the output device by performing xor on
- * the source and destination hw adresses.  If this device is not
- * enabled, find the next slave following this xor slave.
+ * In bond_xmit_xor() , we determine the output device by using a pre-
+ * determined xmit_hash_policy(), If the selected device is not enabled,
+ * find the next active slave.
  */
 static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = bond_dev->priv;
-       struct ethhdr *data = (struct ethhdr *)skb->data;
        struct slave *slave, *start_at;
        int slave_no;
        int i;
@@ -4112,7 +4388,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
                goto out;
        }
 
-       slave_no = (data->h_dest[5]^bond_dev->dev_addr[5]) % bond->slave_cnt;
+       slave_no = bond->xmit_hash_policy(skb, bond_dev, bond->slave_cnt);
 
        bond_for_each_slave(bond, slave, i) {
                slave_no--;
@@ -4208,8 +4484,10 @@ out:
 /*
  * set bond mode specific net device operations
  */
-static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode)
+static inline void bond_set_mode_ops(struct bonding *bond, int mode)
 {
+       struct net_device *bond_dev = bond->dev;
+
        switch (mode) {
        case BOND_MODE_ROUNDROBIN:
                bond_dev->hard_start_xmit = bond_xmit_roundrobin;
@@ -4219,12 +4497,20 @@ static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode)
                break;
        case BOND_MODE_XOR:
                bond_dev->hard_start_xmit = bond_xmit_xor;
+               if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34)
+                       bond->xmit_hash_policy = bond_xmit_hash_policy_l34;
+               else
+                       bond->xmit_hash_policy = bond_xmit_hash_policy_l2;
                break;
        case BOND_MODE_BROADCAST:
                bond_dev->hard_start_xmit = bond_xmit_broadcast;
                break;
        case BOND_MODE_8023AD:
                bond_dev->hard_start_xmit = bond_3ad_xmit_xor;
+               if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34)
+                       bond->xmit_hash_policy = bond_xmit_hash_policy_l34;
+               else
+                       bond->xmit_hash_policy = bond_xmit_hash_policy_l2;
                break;
        case BOND_MODE_TLB:
        case BOND_MODE_ALB:
@@ -4273,7 +4559,7 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par
        bond_dev->change_mtu = bond_change_mtu;
        bond_dev->set_mac_address = bond_set_mac_address;
 
-       bond_set_mode_ops(bond_dev, bond->params.mode);
+       bond_set_mode_ops(bond, bond->params.mode);
 
        bond_dev->destructor = free_netdev;
 
@@ -4384,6 +4670,25 @@ static int bond_check_params(struct bond_params *params)
                }
        }
 
+       if (xmit_hash_policy) {
+               if ((bond_mode != BOND_MODE_XOR) &&
+                   (bond_mode != BOND_MODE_8023AD)) {
+                       printk(KERN_INFO DRV_NAME
+                              ": xor_mode param is irrelevant in mode %s\n",
+                              bond_mode_name(bond_mode));
+               } else {
+                       xmit_hashtype = bond_parse_parm(xmit_hash_policy,
+                                                       xmit_hashtype_tbl);
+                       if (xmit_hashtype == -1) {
+                               printk(KERN_ERR DRV_NAME
+                               ": Error: Invalid xmit_hash_policy \"%s\"\n",
+                               xmit_hash_policy == NULL ? "NULL" :
+                                      xmit_hash_policy);
+                               return -EINVAL;
+                       }
+               }
+       }
+
        if (lacp_rate) {
                if (bond_mode != BOND_MODE_8023AD) {
                        printk(KERN_INFO DRV_NAME
@@ -4595,6 +4900,7 @@ static int bond_check_params(struct bond_params *params)
 
        /* fill params struct with the proper values */
        params->mode = bond_mode;
+       params->xmit_policy = xmit_hashtype;
        params->miimon = miimon;
        params->arp_interval = arp_interval;
        params->updelay = updelay;
@@ -4669,6 +4975,7 @@ static int __init bonding_init(void)
 
        rtnl_unlock();
        register_netdevice_notifier(&bond_netdev_notifier);
+       register_inetaddr_notifier(&bond_inetaddr_notifier);
 
        return 0;
 
@@ -4684,6 +4991,7 @@ out_err:
 static void __exit bonding_exit(void)
 {
        unregister_netdevice_notifier(&bond_netdev_notifier);
+       unregister_inetaddr_notifier(&bond_inetaddr_notifier);
 
        rtnl_lock();
        bond_free_all();
index 8c325308489d9b1c9b265e13b8437394cbed2334..d27f377b3eeb52bf2f8a47c3f3b6a5a61463faad 100644 (file)
  *
  * 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
  *     - Code cleanup and style changes
+ *
+ * 2005/05/05 - Jason Gabler <jygabler at lbl dot gov>
+ *      - added "xmit_policy" kernel parameter for alternate hashing policy
+ *       support for mode 2
  */
 
 #ifndef _LINUX_BONDING_H
@@ -36,8 +40,8 @@
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION    "2.6.1"
-#define DRV_RELDATE    "October 29, 2004"
+#define DRV_VERSION    "2.6.3"
+#define DRV_RELDATE    "June 8, 2005"
 #define DRV_NAME       "bonding"
 #define DRV_DESCRIPTION        "Ethernet Channel Bonding Driver"
 
 
 struct bond_params {
        int mode;
+       int xmit_policy;
        int miimon;
        int arp_interval;
        int use_carrier;
@@ -149,6 +154,7 @@ struct bond_params {
 
 struct vlan_entry {
        struct list_head vlan_list;
+       u32 vlan_ip;
        unsigned short vlan_id;
 };
 
@@ -197,6 +203,8 @@ struct bonding {
 #endif /* CONFIG_PROC_FS */
        struct   list_head bond_list;
        struct   dev_mc_list *mc_list;
+       int      (*xmit_hash_policy)(struct sk_buff *, struct net_device *, int);
+       u32      master_ip;
        u16      flags;
        struct   ad_bond_info ad_info;
        struct   alb_bond_info alb_info;
index 5c5f540da26a28618f7c1f2e017039fe713d4f1e..b96d6fb1929ededc702ec46d90858034ea4c660f 100644 (file)
@@ -174,6 +174,13 @@ static unsigned int cs8900_irq_map[] = {1,0,0,0};
 #include <asm/irq.h>
 static unsigned int netcard_portlist[] __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
 static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
+#elif defined(CONFIG_ARCH_PNX0105)
+#include <asm/irq.h>
+#include <asm/arch/gpio.h>
+#define CIRRUS_DEFAULT_BASE    IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x200000)      /* = Physical address 0x48200000 */
+#define CIRRUS_DEFAULT_IRQ     VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */
+static unsigned int netcard_portlist[] __initdata = {CIRRUS_DEFAULT_BASE, 0};
+static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0};
 #else
 static unsigned int netcard_portlist[] __initdata =
    { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
@@ -319,13 +326,7 @@ struct net_device * __init cs89x0_probe(int unit)
        }
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       outw(PP_ChipID, dev->base_addr + ADD_PORT);
-       release_region(dev->base_addr, NETCARD_IO_EXTENT);
 out:
        free_netdev(dev);
        printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected.  Be sure to disable PnP with SETUP\n");
@@ -437,6 +438,30 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
 #endif
         }
 
+#ifdef CONFIG_ARCH_PNX0105
+       initialize_ebi();
+
+       /* Map GPIO registers for the pins connected to the CS8900a. */
+       if (map_cirrus_gpio() < 0)
+               return -ENODEV;
+
+       reset_cirrus();
+
+       /* Map event-router registers. */
+       if (map_event_router() < 0)
+               return -ENODEV;
+
+       enable_cirrus_irq();
+
+       unmap_cirrus_gpio();
+       unmap_event_router();
+
+       dev->base_addr = ioaddr;
+
+       for (i = 0 ; i < 3 ; i++)
+               readreg(dev, 0);
+#endif
+
        /* Grab the region so we can find another board if autoIRQ fails. */
        /* WTF is going on here? */
        if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) {
@@ -678,7 +703,7 @@ printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT));
        } else {
                i = lp->isa_config & INT_NO_MASK;
                if (lp->chip_type == CS8900) {
-#ifdef CONFIG_ARCH_IXDP2X01
+#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105)
                        i = cs8900_irq_map[0];
 #else
                        /* Translate the IRQ using the IRQ mapping table. */
@@ -735,7 +760,13 @@ printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT));
        printk("\n");
        if (net_debug)
                printk("cs89x0_probe1() successful\n");
+
+       retval = register_netdev(dev);
+       if (retval)
+               goto out3;
        return 0;
+out3:
+       outw(PP_ChipID, dev->base_addr + ADD_PORT);
 out2:
        release_region(ioaddr & ~3, NETCARD_IO_EXTENT);
 out1:
@@ -1145,7 +1176,7 @@ net_open(struct net_device *dev)
        int i;
        int ret;
 
-#ifndef CONFIG_SH_HICOSH4 /* uses irq#1, so this won't work */
+#if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX0105) /* uses irq#1, so this won't work */
        if (dev->irq < 2) {
                /* Allow interrupts to be generated by the chip */
 /* Cirrus' release had this: */
@@ -1176,7 +1207,7 @@ net_open(struct net_device *dev)
        else
 #endif
        {
-#ifndef CONFIG_ARCH_IXDP2X01
+#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105)
                if (((1 << dev->irq) & lp->irq_map) == 0) {
                        printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
                                dev->name, dev->irq, lp->irq_map);
@@ -1261,6 +1292,9 @@ net_open(struct net_device *dev)
        case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;
         default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);
         }
+#ifdef CONFIG_ARCH_PNX0105
+       result = A_CNF_10B_T;
+#endif
         if (!result) {
                 printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);
         release_irq:
@@ -1831,13 +1865,6 @@ init_module(void)
        if (ret)
                goto out;
 
-        if (register_netdev(dev) != 0) {
-                printk(KERN_ERR "cs89x0.c: No card found at 0x%x\n", io);
-                ret = -ENXIO;
-               outw(PP_ChipID, dev->base_addr + ADD_PORT);
-               release_region(dev->base_addr, NETCARD_IO_EXTENT);
-               goto out;
-        }
        dev_cs89x0 = dev;
        return 0;
 out:
index b0ef7ad2baad1980bdacb0a323df09afb8c04ef7..bd3ad8e6cce9c46e02a5da048fb78a1ce7f954cd 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_ARCH_IXDP2X01
+#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105)
 /* IXDP2401/IXDP2801 uses dword-aligned register addressing */
 #define CS89x0_PORT(reg) ((reg) * 2)
 #else
index a6aa56598f2712bec5c1a027f5c54f604b89d4a2..5acd35c312acb0734b91fc9a6983224a7f517e78 100644 (file)
  *             Feb 2001        davej           PCI enable cleanups.
  *             04 Aug 2003     macro           Converted to the DMA API.
  *             14 Aug 2004     macro           Fix device names reported.
+ *             14 Jun 2005     macro           Use irqreturn_t.
  */
 
 /* Include files */
 
 /* Version information string should be updated prior to each new release!  */
 #define DRV_NAME "defxx"
-#define DRV_VERSION "v1.07"
-#define DRV_RELDATE "2004/08/14"
+#define DRV_VERSION "v1.08"
+#define DRV_RELDATE "2005/06/14"
 
 static char version[] __devinitdata =
        DRV_NAME ": " DRV_VERSION " " DRV_RELDATE
@@ -247,7 +248,8 @@ static int          dfx_close(struct net_device *dev);
 static void            dfx_int_pr_halt_id(DFX_board_t *bp);
 static void            dfx_int_type_0_process(DFX_board_t *bp);
 static void            dfx_int_common(struct net_device *dev);
-static void            dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t     dfx_interrupt(int irq, void *dev_id,
+                                     struct pt_regs *regs);
 
 static struct          net_device_stats *dfx_ctl_get_stats(struct net_device *dev);
 static void            dfx_ctl_set_multicast_list(struct net_device *dev);
@@ -437,7 +439,8 @@ static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr)
        }
 
        SET_MODULE_OWNER(dev);
-       SET_NETDEV_DEV(dev, &pdev->dev);
+       if (pdev != NULL)
+               SET_NETDEV_DEV(dev, &pdev->dev);
 
        bp = dev->priv;
 
@@ -1225,7 +1228,7 @@ static int dfx_open(struct net_device *dev)
        
        /* Register IRQ - support shared interrupts by passing device ptr */
 
-       ret = request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev);
+       ret = request_irq(dev->irq, dfx_interrupt, SA_SHIRQ, dev->name, dev);
        if (ret) {
                printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
                return ret;
@@ -1680,13 +1683,13 @@ static void dfx_int_common(struct net_device *dev)
  * =================
  * = dfx_interrupt =
  * =================
- *   
+ *
  * Overview:
  *   Interrupt processing routine
- *  
+ *
  * Returns:
- *   None
- *       
+ *   Whether a valid interrupt was seen.
+ *
  * Arguments:
  *   irq       - interrupt vector
  *   dev_id    - pointer to device information
@@ -1699,7 +1702,8 @@ static void dfx_int_common(struct net_device *dev)
  *   structure context.
  *
  * Return Codes:
- *   None
+ *   IRQ_HANDLED - an IRQ was handled.
+ *   IRQ_NONE    - no IRQ was handled.
  *
  * Assumptions:
  *   The interrupt acknowledgement at the hardware level (eg. ACKing the PIC
@@ -1712,60 +1716,70 @@ static void dfx_int_common(struct net_device *dev)
  *   Interrupts are disabled, then reenabled at the adapter.
  */
 
-static void dfx_interrupt(int irq, void *dev_id, struct pt_regs        *regs)
-       {
+static irqreturn_t dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
        struct net_device       *dev = dev_id;
        DFX_board_t             *bp;    /* private board structure pointer */
-       u8                              tmp;    /* used for disabling/enabling ints */
 
        /* Get board pointer only if device structure is valid */
 
        bp = dev->priv;
 
-       spin_lock(&bp->lock);
-       
        /* See if we're already servicing an interrupt */
 
        /* Service adapter interrupts */
 
-       if (bp->bus_type == DFX_BUS_TYPE_PCI)
-               {
-               /* Disable PDQ-PFI interrupts at PFI */
+       if (bp->bus_type == DFX_BUS_TYPE_PCI) {
+               u32 status;
 
-               dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, PFI_MODE_M_DMA_ENB);
+               dfx_port_read_long(bp, PFI_K_REG_STATUS, &status);
+               if (!(status & PFI_STATUS_M_PDQ_INT))
+                       return IRQ_NONE;
 
-               /* Call interrupt service routine for this adapter */
+               spin_lock(&bp->lock);
+
+               /* Disable PDQ-PFI interrupts at PFI */
+               dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL,
+                                   PFI_MODE_M_DMA_ENB);
 
+               /* Call interrupt service routine for this adapter */
                dfx_int_common(dev);
 
                /* Clear PDQ interrupt status bit and reenable interrupts */
-
-               dfx_port_write_long(bp, PFI_K_REG_STATUS, PFI_STATUS_M_PDQ_INT);
+               dfx_port_write_long(bp, PFI_K_REG_STATUS,
+                                   PFI_STATUS_M_PDQ_INT);
                dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL,
-                                       (PFI_MODE_M_PDQ_INT_ENB + PFI_MODE_M_DMA_ENB));
-               }
-       else
-               {
-               /* Disable interrupts at the ESIC */
+                                   (PFI_MODE_M_PDQ_INT_ENB |
+                                    PFI_MODE_M_DMA_ENB));
 
-               dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &tmp);
-               tmp &= ~PI_CONFIG_STAT_0_M_INT_ENB;
-               dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp);
+               spin_unlock(&bp->lock);
+       } else {
+               u8 status;
 
-               /* Call interrupt service routine for this adapter */
+               dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status);
+               if (!(status & PI_CONFIG_STAT_0_M_PEND))
+                       return IRQ_NONE;
 
+               spin_lock(&bp->lock);
+
+               /* Disable interrupts at the ESIC */
+               status &= ~PI_CONFIG_STAT_0_M_INT_ENB;
+               dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status);
+
+               /* Call interrupt service routine for this adapter */
                dfx_int_common(dev);
 
                /* Reenable interrupts at the ESIC */
+               dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status);
+               status |= PI_CONFIG_STAT_0_M_INT_ENB;
+               dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status);
 
-               dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &tmp);
-               tmp |= PI_CONFIG_STAT_0_M_INT_ENB;
-               dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp);
-               }
-
-       spin_unlock(&bp->lock);
+               spin_unlock(&bp->lock);
        }
 
+       return IRQ_HANDLED;
+}
+
 \f
 /*
  * =====================
index aa42b7a2773595dec1c25f20a1c7076f4b4fc066..430c628279b311b7c18b60240961ab6a3ee577b9 100644 (file)
@@ -547,7 +547,7 @@ rio_timer (unsigned long data)
                                skb_reserve (skb, 2);
                                np->rx_ring[entry].fraginfo =
                                    cpu_to_le64 (pci_map_single
-                                        (np->pdev, skb->tail, np->rx_buf_sz,
+                                        (np->pdev, skb->data, np->rx_buf_sz,
                                          PCI_DMA_FROMDEVICE));
                        }
                        np->rx_ring[entry].fraginfo |=
@@ -618,7 +618,7 @@ alloc_list (struct net_device *dev)
                /* Rubicon now supports 40 bits of addressing space. */
                np->rx_ring[i].fraginfo =
                    cpu_to_le64 ( pci_map_single (
-                                 np->pdev, skb->tail, np->rx_buf_sz,
+                                 np->pdev, skb->data, np->rx_buf_sz,
                                  PCI_DMA_FROMDEVICE));
                np->rx_ring[i].fraginfo |= cpu_to_le64 (np->rx_buf_sz) << 48;
        }
@@ -906,7 +906,7 @@ receive_packet (struct net_device *dev)
                                /* 16 byte align the IP header */
                                skb_reserve (skb, 2);
                                eth_copy_and_sum (skb,
-                                                 np->rx_skbuff[entry]->tail,
+                                                 np->rx_skbuff[entry]->data,
                                                  pkt_len, 0);
                                skb_put (skb, pkt_len);
                                pci_dma_sync_single_for_device(np->pdev,
@@ -950,7 +950,7 @@ receive_packet (struct net_device *dev)
                        skb_reserve (skb, 2);
                        np->rx_ring[entry].fraginfo =
                            cpu_to_le64 (pci_map_single
-                                        (np->pdev, skb->tail, np->rx_buf_sz,
+                                        (np->pdev, skb->data, np->rx_buf_sz,
                                          PCI_DMA_FROMDEVICE));
                }
                np->rx_ring[entry].fraginfo |=
index f4ba0ffb8637bb43f6e846703029ed79d524df0f..5fddc0ff887822fde5cbf904e3db8e46b4becca1 100644 (file)
@@ -224,7 +224,7 @@ static void dm9000_outblk_32bit(void __iomem *reg, void *data, int count)
 
 static void dm9000_inblk_8bit(void __iomem *reg, void *data, int count)
 {
-       readsb(reg, data, count+1);
+       readsb(reg, data, count);
 }
 
 
@@ -364,7 +364,7 @@ dm9000_release_board(struct platform_device *pdev, struct board_info *db)
        }
 
        if (db->addr_res != NULL) {
-               release_resource(db->data_req);
+               release_resource(db->addr_res);
                kfree(db->addr_req);
        }
 }
index 4a47df5a9ff9c076ddee640a437eca7f7c9348c9..d0fa2448761d0fdb1dcebae2b23de9b9c23d0b25 100644 (file)
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/mii.h>
@@ -1092,11 +1093,16 @@ static int e100_phy_init(struct nic *nic)
        }
 
        if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) && 
-               (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) && 
-               (nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled)))
-               /* enable/disable MDI/MDI-X auto-switching */
-               mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG,
-                       nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH);
+          (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000))) {
+               /* enable/disable MDI/MDI-X auto-switching.
+                  MDI/MDI-X auto-switching is disabled for 82551ER/QM chips */
+               if((nic->mac == mac_82551_E) || (nic->mac == mac_82551_F) ||
+                  (nic->mac == mac_82551_10) || (nic->mii.force_media) || 
+                  !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled)) 
+                       mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, 0);
+               else
+                       mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, NCONFIG_AUTO_SWITCH);
+       }
 
        return 0;
 }
@@ -1665,8 +1671,10 @@ static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs)
        if(stat_ack & stat_ack_rnr)
                nic->ru_running = RU_SUSPENDED;
 
-       e100_disable_irq(nic);
-       netif_rx_schedule(netdev);
+       if(likely(netif_rx_schedule_prep(netdev))) {
+               e100_disable_irq(nic);
+               __netif_rx_schedule(netdev);
+       }
 
        return IRQ_HANDLED;
 }
@@ -2286,7 +2294,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
                goto err_out_disable_pdev;
        }
 
-       if((err = pci_set_dma_mask(pdev, 0xFFFFFFFFULL))) {
+       if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
                DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n");
                goto err_out_free_res;
        }
@@ -2334,11 +2342,11 @@ static int __devinit e100_probe(struct pci_dev *pdev,
                goto err_out_iounmap;
        }
 
-       e100_phy_init(nic);
-
        if((err = e100_eeprom_load(nic)))
                goto err_out_free;
 
+       e100_phy_init(nic);
+
        memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
        if(!is_valid_ether_addr(netdev->dev_addr)) {
                DPRINTK(PROBE, ERR, "Invalid MAC address from "
@@ -2439,9 +2447,8 @@ static int e100_resume(struct pci_dev *pdev)
 #endif
 
 
-static void e100_shutdown(struct device *dev)
+static void e100_shutdown(struct pci_dev *pdev)
 {
-       struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct nic *nic = netdev_priv(netdev);
 
@@ -2462,11 +2469,7 @@ static struct pci_driver e100_driver = {
        .suspend =      e100_suspend,
        .resume =       e100_resume,
 #endif
-
-       .driver = {
-               .shutdown = e100_shutdown,
-       }
-
+       .shutdown =     e100_shutdown,
 };
 
 static int __init e100_init_module(void)
index af1e82c5b808d89371b7ad99ff100bb3b5ea666b..092757bc721f0ade1821465d73bedba39348ee89 100644 (file)
@@ -140,7 +140,7 @@ struct e1000_adapter;
 #define E1000_RX_BUFFER_WRITE  16      /* Must be power of 2 */
 
 #define AUTO_ALL_MODES            0
-#define E1000_EEPROM_82544_APM    0x0400
+#define E1000_EEPROM_82544_APM    0x0004
 #define E1000_EEPROM_APME         0x0400
 
 #ifndef E1000_MASTER_SLAVE
@@ -159,7 +159,7 @@ struct e1000_adapter;
  * so a DMA handle can be stored along with the buffer */
 struct e1000_buffer {
        struct sk_buff *skb;
-       uint64_t dma;
+       dma_addr_t dma;
        unsigned long time_stamp;
        uint16_t length;
        uint16_t next_to_watch;
index 237247f74df48f0ae0c8e4c9998e7b8f6be9223d..f133ff0b0b947c6ad6a76635ff5f159f6cad83bd 100644 (file)
@@ -105,7 +105,7 @@ static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
 static int
 e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 
        if(hw->media_type == e1000_media_type_copper) {
@@ -141,9 +141,9 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
                                     SUPPORTED_FIBRE |
                                     SUPPORTED_Autoneg);
 
-               ecmd->advertising = (SUPPORTED_1000baseT_Full |
-                                    SUPPORTED_FIBRE |
-                                    SUPPORTED_Autoneg);
+               ecmd->advertising = (ADVERTISED_1000baseT_Full |
+                                    ADVERTISED_FIBRE |
+                                    ADVERTISED_Autoneg);
 
                ecmd->port = PORT_FIBRE;
 
@@ -179,13 +179,24 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 static int
 e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 
        if(ecmd->autoneg == AUTONEG_ENABLE) {
                hw->autoneg = 1;
-               hw->autoneg_advertised = 0x002F;
-               ecmd->advertising = 0x002F;
+               if(hw->media_type == e1000_media_type_fiber)
+                       hw->autoneg_advertised = ADVERTISED_1000baseT_Full |
+                                    ADVERTISED_FIBRE |
+                                    ADVERTISED_Autoneg;
+               else 
+                       hw->autoneg_advertised = ADVERTISED_10baseT_Half |
+                                                 ADVERTISED_10baseT_Full |
+                                                 ADVERTISED_100baseT_Half |
+                                                 ADVERTISED_100baseT_Full |
+                                                 ADVERTISED_1000baseT_Full|
+                                                 ADVERTISED_Autoneg |
+                                                 ADVERTISED_TP;
+               ecmd->advertising = hw->autoneg_advertised;
        } else
                if(e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex))
                        return -EINVAL;
@@ -206,7 +217,7 @@ static void
 e1000_get_pauseparam(struct net_device *netdev,
                      struct ethtool_pauseparam *pause)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 
        pause->autoneg = 
@@ -226,7 +237,7 @@ static int
 e1000_set_pauseparam(struct net_device *netdev,
                      struct ethtool_pauseparam *pause)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        
        adapter->fc_autoneg = pause->autoneg;
@@ -259,14 +270,14 @@ e1000_set_pauseparam(struct net_device *netdev,
 static uint32_t
 e1000_get_rx_csum(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        return adapter->rx_csum;
 }
 
 static int
 e1000_set_rx_csum(struct net_device *netdev, uint32_t data)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        adapter->rx_csum = data;
 
        if(netif_running(netdev)) {
@@ -286,7 +297,7 @@ e1000_get_tx_csum(struct net_device *netdev)
 static int
 e1000_set_tx_csum(struct net_device *netdev, uint32_t data)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        if(adapter->hw.mac_type < e1000_82543) {
                if (!data)
@@ -306,8 +317,8 @@ e1000_set_tx_csum(struct net_device *netdev, uint32_t data)
 static int
 e1000_set_tso(struct net_device *netdev, uint32_t data)
 {
-       struct e1000_adapter *adapter = netdev->priv;
-       if ((adapter->hw.mac_type < e1000_82544) ||
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       if((adapter->hw.mac_type < e1000_82544) ||
            (adapter->hw.mac_type == e1000_82547)) 
                return data ? -EINVAL : 0;
 
@@ -322,14 +333,14 @@ e1000_set_tso(struct net_device *netdev, uint32_t data)
 static uint32_t
 e1000_get_msglevel(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        return adapter->msg_enable;
 }
 
 static void
 e1000_set_msglevel(struct net_device *netdev, uint32_t data)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        adapter->msg_enable = data;
 }
 
@@ -344,7 +355,7 @@ static void
 e1000_get_regs(struct net_device *netdev,
               struct ethtool_regs *regs, void *p)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        uint32_t *regs_buff = p;
        uint16_t phy_data;
@@ -432,7 +443,7 @@ e1000_get_regs(struct net_device *netdev,
 static int
 e1000_get_eeprom_len(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        return adapter->hw.eeprom.word_size * 2;
 }
 
@@ -440,7 +451,7 @@ static int
 e1000_get_eeprom(struct net_device *netdev,
                       struct ethtool_eeprom *eeprom, uint8_t *bytes)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        uint16_t *eeprom_buff;
        int first_word, last_word;
@@ -486,7 +497,7 @@ static int
 e1000_set_eeprom(struct net_device *netdev,
                       struct ethtool_eeprom *eeprom, uint8_t *bytes)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        uint16_t *eeprom_buff;
        void *ptr;
@@ -547,7 +558,7 @@ static void
 e1000_get_drvinfo(struct net_device *netdev,
                        struct ethtool_drvinfo *drvinfo)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        strncpy(drvinfo->driver,  e1000_driver_name, 32);
        strncpy(drvinfo->version, e1000_driver_version, 32);
@@ -563,7 +574,7 @@ static void
 e1000_get_ringparam(struct net_device *netdev,
                     struct ethtool_ringparam *ring)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        e1000_mac_type mac_type = adapter->hw.mac_type;
        struct e1000_desc_ring *txdr = &adapter->tx_ring;
        struct e1000_desc_ring *rxdr = &adapter->rx_ring;
@@ -584,7 +595,7 @@ static int
 e1000_set_ringparam(struct net_device *netdev,
                     struct ethtool_ringparam *ring)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        e1000_mac_type mac_type = adapter->hw.mac_type;
        struct e1000_desc_ring *txdr = &adapter->tx_ring;
        struct e1000_desc_ring *rxdr = &adapter->rx_ring;
@@ -651,6 +662,9 @@ err_setup_rx:
                E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W));             \
                value = E1000_READ_REG(&adapter->hw, R);                       \
                if(value != (test[pat] & W & M)) {                             \
+                       DPRINTK(DRV, ERR, "pattern test reg %04X failed: got " \
+                               "0x%08X expected 0x%08X\n",                    \
+                               E1000_##R, value, (test[pat] & W & M));        \
                        *data = (adapter->hw.mac_type < e1000_82543) ?         \
                                E1000_82542_##R : E1000_##R;                   \
                        return 1;                                              \
@@ -663,7 +677,9 @@ err_setup_rx:
        uint32_t value;                                                        \
        E1000_WRITE_REG(&adapter->hw, R, W & M);                               \
        value = E1000_READ_REG(&adapter->hw, R);                               \
-       if ((W & M) != (value & M)) {                                          \
+       if((W & M) != (value & M)) {                                          \
+               DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\
+                       "expected 0x%08X\n", E1000_##R, (value & M), (W & M)); \
                *data = (adapter->hw.mac_type < e1000_82543) ?                 \
                        E1000_82542_##R : E1000_##R;                           \
                return 1;                                                      \
@@ -673,18 +689,33 @@ err_setup_rx:
 static int
 e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
 {
-       uint32_t value;
-       uint32_t i;
+       uint32_t value, before, after;
+       uint32_t i, toggle;
 
        /* The status register is Read Only, so a write should fail.
         * Some bits that get toggled are ignored.
         */
-       value = (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833));
-       E1000_WRITE_REG(&adapter->hw, STATUS, (0xFFFFFFFF));
-       if(value != (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833))) {
+        switch (adapter->hw.mac_type) {
+       case e1000_82573:
+               toggle = 0x7FFFF033;
+               break;
+       default:
+               toggle = 0xFFFFF833;
+               break;
+       }
+
+       before = E1000_READ_REG(&adapter->hw, STATUS);
+       value = (E1000_READ_REG(&adapter->hw, STATUS) & toggle);
+       E1000_WRITE_REG(&adapter->hw, STATUS, toggle);
+       after = E1000_READ_REG(&adapter->hw, STATUS) & toggle;
+       if(value != after) {
+               DPRINTK(DRV, ERR, "failed STATUS register test got: "
+                       "0x%08X expected: 0x%08X\n", after, value);
                *data = 1;
                return 1;
        }
+       /* restore previous status */
+       E1000_WRITE_REG(&adapter->hw, STATUS, before);
 
        REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
        REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF);
@@ -766,7 +797,7 @@ e1000_test_intr(int irq,
                struct pt_regs *regs)
 {
        struct net_device *netdev = (struct net_device *) data;
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        adapter->test_icr |= E1000_READ_REG(&adapter->hw, ICR);
 
@@ -1214,6 +1245,7 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter)
        case e1000_82541_rev_2:
        case e1000_82547:
        case e1000_82547_rev_2:
+       case e1000_82573:
                return e1000_integrated_phy_loopback(adapter);
                break;
 
@@ -1422,7 +1454,7 @@ static void
 e1000_diag_test(struct net_device *netdev,
                   struct ethtool_test *eth_test, uint64_t *data)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        boolean_t if_running = netif_running(netdev);
 
        if(eth_test->flags == ETH_TEST_FL_OFFLINE) {
@@ -1482,7 +1514,7 @@ e1000_diag_test(struct net_device *netdev,
 static void
 e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 
        switch(adapter->hw.device_id) {
@@ -1527,7 +1559,7 @@ e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 static int
 e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 
        switch(adapter->hw.device_id) {
@@ -1588,22 +1620,31 @@ e1000_led_blink_callback(unsigned long data)
 static int
 e1000_phys_id(struct net_device *netdev, uint32_t data)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ))
                data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ);
 
-       if(!adapter->blink_timer.function) {
-               init_timer(&adapter->blink_timer);
-               adapter->blink_timer.function = e1000_led_blink_callback;
-               adapter->blink_timer.data = (unsigned long) adapter;
+       if(adapter->hw.mac_type < e1000_82573) {
+               if(!adapter->blink_timer.function) {
+                       init_timer(&adapter->blink_timer);
+                       adapter->blink_timer.function = e1000_led_blink_callback;
+                       adapter->blink_timer.data = (unsigned long) adapter;
+               }
+               e1000_setup_led(&adapter->hw);
+               mod_timer(&adapter->blink_timer, jiffies);
+               msleep_interruptible(data * 1000);
+               del_timer_sync(&adapter->blink_timer);
+       }
+       else {
+               E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE |
+                       E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK | 
+                       (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) |
+                       (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED1_MODE_SHIFT) |
+                       (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT)));
+               msleep_interruptible(data * 1000);
        }
 
-       e1000_setup_led(&adapter->hw);
-       mod_timer(&adapter->blink_timer, jiffies);
-
-       msleep_interruptible(data * 1000);
-       del_timer_sync(&adapter->blink_timer);
        e1000_led_off(&adapter->hw);
        clear_bit(E1000_LED_ON, &adapter->led_status);
        e1000_cleanup_led(&adapter->hw);
@@ -1614,7 +1655,7 @@ e1000_phys_id(struct net_device *netdev, uint32_t data)
 static int
 e1000_nway_reset(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        if(netif_running(netdev)) {
                e1000_down(adapter);
                e1000_up(adapter);
@@ -1632,7 +1673,7 @@ static void
 e1000_get_ethtool_stats(struct net_device *netdev, 
                struct ethtool_stats *stats, uint64_t *data)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        int i;
 
        e1000_update_stats(adapter);
index 723589b28be5d7a1716e89858ae1fe6303d9dd63..045f5426ab9a68c6af41690f450839d77dca0110 100644 (file)
@@ -354,18 +354,27 @@ e1000_set_media_type(struct e1000_hw *hw)
         hw->media_type = e1000_media_type_internal_serdes;
         break;
     default:
-        if(hw->mac_type >= e1000_82543) {
+        switch (hw->mac_type) {
+        case e1000_82542_rev2_0:
+        case e1000_82542_rev2_1:
+            hw->media_type = e1000_media_type_fiber;
+            break;
+        case e1000_82573:
+            /* The STATUS_TBIMODE bit is reserved or reused for the this
+             * device.
+             */
+            hw->media_type = e1000_media_type_copper;
+            break;
+        default:
             status = E1000_READ_REG(hw, STATUS);
-            if(status & E1000_STATUS_TBIMODE) {
+            if (status & E1000_STATUS_TBIMODE) {
                 hw->media_type = e1000_media_type_fiber;
                 /* tbi_compatibility not valid on fiber */
                 hw->tbi_compatibility_en = FALSE;
             } else {
                 hw->media_type = e1000_media_type_copper;
             }
-        } else {
-            /* This is an 82542 (fiber only) */
-            hw->media_type = e1000_media_type_fiber;
+            break;
         }
     }
 }
@@ -1189,9 +1198,9 @@ e1000_copper_link_igp_setup(struct e1000_hw *hw)
         ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
         if(ret_val)
             return ret_val;
-        }
+    }
 
-   return E1000_SUCCESS;
+    return E1000_SUCCESS;
 }
 
 
index a0263ee96c6b0ee9133cc0ebdbee7ce08bfe5d75..93e9f8788751e462f31d2f2edb17212f7aa7e954 100644 (file)
@@ -66,6 +66,7 @@ typedef enum {
     e1000_eeprom_spi,
     e1000_eeprom_microwire,
     e1000_eeprom_flash,
+    e1000_eeprom_none, /* No NVM support */
     e1000_num_eeprom_types
 } e1000_eeprom_type;
 
index 137226d98d4760f8d1a72b536ffa530effcbd541..cb7f051a60ad6a29b914b1af36fa3090c249bbf0 100644 (file)
@@ -29,6 +29,8 @@
 #include "e1000.h"
 
 /* Change Log
+ * 6.0.58       4/20/05
+ *   o Accepted ethtool cleanup patch from Stephen Hemminger 
  * 6.0.44+     2/15/05
  *   o applied Anton's patch to resolve tx hang in hardware
  *   o Applied Andrew Mortons patch - e1000 stops working after resume
@@ -41,9 +43,9 @@ char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
 #else
 #define DRIVERNAPI "-NAPI"
 #endif
-#define DRV_VERSION "6.0.54-k2"DRIVERNAPI
+#define DRV_VERSION            "6.0.60-k2"DRIVERNAPI
 char e1000_driver_version[] = DRV_VERSION;
-char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation.";
+char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
  *
@@ -517,7 +519,7 @@ e1000_probe(struct pci_dev *pdev,
        SET_NETDEV_DEV(netdev, &pdev->dev);
 
        pci_set_drvdata(pdev, netdev);
-       adapter = netdev->priv;
+       adapter = netdev_priv(netdev);
        adapter->netdev = netdev;
        adapter->pdev = pdev;
        adapter->hw.back = adapter;
@@ -738,7 +740,7 @@ static void __devexit
 e1000_remove(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        uint32_t manc, swsm;
 
        flush_scheduled_work();
@@ -871,7 +873,7 @@ e1000_sw_init(struct e1000_adapter *adapter)
 static int
 e1000_open(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        int err;
 
        /* allocate transmit descriptors */
@@ -919,7 +921,7 @@ err_setup_tx:
 static int
 e1000_close(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        e1000_down(adapter);
 
@@ -1599,7 +1601,7 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter)
 static int
 e1000_set_mac(struct net_device *netdev, void *p)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct sockaddr *addr = p;
 
        if(!is_valid_ether_addr(addr->sa_data))
@@ -1634,7 +1636,7 @@ e1000_set_mac(struct net_device *netdev, void *p)
 static void
 e1000_set_multi(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        struct dev_mc_list *mc_ptr;
        unsigned long flags;
@@ -2213,7 +2215,7 @@ e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct sk_buff *skb)
 static int
 e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD;
        unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
        unsigned int tx_flags = 0;
@@ -2344,7 +2346,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 static void
 e1000_tx_timeout(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        /* Do the reset outside of interrupt context */
        schedule_work(&adapter->tx_timeout_task);
@@ -2353,7 +2355,7 @@ e1000_tx_timeout(struct net_device *netdev)
 static void
 e1000_tx_timeout_task(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        e1000_down(adapter);
        e1000_up(adapter);
@@ -2370,7 +2372,7 @@ e1000_tx_timeout_task(struct net_device *netdev)
 static struct net_device_stats *
 e1000_get_stats(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        e1000_update_stats(adapter);
        return &adapter->net_stats;
@@ -2387,7 +2389,7 @@ e1000_get_stats(struct net_device *netdev)
 static int
 e1000_change_mtu(struct net_device *netdev, int new_mtu)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
 
        if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
@@ -2598,7 +2600,7 @@ static irqreturn_t
 e1000_intr(int irq, void *data, struct pt_regs *regs)
 {
        struct net_device *netdev = data;
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        uint32_t icr = E1000_READ_REG(hw, ICR);
 #ifndef CONFIG_E1000_NAPI
@@ -2661,7 +2663,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
 static int
 e1000_clean(struct net_device *netdev, int *budget)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        int work_to_do = min(*budget, netdev->quota);
        int tx_cleaned;
        int work_done = 0;
@@ -2672,8 +2674,8 @@ e1000_clean(struct net_device *netdev, int *budget)
        *budget -= work_done;
        netdev->quota -= work_done;
        
-       /* If no Tx and no Rx work done, exit the polling mode */
        if ((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
+       /* If no Tx and not enough Rx work done, exit the polling mode */
                netif_rx_complete(netdev);
                e1000_irq_enable(adapter);
                return 0;
@@ -2769,13 +2771,13 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
                        i = tx_ring->next_to_clean;
                        eop = tx_ring->buffer_info[i].next_to_watch;
                        eop_desc = E1000_TX_DESC(*tx_ring, eop);
-                       DPRINTK(TX_ERR, ERR, "Detected Tx Unit Hang\n"
+                       DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
                                        "  TDH                  <%x>\n"
                                        "  TDT                  <%x>\n"
                                        "  next_to_use          <%x>\n"
                                        "  next_to_clean        <%x>\n"
                                        "buffer_info[next_to_clean]\n"
-                                       "  dma                  <%llx>\n"
+                                       "  dma                  <%zx>\n"
                                        "  time_stamp           <%lx>\n"
                                        "  next_to_watch        <%x>\n"
                                        "  jiffies              <%lx>\n"
@@ -2994,7 +2996,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
 
        i = rx_ring->next_to_clean;
        rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
-       staterr = rx_desc->wb.middle.status_error;
+       staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
 
        while(staterr & E1000_RXD_STAT_DD) {
                buffer_info = &rx_ring->buffer_info[i];
@@ -3065,16 +3067,16 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
 #ifdef CONFIG_E1000_NAPI
                if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
                        vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
-                               le16_to_cpu(rx_desc->wb.middle.vlan &
-                                       E1000_RXD_SPC_VLAN_MASK));
+                               le16_to_cpu(rx_desc->wb.middle.vlan) &
+                               E1000_RXD_SPC_VLAN_MASK);
                } else {
                        netif_receive_skb(skb);
                }
 #else /* CONFIG_E1000_NAPI */
                if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
                        vlan_hwaccel_rx(skb, adapter->vlgrp,
-                               le16_to_cpu(rx_desc->wb.middle.vlan &
-                                       E1000_RXD_SPC_VLAN_MASK));
+                               le16_to_cpu(rx_desc->wb.middle.vlan) &
+                               E1000_RXD_SPC_VLAN_MASK);
                } else {
                        netif_rx(skb);
                }
@@ -3087,7 +3089,7 @@ next_desc:
                if(unlikely(++i == rx_ring->count)) i = 0;
 
                rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
-               staterr = rx_desc->wb.middle.status_error;
+               staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
        }
        rx_ring->next_to_clean = i;
        adapter->alloc_rx_buf(adapter);
@@ -3371,11 +3373,12 @@ e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 static int
 e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct mii_ioctl_data *data = if_mii(ifr);
        int retval;
        uint16_t mii_reg;
        uint16_t spddplx;
+       unsigned long flags;
 
        if(adapter->hw.media_type != e1000_media_type_copper)
                return -EOPNOTSUPP;
@@ -3385,22 +3388,29 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
                data->phy_id = adapter->hw.phy_addr;
                break;
        case SIOCGMIIREG:
-               if (!capable(CAP_NET_ADMIN))
+               if(!capable(CAP_NET_ADMIN))
                        return -EPERM;
-               if (e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
-                                  &data->val_out))
+               spin_lock_irqsave(&adapter->stats_lock, flags);
+               if(e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
+                                  &data->val_out)) {
+                       spin_unlock_irqrestore(&adapter->stats_lock, flags);
                        return -EIO;
+               }
+               spin_unlock_irqrestore(&adapter->stats_lock, flags);
                break;
        case SIOCSMIIREG:
-               if (!capable(CAP_NET_ADMIN))
+               if(!capable(CAP_NET_ADMIN))
                        return -EPERM;
-               if (data->reg_num & ~(0x1F))
+               if(data->reg_num & ~(0x1F))
                        return -EFAULT;
                mii_reg = data->val_in;
-               if (e1000_write_phy_reg(&adapter->hw, data->reg_num,
-                                       mii_reg))
+               spin_lock_irqsave(&adapter->stats_lock, flags);
+               if(e1000_write_phy_reg(&adapter->hw, data->reg_num,
+                                       mii_reg)) {
+                       spin_unlock_irqrestore(&adapter->stats_lock, flags);
                        return -EIO;
-               if (adapter->hw.phy_type == e1000_phy_m88) {
+               }
+               if(adapter->hw.phy_type == e1000_phy_m88) {
                        switch (data->reg_num) {
                        case PHY_CTRL:
                                if(mii_reg & MII_CR_POWER_DOWN)
@@ -3420,8 +3430,12 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
                                                   HALF_DUPLEX;
                                        retval = e1000_set_spd_dplx(adapter,
                                                                    spddplx);
-                                       if(retval)
+                                       if(retval) {
+                                               spin_unlock_irqrestore(
+                                                       &adapter->stats_lock, 
+                                                       flags);
                                                return retval;
+                                       }
                                }
                                if(netif_running(adapter->netdev)) {
                                        e1000_down(adapter);
@@ -3431,8 +3445,11 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
                                break;
                        case M88E1000_PHY_SPEC_CTRL:
                        case M88E1000_EXT_PHY_SPEC_CTRL:
-                               if (e1000_phy_reset(&adapter->hw))
+                               if(e1000_phy_reset(&adapter->hw)) {
+                                       spin_unlock_irqrestore(
+                                               &adapter->stats_lock, flags);
                                        return -EIO;
+                               }
                                break;
                        }
                } else {
@@ -3448,6 +3465,7 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
                                break;
                        }
                }
+               spin_unlock_irqrestore(&adapter->stats_lock, flags);
                break;
        default:
                return -EOPNOTSUPP;
@@ -3504,7 +3522,7 @@ e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value)
 static void
 e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        uint32_t ctrl, rctl;
 
        e1000_irq_disable(adapter);
@@ -3544,7 +3562,7 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
 static void
 e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        uint32_t vfta, index;
        if((adapter->hw.mng_cookie.status &
                E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
@@ -3560,7 +3578,7 @@ e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
 static void
 e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        uint32_t vfta, index;
 
        e1000_irq_disable(adapter);
@@ -3601,6 +3619,13 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx)
 {
        adapter->hw.autoneg = 0;
 
+       /* Fiber NICs only allow 1000 gbps Full duplex */
+       if((adapter->hw.media_type == e1000_media_type_fiber) &&
+               spddplx != (SPEED_1000 + DUPLEX_FULL)) {
+               DPRINTK(PROBE, ERR, "Unsupported Speed/Duplex configuration\n");
+               return -EINVAL;
+       }
+
        switch(spddplx) {
        case SPEED_10 + DUPLEX_HALF:
                adapter->hw.forced_speed_duplex = e1000_10_half;
@@ -3647,7 +3672,7 @@ static int
 e1000_suspend(struct pci_dev *pdev, uint32_t state)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        uint32_t ctrl, ctrl_ext, rctl, manc, status, swsm;
        uint32_t wufc = adapter->wol;
 
@@ -3740,12 +3765,12 @@ static int
 e1000_resume(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
-       struct e1000_adapter *adapter = netdev->priv;
-       uint32_t manc, ret, swsm;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       uint32_t manc, ret_val, swsm;
 
        pci_set_power_state(pdev, 0);
        pci_restore_state(pdev);
-       ret = pci_enable_device(pdev);
+       ret_val = pci_enable_device(pdev);
        pci_set_master(pdev);
 
        pci_enable_wake(pdev, 3, 0);
@@ -3788,7 +3813,7 @@ e1000_resume(struct pci_dev *pdev)
 static void
 e1000_netpoll(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        disable_irq(adapter->pdev->irq);
        e1000_intr(adapter->pdev->irq, netdev, NULL);
        enable_irq(adapter->pdev->irq);
index 51c9fa2608306e751edd2348d30fe78c013bfaf4..f5a4dd7d856440d5ae6b5a41784ee80952dec4b3 100644 (file)
@@ -162,12 +162,7 @@ struct net_device * __init e2100_probe(int unit)
        err = do_e2100_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -286,6 +281,9 @@ static int __init e21_probe1(struct net_device *dev, int ioaddr)
 #endif
        NS8390_init(dev, 0);
 
+       retval = register_netdev(dev);
+       if (retval)
+               goto out;
        return 0;
 out:
        release_region(ioaddr, E21_IO_EXTENT);
@@ -453,11 +451,8 @@ init_module(void)
                dev->mem_start = mem[this_dev];
                dev->mem_end = xcvr[this_dev];  /* low 4bits = xcvr sel. */
                if (do_e2100_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_e21[found++] = dev;
-                               continue;
-                       }
-                       cleanup_card(dev);
+                       dev_e21[found++] = dev;
+                       continue;
                }
                free_netdev(dev);
                printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]);
index cd2475683027703d588727ecfbd481ad877040c0..dcb3028bb60f8d75f73e68ef1d0e32eb7df5ccfb 100644 (file)
@@ -600,12 +600,7 @@ struct net_device * __init eepro_probe(int unit)
        err = do_eepro_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       release_region(dev->base_addr, EEPRO_IO_EXTENT);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -758,6 +753,7 @@ static int __init eepro_probe1(struct net_device *dev, int autoprobe)
        int i;
        struct eepro_local *lp;
        int ioaddr = dev->base_addr;
+       int err;
 
        /* Grab the region so we can find another board if autoIRQ fails. */
        if (!request_region(ioaddr, EEPRO_IO_EXTENT, DRV_NAME)) { 
@@ -873,10 +869,16 @@ static int __init eepro_probe1(struct net_device *dev, int autoprobe)
 
        /* reset 82595 */
        eepro_reset(ioaddr);
+
+       err = register_netdev(dev);
+       if (err)
+               goto err;
        return 0;
 exit:
+       err = -ENODEV;
+err:
        release_region(dev->base_addr, EEPRO_IO_EXTENT);
-       return -ENODEV;
+       return err;
 }
 
 /* Open/initialize the board.  This is called (in the current kernel)
@@ -1834,11 +1836,8 @@ init_module(void)
                dev->irq = irq[i];
 
                if (do_eepro_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_eepro[n_eepro++] = dev;
-                               continue;
-                       }
-                       release_region(dev->base_addr, EEPRO_IO_EXTENT);
+                       dev_eepro[n_eepro++] = dev;
+                       continue;
                }
                free_netdev(dev);
                break;
index 98b3a2fdce90d6dbc9d737b48d1c4c1885d65a48..1795425f512e1f789dbccea4492cc1d659ed2111 100644 (file)
@@ -1269,7 +1269,7 @@ speedo_init_rx_ring(struct net_device *dev)
                if (skb == NULL)
                        break;                  /* OK.  Just initially short of Rx bufs. */
                skb->dev = dev;                 /* Mark as being used by this device. */
-               rxf = (struct RxFD *)skb->tail;
+               rxf = (struct RxFD *)skb->data;
                sp->rx_ringp[i] = rxf;
                sp->rx_ring_dma[i] =
                        pci_map_single(sp->pdev, rxf,
@@ -1661,7 +1661,7 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry)
                sp->rx_ringp[entry] = NULL;
                return NULL;
        }
-       rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
+       rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->data;
        sp->rx_ring_dma[entry] =
                pci_map_single(sp->pdev, rxf,
                                           PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
@@ -1808,10 +1808,10 @@ speedo_rx(struct net_device *dev)
 
 #if 1 || USE_IP_CSUM
                                /* Packet is in one chunk -- we can copy + cksum. */
-                               eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0);
+                               eth_copy_and_sum(skb, sp->rx_skbuff[entry]->data, pkt_len, 0);
                                skb_put(skb, pkt_len);
 #else
-                               memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->tail,
+                               memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->data,
                                           pkt_len);
 #endif
                                pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry],
index fc8e7947b3346bf0b282da1c73af096529a45aa0..82bd356e4f3abf8d2ecf7ff909f8ce4b7bda149f 100644 (file)
@@ -436,11 +436,8 @@ struct net_device * __init express_probe(int unit)
        netdev_boot_setup_check(dev);
 
        err = do_express_probe(dev);
-       if (!err) {
-               err = register_netdev(dev);
-               if (!err)
-                       return dev;
-       }
+       if (!err)
+               return dev;
        free_netdev(dev);
        return ERR_PTR(err);
 }
@@ -1205,7 +1202,8 @@ static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
        dev->set_multicast_list = &eexp_set_multicast;
        dev->tx_timeout = eexp_timeout;
        dev->watchdog_timeo = 2*HZ;
-       return 0;
+
+       return register_netdev(dev);
 }
 
 /*
@@ -1716,7 +1714,7 @@ int init_module(void)
                                break;
                        printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n");
                }
-               if (do_express_probe(dev) == 0 && register_netdev(dev) == 0) {
+               if (do_express_probe(dev) == 0) {
                        dev_eexp[this_dev] = dev;
                        found++;
                        continue;
index 81ebaedaa2408ee86d55e58284a3dbef69ea1a6e..87f522738bfcb718b63526450844f696bd750181 100644 (file)
@@ -1003,7 +1003,7 @@ static void epic_init_ring(struct net_device *dev)
                skb->dev = dev;                 /* Mark as being used by this device. */
                skb_reserve(skb, 2);    /* 16 byte align the IP header. */
                ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev, 
-                       skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
+                       skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
                ep->rx_ring[i].rxstatus = cpu_to_le32(DescOwn);
        }
        ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
@@ -1274,7 +1274,7 @@ static int epic_rx(struct net_device *dev, int budget)
                                                            ep->rx_ring[entry].bufaddr,
                                                            ep->rx_buf_sz,
                                                            PCI_DMA_FROMDEVICE);
-                               eth_copy_and_sum(skb, ep->rx_skbuff[entry]->tail, pkt_len, 0);
+                               eth_copy_and_sum(skb, ep->rx_skbuff[entry]->data, pkt_len, 0);
                                skb_put(skb, pkt_len);
                                pci_dma_sync_single_for_device(ep->pci_dev,
                                                               ep->rx_ring[entry].bufaddr,
@@ -1308,7 +1308,7 @@ static int epic_rx(struct net_device *dev, int budget)
                        skb->dev = dev;                 /* Mark as being used by this device. */
                        skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
                        ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, 
-                               skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
+                               skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
                        work_done++;
                }
                ep->rx_ring[entry].rxstatus = cpu_to_le32(DescOwn);
index f1e8150ed2a0918882a4654bc2564e54064e91e2..50f8e23bb9e503782693aa7a7c2f8b76c564f983 100644 (file)
@@ -177,12 +177,7 @@ struct net_device * __init es_probe(int unit)
        err = do_es_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -310,6 +305,10 @@ static int __init es_probe1(struct net_device *dev, int ioaddr)
        dev->poll_controller = ei_poll;
 #endif
        NS8390_init(dev, 0);
+
+       retval = register_netdev(dev);
+       if (retval)
+               goto out1;
        return 0;
 out1:
        free_irq(dev->irq, dev);
@@ -445,11 +444,8 @@ init_module(void)
                dev->base_addr = io[this_dev];
                dev->mem_start = mem[this_dev];
                if (do_es_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_es3210[found++] = dev;
-                               continue;
-                       }
-                       cleanup_card(dev);
+                       dev_es3210[found++] = dev;
+                       continue;
                }
                free_netdev(dev);
                printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]);
index ccae6ba5f7c591b90194291ddfe2e4c2f91acf0f..f32a6b3acb2a4b5dbd97921f77c1be45cfb28b71 100644 (file)
@@ -473,13 +473,7 @@ struct net_device * __init eth16i_probe(int unit)
        err = do_eth16i_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       free_irq(dev->irq, dev);
-       release_region(dev->base_addr, ETH16I_IO_EXTENT);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -569,7 +563,13 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
        dev->tx_timeout         = eth16i_timeout;
        dev->watchdog_timeo     = TX_TIMEOUT;
        spin_lock_init(&lp->lock);
+
+       retval = register_netdev(dev);
+       if (retval)
+               goto out1;
        return 0;
+out1:
+       free_irq(dev->irq, dev);
 out:
        release_region(ioaddr, ETH16I_IO_EXTENT);
        return retval;
@@ -1462,12 +1462,8 @@ int init_module(void)
                }
 
                if (do_eth16i_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_eth16i[found++] = dev;
-                               continue;
-                       }
-                       free_irq(dev->irq, dev);
-                       release_region(dev->base_addr, ETH16I_IO_EXTENT);
+                       dev_eth16i[found++] = dev;
+                       continue;
                }
                printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n",
                       io[this_dev]);
index dcf969b20be90848035e21a0424c903e69c5d3b8..b987f9474730c29ec7106253212be4694f6de9cd 100644 (file)
@@ -1308,15 +1308,9 @@ static int __init eisa_probe(struct net_device *dev, u_long ioaddr)
        if (ioaddr < 0x1000)
                goto out;
 
-       if (ioaddr == 0) {      /* Autoprobing */
-               iobase = EISA_SLOT_INC;         /* Get the first slot address */
-               i = 1;
-               maxSlots = MAX_EISA_SLOTS;
-       } else {                /* Probe a specific location */
-               iobase = ioaddr;
-               i = (ioaddr >> 12);
-               maxSlots = i + 1;
-       }
+       iobase = ioaddr;
+       i = (ioaddr >> 12);
+       maxSlots = i + 1;
 
        for (i = 1; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) {
                if (EISA_signature(name, EISA_ID) == 0) {
index d05e9dd1e14011a99df9f4d77955512a1dc561c4..55dbe9a3fd56fadcd2cab367cc26924489f5d06e 100644 (file)
@@ -1107,7 +1107,7 @@ static void allocate_rx_buffers(struct net_device *dev)
 
                skb->dev = dev; /* Mark as being used by this device. */
                np->lack_rxbuf->skbuff = skb;
-               np->lack_rxbuf->buffer = pci_map_single(np->pci_dev, skb->tail,
+               np->lack_rxbuf->buffer = pci_map_single(np->pci_dev, skb->data,
                        np->rx_buf_sz, PCI_DMA_FROMDEVICE);
                np->lack_rxbuf->status = RXOWN;
                ++np->really_rx_count;
@@ -1300,7 +1300,7 @@ static void init_ring(struct net_device *dev)
                ++np->really_rx_count;
                np->rx_ring[i].skbuff = skb;
                skb->dev = dev; /* Mark as being used by this device. */
-               np->rx_ring[i].buffer = pci_map_single(np->pci_dev, skb->tail,
+               np->rx_ring[i].buffer = pci_map_single(np->pci_dev, skb->data,
                        np->rx_buf_sz, PCI_DMA_FROMDEVICE);
                np->rx_ring[i].status = RXOWN;
                np->rx_ring[i].control |= RXIC;
@@ -1423,8 +1423,7 @@ static void reset_tx_descriptors(struct net_device *dev)
                if (cur->skbuff) {
                        pci_unmap_single(np->pci_dev, cur->buffer,
                                cur->skbuff->len, PCI_DMA_TODEVICE);
-                       dev_kfree_skb(cur->skbuff);
-                       /* or dev_kfree_skb_irq(cur->skbuff); ? */
+                       dev_kfree_skb_any(cur->skbuff);
                        cur->skbuff = NULL;
                }
                cur->status = 0;
@@ -1738,11 +1737,11 @@ static int netdev_rx(struct net_device *dev)
 
 #if ! defined(__alpha__)
                                eth_copy_and_sum(skb, 
-                                       np->cur_rx->skbuff->tail, pkt_len, 0);
+                                       np->cur_rx->skbuff->data, pkt_len, 0);
                                skb_put(skb, pkt_len);
 #else
                                memcpy(skb_put(skb, pkt_len),
-                                       np->cur_rx->skbuff->tail, pkt_len);
+                                       np->cur_rx->skbuff->data, pkt_len);
 #endif
                                pci_dma_sync_single_for_device(np->pci_dev,
                                                               np->cur_rx->buffer,
index 4ebcd052e15093b0c6e59c5880d974cf06f108dc..64f0f697c958ad399317fe7cc628bf93d9f73018 100644 (file)
@@ -82,6 +82,9 @@
  *     0.31: 14 Nov 2004: ethtool support for getting/setting link
  *                        capabilities.
  *     0.32: 16 Apr 2005: RX_ERROR4 handling added.
+ *     0.33: 16 May 2005: Support for MCP51 added.
+ *     0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics.
+ *     0.35: 26 Jun 2005: Support for MCP55 added.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
@@ -93,7 +96,7 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION              "0.32"
+#define FORCEDETH_VERSION              "0.35"
 #define DRV_NAME                       "forcedeth"
 
 #include <linux/module.h>
@@ -2005,7 +2008,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        /* handle different descriptor versions */
        if (pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_1 ||
                pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_2 ||
-               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3)
+               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3 ||    
+               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 ||
+               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_13)
                np->desc_ver = DESC_VER_1;
        else
                np->desc_ver = DESC_VER_2;
@@ -2215,56 +2220,84 @@ static struct pci_device_id pci_tbl[] = {
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_4,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_5,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_6,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_7,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* CK804 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_8,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* CK804 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_9,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* MCP04 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_10,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* MCP04 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_11,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+       },
+       {       /* MCP51 Ethernet Controller */
+               .vendor = PCI_VENDOR_ID_NVIDIA,
+               .device = PCI_DEVICE_ID_NVIDIA_NVENET_12,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+       },
+       {       /* MCP51 Ethernet Controller */
+               .vendor = PCI_VENDOR_ID_NVIDIA,
+               .device = PCI_DEVICE_ID_NVIDIA_NVENET_13,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+       },
+       {       /* MCP55 Ethernet Controller */
+               .vendor = PCI_VENDOR_ID_NVIDIA,
+               .device = PCI_DEVICE_ID_NVIDIA_NVENET_14,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+       },
+       {       /* MCP55 Ethernet Controller */
+               .vendor = PCI_VENDOR_ID_NVIDIA,
+               .device = PCI_DEVICE_ID_NVIDIA_NVENET_15,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {0,},
 };
index b43b2b11aacd752318c279264ee0e4e1a9865419..6518334b92801a41745718b09a74805e3e7b8004 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * drivers/net/gianfar.c
  *
  * Gianfar Ethernet Driver
  *  B-V +1.62
  *
  *  Theory of operation
- *  This driver is designed for the Triple-speed Ethernet
- *  controllers on the Freescale 8540/8560 integrated processors,
- *  as well as the Fast Ethernet Controller on the 8540.  
- *  
+ *  This driver is designed for the non-CPM ethernet controllers
+ *  on the 85xx and 83xx family of integrated processors
+ *
  *  The driver is initialized through platform_device.  Structures which
  *  define the configuration needed by the board are defined in a
  *  board structure in arch/ppc/platforms (though I do not
  *
  *  The Gianfar Ethernet Controller uses a ring of buffer
  *  descriptors.  The beginning is indicated by a register
- *  pointing to the physical address of the start of the ring. 
- *  The end is determined by a "wrap" bit being set in the 
+ *  pointing to the physical address of the start of the ring.
+ *  The end is determined by a "wrap" bit being set in the
  *  last descriptor of the ring.
  *
  *  When a packet is received, the RXF bit in the
- *  IEVENT register is set, triggering an interrupt when the 
+ *  IEVENT register is set, triggering an interrupt when the
  *  corresponding bit in the IMASK register is also set (if
  *  interrupt coalescing is active, then the interrupt may not
  *  happen immediately, but will wait until either a set number
@@ -52,7 +51,7 @@
  *  interrupt handler will signal there is work to be done, and
  *  exit.  Without NAPI, the packet(s) will be handled
  *  immediately.  Both methods will start at the last known empty
- *  descriptor, and process every subsequent descriptor until there 
+ *  descriptor, and process every subsequent descriptor until there
  *  are none left with data (NAPI will stop after a set number of
  *  packets to give time to other tasks, but will eventually
  *  process all the packets).  The data arrives inside a
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/if_vlan.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/device.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -123,7 +126,7 @@ static int gfar_set_mac_address(struct net_device *dev);
 static int gfar_change_mtu(struct net_device *dev, int new_mtu);
 static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs);
 static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs);
-irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
 static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void gfar_phy_change(void *data);
@@ -139,9 +142,12 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
 #ifdef CONFIG_GFAR_NAPI
 static int gfar_poll(struct net_device *dev, int *budget);
 #endif
-static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
+int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
 static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
 static void gfar_phy_startup_timer(unsigned long data);
+static void gfar_vlan_rx_register(struct net_device *netdev,
+                               struct vlan_group *grp);
+static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
 
 extern struct ethtool_ops gfar_ethtool_ops;
 
@@ -149,6 +155,13 @@ MODULE_AUTHOR("Freescale Semiconductor, Inc");
 MODULE_DESCRIPTION("Gianfar Ethernet Driver");
 MODULE_LICENSE("GPL");
 
+int gfar_uses_fcb(struct gfar_private *priv)
+{
+       if (priv->vlan_enable || priv->rx_csum_enable)
+               return 1;
+       else
+               return 0;
+}
 static int gfar_probe(struct device *device)
 {
        u32 tempval;
@@ -159,7 +172,6 @@ static int gfar_probe(struct device *device)
        struct resource *r;
        int idx;
        int err = 0;
-       int dev_ethtool_ops = 0;
 
        einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
 
@@ -265,15 +277,69 @@ static int gfar_probe(struct device *device)
        dev->mtu = 1500;
        dev->set_multicast_list = gfar_set_multi;
 
-       /* Index into the array of possible ethtool
-        * ops to catch all 4 possibilities */
-       if((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) == 0)
-               dev_ethtool_ops += 1;
+       dev->ethtool_ops = &gfar_ethtool_ops;
+
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
+               priv->rx_csum_enable = 1;
+               dev->features |= NETIF_F_IP_CSUM;
+       } else
+               priv->rx_csum_enable = 0;
+
+       priv->vlgrp = NULL;
 
-       if((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE) == 0)
-               dev_ethtool_ops += 2;
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
+               dev->vlan_rx_register = gfar_vlan_rx_register;
+               dev->vlan_rx_kill_vid = gfar_vlan_rx_kill_vid;
 
-       dev->ethtool_ops = gfar_op_array[dev_ethtool_ops];
+               dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+
+               priv->vlan_enable = 1;
+       }
+
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
+               priv->extended_hash = 1;
+               priv->hash_width = 9;
+
+               priv->hash_regs[0] = &priv->regs->igaddr0;
+               priv->hash_regs[1] = &priv->regs->igaddr1;
+               priv->hash_regs[2] = &priv->regs->igaddr2;
+               priv->hash_regs[3] = &priv->regs->igaddr3;
+               priv->hash_regs[4] = &priv->regs->igaddr4;
+               priv->hash_regs[5] = &priv->regs->igaddr5;
+               priv->hash_regs[6] = &priv->regs->igaddr6;
+               priv->hash_regs[7] = &priv->regs->igaddr7;
+               priv->hash_regs[8] = &priv->regs->gaddr0;
+               priv->hash_regs[9] = &priv->regs->gaddr1;
+               priv->hash_regs[10] = &priv->regs->gaddr2;
+               priv->hash_regs[11] = &priv->regs->gaddr3;
+               priv->hash_regs[12] = &priv->regs->gaddr4;
+               priv->hash_regs[13] = &priv->regs->gaddr5;
+               priv->hash_regs[14] = &priv->regs->gaddr6;
+               priv->hash_regs[15] = &priv->regs->gaddr7;
+
+       } else {
+               priv->extended_hash = 0;
+               priv->hash_width = 8;
+
+               priv->hash_regs[0] = &priv->regs->gaddr0;
+                priv->hash_regs[1] = &priv->regs->gaddr1;
+               priv->hash_regs[2] = &priv->regs->gaddr2;
+               priv->hash_regs[3] = &priv->regs->gaddr3;
+               priv->hash_regs[4] = &priv->regs->gaddr4;
+               priv->hash_regs[5] = &priv->regs->gaddr5;
+               priv->hash_regs[6] = &priv->regs->gaddr6;
+               priv->hash_regs[7] = &priv->regs->gaddr7;
+       }
+
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_PADDING)
+               priv->padding = DEFAULT_PADDING;
+       else
+               priv->padding = 0;
+
+       dev->hard_header_len += priv->padding;
+
+       if (dev->features & NETIF_F_IP_CSUM)
+               dev->hard_header_len += GMAC_FCB_LEN;
 
        priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
 #ifdef CONFIG_GFAR_BUFSTASH
@@ -289,6 +355,9 @@ static int gfar_probe(struct device *device)
        priv->rxcount = DEFAULT_RXCOUNT;
        priv->rxtime = DEFAULT_RXTIME;
 
+       /* Enable most messages by default */
+       priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
+
        err = register_netdev(dev);
 
        if (err) {
@@ -360,8 +429,9 @@ static int init_phy(struct net_device *dev)
                        GFP_KERNEL);
 
        if(NULL == mii_info) {
-               printk(KERN_ERR "%s: Could not allocate mii_info\n", 
-                               dev->name);
+               if (netif_msg_ifup(priv))
+                       printk(KERN_ERR "%s: Could not allocate mii_info\n",
+                                       dev->name);
                return -ENOMEM;
        }
 
@@ -410,7 +480,8 @@ static int init_phy(struct net_device *dev)
        curphy = get_phy_info(priv->mii_info);
 
        if (curphy == NULL) {
-               printk(KERN_ERR "%s: No PHY found\n", dev->name);
+               if (netif_msg_ifup(priv))
+                       printk(KERN_ERR "%s: No PHY found\n", dev->name);
                err = -1;
                goto no_phy;
        }
@@ -421,7 +492,7 @@ static int init_phy(struct net_device *dev)
        if(curphy->init) {
                err = curphy->init(priv->mii_info);
 
-               if (err) 
+               if (err)
                        goto phy_init_fail;
        }
 
@@ -446,14 +517,14 @@ static void init_registers(struct net_device *dev)
        gfar_write(&priv->regs->imask, IMASK_INIT_CLEAR);
 
        /* Init hash registers to zero */
-       gfar_write(&priv->regs->iaddr0, 0);
-       gfar_write(&priv->regs->iaddr1, 0);
-       gfar_write(&priv->regs->iaddr2, 0);
-       gfar_write(&priv->regs->iaddr3, 0);
-       gfar_write(&priv->regs->iaddr4, 0);
-       gfar_write(&priv->regs->iaddr5, 0);
-       gfar_write(&priv->regs->iaddr6, 0);
-       gfar_write(&priv->regs->iaddr7, 0);
+       gfar_write(&priv->regs->igaddr0, 0);
+       gfar_write(&priv->regs->igaddr1, 0);
+       gfar_write(&priv->regs->igaddr2, 0);
+       gfar_write(&priv->regs->igaddr3, 0);
+       gfar_write(&priv->regs->igaddr4, 0);
+       gfar_write(&priv->regs->igaddr5, 0);
+       gfar_write(&priv->regs->igaddr6, 0);
+       gfar_write(&priv->regs->igaddr7, 0);
 
        gfar_write(&priv->regs->gaddr0, 0);
        gfar_write(&priv->regs->gaddr1, 0);
@@ -464,9 +535,6 @@ static void init_registers(struct net_device *dev)
        gfar_write(&priv->regs->gaddr6, 0);
        gfar_write(&priv->regs->gaddr7, 0);
 
-       /* Zero out rctrl */
-       gfar_write(&priv->regs->rctrl, 0x00000000);
-
        /* Zero out the rmon mib registers if it has them */
        if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
                memset((void *) &(priv->regs->rmon), 0,
@@ -497,20 +565,14 @@ static void init_registers(struct net_device *dev)
        gfar_write(&priv->regs->tbipa, TBIPA_VALUE);
 }
 
-void stop_gfar(struct net_device *dev)
+
+/* Halt the receive and transmit queues */
+void gfar_halt(struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
        struct gfar *regs = priv->regs;
-       unsigned long flags;
        u32 tempval;
 
-       /* Lock it down */
-       spin_lock_irqsave(&priv->lock, flags);
-
-       /* Tell the kernel the link is down */
-       priv->mii_info->link = 0;
-       adjust_link(dev);
-
        /* Mask all interrupts */
        gfar_write(&regs->imask, IMASK_INIT_CLEAR);
 
@@ -533,13 +595,29 @@ void stop_gfar(struct net_device *dev)
        tempval = gfar_read(&regs->maccfg1);
        tempval &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN);
        gfar_write(&regs->maccfg1, tempval);
+}
+
+void stop_gfar(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       struct gfar *regs = priv->regs;
+       unsigned long flags;
+
+       /* Lock it down */
+       spin_lock_irqsave(&priv->lock, flags);
+
+       /* Tell the kernel the link is down */
+       priv->mii_info->link = 0;
+       adjust_link(dev);
+
+       gfar_halt(dev);
 
        if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
                /* Clear any pending interrupts */
                mii_clear_phy_interrupt(priv->mii_info);
 
                /* Disable PHY Interrupts */
-               mii_configure_phy_interrupt(priv->mii_info, 
+               mii_configure_phy_interrupt(priv->mii_info,
                                MII_INTERRUPT_DISABLED);
        }
 
@@ -566,7 +644,7 @@ void stop_gfar(struct net_device *dev)
                        sizeof(struct txbd8)*priv->tx_ring_size
                        + sizeof(struct rxbd8)*priv->rx_ring_size,
                        priv->tx_bd_base,
-                       gfar_read(&regs->tbase));
+                       gfar_read(&regs->tbase0));
 }
 
 /* If there are any tx skbs or rx skbs still around, free them.
@@ -620,6 +698,34 @@ void free_skb_resources(struct gfar_private *priv)
        }
 }
 
+void gfar_start(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       struct gfar *regs = priv->regs;
+       u32 tempval;
+
+       /* Enable Rx and Tx in MACCFG1 */
+       tempval = gfar_read(&regs->maccfg1);
+       tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
+       gfar_write(&regs->maccfg1, tempval);
+
+       /* Initialize DMACTRL to have WWR and WOP */
+       tempval = gfar_read(&priv->regs->dmactrl);
+       tempval |= DMACTRL_INIT_SETTINGS;
+       gfar_write(&priv->regs->dmactrl, tempval);
+
+       /* Clear THLT, so that the DMA starts polling now */
+       gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+
+       /* Make sure we aren't stopped */
+       tempval = gfar_read(&priv->regs->dmactrl);
+       tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
+       gfar_write(&priv->regs->dmactrl, tempval);
+
+       /* Unmask the interrupts we look for */
+       gfar_write(&regs->imask, IMASK_DEFAULT);
+}
+
 /* Bring the controller up and running */
 int startup_gfar(struct net_device *dev)
 {
@@ -630,33 +736,34 @@ int startup_gfar(struct net_device *dev)
        int i;
        struct gfar_private *priv = netdev_priv(dev);
        struct gfar *regs = priv->regs;
-       u32 tempval;
        int err = 0;
+       u32 rctrl = 0;
 
        gfar_write(&regs->imask, IMASK_INIT_CLEAR);
 
        /* Allocate memory for the buffer descriptors */
-       vaddr = (unsigned long) dma_alloc_coherent(NULL, 
+       vaddr = (unsigned long) dma_alloc_coherent(NULL,
                        sizeof (struct txbd8) * priv->tx_ring_size +
                        sizeof (struct rxbd8) * priv->rx_ring_size,
                        &addr, GFP_KERNEL);
 
        if (vaddr == 0) {
-               printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
-                      dev->name);
+               if (netif_msg_ifup(priv))
+                       printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
+                                       dev->name);
                return -ENOMEM;
        }
 
        priv->tx_bd_base = (struct txbd8 *) vaddr;
 
        /* enet DMA only understands physical addresses */
-       gfar_write(&regs->tbase, addr);
+       gfar_write(&regs->tbase0, addr);
 
        /* Start the rx descriptor ring where the tx ring leaves off */
        addr = addr + sizeof (struct txbd8) * priv->tx_ring_size;
        vaddr = vaddr + sizeof (struct txbd8) * priv->tx_ring_size;
        priv->rx_bd_base = (struct rxbd8 *) vaddr;
-       gfar_write(&regs->rbase, addr);
+       gfar_write(&regs->rbase0, addr);
 
        /* Setup the skbuff rings */
        priv->tx_skbuff =
@@ -664,8 +771,9 @@ int startup_gfar(struct net_device *dev)
                                        priv->tx_ring_size, GFP_KERNEL);
 
        if (priv->tx_skbuff == NULL) {
-               printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
-                      dev->name);
+               if (netif_msg_ifup(priv))
+                       printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
+                                       dev->name);
                err = -ENOMEM;
                goto tx_skb_fail;
        }
@@ -678,8 +786,9 @@ int startup_gfar(struct net_device *dev)
                                        priv->rx_ring_size, GFP_KERNEL);
 
        if (priv->rx_skbuff == NULL) {
-               printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
-                      dev->name);
+               if (netif_msg_ifup(priv))
+                       printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
+                                       dev->name);
                err = -ENOMEM;
                goto rx_skb_fail;
        }
@@ -726,12 +835,13 @@ int startup_gfar(struct net_device *dev)
        /* If the device has multiple interrupts, register for
         * them.  Otherwise, only register for the one */
        if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-               /* Install our interrupt handlers for Error, 
+               /* Install our interrupt handlers for Error,
                 * Transmit, and Receive */
                if (request_irq(priv->interruptError, gfar_error,
                                0, "enet_error", dev) < 0) {
-                       printk(KERN_ERR "%s: Can't get IRQ %d\n",
-                              dev->name, priv->interruptError);
+                       if (netif_msg_intr(priv))
+                               printk(KERN_ERR "%s: Can't get IRQ %d\n",
+                                       dev->name, priv->interruptError);
 
                        err = -1;
                        goto err_irq_fail;
@@ -739,8 +849,9 @@ int startup_gfar(struct net_device *dev)
 
                if (request_irq(priv->interruptTransmit, gfar_transmit,
                                0, "enet_tx", dev) < 0) {
-                       printk(KERN_ERR "%s: Can't get IRQ %d\n",
-                              dev->name, priv->interruptTransmit);
+                       if (netif_msg_intr(priv))
+                               printk(KERN_ERR "%s: Can't get IRQ %d\n",
+                                       dev->name, priv->interruptTransmit);
 
                        err = -1;
 
@@ -749,8 +860,9 @@ int startup_gfar(struct net_device *dev)
 
                if (request_irq(priv->interruptReceive, gfar_receive,
                                0, "enet_rx", dev) < 0) {
-                       printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
-                              dev->name, priv->interruptReceive);
+                       if (netif_msg_intr(priv))
+                               printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
+                                               dev->name, priv->interruptReceive);
 
                        err = -1;
                        goto rx_irq_fail;
@@ -758,8 +870,9 @@ int startup_gfar(struct net_device *dev)
        } else {
                if (request_irq(priv->interruptTransmit, gfar_interrupt,
                                0, "gfar_interrupt", dev) < 0) {
-                       printk(KERN_ERR "%s: Can't get IRQ %d\n",
-                              dev->name, priv->interruptError);
+                       if (netif_msg_intr(priv))
+                               printk(KERN_ERR "%s: Can't get IRQ %d\n",
+                                       dev->name, priv->interruptError);
 
                        err = -1;
                        goto err_irq_fail;
@@ -787,28 +900,22 @@ int startup_gfar(struct net_device *dev)
        else
                gfar_write(&regs->rxic, 0);
 
-       init_waitqueue_head(&priv->rxcleanupq);
+       if (priv->rx_csum_enable)
+               rctrl |= RCTRL_CHECKSUMMING;
 
-       /* Enable Rx and Tx in MACCFG1 */
-       tempval = gfar_read(&regs->maccfg1);
-       tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
-       gfar_write(&regs->maccfg1, tempval);
+       if (priv->extended_hash)
+               rctrl |= RCTRL_EXTHASH;
 
-       /* Initialize DMACTRL to have WWR and WOP */
-       tempval = gfar_read(&priv->regs->dmactrl);
-       tempval |= DMACTRL_INIT_SETTINGS;
-       gfar_write(&priv->regs->dmactrl, tempval);
+       if (priv->vlan_enable)
+               rctrl |= RCTRL_VLAN;
 
-       /* Clear THLT, so that the DMA starts polling now */
-       gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+       /* Init rctrl based on our settings */
+       gfar_write(&priv->regs->rctrl, rctrl);
 
-       /* Make sure we aren't stopped */
-       tempval = gfar_read(&priv->regs->dmactrl);
-       tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
-       gfar_write(&priv->regs->dmactrl, tempval);
+       if (dev->features & NETIF_F_IP_CSUM)
+               gfar_write(&priv->regs->tctrl, TCTRL_INIT_CSUM);
 
-       /* Unmask the interrupts we look for */
-       gfar_write(&regs->imask, IMASK_DEFAULT);
+       gfar_start(dev);
 
        return 0;
 
@@ -824,7 +931,7 @@ tx_skb_fail:
                        sizeof(struct txbd8)*priv->tx_ring_size
                        + sizeof(struct rxbd8)*priv->rx_ring_size,
                        priv->tx_bd_base,
-                       gfar_read(&regs->tbase));
+                       gfar_read(&regs->tbase0));
 
        if (priv->mii_info->phyinfo->close)
                priv->mii_info->phyinfo->close(priv->mii_info);
@@ -857,11 +964,62 @@ static int gfar_enet_open(struct net_device *dev)
        return err;
 }
 
+static struct txfcb *gfar_add_fcb(struct sk_buff *skb, struct txbd8 *bdp)
+{
+       struct txfcb *fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN);
+
+       memset(fcb, 0, GMAC_FCB_LEN);
+
+       /* Flag the bd so the controller looks for the FCB */
+       bdp->status |= TXBD_TOE;
+
+       return fcb;
+}
+
+static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
+{
+       int len;
+
+       /* If we're here, it's a IP packet with a TCP or UDP
+        * payload.  We set it to checksum, using a pseudo-header
+        * we provide
+        */
+       fcb->ip = 1;
+       fcb->tup = 1;
+       fcb->ctu = 1;
+       fcb->nph = 1;
+
+       /* Notify the controller what the protocol is */
+       if (skb->nh.iph->protocol == IPPROTO_UDP)
+               fcb->udp = 1;
+
+       /* l3os is the distance between the start of the
+        * frame (skb->data) and the start of the IP hdr.
+        * l4os is the distance between the start of the
+        * l3 hdr and the l4 hdr */
+       fcb->l3os = (u16)(skb->nh.raw - skb->data - GMAC_FCB_LEN);
+       fcb->l4os = (u16)(skb->h.raw - skb->nh.raw);
+
+       len = skb->nh.iph->tot_len - fcb->l4os;
+
+       /* Provide the pseudoheader csum */
+       fcb->phcs = ~csum_tcpudp_magic(skb->nh.iph->saddr,
+                       skb->nh.iph->daddr, len,
+                       skb->nh.iph->protocol, 0);
+}
+
+void gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb)
+{
+       fcb->vln = 1;
+       fcb->vlctl = vlan_tx_tag_get(skb);
+}
+
 /* This is called by the kernel when a frame is ready for transmission. */
 /* It is pointed to by the dev->hard_start_xmit function pointer */
 static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
+       struct txfcb *fcb = NULL;
        struct txbd8 *txbdp;
 
        /* Update transmit stats */
@@ -876,9 +1034,24 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Clear all but the WRAP status flags */
        txbdp->status &= TXBD_WRAP;
 
+       /* Set up checksumming */
+       if ((dev->features & NETIF_F_IP_CSUM) 
+                       && (CHECKSUM_HW == skb->ip_summed)) {
+               fcb = gfar_add_fcb(skb, txbdp);
+               gfar_tx_checksum(skb, fcb);
+       }
+
+       if (priv->vlan_enable &&
+                       unlikely(priv->vlgrp && vlan_tx_tag_present(skb))) {
+               if (NULL == fcb)
+                       fcb = gfar_add_fcb(skb, txbdp);
+
+               gfar_tx_vlan(skb, fcb);
+       }
+
        /* Set buffer length and pointer */
        txbdp->length = skb->len;
-       txbdp->bufPtr = dma_map_single(NULL, skb->data, 
+       txbdp->bufPtr = dma_map_single(NULL, skb->data,
                        skb->len, DMA_TO_DEVICE);
 
        /* Save the skb pointer so we can free it later */
@@ -972,15 +1145,78 @@ int gfar_set_mac_address(struct net_device *dev)
 }
 
 
+/* Enables and disables VLAN insertion/extraction */
+static void gfar_vlan_rx_register(struct net_device *dev,
+               struct vlan_group *grp)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       unsigned long flags;
+       u32 tempval;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       priv->vlgrp = grp;
+
+       if (grp) {
+               /* Enable VLAN tag insertion */
+               tempval = gfar_read(&priv->regs->tctrl);
+               tempval |= TCTRL_VLINS;
+
+               gfar_write(&priv->regs->tctrl, tempval);
+               
+               /* Enable VLAN tag extraction */
+               tempval = gfar_read(&priv->regs->rctrl);
+               tempval |= RCTRL_VLEX;
+               gfar_write(&priv->regs->rctrl, tempval);
+       } else {
+               /* Disable VLAN tag insertion */
+               tempval = gfar_read(&priv->regs->tctrl);
+               tempval &= ~TCTRL_VLINS;
+               gfar_write(&priv->regs->tctrl, tempval);
+
+               /* Disable VLAN tag extraction */
+               tempval = gfar_read(&priv->regs->rctrl);
+               tempval &= ~RCTRL_VLEX;
+               gfar_write(&priv->regs->rctrl, tempval);
+       }
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
+static void gfar_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       if (priv->vlgrp)
+               priv->vlgrp->vlan_devices[vid] = NULL;
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
 static int gfar_change_mtu(struct net_device *dev, int new_mtu)
 {
        int tempsize, tempval;
        struct gfar_private *priv = netdev_priv(dev);
        int oldsize = priv->rx_buffer_size;
-       int frame_size = new_mtu + 18;
+       int frame_size = new_mtu + ETH_HLEN;
+
+       if (priv->vlan_enable)
+               frame_size += VLAN_ETH_HLEN;
+
+       if (gfar_uses_fcb(priv))
+               frame_size += GMAC_FCB_LEN;
+
+       frame_size += priv->padding;
 
        if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) {
-               printk(KERN_ERR "%s: Invalid MTU setting\n", dev->name);
+               if (netif_msg_drv(priv))
+                       printk(KERN_ERR "%s: Invalid MTU setting\n",
+                                       dev->name);
                return -EINVAL;
        }
 
@@ -1120,7 +1356,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
        skb->dev = dev;
 
        bdp->bufPtr = dma_map_single(NULL, skb->data,
-                       priv->rx_buffer_size + RXBUF_ALIGNMENT, 
+                       priv->rx_buffer_size + RXBUF_ALIGNMENT,
                        DMA_FROM_DEVICE);
 
        bdp->length = 0;
@@ -1190,11 +1426,10 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
 
                __netif_rx_schedule(dev);
        } else {
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
-                      dev->name, gfar_read(&priv->regs->ievent),
-                      gfar_read(&priv->regs->imask));
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
+                               dev->name, gfar_read(&priv->regs->ievent),
+                               gfar_read(&priv->regs->imask));
        }
 #else
 
@@ -1209,15 +1444,43 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
        else
                gfar_write(&priv->regs->rxic, 0);
 
-       /* Just in case we need to wake the ring param changer */
-       priv->rxclean = 1;
-
        spin_unlock(&priv->lock);
 #endif
 
        return IRQ_HANDLED;
 }
 
+static inline int gfar_rx_vlan(struct sk_buff *skb,
+               struct vlan_group *vlgrp, unsigned short vlctl)
+{
+#ifdef CONFIG_GFAR_NAPI
+       return vlan_hwaccel_receive_skb(skb, vlgrp, vlctl);
+#else
+       return vlan_hwaccel_rx(skb, vlgrp, vlctl);
+#endif
+}
+
+static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
+{
+       /* If valid headers were found, and valid sums
+        * were verified, then we tell the kernel that no
+        * checksumming is necessary.  Otherwise, it is */
+       if (fcb->cip && !fcb->eip && fcb->ctu && !fcb->etu)
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+       else
+               skb->ip_summed = CHECKSUM_NONE;
+}
+
+
+static inline struct rxfcb *gfar_get_fcb(struct sk_buff *skb)
+{
+       struct rxfcb *fcb = (struct rxfcb *)skb->data;
+
+       /* Remove the FCB from the skb */
+       skb_pull(skb, GMAC_FCB_LEN);
+
+       return fcb;
+}
 
 /* gfar_process_frame() -- handle one incoming packet if skb
  * isn't NULL.  */
@@ -1225,35 +1488,51 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
                int length)
 {
        struct gfar_private *priv = netdev_priv(dev);
+       struct rxfcb *fcb = NULL;
 
        if (skb == NULL) {
-#ifdef BRIEF_GFAR_ERRORS
-               printk(KERN_WARNING "%s: Missing skb!!.\n",
-                               dev->name);
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
                priv->stats.rx_dropped++;
                priv->extra_stats.rx_skbmissing++;
        } else {
+               int ret;
+
                /* Prep the skb for the packet */
                skb_put(skb, length);
 
+               /* Grab the FCB if there is one */
+               if (gfar_uses_fcb(priv))
+                       fcb = gfar_get_fcb(skb);
+
+               /* Remove the padded bytes, if there are any */
+               if (priv->padding)
+                       skb_pull(skb, priv->padding);
+
+               if (priv->rx_csum_enable)
+                       gfar_rx_checksum(skb, fcb);
+
                /* Tell the skb what kind of packet this is */
                skb->protocol = eth_type_trans(skb, dev);
 
                /* Send the packet up the stack */
-               if (RECEIVE(skb) == NET_RX_DROP) {
+               if (unlikely(priv->vlgrp && fcb->vln))
+                       ret = gfar_rx_vlan(skb, priv->vlgrp, fcb->vlctl);
+               else
+                       ret = RECEIVE(skb);
+
+               if (NET_RX_DROP == ret)
                        priv->extra_stats.kernel_dropped++;
-               }
        }
 
        return 0;
 }
 
 /* gfar_clean_rx_ring() -- Processes each frame in the rx ring
- *   until the budget/quota has been reached. Returns the number 
+ *   until the budget/quota has been reached. Returns the number
  *   of frames handled
  */
-static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
+int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
 {
        struct rxbd8 *bdp;
        struct sk_buff *skb;
@@ -1355,9 +1634,6 @@ static int gfar_poll(struct net_device *dev, int *budget)
                                   mk_ic_value(priv->rxcount, priv->rxtime));
                else
                        gfar_write(&priv->regs->rxic, 0);
-
-               /* Signal to the ring size changer that it's safe to go */
-               priv->rxclean = 1;
        }
 
        return (rx_work_limit < 0) ? 1 : 0;
@@ -1393,10 +1669,8 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                if (events & IEVENT_CRL)
                        priv->stats.tx_aborted_errors++;
                if (events & IEVENT_XFUN) {
-#ifdef VERBOSE_GFAR_ERRORS
-                       printk(KERN_WARNING "%s: tx underrun. dropped packet\n",
-                              dev->name);
-#endif
+                       if (netif_msg_tx_err(priv))
+                               printk(KERN_WARNING "%s: tx underrun. dropped packet\n", dev->name);
                        priv->stats.tx_dropped++;
                        priv->extra_stats.tx_underrun++;
 
@@ -1415,36 +1689,30 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
 #endif
 
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name,
-                      gfar_read(&priv->regs->rstat));
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
+                                       dev->name,
+                                       gfar_read(&priv->regs->rstat));
        }
        if (events & IEVENT_BABR) {
                priv->stats.rx_errors++;
                priv->extra_stats.rx_babr++;
 
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: babbling error\n", dev->name);
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: babbling error\n", dev->name);
        }
        if (events & IEVENT_EBERR) {
                priv->extra_stats.eberr++;
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: EBERR\n", dev->name);
-#endif
-       }
-       if (events & IEVENT_RXC) {
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: control frame\n", dev->name);
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: EBERR\n", dev->name);
        }
+       if ((events & IEVENT_RXC) && (netif_msg_rx_err(priv)))
+                       printk(KERN_DEBUG "%s: control frame\n", dev->name);
 
        if (events & IEVENT_BABT) {
                priv->extra_stats.tx_babt++;
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: babt error\n", dev->name);
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: babt error\n", dev->name);
        }
 
        return IRQ_HANDLED;
@@ -1510,7 +1778,7 @@ static void gfar_phy_timer(unsigned long data)
  * If, after GFAR_AN_TIMEOUT seconds, it has not
  * finished, we switch to forced.
  * Either way, once the process has completed, we either
- * request the interrupt, or switch the timer over to 
+ * request the interrupt, or switch the timer over to
  * using gfar_phy_timer to check status */
 static void gfar_phy_startup_timer(unsigned long data)
 {
@@ -1535,8 +1803,9 @@ static void gfar_phy_startup_timer(unsigned long data)
 
                /* Forcing failed!  Give up */
                if(result) {
-                       printk(KERN_ERR "%s: Forcing failed!\n",
-                                       mii_info->dev->name);
+                       if (netif_msg_link(priv))
+                               printk(KERN_ERR "%s: Forcing failed!\n",
+                                               mii_info->dev->name);
                        return;
                }
        }
@@ -1546,16 +1815,17 @@ static void gfar_phy_startup_timer(unsigned long data)
 
        /* Grab the PHY interrupt, if necessary/possible */
        if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
-               if (request_irq(priv->einfo->interruptPHY, 
+               if (request_irq(priv->einfo->interruptPHY,
                                        phy_interrupt,
-                                       SA_SHIRQ, 
-                                       "phy_interrupt", 
+                                       SA_SHIRQ,
+                                       "phy_interrupt",
                                        mii_info->dev) < 0) {
-                       printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n",
-                                       mii_info->dev->name,
+                       if (netif_msg_intr(priv))
+                               printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n",
+                                               mii_info->dev->name,
                                        priv->einfo->interruptPHY);
                } else {
-                       mii_configure_phy_interrupt(priv->mii_info, 
+                       mii_configure_phy_interrupt(priv->mii_info,
                                        MII_INTERRUPT_ENABLED);
                        return;
                }
@@ -1592,15 +1862,17 @@ static void adjust_link(struct net_device *dev)
                                tempval &= ~(MACCFG2_FULL_DUPLEX);
                                gfar_write(&regs->maccfg2, tempval);
 
-                               printk(KERN_INFO "%s: Half Duplex\n",
-                                      dev->name);
+                               if (netif_msg_link(priv))
+                                       printk(KERN_INFO "%s: Half Duplex\n",
+                                                       dev->name);
                        } else {
                                tempval = gfar_read(&regs->maccfg2);
                                tempval |= MACCFG2_FULL_DUPLEX;
                                gfar_write(&regs->maccfg2, tempval);
 
-                               printk(KERN_INFO "%s: Full Duplex\n",
-                                      dev->name);
+                               if (netif_msg_link(priv))
+                                       printk(KERN_INFO "%s: Full Duplex\n",
+                                                       dev->name);
                        }
 
                        priv->oldduplex = mii_info->duplex;
@@ -1622,27 +1894,32 @@ static void adjust_link(struct net_device *dev)
                                gfar_write(&regs->maccfg2, tempval);
                                break;
                        default:
-                               printk(KERN_WARNING
-                                      "%s: Ack!  Speed (%d) is not 10/100/1000!\n",
-                                      dev->name, mii_info->speed);
+                               if (netif_msg_link(priv))
+                                       printk(KERN_WARNING
+                                                       "%s: Ack!  Speed (%d) is not 10/100/1000!\n",
+                                                       dev->name, mii_info->speed);
                                break;
                        }
 
-                       printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
-                              mii_info->speed);
+                       if (netif_msg_link(priv))
+                               printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
+                                               mii_info->speed);
 
                        priv->oldspeed = mii_info->speed;
                }
 
                if (!priv->oldlink) {
-                       printk(KERN_INFO "%s: Link is up\n", dev->name);
+                       if (netif_msg_link(priv))
+                               printk(KERN_INFO "%s: Link is up\n", dev->name);
                        priv->oldlink = 1;
                        netif_carrier_on(dev);
                        netif_schedule(dev);
                }
        } else {
                if (priv->oldlink) {
-                       printk(KERN_INFO "%s: Link is down\n", dev->name);
+                       if (netif_msg_link(priv))
+                               printk(KERN_INFO "%s: Link is down\n",
+                                               dev->name);
                        priv->oldlink = 0;
                        priv->oldspeed = 0;
                        priv->oldduplex = -1;
@@ -1664,8 +1941,9 @@ static void gfar_set_multi(struct net_device *dev)
        u32 tempval;
 
        if(dev->flags & IFF_PROMISC) {
-               printk(KERN_INFO "%s: Entering promiscuous mode.\n",
-                               dev->name);
+               if (netif_msg_drv(priv))
+                       printk(KERN_INFO "%s: Entering promiscuous mode.\n",
+                                       dev->name);
                /* Set RCTRL to PROM */
                tempval = gfar_read(&regs->rctrl);
                tempval |= RCTRL_PROM;
@@ -1679,6 +1957,14 @@ static void gfar_set_multi(struct net_device *dev)
        
        if(dev->flags & IFF_ALLMULTI) {
                /* Set the hash to rx all multicast frames */
+               gfar_write(&regs->igaddr0, 0xffffffff);
+               gfar_write(&regs->igaddr1, 0xffffffff);
+               gfar_write(&regs->igaddr2, 0xffffffff);
+               gfar_write(&regs->igaddr3, 0xffffffff);
+               gfar_write(&regs->igaddr4, 0xffffffff);
+               gfar_write(&regs->igaddr5, 0xffffffff);
+               gfar_write(&regs->igaddr6, 0xffffffff);
+               gfar_write(&regs->igaddr7, 0xffffffff);
                gfar_write(&regs->gaddr0, 0xffffffff);
                gfar_write(&regs->gaddr1, 0xffffffff);
                gfar_write(&regs->gaddr2, 0xffffffff);
@@ -1689,6 +1975,14 @@ static void gfar_set_multi(struct net_device *dev)
                gfar_write(&regs->gaddr7, 0xffffffff);
        } else {
                /* zero out the hash */
+               gfar_write(&regs->igaddr0, 0x0);
+               gfar_write(&regs->igaddr1, 0x0);
+               gfar_write(&regs->igaddr2, 0x0);
+               gfar_write(&regs->igaddr3, 0x0);
+               gfar_write(&regs->igaddr4, 0x0);
+               gfar_write(&regs->igaddr5, 0x0);
+               gfar_write(&regs->igaddr6, 0x0);
+               gfar_write(&regs->igaddr7, 0x0);
                gfar_write(&regs->gaddr0, 0x0);
                gfar_write(&regs->gaddr1, 0x0);
                gfar_write(&regs->gaddr2, 0x0);
@@ -1727,16 +2021,15 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
 {
        u32 tempval;
        struct gfar_private *priv = netdev_priv(dev);
-       struct gfar *regs = priv->regs;
-       u32 *hash = &regs->gaddr0;
        u32 result = ether_crc(MAC_ADDR_LEN, addr);
-       u8 whichreg = ((result >> 29) & 0x7);
-       u8 whichbit = ((result >> 24) & 0x1f);
+       int width = priv->hash_width;
+       u8 whichbit = (result >> (32 - width)) & 0x1f;
+       u8 whichreg = result >> (32 - width + 5);
        u32 value = (1 << (31-whichbit));
 
-       tempval = gfar_read(&hash[whichreg]);
+       tempval = gfar_read(priv->hash_regs[whichreg]);
        tempval |= value;
-       gfar_write(&hash[whichreg], tempval);
+       gfar_write(priv->hash_regs[whichreg], tempval);
 
        return;
 }
@@ -1754,10 +2047,9 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
        gfar_write(&priv->regs->ievent, IEVENT_ERR_MASK);
 
        /* Hmm... */
-#if defined (BRIEF_GFAR_ERRORS) || defined (VERBOSE_GFAR_ERRORS)
-       printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
-              dev->name, events, gfar_read(&priv->regs->imask));
-#endif
+       if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv))
+               printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
+                               dev->name, events, gfar_read(&priv->regs->imask));
 
        /* Update the error counters */
        if (events & IEVENT_TXE) {
@@ -1768,19 +2060,17 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
                if (events & IEVENT_CRL)
                        priv->stats.tx_aborted_errors++;
                if (events & IEVENT_XFUN) {
-#ifdef VERBOSE_GFAR_ERRORS
-                       printk(KERN_DEBUG "%s: underrun.  packet dropped.\n",
-                              dev->name);
-#endif
+                       if (netif_msg_tx_err(priv))
+                               printk(KERN_DEBUG "%s: underrun.  packet dropped.\n",
+                                               dev->name);
                        priv->stats.tx_dropped++;
                        priv->extra_stats.tx_underrun++;
 
                        /* Reactivate the Tx Queues */
                        gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
                }
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
-#endif
+               if (netif_msg_tx_err(priv))
+                       printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
        }
        if (events & IEVENT_BSY) {
                priv->stats.rx_errors++;
@@ -1793,35 +2083,31 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
                gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
 #endif
 
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name,
-                      gfar_read(&priv->regs->rstat));
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
+                                       dev->name,
+                                       gfar_read(&priv->regs->rstat));
        }
        if (events & IEVENT_BABR) {
                priv->stats.rx_errors++;
                priv->extra_stats.rx_babr++;
 
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: babbling error\n", dev->name);
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: babbling error\n", dev->name);
        }
        if (events & IEVENT_EBERR) {
                priv->extra_stats.eberr++;
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: EBERR\n", dev->name);
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: EBERR\n", dev->name);
        }
-       if (events & IEVENT_RXC)
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: control frame\n", dev->name);
-#endif
+       if ((events & IEVENT_RXC) && netif_msg_rx_status(priv))
+               if (netif_msg_rx_status(priv))
+                       printk(KERN_DEBUG "%s: control frame\n", dev->name);
 
        if (events & IEVENT_BABT) {
                priv->extra_stats.tx_babt++;
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: babt error\n", dev->name);
-#endif
+               if (netif_msg_tx_err(priv))
+                       printk(KERN_DEBUG "%s: babt error\n", dev->name);
        }
        return IRQ_HANDLED;
 }
index c2f783a6a9fab85ea221643aeb31c40462e52c87..28af087d9fbba24d0005fd66c34f765005565610 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * drivers/net/gianfar.h
  *
  * Gianfar Ethernet Driver
 /* The maximum number of packets to be handled in one call of gfar_poll */
 #define GFAR_DEV_WEIGHT 64
 
+/* Length for FCB */
+#define GMAC_FCB_LEN 8
+
+/* Default padding amount */
+#define DEFAULT_PADDING 2
+
 /* Number of bytes to align the rx bufs to */
 #define RXBUF_ALIGNMENT 64
 
@@ -91,7 +97,7 @@ extern const char gfar_driver_version[];
 #define JUMBO_FRAME_SIZE 9600
 
 /* Latency of interface clock in nanoseconds */
-/* Interface clock latency , in this case, means the 
+/* Interface clock latency , in this case, means the
  * time described by a value of 1 in the interrupt
  * coalescing registers' time fields.  Since those fields
  * refer to the time it takes for 64 clocks to pass, the
@@ -166,9 +172,28 @@ extern const char gfar_driver_version[];
                                mk_ic_icft(count) | \
                                mk_ic_ictt(time))
 
+#define RCTRL_PAL_MASK         0x001f0000
+#define RCTRL_VLEX             0x00002000
+#define RCTRL_FILREN           0x00001000
+#define RCTRL_GHTX             0x00000400
+#define RCTRL_IPCSEN           0x00000200
+#define RCTRL_TUCSEN           0x00000100
+#define RCTRL_PRSDEP_MASK      0x000000c0
+#define RCTRL_PRSDEP_INIT      0x000000c0
 #define RCTRL_PROM             0x00000008
+#define RCTRL_CHECKSUMMING     (RCTRL_IPCSEN \
+               | RCTRL_TUCSEN | RCTRL_PRSDEP_INIT)
+#define RCTRL_EXTHASH          (RCTRL_GHTX)
+#define RCTRL_VLAN             (RCTRL_PRSDEP_INIT)
+
+
 #define RSTAT_CLEAR_RHALT       0x00800000
 
+#define TCTRL_IPCSEN           0x00004000
+#define TCTRL_TUCSEN           0x00002000
+#define TCTRL_VLINS            0x00001000
+#define TCTRL_INIT_CSUM                (TCTRL_TUCSEN | TCTRL_IPCSEN)
+
 #define IEVENT_INIT_CLEAR      0xffffffff
 #define IEVENT_BABR            0x80000000
 #define IEVENT_RXC             0x40000000
@@ -187,12 +212,16 @@ extern const char gfar_driver_version[];
 #define IEVENT_RXB0            0x00008000
 #define IEVENT_GRSC            0x00000100
 #define IEVENT_RXF0            0x00000080
+#define IEVENT_FIR             0x00000008
+#define IEVENT_FIQ             0x00000004
+#define IEVENT_DPE             0x00000002
+#define IEVENT_PERR            0x00000001
 #define IEVENT_RX_MASK          (IEVENT_RXB0 | IEVENT_RXF0)
 #define IEVENT_TX_MASK          (IEVENT_TXB | IEVENT_TXF)
 #define IEVENT_ERR_MASK         \
 (IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \
  IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \
- | IEVENT_CRL | IEVENT_XFUN)
+ | IEVENT_CRL | IEVENT_XFUN | IEVENT_DPE | IEVENT_PERR)
 
 #define IMASK_INIT_CLEAR       0x00000000
 #define IMASK_BABR              0x80000000
@@ -212,10 +241,15 @@ extern const char gfar_driver_version[];
 #define IMASK_RXB0              0x00008000
 #define IMASK_GTSC              0x00000100
 #define IMASK_RXFEN0           0x00000080
+#define IMASK_FIR              0x00000008
+#define IMASK_FIQ              0x00000004
+#define IMASK_DPE              0x00000002
+#define IMASK_PERR             0x00000001
 #define IMASK_RX_DISABLED ~(IMASK_RXFEN0 | IMASK_BSY)
 #define IMASK_DEFAULT  (IMASK_TXEEN | IMASK_TXFEN | IMASK_TXBEN | \
                IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \
-               IMASK_XFUN | IMASK_RXC | IMASK_BABT)
+               IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \
+               | IMASK_PERR)
 
 
 /* Attribute fields */
@@ -254,6 +288,18 @@ extern const char gfar_driver_version[];
 #define TXBD_RETRYLIMIT                0x0040
 #define        TXBD_RETRYCOUNTMASK     0x003c
 #define TXBD_UNDERRUN          0x0002
+#define TXBD_TOE               0x0002
+
+/* Tx FCB param bits */
+#define TXFCB_VLN              0x80
+#define TXFCB_IP               0x40
+#define TXFCB_IP6              0x20
+#define TXFCB_TUP              0x10
+#define TXFCB_UDP              0x08
+#define TXFCB_CIP              0x04
+#define TXFCB_CTU              0x02
+#define TXFCB_NPH              0x01
+#define TXFCB_DEFAULT          (TXFCB_IP|TXFCB_TUP|TXFCB_CTU|TXFCB_NPH)
 
 /* RxBD status field bits */
 #define RXBD_EMPTY             0x8000
@@ -273,6 +319,18 @@ extern const char gfar_driver_version[];
 #define RXBD_TRUNCATED         0x0001
 #define RXBD_STATS             0x01ff
 
+/* Rx FCB status field bits */
+#define RXFCB_VLN              0x8000
+#define RXFCB_IP               0x4000
+#define RXFCB_IP6              0x2000
+#define RXFCB_TUP              0x1000
+#define RXFCB_CIP              0x0800
+#define RXFCB_CTU              0x0400
+#define RXFCB_EIP              0x0200
+#define RXFCB_ETU              0x0100
+#define RXFCB_PERR_MASK                0x000c
+#define RXFCB_PERR_BADL3       0x0008
+
 struct txbd8
 {
        u16     status; /* Status Fields */
@@ -280,6 +338,22 @@ struct txbd8
        u32     bufPtr; /* Buffer Pointer */
 };
 
+struct txfcb {
+       u8      vln:1,
+               ip:1,
+               ip6:1,
+               tup:1,
+               udp:1,
+               cip:1,
+               ctu:1,
+               nph:1;
+       u8      reserved;
+       u8      l4os;   /* Level 4 Header Offset */
+       u8      l3os;   /* Level 3 Header Offset */
+       u16     phcs;   /* Pseudo-header Checksum */
+       u16     vlctl;  /* VLAN control word */
+};
+
 struct rxbd8
 {
        u16     status; /* Status Fields */
@@ -287,6 +361,21 @@ struct rxbd8
        u32     bufPtr; /* Buffer Pointer */
 };
 
+struct rxfcb {
+       u16     vln:1,
+               ip:1,
+               ip6:1,
+               tup:1,
+               cip:1,
+               ctu:1,
+               eip:1,
+               etu:1;
+       u8      rq;     /* Receive Queue index */
+       u8      pro;    /* Layer 4 Protocol */
+       u16     reserved;
+       u16     vlctl;  /* VLAN control word */
+};
+
 struct rmon_mib
 {
        u32     tr64;   /* 0x.680 - Transmit and Receive 64-byte Frame Counter */
@@ -371,90 +460,191 @@ struct gfar_stats {
 
 
 struct gfar {
-       u8      res1[16];
-       u32     ievent;                 /* 0x.010 - Interrupt Event Register */
-       u32     imask;                  /* 0x.014 - Interrupt Mask Register */
-       u32     edis;                   /* 0x.018 - Error Disabled Register */
+       u32     tsec_id;        /* 0x.000 - Controller ID register */
+       u8      res1[12];
+       u32     ievent;         /* 0x.010 - Interrupt Event Register */
+       u32     imask;          /* 0x.014 - Interrupt Mask Register */
+       u32     edis;           /* 0x.018 - Error Disabled Register */
        u8      res2[4];
-       u32     ecntrl;                 /* 0x.020 - Ethernet Control Register */
-       u32     minflr;                 /* 0x.024 - Minimum Frame Length Register */
-       u32     ptv;                    /* 0x.028 - Pause Time Value Register */
-       u32     dmactrl;                /* 0x.02c - DMA Control Register */
-       u32     tbipa;                  /* 0x.030 - TBI PHY Address Register */
+       u32     ecntrl;         /* 0x.020 - Ethernet Control Register */
+       u32     minflr;         /* 0x.024 - Minimum Frame Length Register */
+       u32     ptv;            /* 0x.028 - Pause Time Value Register */
+       u32     dmactrl;        /* 0x.02c - DMA Control Register */
+       u32     tbipa;          /* 0x.030 - TBI PHY Address Register */
        u8      res3[88];
-       u32     fifo_tx_thr;            /* 0x.08c - FIFO transmit threshold register */
+       u32     fifo_tx_thr;    /* 0x.08c - FIFO transmit threshold register */
        u8      res4[8];
-       u32     fifo_tx_starve;         /* 0x.098 - FIFO transmit starve register */
+       u32     fifo_tx_starve; /* 0x.098 - FIFO transmit starve register */
        u32     fifo_tx_starve_shutoff; /* 0x.09c - FIFO transmit starve shutoff register */
-       u8      res5[96];
-       u32     tctrl;                  /* 0x.100 - Transmit Control Register */
-       u32     tstat;                  /* 0x.104 - Transmit Status Register */
-       u8      res6[4];
-       u32     tbdlen;                 /* 0x.10c - Transmit Buffer Descriptor Data Length Register */
-       u32     txic;                   /* 0x.110 - Transmit Interrupt Coalescing Configuration Register */
-       u8      res7[16];
-       u32     ctbptr;                 /* 0x.124 - Current Transmit Buffer Descriptor Pointer Register */
-       u8      res8[92];
-       u32     tbptr;                  /* 0x.184 - Transmit Buffer Descriptor Pointer Low Register */
-       u8      res9[124];
-       u32     tbase;                  /* 0x.204 - Transmit Descriptor Base Address Register */
-       u8      res10[168];
-       u32     ostbd;                  /* 0x.2b0 - Out-of-Sequence Transmit Buffer Descriptor Register */
-       u32     ostbdp;                 /* 0x.2b4 - Out-of-Sequence Transmit Data Buffer Pointer Register */
-       u8      res11[72];
-       u32     rctrl;                  /* 0x.300 - Receive Control Register */
-       u32     rstat;                  /* 0x.304 - Receive Status Register */
-       u8      res12[4];
-       u32     rbdlen;                 /* 0x.30c - RxBD Data Length Register */
-       u32     rxic;                   /* 0x.310 - Receive Interrupt Coalescing Configuration Register */
-       u8      res13[16];
-       u32     crbptr;                 /* 0x.324 - Current Receive Buffer Descriptor Pointer */
-       u8      res14[24];
-       u32     mrblr;                  /* 0x.340 - Maximum Receive Buffer Length Register */
-       u8      res15[64];
-       u32     rbptr;                  /* 0x.384 - Receive Buffer Descriptor Pointer */
-       u8      res16[124];
-       u32     rbase;                  /* 0x.404 - Receive Descriptor Base Address */
-       u8      res17[248];
-       u32     maccfg1;                /* 0x.500 - MAC Configuration 1 Register */
-       u32     maccfg2;                /* 0x.504 - MAC Configuration 2 Register */
-       u32     ipgifg;                 /* 0x.508 - Inter Packet Gap/Inter Frame Gap Register */
-       u32     hafdup;                 /* 0x.50c - Half Duplex Register */
-       u32     maxfrm;                 /* 0x.510 - Maximum Frame Length Register */
+       u8      res5[4];
+       u32     fifo_rx_pause;  /* 0x.0a4 - FIFO receive pause threshold register */
+       u32     fifo_rx_alarm;  /* 0x.0a8 - FIFO receive alarm threshold register */
+       u8      res6[84];
+       u32     tctrl;          /* 0x.100 - Transmit Control Register */
+       u32     tstat;          /* 0x.104 - Transmit Status Register */
+       u32     dfvlan;         /* 0x.108 - Default VLAN Control word */
+       u32     tbdlen;         /* 0x.10c - Transmit Buffer Descriptor Data Length Register */
+       u32     txic;           /* 0x.110 - Transmit Interrupt Coalescing Configuration Register */
+       u32     tqueue;         /* 0x.114 - Transmit queue control register */
+       u8      res7[40];
+       u32     tr03wt;         /* 0x.140 - TxBD Rings 0-3 round-robin weightings */
+       u32     tr47wt;         /* 0x.144 - TxBD Rings 4-7 round-robin weightings */
+       u8      res8[52];
+       u32     tbdbph;         /* 0x.17c - Tx data buffer pointer high */
+       u8      res9a[4];
+       u32     tbptr0;         /* 0x.184 - TxBD Pointer for ring 0 */
+       u8      res9b[4];
+       u32     tbptr1;         /* 0x.18c - TxBD Pointer for ring 1 */
+       u8      res9c[4];
+       u32     tbptr2;         /* 0x.194 - TxBD Pointer for ring 2 */
+       u8      res9d[4];
+       u32     tbptr3;         /* 0x.19c - TxBD Pointer for ring 3 */
+       u8      res9e[4];
+       u32     tbptr4;         /* 0x.1a4 - TxBD Pointer for ring 4 */
+       u8      res9f[4];
+       u32     tbptr5;         /* 0x.1ac - TxBD Pointer for ring 5 */
+       u8      res9g[4];
+       u32     tbptr6;         /* 0x.1b4 - TxBD Pointer for ring 6 */
+       u8      res9h[4];
+       u32     tbptr7;         /* 0x.1bc - TxBD Pointer for ring 7 */
+       u8      res9[64];
+       u32     tbaseh;         /* 0x.200 - TxBD base address high */
+       u32     tbase0;         /* 0x.204 - TxBD Base Address of ring 0 */
+       u8      res10a[4];
+       u32     tbase1;         /* 0x.20c - TxBD Base Address of ring 1 */
+       u8      res10b[4];
+       u32     tbase2;         /* 0x.214 - TxBD Base Address of ring 2 */
+       u8      res10c[4];
+       u32     tbase3;         /* 0x.21c - TxBD Base Address of ring 3 */
+       u8      res10d[4];
+       u32     tbase4;         /* 0x.224 - TxBD Base Address of ring 4 */
+       u8      res10e[4];
+       u32     tbase5;         /* 0x.22c - TxBD Base Address of ring 5 */
+       u8      res10f[4];
+       u32     tbase6;         /* 0x.234 - TxBD Base Address of ring 6 */
+       u8      res10g[4];
+       u32     tbase7;         /* 0x.23c - TxBD Base Address of ring 7 */
+       u8      res10[192];
+       u32     rctrl;          /* 0x.300 - Receive Control Register */
+       u32     rstat;          /* 0x.304 - Receive Status Register */
+       u8      res12[8];
+       u32     rxic;           /* 0x.310 - Receive Interrupt Coalescing Configuration Register */
+       u32     rqueue;         /* 0x.314 - Receive queue control register */
+       u8      res13[24];
+       u32     rbifx;          /* 0x.330 - Receive bit field extract control register */
+       u32     rqfar;          /* 0x.334 - Receive queue filing table address register */
+       u32     rqfcr;          /* 0x.338 - Receive queue filing table control register */
+       u32     rqfpr;          /* 0x.33c - Receive queue filing table property register */
+       u32     mrblr;          /* 0x.340 - Maximum Receive Buffer Length Register */
+       u8      res14[56];
+       u32     rbdbph;         /* 0x.37c - Rx data buffer pointer high */
+       u8      res15a[4];
+       u32     rbptr0;         /* 0x.384 - RxBD pointer for ring 0 */
+       u8      res15b[4];
+       u32     rbptr1;         /* 0x.38c - RxBD pointer for ring 1 */
+       u8      res15c[4];
+       u32     rbptr2;         /* 0x.394 - RxBD pointer for ring 2 */
+       u8      res15d[4];
+       u32     rbptr3;         /* 0x.39c - RxBD pointer for ring 3 */
+       u8      res15e[4];
+       u32     rbptr4;         /* 0x.3a4 - RxBD pointer for ring 4 */
+       u8      res15f[4];
+       u32     rbptr5;         /* 0x.3ac - RxBD pointer for ring 5 */
+       u8      res15g[4];
+       u32     rbptr6;         /* 0x.3b4 - RxBD pointer for ring 6 */
+       u8      res15h[4];
+       u32     rbptr7;         /* 0x.3bc - RxBD pointer for ring 7 */
+       u8      res16[64];
+       u32     rbaseh;         /* 0x.400 - RxBD base address high */
+       u32     rbase0;         /* 0x.404 - RxBD base address of ring 0 */
+       u8      res17a[4];
+       u32     rbase1;         /* 0x.40c - RxBD base address of ring 1 */
+       u8      res17b[4];
+       u32     rbase2;         /* 0x.414 - RxBD base address of ring 2 */
+       u8      res17c[4];
+       u32     rbase3;         /* 0x.41c - RxBD base address of ring 3 */
+       u8      res17d[4];
+       u32     rbase4;         /* 0x.424 - RxBD base address of ring 4 */
+       u8      res17e[4];
+       u32     rbase5;         /* 0x.42c - RxBD base address of ring 5 */
+       u8      res17f[4];
+       u32     rbase6;         /* 0x.434 - RxBD base address of ring 6 */
+       u8      res17g[4];
+       u32     rbase7;         /* 0x.43c - RxBD base address of ring 7 */
+       u8      res17[192];
+       u32     maccfg1;        /* 0x.500 - MAC Configuration 1 Register */
+       u32     maccfg2;        /* 0x.504 - MAC Configuration 2 Register */
+       u32     ipgifg;         /* 0x.508 - Inter Packet Gap/Inter Frame Gap Register */
+       u32     hafdup;         /* 0x.50c - Half Duplex Register */
+       u32     maxfrm;         /* 0x.510 - Maximum Frame Length Register */
        u8      res18[12];
-       u32     miimcfg;                /* 0x.520 - MII Management Configuration Register */
-       u32     miimcom;                /* 0x.524 - MII Management Command Register */
-       u32     miimadd;                /* 0x.528 - MII Management Address Register */
-       u32     miimcon;                /* 0x.52c - MII Management Control Register */
-       u32     miimstat;               /* 0x.530 - MII Management Status Register */
-       u32     miimind;                /* 0x.534 - MII Management Indicator Register */
+       u32     miimcfg;        /* 0x.520 - MII Management Configuration Register */
+       u32     miimcom;        /* 0x.524 - MII Management Command Register */
+       u32     miimadd;        /* 0x.528 - MII Management Address Register */
+       u32     miimcon;        /* 0x.52c - MII Management Control Register */
+       u32     miimstat;       /* 0x.530 - MII Management Status Register */
+       u32     miimind;        /* 0x.534 - MII Management Indicator Register */
        u8      res19[4];
-       u32     ifstat;                 /* 0x.53c - Interface Status Register */
-       u32     macstnaddr1;            /* 0x.540 - Station Address Part 1 Register */
-       u32     macstnaddr2;            /* 0x.544 - Station Address Part 2 Register */
-       u8      res20[312];
-       struct rmon_mib rmon;
-       u8      res21[192];
-       u32     iaddr0;                 /* 0x.800 - Indivdual address register 0 */
-       u32     iaddr1;                 /* 0x.804 - Indivdual address register 1 */
-       u32     iaddr2;                 /* 0x.808 - Indivdual address register 2 */
-       u32     iaddr3;                 /* 0x.80c - Indivdual address register 3 */
-       u32     iaddr4;                 /* 0x.810 - Indivdual address register 4 */
-       u32     iaddr5;                 /* 0x.814 - Indivdual address register 5 */
-       u32     iaddr6;                 /* 0x.818 - Indivdual address register 6 */
-       u32     iaddr7;                 /* 0x.81c - Indivdual address register 7 */
+       u32     ifstat;         /* 0x.53c - Interface Status Register */
+       u32     macstnaddr1;    /* 0x.540 - Station Address Part 1 Register */
+       u32     macstnaddr2;    /* 0x.544 - Station Address Part 2 Register */
+       u32     mac01addr1;     /* 0x.548 - MAC exact match address 1, part 1 */
+       u32     mac01addr2;     /* 0x.54c - MAC exact match address 1, part 2 */
+       u32     mac02addr1;     /* 0x.550 - MAC exact match address 2, part 1 */
+       u32     mac02addr2;     /* 0x.554 - MAC exact match address 2, part 2 */
+       u32     mac03addr1;     /* 0x.558 - MAC exact match address 3, part 1 */
+       u32     mac03addr2;     /* 0x.55c - MAC exact match address 3, part 2 */
+       u32     mac04addr1;     /* 0x.560 - MAC exact match address 4, part 1 */
+       u32     mac04addr2;     /* 0x.564 - MAC exact match address 4, part 2 */
+       u32     mac05addr1;     /* 0x.568 - MAC exact match address 5, part 1 */
+       u32     mac05addr2;     /* 0x.56c - MAC exact match address 5, part 2 */
+       u32     mac06addr1;     /* 0x.570 - MAC exact match address 6, part 1 */
+       u32     mac06addr2;     /* 0x.574 - MAC exact match address 6, part 2 */
+       u32     mac07addr1;     /* 0x.578 - MAC exact match address 7, part 1 */
+       u32     mac07addr2;     /* 0x.57c - MAC exact match address 7, part 2 */
+       u32     mac08addr1;     /* 0x.580 - MAC exact match address 8, part 1 */
+       u32     mac08addr2;     /* 0x.584 - MAC exact match address 8, part 2 */
+       u32     mac09addr1;     /* 0x.588 - MAC exact match address 9, part 1 */
+       u32     mac09addr2;     /* 0x.58c - MAC exact match address 9, part 2 */
+       u32     mac10addr1;     /* 0x.590 - MAC exact match address 10, part 1*/
+       u32     mac10addr2;     /* 0x.594 - MAC exact match address 10, part 2*/
+       u32     mac11addr1;     /* 0x.598 - MAC exact match address 11, part 1*/
+       u32     mac11addr2;     /* 0x.59c - MAC exact match address 11, part 2*/
+       u32     mac12addr1;     /* 0x.5a0 - MAC exact match address 12, part 1*/
+       u32     mac12addr2;     /* 0x.5a4 - MAC exact match address 12, part 2*/
+       u32     mac13addr1;     /* 0x.5a8 - MAC exact match address 13, part 1*/
+       u32     mac13addr2;     /* 0x.5ac - MAC exact match address 13, part 2*/
+       u32     mac14addr1;     /* 0x.5b0 - MAC exact match address 14, part 1*/
+       u32     mac14addr2;     /* 0x.5b4 - MAC exact match address 14, part 2*/
+       u32     mac15addr1;     /* 0x.5b8 - MAC exact match address 15, part 1*/
+       u32     mac15addr2;     /* 0x.5bc - MAC exact match address 15, part 2*/
+       u8      res20[192];
+       struct rmon_mib rmon;   /* 0x.680-0x.73c */
+       u32     rrej;           /* 0x.740 - Receive filer rejected packet counter */
+       u8      res21[188];
+       u32     igaddr0;        /* 0x.800 - Indivdual/Group address register 0*/
+       u32     igaddr1;        /* 0x.804 - Indivdual/Group address register 1*/
+       u32     igaddr2;        /* 0x.808 - Indivdual/Group address register 2*/
+       u32     igaddr3;        /* 0x.80c - Indivdual/Group address register 3*/
+       u32     igaddr4;        /* 0x.810 - Indivdual/Group address register 4*/
+       u32     igaddr5;        /* 0x.814 - Indivdual/Group address register 5*/
+       u32     igaddr6;        /* 0x.818 - Indivdual/Group address register 6*/
+       u32     igaddr7;        /* 0x.81c - Indivdual/Group address register 7*/
        u8      res22[96];
-       u32     gaddr0;                 /* 0x.880 - Global address register 0 */
-       u32     gaddr1;                 /* 0x.884 - Global address register 1 */
-       u32     gaddr2;                 /* 0x.888 - Global address register 2 */
-       u32     gaddr3;                 /* 0x.88c - Global address register 3 */
-       u32     gaddr4;                 /* 0x.890 - Global address register 4 */
-       u32     gaddr5;                 /* 0x.894 - Global address register 5 */
-       u32     gaddr6;                 /* 0x.898 - Global address register 6 */
-       u32     gaddr7;                 /* 0x.89c - Global address register 7 */
-       u8      res23[856];
-       u32     attr;                   /* 0x.bf8 - Attributes Register */
-       u32     attreli;                /* 0x.bfc - Attributes Extract Length and Extract Index Register */
+       u32     gaddr0;         /* 0x.880 - Group address register 0 */
+       u32     gaddr1;         /* 0x.884 - Group address register 1 */
+       u32     gaddr2;         /* 0x.888 - Group address register 2 */
+       u32     gaddr3;         /* 0x.88c - Group address register 3 */
+       u32     gaddr4;         /* 0x.890 - Group address register 4 */
+       u32     gaddr5;         /* 0x.894 - Group address register 5 */
+       u32     gaddr6;         /* 0x.898 - Group address register 6 */
+       u32     gaddr7;         /* 0x.89c - Group address register 7 */
+       u8      res23a[352];
+       u32     fifocfg;        /* 0x.a00 - FIFO interface config register */
+       u8      res23b[252];
+       u8      res23c[248];
+       u32     attr;           /* 0x.bf8 - Attributes Register */
+       u32     attreli;        /* 0x.bfc - Attributes Extract Length and Extract Index Register */
        u8      res24[1024];
 
 };
@@ -496,6 +686,8 @@ struct gfar_private {
        struct txbd8 *cur_tx;           /* Next free ring entry */
        struct txbd8 *dirty_tx;         /* The Ring entry to be freed. */
        struct gfar *regs;      /* Pointer to the GFAR memory mapped Registers */
+       u32 *hash_regs[16];
+       int hash_width;
        struct gfar *phyregs;
        struct work_struct tq;
        struct timer_list phy_info_timer;
@@ -506,9 +698,12 @@ struct gfar_private {
        unsigned int rx_stash_size;
        unsigned int tx_ring_size;
        unsigned int rx_ring_size;
-       wait_queue_head_t rxcleanupq;
-       unsigned int rxclean;
 
+       unsigned char vlan_enable:1,
+               rx_csum_enable:1,
+               extended_hash:1;
+       unsigned short padding;
+       struct vlan_group *vlgrp;
        /* Info structure initialized by board setup code */
        unsigned int interruptTransmit;
        unsigned int interruptReceive;
@@ -519,6 +714,8 @@ struct gfar_private {
        int oldspeed;
        int oldduplex;
        int oldlink;
+
+       uint32_t msg_enable;
 };
 
 extern inline u32 gfar_read(volatile unsigned *addr)
index 28046e9e88ba1f369030c33f29e49395bdb9dc2a..a451de629197b13e1204f59b2707fef1d425e91d 100644 (file)
 
 extern int startup_gfar(struct net_device *dev);
 extern void stop_gfar(struct net_device *dev);
-extern void gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+extern void gfar_halt(struct net_device *dev);
+extern void gfar_start(struct net_device *dev);
+extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
 
-void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
                     u64 * buf);
-void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
-int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
+static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
+static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
+static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
+static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
+static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
+static void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
 
 static char stat_gstrings[][ETH_GSTRING_LEN] = {
        "rx-dropped-by-kernel",
@@ -118,57 +120,56 @@ static char stat_gstrings[][ETH_GSTRING_LEN] = {
        "tx-fragmented-frames",
 };
 
+/* Fill in a buffer with the strings which correspond to the
+ * stats */
+static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+               memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
+       else
+               memcpy(buf, stat_gstrings,
+                               GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+}
+
 /* Fill in an array of 64-bit statistics from various sources.
  * This array will be appended to the end of the ethtool_stats
  * structure, and returned to user space
  */
-void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
 {
        int i;
        struct gfar_private *priv = netdev_priv(dev);
-       u32 *rmon = (u32 *) & priv->regs->rmon;
        u64 *extra = (u64 *) & priv->extra_stats;
-       struct gfar_stats *stats = (struct gfar_stats *) buf;
 
-       for (i = 0; i < GFAR_RMON_LEN; i++) {
-               stats->rmon[i] = (u64) (rmon[i]);
-       }
-
-       for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
-               stats->extra[i] = extra[i];
-       }
-}
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+               u32 *rmon = (u32 *) & priv->regs->rmon;
+               struct gfar_stats *stats = (struct gfar_stats *) buf;
 
-/* Returns the number of stats (and their corresponding strings) */
-int gfar_stats_count(struct net_device *dev)
-{
-       return GFAR_STATS_LEN;
-}
+               for (i = 0; i < GFAR_RMON_LEN; i++)
+                       stats->rmon[i] = (u64) (rmon[i]);
 
-void gfar_gstrings_normon(struct net_device *dev, u32 stringset, u8 * buf)
-{
-       memcpy(buf, stat_gstrings, GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+               for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+                       stats->extra[i] = extra[i];
+       } else
+               for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+                       buf[i] = extra[i];
 }
 
-void gfar_fill_stats_normon(struct net_device *dev, 
-               struct ethtool_stats *dummy, u64 * buf)
+/* Returns the number of stats (and their corresponding strings) */
+static int gfar_stats_count(struct net_device *dev)
 {
-       int i;
        struct gfar_private *priv = netdev_priv(dev);
-       u64 *extra = (u64 *) & priv->extra_stats;
 
-       for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
-               buf[i] = extra[i];
-       }
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+               return GFAR_STATS_LEN;
+       else
+               return GFAR_EXTRA_STATS_LEN;
 }
 
-
-int gfar_stats_count_normon(struct net_device *dev)
-{
-       return GFAR_EXTRA_STATS_LEN;
-}
 /* Fills in the drvinfo structure with some basic info */
-void gfar_gdrvinfo(struct net_device *dev, struct
+static void gfar_gdrvinfo(struct net_device *dev, struct
              ethtool_drvinfo *drvinfo)
 {
        strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN);
@@ -182,7 +183,7 @@ void gfar_gdrvinfo(struct net_device *dev, struct
 }
 
 /* Return the current settings in the ethtool_cmd structure */
-int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct gfar_private *priv = netdev_priv(dev);
        uint gigabit_support = 
@@ -216,13 +217,13 @@ int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
 }
 
 /* Return the length of the register structure */
-int gfar_reglen(struct net_device *dev)
+static int gfar_reglen(struct net_device *dev)
 {
        return sizeof (struct gfar);
 }
 
 /* Return a dump of the GFAR register space */
-void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
+static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
 {
        int i;
        struct gfar_private *priv = netdev_priv(dev);
@@ -233,13 +234,6 @@ void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regb
                buf[i] = theregs[i];
 }
 
-/* Fill in a buffer with the strings which correspond to the
- * stats */
-void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
-{
-       memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
-}
-
 /* Convert microseconds to ethernet clock ticks, which changes
  * depending on what speed the controller is running at */
 static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int usecs)
@@ -291,9 +285,12 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic
 
 /* Get the coalescing parameters, and put them in the cvals
  * structure.  */
-int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 {
        struct gfar_private *priv = netdev_priv(dev);
+       
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+               return -EOPNOTSUPP;
 
        cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime);
        cvals->rx_max_coalesced_frames = priv->rxcount;
@@ -337,10 +334,13 @@ int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
  * Both cvals->*_usecs and cvals->*_frames have to be > 0
  * in order for coalescing to be active
  */
-int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 {
        struct gfar_private *priv = netdev_priv(dev);
 
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+               return -EOPNOTSUPP;
+
        /* Set up rx coalescing */
        if ((cvals->rx_coalesce_usecs == 0) ||
            (cvals->rx_max_coalesced_frames == 0))
@@ -379,7 +379,7 @@ int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 /* Fills in rvals with the current ring parameters.  Currently,
  * rx, rx_mini, and rx_jumbo rings are the same size, as mini and
  * jumbo are ignored by the driver */
-void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
 {
        struct gfar_private *priv = netdev_priv(dev);
 
@@ -401,9 +401,8 @@ void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
  * necessary so that we don't mess things up while we're in
  * motion.  We wait for the ring to be clean before reallocating
  * the rings. */
-int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
 {
-       u32 tempval;
        struct gfar_private *priv = netdev_priv(dev);
        int err = 0;
 
@@ -425,37 +424,54 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
                return -EINVAL;
        }
 
-       /* Stop the controller so we don't rx any more frames */
-       /* But first, make sure we clear the bits */
-       tempval = gfar_read(&priv->regs->dmactrl);
-       tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
-       gfar_write(&priv->regs->dmactrl, tempval);
+       if (dev->flags & IFF_UP) {
+               unsigned long flags;
 
-       tempval = gfar_read(&priv->regs->dmactrl);
-       tempval |= (DMACTRL_GRS | DMACTRL_GTS);
-       gfar_write(&priv->regs->dmactrl, tempval);
+               /* Halt TX and RX, and process the frames which
+                * have already been received */
+               spin_lock_irqsave(&priv->lock, flags);
+               gfar_halt(dev);
+               gfar_clean_rx_ring(dev, priv->rx_ring_size);
+               spin_unlock_irqrestore(&priv->lock, flags);
 
-       while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC)))
-               cpu_relax();
+               /* Now we take down the rings to rebuild them */
+               stop_gfar(dev);
+       }
 
-       /* Note that rx is not clean right now */
-       priv->rxclean = 0;
+       /* Change the size */
+       priv->rx_ring_size = rvals->rx_pending;
+       priv->tx_ring_size = rvals->tx_pending;
 
-       if (dev->flags & IFF_UP) {
-               /* Tell the driver to process the rest of the frames */
-               gfar_receive(0, (void *) dev, NULL);
+       /* Rebuild the rings with the new size */
+       if (dev->flags & IFF_UP)
+               err = startup_gfar(dev);
 
-               /* Now wait for it to be done */
-               wait_event_interruptible(priv->rxcleanupq, priv->rxclean);
+       return err;
+}
 
-               /* Ok, all packets have been handled.  Now we bring it down,
-                * change the ring size, and bring it up */
+static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       int err = 0;
 
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+               return -EOPNOTSUPP;
+
+       if (dev->flags & IFF_UP) {
+               unsigned long flags;
+
+               /* Halt TX and RX, and process the frames which
+                * have already been received */
+               spin_lock_irqsave(&priv->lock, flags);
+               gfar_halt(dev);
+               gfar_clean_rx_ring(dev, priv->rx_ring_size);
+               spin_unlock_irqrestore(&priv->lock, flags);
+
+               /* Now we take down the rings to rebuild them */
                stop_gfar(dev);
        }
 
-       priv->rx_ring_size = rvals->rx_pending;
-       priv->tx_ring_size = rvals->tx_pending;
+       priv->rx_csum_enable = data;
 
        if (dev->flags & IFF_UP)
                err = startup_gfar(dev);
@@ -463,6 +479,61 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
        return err;
 }
 
+static uint32_t gfar_get_rx_csum(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+               return 0;
+
+       return priv->rx_csum_enable;
+}
+
+static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
+{
+       unsigned long flags;
+       struct gfar_private *priv = netdev_priv(dev);
+
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+               return -EOPNOTSUPP;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       gfar_halt(dev);
+
+       if (data)
+               dev->features |= NETIF_F_IP_CSUM;
+       else
+               dev->features &= ~NETIF_F_IP_CSUM;
+
+       gfar_start(dev);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static uint32_t gfar_get_tx_csum(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+               return 0;
+
+       return (dev->features & NETIF_F_IP_CSUM) != 0;
+}
+
+static uint32_t gfar_get_msglevel(struct net_device *dev)
+{       
+       struct gfar_private *priv = netdev_priv(dev);
+       return priv->msg_enable;
+}       
+        
+static void gfar_set_msglevel(struct net_device *dev, uint32_t data)
+{       
+       struct gfar_private *priv = netdev_priv(dev);
+       priv->msg_enable = data;
+}
+
+
 struct ethtool_ops gfar_ethtool_ops = {
        .get_settings = gfar_gsettings,
        .get_drvinfo = gfar_gdrvinfo,
@@ -476,52 +547,10 @@ struct ethtool_ops gfar_ethtool_ops = {
        .get_strings = gfar_gstrings,
        .get_stats_count = gfar_stats_count,
        .get_ethtool_stats = gfar_fill_stats,
-};
-
-struct ethtool_ops gfar_normon_nocoalesce_ethtool_ops = {
-       .get_settings = gfar_gsettings,
-       .get_drvinfo = gfar_gdrvinfo,
-       .get_regs_len = gfar_reglen,
-       .get_regs = gfar_get_regs,
-       .get_link = ethtool_op_get_link,
-       .get_ringparam = gfar_gringparam,
-       .set_ringparam = gfar_sringparam,
-       .get_strings = gfar_gstrings_normon,
-       .get_stats_count = gfar_stats_count_normon,
-       .get_ethtool_stats = gfar_fill_stats_normon,
-};
-
-struct ethtool_ops gfar_nocoalesce_ethtool_ops = {
-       .get_settings = gfar_gsettings,
-       .get_drvinfo = gfar_gdrvinfo,
-       .get_regs_len = gfar_reglen,
-       .get_regs = gfar_get_regs,
-       .get_link = ethtool_op_get_link,
-       .get_ringparam = gfar_gringparam,
-       .set_ringparam = gfar_sringparam,
-       .get_strings = gfar_gstrings,
-       .get_stats_count = gfar_stats_count,
-       .get_ethtool_stats = gfar_fill_stats,
-};
-
-struct ethtool_ops gfar_normon_ethtool_ops = {
-       .get_settings = gfar_gsettings,
-       .get_drvinfo = gfar_gdrvinfo,
-       .get_regs_len = gfar_reglen,
-       .get_regs = gfar_get_regs,
-       .get_link = ethtool_op_get_link,
-       .get_coalesce = gfar_gcoalesce,
-       .set_coalesce = gfar_scoalesce,
-       .get_ringparam = gfar_gringparam,
-       .set_ringparam = gfar_sringparam,
-       .get_strings = gfar_gstrings_normon,
-       .get_stats_count = gfar_stats_count_normon,
-       .get_ethtool_stats = gfar_fill_stats_normon,
-};
-
-struct ethtool_ops *gfar_op_array[] = {
-       &gfar_ethtool_ops,
-       &gfar_normon_ethtool_ops,
-       &gfar_nocoalesce_ethtool_ops,
-       &gfar_normon_nocoalesce_ethtool_ops
+       .get_rx_csum = gfar_get_rx_csum,
+       .get_tx_csum = gfar_get_tx_csum,
+       .set_rx_csum = gfar_set_rx_csum,
+       .set_tx_csum = gfar_set_tx_csum,
+       .get_msglevel = gfar_get_msglevel,
+       .set_msglevel = gfar_set_msglevel,
 };
index 02b16abc89bdf6225c421e83f7c376822e563560..7c965f268a824a8df57e302d7c7272789ce1691a 100644 (file)
@@ -572,7 +572,7 @@ static struct phy_info phy_info_dm9161 = {
 static struct phy_info phy_info_marvell = {
        .phy_id         = 0x01410c00,
        .phy_id_mask    = 0xffffff00,
-       .name           = "Marvell 88E1101",
+       .name           = "Marvell 88E1101/88E1111",
        .features       = MII_GBIT_FEATURES,
        .config_aneg    = &marvell_config_aneg,
        .read_status    = &marvell_read_status,
index 3d96714ed3cf8dbddbd4a8fc1a920604d18c98df..d9df1d9a5739c471c82ec43186c8312c90f6b63f 100644 (file)
@@ -1149,7 +1149,7 @@ static void hamachi_tx_timeout(struct net_device *dev)
                skb->dev = dev;         /* Mark as being used by this device. */
                skb_reserve(skb, 2); /* 16 byte align the IP header. */
                 hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, 
-                       skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+                       skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
                hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | 
                        DescEndPacket | DescIntr | (hmp->rx_buf_sz - 2));
        }
@@ -1210,7 +1210,7 @@ static void hamachi_init_ring(struct net_device *dev)
                skb->dev = dev;         /* Mark as being used by this device. */
                skb_reserve(skb, 2); /* 16 byte align the IP header. */
                 hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, 
-                       skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+                       skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
                /* -2 because it doesn't REALLY have that first 2 bytes -KDU */
                hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | 
                        DescEndPacket | DescIntr | (hmp->rx_buf_sz -2));
@@ -1509,7 +1509,7 @@ static int hamachi_rx(struct net_device *dev)
                                            desc->addr,
                                            hmp->rx_buf_sz,
                                            PCI_DMA_FROMDEVICE);
-               buf_addr = (u8 *) hmp->rx_skbuff[entry]->tail;
+               buf_addr = (u8 *) hmp->rx_skbuff[entry]->data;
                frame_status = le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12])));
                if (hamachi_debug > 4)
                        printk(KERN_DEBUG "  hamachi_rx() status was %8.8x.\n",
@@ -1678,7 +1678,7 @@ static int hamachi_rx(struct net_device *dev)
                        skb->dev = dev;         /* Mark as being used by this device. */
                        skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
                        desc->addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, 
-                               skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+                               skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
                }
                desc->status_n_length = cpu_to_le32(hmp->rx_buf_sz);
                if (entry >= RX_RING_SIZE-1)
@@ -1772,9 +1772,9 @@ static int hamachi_close(struct net_device *dev)
                                   readl(ioaddr + RxCurPtr) == (long)&hmp->rx_ring[i] ? '>' : ' ',
                                   i, hmp->rx_ring[i].status_n_length, hmp->rx_ring[i].addr);
                        if (hamachi_debug > 6) {
-                               if (*(u8*)hmp->rx_skbuff[i]->tail != 0x69) {
+                               if (*(u8*)hmp->rx_skbuff[i]->data != 0x69) {
                                        u16 *addr = (u16 *)
-                                               hmp->rx_skbuff[i]->tail;
+                                               hmp->rx_skbuff[i]->data;
                                        int j;
 
                                        for (j = 0; j < 0x50; j++)
index 4834314b676dca0dd87f426ea0443f691eef96d4..0abf5dd08b4c5030e4c1b26021eb7f969fef20d2 100644 (file)
@@ -159,12 +159,7 @@ struct net_device * __init hp_plus_probe(int unit)
        err = do_hpp_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -271,6 +266,9 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr)
        /* Leave the 8390 and HP chip reset. */
        outw(inw(ioaddr + HPP_OPTION) & ~EnableIRQ, ioaddr + HPP_OPTION);
 
+       retval = register_netdev(dev);
+       if (retval)
+               goto out;
        return 0;
 out:
        release_region(ioaddr, HP_IO_EXTENT);
@@ -463,11 +461,8 @@ init_module(void)
                dev->irq = irq[this_dev];
                dev->base_addr = io[this_dev];
                if (do_hpp_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_hpp[found++] = dev;
-                               continue;
-                       }
-                       cleanup_card(dev);
+                       dev_hpp[found++] = dev;
+                       continue;
                }
                free_netdev(dev);
                printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]);
index 026888611d6fef7b364fe356e1fdc2c8cbea98ea..59cf841b14abc06ad2fa11f44ca55ac0dfa6f157 100644 (file)
@@ -123,12 +123,7 @@ struct net_device * __init hp_probe(int unit)
        err = do_hp_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -227,7 +222,12 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr)
        ei_status.block_output = &hp_block_output;
        hp_init_card(dev);
 
+       retval = register_netdev(dev);
+       if (retval)
+               goto out1;
        return 0;
+out1:
+       free_irq(dev->irq, dev);
 out:
        release_region(ioaddr, HP_IO_EXTENT);
        return retval;
@@ -432,11 +432,8 @@ init_module(void)
                dev->irq = irq[this_dev];
                dev->base_addr = io[this_dev];
                if (do_hp_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_hp[found++] = dev;
-                               continue;
-                       }
-                       cleanup_card(dev);
+                       dev_hp[found++] = dev;
+                       continue;
                }
                free_netdev(dev);
                printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]);
index b3a898c5a585b73ec55a5278e3ed21d892e19f4a..cf0ac6fda1a1741390486e2168271cf3fc4ba554 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/eisa.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/spinlock.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -417,12 +418,7 @@ struct net_device * __init hp100_probe(int unit)
        if (err)
                goto out;
 
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
- out1:
-       release_region(dev->base_addr, HP100_REGION_SIZE);
  out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -562,7 +558,7 @@ static int __devinit hp100_probe1(struct net_device *dev, int ioaddr,
                         * Also, we can have EISA Busmaster cards (not tested),
                         * so beware !!! - Jean II */
                        if((bus == HP100_BUS_PCI) &&
-                          (pci_set_dma_mask(pci_dev, 0xffffffff))) {
+                          (pci_set_dma_mask(pci_dev, DMA_32BIT_MASK))) {
                                /* Gracefully fallback to shared memory */
                                goto busmasterfail;
                        }
@@ -776,11 +772,22 @@ static int __devinit hp100_probe1(struct net_device *dev, int ioaddr,
                printk("Warning! Link down.\n");
        }
 
+       err = register_netdev(dev);
+       if (err)
+               goto out3;
+
        return 0;
+out3:
+       if (local_mode == 1)
+               pci_free_consistent(lp->pci_dev, MAX_RINGSIZE + 0x0f, 
+                                   lp->page_vaddr_algn, 
+                                   virt_to_whatever(dev, lp->page_vaddr_algn));
+       if (mem_ptr_virt)
+               iounmap(mem_ptr_virt);
 out2:
        release_region(ioaddr, HP100_REGION_SIZE);
 out1:
-       return -ENODEV;
+       return err;
 }
 
 /* This procedure puts the card into a stable init state */
@@ -2875,18 +2882,12 @@ static int __init hp100_eisa_probe (struct device *gendev)
        if (err)
                goto out1;
 
-       err = register_netdev(dev);
-       if (err)
-               goto out2;
-       
 #ifdef HP100_DEBUG
        printk("hp100: %s: EISA adapter found at 0x%x\n", dev->name, 
               dev->base_addr);
 #endif
        gendev->driver_data = dev;
        return 0;
- out2:
-       release_region(dev->base_addr, HP100_REGION_SIZE);
  out1:
        free_netdev(dev);
        return err;
@@ -2951,17 +2952,12 @@ static int __devinit hp100_pci_probe (struct pci_dev *pdev,
        err = hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pdev);
        if (err) 
                goto out1;
-       err = register_netdev(dev);
-       if (err)
-               goto out2;
        
 #ifdef HP100_DEBUG
        printk("hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr);
 #endif
        pci_set_drvdata(pdev, dev);
        return 0;
- out2:
-       release_region(dev->base_addr, HP100_REGION_SIZE);
  out1:
        free_netdev(dev);
  out0:
@@ -3032,15 +3028,9 @@ static int __init hp100_isa_init(void)
                SET_MODULE_OWNER(dev);
 
                err = hp100_isa_probe(dev, hp100_port[i]);
-               if (!err) {
-                       err = register_netdev(dev);
-                       if (!err) 
-                               hp100_devlist[cards++] = dev;
-                       else
-                               release_region(dev->base_addr, HP100_REGION_SIZE);
-               }
-
-               if (err)
+               if (!err)
+                       hp100_devlist[cards++] = dev;
+               else
                        free_netdev(dev);
        }
 
index 18cea1099530a1131552879fa42fb304e6264e48..c65054364bca45cb49630df0b13682b90c1b0e6e 100644 (file)
@@ -135,8 +135,7 @@ static int irda_thread(void *startup)
                remove_wait_queue(&irda_rq_queue.kick, &wait);
 
                /* make swsusp happy with our thread */
-               if (current->flags & PF_FREEZE)
-                       refrigerator(PF_FREEZE);
+               try_to_freeze();
 
                run_irda_queue();
        }
index 66f488c13717415b151c1bb1ad5442c09e4486e5..15f207323d97043b124dd6282835447804abf5aa 100644 (file)
@@ -763,7 +763,7 @@ static int stir_transmit_thread(void *arg)
        {
 #ifdef CONFIG_PM
                /* if suspending, then power off and wait */
-               if (unlikely(current->flags & PF_FREEZE)) {
+               if (unlikely(freezing(current))) {
                        if (stir->receiving)
                                receive_stop(stir);
                        else
@@ -771,7 +771,7 @@ static int stir_transmit_thread(void *arg)
 
                        write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD);
 
-                       refrigerator(PF_FREEZE);
+                       refrigerator();
 
                        if (change_speed(stir, stir->speed))
                                break;
index 50bebb55e9ee4c2293fe10423d8639fe3f65b6a6..88ae8a04fabc0532cd8e883eb9b6781b117f9839 100644 (file)
@@ -176,12 +176,7 @@ struct net_device * __init netcard_probe(int unit)
        err = do_netcard_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -316,7 +311,15 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr)
 
         dev->tx_timeout                = &net_tx_timeout;
         dev->watchdog_timeo    = MY_TX_TIMEOUT; 
+
+       err = register_netdev(dev);
+       if (err)
+               goto out2;
        return 0;
+out2:
+#ifdef jumpered_dma
+       free_dma(dev->dma);
+#endif
 out1:
 #ifdef jumpered_interrupts
        free_irq(dev->irq, dev);
@@ -691,11 +694,8 @@ int init_module(void)
        dev->dma       = dma;
        dev->mem_start = mem;
        if (do_netcard_probe(dev) == 0) {
-               if (register_netdev(dev) == 0)
-                       this_device = dev;
-                       return 0;
-               }
-               cleanup_card(dev);
+               this_device = dev;
+               return 0;
        }
        free_netdev(dev);
        return -ENXIO;
index 35f6a7c271a2be3a1f749716cbe27b1bffc66b98..097b90ccf575b2d17e8f6f67458bcd6003dba96c 100644 (file)
@@ -47,7 +47,9 @@ char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver";
 #else
 #define DRIVERNAPI "-NAPI"
 #endif
-char ixgb_driver_version[] = "1.0.95-k2"DRIVERNAPI;
+
+#define DRV_VERSION "1.0.95-k2"DRIVERNAPI
+char ixgb_driver_version[] = DRV_VERSION;
 char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
 
 /* ixgb_pci_tbl - PCI Device ID Table
@@ -140,6 +142,7 @@ static struct pci_driver ixgb_driver = {
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
 MODULE_DESCRIPTION("Intel(R) PRO/10GbE Network Driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
 
 /* some defines for controlling descriptor fetches in h/w */
 #define RXDCTL_PTHRESH_DEFAULT 128     /* chip considers prefech below this */
index dec557fb6a99fe47bfe5124c8d70e0e5f39453e4..b4929beb33b2359d29a37fc16e4535590c1098e9 100644 (file)
@@ -356,11 +356,8 @@ int init_module(void)
                dev->base_addr = io[this_dev];
                dev->dma = dma[this_dev];
                if (do_lance_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_lance[found++] = dev;
-                               continue;
-                       }
-                       cleanup_card(dev);
+                       dev_lance[found++] = dev;
+                       continue;
                }
                free_netdev(dev);
                break;
@@ -448,12 +445,7 @@ struct net_device * __init lance_probe(int unit)
        err = do_lance_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -724,6 +716,9 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
        dev->tx_timeout = lance_tx_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
 
+       err = register_netdev(dev);
+       if (err)
+               goto out_dma;
        return 0;
 out_dma:
        if (dev->dma != 4)
@@ -867,7 +862,7 @@ lance_init_ring(struct net_device *dev, int gfp)
                lp->rx_skbuff[i] = skb;
                if (skb) {
                        skb->dev = dev;
-                       rx_buff = skb->tail;
+                       rx_buff = skb->data;
                } else
                        rx_buff = kmalloc(PKT_BUF_SZ, GFP_DMA | gfp);
                if (rx_buff == NULL)
index 5e263fcba6696046b8dad88a4d61064ebb7ca8de..41bad07ac1acc94be2b4db36b13e27d0faceaf5c 100644 (file)
@@ -553,14 +553,14 @@ static inline void init_rx_bufs(struct net_device *dev)
                if (skb == NULL)
                        panic("%s: alloc_skb() failed", __FILE__);
                skb_reserve(skb, 2);
-               dma_addr = dma_map_single(lp->dev, skb->tail,PKT_BUF_SZ,
+               dma_addr = dma_map_single(lp->dev, skb->data,PKT_BUF_SZ,
                                          DMA_FROM_DEVICE);
                skb->dev = dev;
                rbd->v_next = rbd+1;
                rbd->b_next = WSWAPrbd(virt_to_dma(lp,rbd+1));
                rbd->b_addr = WSWAPrbd(virt_to_dma(lp,rbd));
                rbd->skb = skb;
-               rbd->v_data = skb->tail;
+               rbd->v_data = skb->data;
                rbd->b_data = WSWAPchar(dma_addr);
                rbd->size = PKT_BUF_SZ;
        }
@@ -783,8 +783,8 @@ static inline int i596_rx(struct net_device *dev)
                                rx_in_place = 1;
                                rbd->skb = newskb;
                                newskb->dev = dev;
-                               dma_addr = dma_map_single(lp->dev, newskb->tail, PKT_BUF_SZ, DMA_FROM_DEVICE);
-                               rbd->v_data = newskb->tail;
+                               dma_addr = dma_map_single(lp->dev, newskb->data, PKT_BUF_SZ, DMA_FROM_DEVICE);
+                               rbd->v_data = newskb->data;
                                rbd->b_data = WSWAPchar(dma_addr);
                                CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd));
                        }
index 179a97c0af69de8f3f692fee055423becebba788..27f0d8ac4c40d99a869e2cd297007dbeeb487d0e 100644 (file)
@@ -167,12 +167,7 @@ struct net_device * __init lne390_probe(int unit)
        err = do_lne390_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -296,7 +291,14 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr)
        dev->poll_controller = ei_poll;
 #endif
        NS8390_init(dev, 0);
+
+       ret = register_netdev(dev);
+       if (ret)
+               goto unmap;
        return 0;
+unmap:
+       if (ei_status.reg0)
+               iounmap((void *)dev->mem_start);
 cleanup:
        free_irq(dev->irq, dev);
        return ret;
@@ -426,11 +428,8 @@ int init_module(void)
                dev->base_addr = io[this_dev];
                dev->mem_start = mem[this_dev];
                if (do_lne390_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_lne[found++] = dev;
-                               continue;
-                       }
-                       cleanup_card(dev);
+                       dev_lne[found++] = dev;
+                       continue;
                }
                free_netdev(dev);
                printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]);
index 851eba8a3e00e2d1f02f5ca3092d50318c28e9fe..e9c6e569d1f475074f265a64912ffc9450ff53c3 100644 (file)
@@ -4775,1288 +4775,7 @@ static unsigned char lanai4_code[76256] __initdata = {
 /* This is the LANai data */ 
 
 static unsigned int lanai4_data_off = 0x94F0; /* half-word offset */
-static unsigned char lanai4_data[20472] __initdata = {
-0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x01, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
-0x00,0x00, 0x00,0x00, 0x00,0x00, } ;
+static unsigned char lanai4_data[20472] __initdata;
 
 
 #ifdef SYMBOL_DEFINES_COMPILED
index babb59e146ea62524fc00c50ee1d284502e69c56..9d6d2548c2d36a4a04f9dfb9e31dbccb2e7729e4 100644 (file)
@@ -1926,7 +1926,7 @@ static void refill_rx(struct net_device *dev)
                                break; /* Better luck next round. */
                        skb->dev = dev; /* Mark as being used by this device. */
                        np->rx_dma[entry] = pci_map_single(np->pci_dev,
-                               skb->tail, buflen, PCI_DMA_FROMDEVICE);
+                               skb->data, buflen, PCI_DMA_FROMDEVICE);
                        np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]);
                }
                np->rx_ring[entry].cmd_status = cpu_to_le32(np->rx_buf_sz);
@@ -2280,7 +2280,7 @@ static void netdev_rx(struct net_device *dev)
                                        buflen,
                                        PCI_DMA_FROMDEVICE);
                                eth_copy_and_sum(skb,
-                                       np->rx_skbuff[entry]->tail, pkt_len, 0);
+                                       np->rx_skbuff[entry]->data, pkt_len, 0);
                                skb_put(skb, pkt_len);
                                pci_dma_sync_single_for_device(np->pci_dev,
                                        np->rx_dma[entry],
index 84e291e249357db7cc2f4a7b756bbb900a600f13..8f40368cf2e9ba0b9d9b642b27044630e2e2983b 100644 (file)
@@ -180,12 +180,7 @@ struct net_device * __init ne_probe(int unit)
        err = do_ne_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -325,8 +320,13 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
        dev->poll_controller = ei_poll;
 #endif
        NS8390_init(dev, 0);
-       return 0;
 
+       ret = register_netdev(dev);
+       if (ret)
+               goto out_irq;
+       return 0;
+out_irq:
+       free_irq(dev->irq, dev);
 err_out:
        release_region(ioaddr, NE_IO_EXTENT);
        return ret;
@@ -633,11 +633,8 @@ int init_module(void)
                err = init_reg_offset(dev, dev->base_addr);
                if (!err) {
                        if (do_ne_probe(dev) == 0) {
-                               if (register_netdev(dev) == 0) {
-                                       dev_ne[found++] = dev;
-                                       continue;
-                               }
-                               cleanup_card(dev);
+                               dev_ne[found++] = dev;
+                               continue;
                        }
                }
                free_netdev(dev);
index 496433902adee0740c94f251d7519ea26f8fddb0..6c57096aa2e1a82db4127e71662e5e30ce49aade 100644 (file)
@@ -229,12 +229,7 @@ struct net_device * __init ne_probe(int unit)
        err = do_ne_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -534,8 +529,14 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
        dev->poll_controller = ei_poll;
 #endif
        NS8390_init(dev, 0);
+
+       ret = register_netdev(dev);
+       if (ret)
+               goto out_irq;
        return 0;
 
+out_irq:
+       free_irq(dev->irq, dev);
 err_out:
        release_region(ioaddr, NE_IO_EXTENT);
        return ret;
@@ -826,11 +827,8 @@ int init_module(void)
                dev->mem_end = bad[this_dev];
                dev->base_addr = io[this_dev];
                if (do_ne_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_ne[found++] = dev;
-                               continue;
-                       }
-                       cleanup_card(dev);
+                       dev_ne[found++] = dev;
+                       continue;
                }
                free_netdev(dev);
                if (found)
index 6ebef27dbfaea890ec85a9fb54c3d09ae81ec224..6d62ada85de61c03eb90f7399dee5657df1a9578 100644 (file)
@@ -301,12 +301,7 @@ struct net_device * __init ne2_probe(int unit)
        err = do_ne2_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -517,7 +512,14 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
        dev->poll_controller = ei_poll;
 #endif
        NS8390_init(dev, 0);
+
+       retval = register_netdev(dev);
+       if (retval)
+               goto out1;
        return 0;
+out1:
+       mca_set_adapter_procfn( ei_status.priv, NULL, NULL);
+       free_irq(dev->irq, dev);
 out:
        release_region(base_addr, NE_IO_EXTENT);
        return retval;
@@ -798,11 +800,8 @@ int init_module(void)
                dev->mem_end = bad[this_dev];
                dev->base_addr = io[this_dev];
                if (do_ne2_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_ne[found++] = dev;
-                               continue;
-                       }
-                       cleanup_card(dev);
+                       dev_ne[found++] = dev;
+                       continue;
                }
                free_netdev(dev);
                break;
index c336b46bd332676155f01fee160a63b590b30e9b..e64df4d0800b2a1802f5e350871f62f5ad58d85f 100644 (file)
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
@@ -573,7 +574,7 @@ static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb)
 
        dev->rx_info.next_empty = (next_empty + 1) % NR_RX_DESC;
        cmdsts = REAL_RX_BUF_SIZE | CMDSTS_INTR;
-       buf = pci_map_single(dev->pci_dev, skb->tail,
+       buf = pci_map_single(dev->pci_dev, skb->data,
                             REAL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
        build_rx_desc(dev, sg, 0, buf, cmdsts, 0);
        /* update link of previous rx */
@@ -603,7 +604,7 @@ static inline int rx_refill(struct net_device *ndev, int gfp)
                if (unlikely(!skb))
                        break;
 
-               res = (long)skb->tail & 0xf;
+               res = (long)skb->data & 0xf;
                res = 0x10 - res;
                res &= 0xf;
                skb_reserve(skb, res);
index c6e8b25f968529837ec3987baac52e7f55d73dea..f0fc04bd37c4f6404d8458fb16c07c7b7fd293fd 100644 (file)
@@ -1286,6 +1286,13 @@ static int el3_close(struct net_device *dev)
        return 0;
 }
 
+static struct pcmcia_device_id tc574_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "3CCFEM556.cis"),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, tc574_ids);
+
 static struct pcmcia_driver tc574_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -1293,6 +1300,7 @@ static struct pcmcia_driver tc574_driver = {
        },
        .attach         = tc574_attach,
        .detach         = tc574_detach,
+       .id_table       = tc574_ids,
 };
 
 static int __init init_tc574(void)
index 89abdda1d3434f864ab813bb6035922657828783..8fa1b5f0fb68a5f82e3d235e819d8c44852dbbbf 100644 (file)
@@ -1057,6 +1057,17 @@ static int el3_close(struct net_device *dev)
     return 0;
 }
 
+static struct pcmcia_device_id tc589_ids[] = {
+       PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562),
+       PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77),
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589),
+       PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "3CXEM556.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "3CXEM556.cis"),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, tc589_ids);
+
 static struct pcmcia_driver tc589_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -1064,6 +1075,7 @@ static struct pcmcia_driver tc589_driver = {
        },
        .attach         = tc589_attach,
        .detach         = tc589_detach,
+        .id_table       = tc589_ids,
 };
 
 static int __init init_tc589(void)
index 853b586e481a1c0070e62f8ce3ed5e0d680b42cf..23ce77b1d5b013bda9fb9770e4b2f9847714fc8a 100644 (file)
@@ -850,6 +850,34 @@ static void block_output(struct net_device *dev, int count,
     outsw(nic_base + AXNET_DATAPORT, buf, count>>1);
 }
 
+static struct pcmcia_device_id axnet_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081),
+       PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0301),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0303),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309),
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106),
+       PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab),
+       PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef),
+       PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef),
+       PCMCIA_DEVICE_PROD_ID12("Billionton", "LNA-100B", 0x552ab682, 0xbc3b87e1),
+       PCMCIA_DEVICE_PROD_ID12("CHEETAH ETHERCARD", "EN2228", 0x00fa7bc8, 0x00e990cc),
+       PCMCIA_DEVICE_PROD_ID12("CNet", "CNF301", 0xbc477dde, 0x78c5f40b),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXD", 0x5261440f, 0x436768c5),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEtherII PCC-TXD", 0x5261440f, 0x730df72e),
+       PCMCIA_DEVICE_PROD_ID12("Dynalink", "L100C16", 0x55632fd5, 0x66bc2a90),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V3)", 0x0733cc81, 0x232019a8),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC3-TX", 0x481e0094, 0xf91af609),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "100BASE", 0x281f1c5d, 0x7c2add04),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEtherCard", 0x281f1c5d, 0x7ef26116),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FEP501", 0x281f1c5d, 0x2e272058),
+       PCMCIA_DEVICE_PROD_ID14("Network Everywhere", "AX88190", 0x820a67b6,  0xab9be5ef),
+       /* this is not specific enough */
+       /* PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, axnet_ids);
+
 static struct pcmcia_driver axnet_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -857,6 +885,7 @@ static struct pcmcia_driver axnet_cs_driver = {
        },
        .attach         = axnet_attach,
        .detach         = axnet_detach,
+       .id_table       = axnet_ids,
 };
 
 static int __init init_axnet_cs(void)
index 4294e1e3f156caf53e0ddf449445ef2092b3ad42..68d58cc58d31d8ee9f9d2aaafe6a2e02a76aeebb 100644 (file)
@@ -483,7 +483,11 @@ static int com20020_event(event_t event, int priority,
     return 0;
 } /* com20020_event */
 
-
+static struct pcmcia_device_id com20020_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
 
 static struct pcmcia_driver com20020_cs_driver = {
        .owner          = THIS_MODULE,
@@ -492,6 +496,7 @@ static struct pcmcia_driver com20020_cs_driver = {
        },
        .attach         = com20020_attach,
        .detach         = com20020_detach,
+       .id_table       = com20020_ids,
 };
 
 static int __init init_com20020_cs(void)
index 0424865e8094e3601a44c8330d775112decd89ea..917adbbf0b5b88e80f39df9242ca450727b4c0f8 100644 (file)
@@ -435,7 +435,9 @@ static void fmvj18x_config(dev_link_t *link)
                pcmcia_get_status(handle, &status);
                if (status.CardState & CS_EVENT_3VCARD)
                    link->conf.Vcc = 33; /* inserted in 3.3V slot */
-           } else if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410) {
+           } else if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410
+                       || le16_to_cpu(buf[1]) == PRODID_TDK_NP9610
+                       || le16_to_cpu(buf[1]) == PRODID_TDK_MN3200) {
                /* MultiFunction Card */
                link->conf.ConfigBase = 0x800;
                link->conf.ConfigIndex = 0x47;
@@ -764,6 +766,31 @@ static int fmvj18x_event(event_t event, int priority,
     return 0;
 } /* fmvj18x_event */
 
+static struct pcmcia_device_id fmvj18x_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004),
+       PCMCIA_DEVICE_PROD_ID12("EAGLE Technology", "NE200 ETHERNET LAN MBH10302 04", 0x528c88c4, 0x74f91e59),
+       PCMCIA_DEVICE_PROD_ID12("Eiger Labs,Inc", "EPX-10BT PC Card Ethernet 10BT", 0x53af556e, 0x877f9922),
+       PCMCIA_DEVICE_PROD_ID12("Eiger labs,Inc.", "EPX-10BT PC Card Ethernet 10BT", 0xf47e6c66, 0x877f9922),
+       PCMCIA_DEVICE_PROD_ID12("FUJITSU", "LAN Card(FMV-J182)", 0x6ee5a3d8, 0x5baf31db),
+       PCMCIA_DEVICE_PROD_ID12("FUJITSU", "MBH10308", 0x6ee5a3d8, 0x3f04875e),
+       PCMCIA_DEVICE_PROD_ID12("FUJITSU TOWA", "LA501", 0xb8451188, 0x12939ba2),
+       PCMCIA_DEVICE_PROD_ID12("HITACHI", "HT-4840-11", 0xf4f43949, 0x773910f4),
+       PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310B Ver1.0       ", 0x8cef4d3a, 0x075fc7b6),
+       PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310 Ver1.0        ", 0x8cef4d3a, 0xbccf43e6),
+       PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "10BASE_T CARD R280", 0x85c10e17, 0xd9413666),
+       PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CD02x", 0x1eae9475, 0x8fa0ee70),
+       PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CF010", 0x1eae9475, 0x7683bc9a),
+       PCMCIA_DEVICE_PROD_ID1("CONTEC Co.,Ltd.", 0x58d8fee2),
+       PCMCIA_DEVICE_PROD_ID1("PCMCIA LAN MBH10304  ES", 0x2599f454),
+       PCMCIA_DEVICE_PROD_ID1("PCMCIA MBH10302", 0x8f4005da),
+       PCMCIA_DEVICE_PROD_ID1("UBKK,V2.0", 0x90888080),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0d0a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0e0a),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, fmvj18x_ids);
+
 static struct pcmcia_driver fmvj18x_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -771,6 +798,7 @@ static struct pcmcia_driver fmvj18x_cs_driver = {
        },
        .attach         = fmvj18x_attach,
        .detach         = fmvj18x_detach,
+       .id_table       = fmvj18x_ids,
 };
 
 static int __init init_fmvj18x_cs(void)
index 3107ccfe8f3d78b2023cf65010b955cc491801fb..cf6d073ea558df00b4149aa8a9ab3b09a7a77284 100644 (file)
@@ -119,9 +119,6 @@ static void ibmtr_detach(dev_link_t *);
 
 static dev_link_t *dev_list;
 
-extern int ibmtr_probe_card(struct net_device *dev);
-extern irqreturn_t tok_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-
 /*====================================================================*/
 
 typedef struct ibmtr_dev_t {
@@ -511,6 +508,13 @@ static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
     return;
 }
 
+static struct pcmcia_device_id ibmtr_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
+       PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
+
 static struct pcmcia_driver ibmtr_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -518,6 +522,7 @@ static struct pcmcia_driver ibmtr_cs_driver = {
        },
        .attach         = ibmtr_attach,
        .detach         = ibmtr_detach,
+       .id_table       = ibmtr_ids,
 };
 
 static int __init init_ibmtr_cs(void)
index 4603807fcafbd29d087e080d9db723ca4b7eb500..b86e7253fbfce721361b2058287e934429ce4e6c 100644 (file)
@@ -1675,6 +1675,13 @@ static void set_multicast_list(struct net_device *dev)
 
 } /* set_multicast_list */
 
+static struct pcmcia_device_id nmclan_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Ethernet", 0x085a850b, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID12("Portable Add-ons", "Ethernet", 0x0ebf1d60, 0x00b2e941),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, nmclan_ids);
+
 static struct pcmcia_driver nmclan_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -1682,6 +1689,7 @@ static struct pcmcia_driver nmclan_cs_driver = {
        },
        .attach         = nmclan_attach,
        .detach         = nmclan_detach,
+       .id_table       = nmclan_ids,
 };
 
 static int __init init_nmclan_cs(void)
index 181b6ed550036852196bb0d67ae6ef753be5c78b..855a45d062b19ea77260f1822e5d55984bdaff9b 100644 (file)
@@ -1155,11 +1155,13 @@ static int set_config(struct net_device *dev, struct ifmap *map)
 static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs)
 {
     struct net_device *dev = dev_id;
-    pcnet_dev_t *info = PRIV(dev);
+    pcnet_dev_t *info;
     irqreturn_t ret = ei_interrupt(irq, dev_id, regs);
 
-    if (ret == IRQ_HANDLED)
+    if (ret == IRQ_HANDLED) {
+           info = PRIV(dev);
            info->stale = 0;
+    }
     return ret;
 }
 
@@ -1350,7 +1352,7 @@ static void dma_block_input(struct net_device *dev, int count,
     if (count & 0x01)
        buf[count-1] = inb(nic_base + PCNET_DATAPORT), xfer_count++;
 
-    /* This was for the ALPHA version only, but enough people have
+    /* This was for the ALPHA version only, but enough people have been
        encountering problems that it is still here. */
 #ifdef PCMCIA_DEBUG
     if (ei_debug > 4) {                /* DMA termination address check... */
@@ -1424,7 +1426,7 @@ static void dma_block_output(struct net_device *dev, int count,
     dma_start = jiffies;
 
 #ifdef PCMCIA_DEBUG
-    /* This was for the ALPHA version only, but enough people have
+    /* This was for the ALPHA version only, but enough people have been
        encountering problems that it is still here. */
     if (ei_debug > 4) {        /* DMA termination address check... */
        int addr, tries = 20;
@@ -1635,6 +1637,208 @@ failed:
 
 /*====================================================================*/
 
+static struct pcmcia_device_id pcnet_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0057, 0x0021),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0104, 0x000a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0xea15),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0143, 0x3341),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0143, 0xc0ab),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x021b, 0x0101),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x08a1, 0xc0ab),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "AnyCom", "Fast Ethernet ", 0x578ba6e7, 0x02d92d1e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "Home and Away 28.8 PC Card       ", 0xb569a6e5, 0x5bd4ff2c),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
+       PCMCIA_MFC_DEVICE_PROD_ID123(0, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
+       PCMCIA_MFC_DEVICE_PROD_ID2(0, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
+       PCMCIA_DEVICE_MANF_CARD(0x0057, 0x1004),
+       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x000d),
+       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0075),
+       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0145),
+       PCMCIA_DEVICE_MANF_CARD(0x0149, 0x0230),
+       PCMCIA_DEVICE_MANF_CARD(0x0149, 0x4530),
+/*     PCMCIA_DEVICE_MANF_CARD(0x0149, 0xc1ab), conflict with axnet_cs */
+       PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0110),
+       PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328),
+       PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x8041),
+       PCMCIA_DEVICE_MANF_CARD(0x0213, 0x2452),
+/*     PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), conflict with axnet_cs */
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0300),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0307),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030a),
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1103),
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1121),
+       PCMCIA_DEVICE_PROD_ID12("2408LAN", "Ethernet", 0x352fff7f, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID123("Cardwell", "PCMCIA", "ETHERNET", 0x9533672e, 0x281f1c5d, 0x3ff7175b),
+       PCMCIA_DEVICE_PROD_ID123("CNet  ", "CN30BC", "ETHERNET", 0x9fe55d3d, 0x85601198, 0x3ff7175b),
+       PCMCIA_DEVICE_PROD_ID123("Digital", "Ethernet", "Adapter", 0x9999ab35, 0x00b2e941, 0x4b0d829e),
+       PCMCIA_DEVICE_PROD_ID123("Edimax Technology Inc.", "PCMCIA", "Ethernet Card", 0x738a0019, 0x281f1c5d, 0x5e9d92c0),
+       PCMCIA_DEVICE_PROD_ID123("EFA   ", "EFA207", "ETHERNET", 0x3d294be4, 0xeb9aab6c, 0x3ff7175b),
+       PCMCIA_DEVICE_PROD_ID123("I-O DATA", "PCLA", "ETHERNET", 0x1d55d7ec, 0xe4c64d34, 0x3ff7175b),
+       PCMCIA_DEVICE_PROD_ID123("IO DATA", "PCLATE", "ETHERNET", 0x547e66dc, 0x6b260753, 0x3ff7175b),
+       PCMCIA_DEVICE_PROD_ID123("KingMax Technology Inc.", "EN10-T2", "PCMCIA Ethernet Card", 0x932b7189, 0x699e4436, 0x6f6652e0),
+       PCMCIA_DEVICE_PROD_ID123("PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2216", 0x281f1c5d, 0xd4cd2f20, 0xb87add82),
+       PCMCIA_DEVICE_PROD_ID123("PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2620", 0x281f1c5d, 0xd4cd2f20, 0x7d3d83a8),
+       PCMCIA_DEVICE_PROD_ID1("2412LAN", 0x67f236ab),
+       PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2212", 0xdfc6b5b2, 0xcb112a11),
+       PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2216-PCMCIA-ETHERNET", 0xdfc6b5b2, 0x5542bfff),
+       PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA100-PCM-T V2 100/10M LAN PC Card", 0xbb7fbdd7, 0xcd91cc68),
+       PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM", 0xbb7fbdd7, 0x5ba10d49),
+       PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA100-PCM V2", 0x36634a66, 0xc6d05997),
+       PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM_V2", 0xbb7fBdd7, 0x28e299f8),
+       PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA-PCM V3", 0x36634a66, 0x62241d96),
+       PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8010", 0x5070a7f9, 0x82f96e96),
+       PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8610", 0x5070a7f9, 0x86741224),
+       PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8002", 0x93b15570, 0x75ec3efb),
+       PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8002T", 0x93b15570, 0x461c5247),
+       PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8010", 0x93b15570, 0x82f96e96),
+       PCMCIA_DEVICE_PROD_ID12("AnyCom", "ECO Ethernet", 0x578ba6e7, 0x0a9888c1),
+       PCMCIA_DEVICE_PROD_ID12("AnyCom", "ECO Ethernet 10/100", 0x578ba6e7, 0x939fedbd),
+       PCMCIA_DEVICE_PROD_ID12("AROWANA", "PCMCIA Ethernet LAN Card", 0x313adbc8, 0x08d9f190),
+       PCMCIA_DEVICE_PROD_ID12("ASANTE", "FriendlyNet PC Card", 0x3a7ade0f, 0x41c64504),
+       PCMCIA_DEVICE_PROD_ID12("Billionton", "LNT-10TB", 0x552ab682, 0xeeb1ba6a),
+       PCMCIA_DEVICE_PROD_ID12("CF", "10Base-Ethernet", 0x44ebf863, 0x93ae4d79),
+       PCMCIA_DEVICE_PROD_ID12("CNet", "CN40BC Ethernet", 0xbc477dde, 0xfba775a7),
+       PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "BASEline PCMCIA 10 MBit Ethernetadapter", 0xfa2e424d, 0xe9190d8a),
+       PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "FASTline PCMCIA 10/100 Fast-Ethernet", 0xfa2e424d, 0x3953d9b9),
+       PCMCIA_DEVICE_PROD_ID12("CONTEC", "C-NET(PC)C-10L", 0x21cab552, 0xf6f90722),
+       PCMCIA_DEVICE_PROD_ID12("corega", "FEther PCC-TXF", 0x0a21501a, 0xa51564a2),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-T", 0x5261440f, 0xfa9d85bd),
+       PCMCIA_DEVICE_PROD_ID12("Corega K.K.", "corega EtherII PCC-TD", 0xd4fdcbd8, 0xc49bd73d),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-T", 0x5261440f, 0x6705fcaa),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FastEther PCC-TX", 0x5261440f, 0x485e85d9),
+       PCMCIA_DEVICE_PROD_ID12("Corega,K.K.", "Ethernet LAN Card", 0x110d26d9, 0x9fd2f0a2),
+       PCMCIA_DEVICE_PROD_ID12("corega,K.K.", "Ethernet LAN Card", 0x9791a90e, 0x9fd2f0a2),
+       PCMCIA_DEVICE_PROD_ID12("CouplerlessPCMCIA", "100BASE", 0xee5af0ad, 0x7c2add04),
+       PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-010", 0x77008979, 0x9d8d445d),
+       PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-110E 10/100M LAN Card", 0x77008979, 0xfd184814),
+       PCMCIA_DEVICE_PROD_ID12("DataTrek.", "NetCard ", 0x5cd66d9d, 0x84697ce0),
+       PCMCIA_DEVICE_PROD_ID12("Dayna Communications, Inc.", "CommuniCard E", 0x0c629325, 0xb4e7dbaf),
+       PCMCIA_DEVICE_PROD_ID12("Digicom", "Palladio LAN 10/100", 0x697403d8, 0xe160b995),
+       PCMCIA_DEVICE_PROD_ID12("Digicom", "Palladio LAN 10/100 Dongless", 0x697403d8, 0xa6d3b233),
+       PCMCIA_DEVICE_PROD_ID12("DIGITAL", "DEPCM-XX", 0x69616cb3, 0xe600e76e),
+       PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-650", 0x1a424a1c, 0xf28c8398),
+       PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-660", 0x1a424a1c, 0xd9a1d05b),
+       PCMCIA_DEVICE_PROD_ID12("D-Link", "DFE-650", 0x1a424a1c, 0x0f0073f9),
+       PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 PC Card", 0x725b842d, 0xf1efee84),
+       PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 Port Attached PC Card", 0x725b842d, 0x2db1f8e9),
+       PCMCIA_DEVICE_PROD_ID12("Dynalink", "L10BC", 0x55632fd5, 0xdc65f2b1),
+       PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L10BC", 0x6a26d1cf, 0xdc65f2b1),
+       PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L10C", 0x6a26d1cf, 0xc4f84efb),
+       PCMCIA_DEVICE_PROD_ID12("E-CARD", "E-CARD", 0x6701da11, 0x6701da11),
+       PCMCIA_DEVICE_PROD_ID12("EIGER Labs Inc.", "Ethernet 10BaseT card", 0x53c864c6, 0xedd059f6),
+       PCMCIA_DEVICE_PROD_ID12("EIGER Labs Inc.", "Ethernet Combo card", 0x53c864c6, 0x929c486c),
+       PCMCIA_DEVICE_PROD_ID12("Ethernet", "Adapter", 0x00b2e941, 0x4b0d829e),
+       PCMCIA_DEVICE_PROD_ID12("Ethernet Adapter", "E2000 PCMCIA Ethernet", 0x96767301, 0x71fbbc61),
+       PCMCIA_DEVICE_PROD_ID12("Ethernet PCMCIA adapter", "EP-210", 0x8dd86181, 0xf2b52517),
+       PCMCIA_DEVICE_PROD_ID12("Fast Ethernet", "Adapter", 0xb4be14e3, 0x4b0d829e),
+       PCMCIA_DEVICE_PROD_ID12("Grey Cell", "GCS2000", 0x2a151fac, 0xf00555cb),
+       PCMCIA_DEVICE_PROD_ID12("Grey Cell", "GCS2220", 0x2a151fac, 0xc1b7e327),
+       PCMCIA_DEVICE_PROD_ID12("GVC", "NIC-2000p", 0x76e171bd, 0x6eb1c947),
+       PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "Ethernet", 0xe3736c88, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID12("IC-CARD", "IC-CARD", 0x60cb09a6, 0x60cb09a6),
+       PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCETTX", 0x547e66dc, 0x6fc5459b),
+       PCMCIA_DEVICE_PROD_ID12("iPort", "10/100 Ethernet Card", 0x56c538d2, 0x11b0ffc0),
+       PCMCIA_DEVICE_PROD_ID12("KANSAI ELECTRIC CO.,LTD", "KLA-PCM/T", 0xb18dc3b4, 0xcc51a956),
+       PCMCIA_DEVICE_PROD_ID12("KCI", "PE520 PCMCIA Ethernet Adapter", 0xa89b87d3, 0x1eb88e64),
+       PCMCIA_DEVICE_PROD_ID12("KINGMAX", "EN10T2T", 0x7bcb459a, 0xa5c81fa5),
+       PCMCIA_DEVICE_PROD_ID12("Kingston", "KNE-PC2", 0x1128e633, 0xce2a89b3),
+       PCMCIA_DEVICE_PROD_ID12("Kingston Technology Corp.", "EtheRx PC Card Ethernet Adapter", 0x313c7be3, 0x0afb54a2),
+       PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-10/100CD", 0x1b7827b2, 0xcda71d1c),
+       PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDF", 0x1b7827b2, 0xfec71e40),
+       PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDL/T", 0x1b7827b2, 0x79fba4f7),
+       PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDS", 0x1b7827b2, 0x931afaab),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "Combo PCMCIA EthernetCard (EC2T)", 0x0733cc81, 0x32ee8c78),
+       PCMCIA_DEVICE_PROD_ID12("LINKSYS", "E-CARD", 0xf7cb0b07, 0x6701da11),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 Integrated PC Card (PCM100)", 0x0733cc81, 0x453c3f9d),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100)", 0x0733cc81, 0x66c5a389),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V2)", 0x0733cc81, 0x3a3b28e9),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "HomeLink Phoneline ", 0x0733cc81, 0x5e07cfa0),
+       PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TX", 0x88fcdeda, 0x6d772737),
+       PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN20T", 0x88fcdeda, 0x81090922),
+       PCMCIA_DEVICE_PROD_ID12("LONGSHINE", "PCMCIA Ethernet Card", 0xf866b0b0, 0x6f6652e0),
+       PCMCIA_DEVICE_PROD_ID12("MACNICA", "ME1-JEIDA", 0x20841b68, 0xaf8a3578),
+       PCMCIA_DEVICE_PROD_ID12("Macsense", "MPC-10", 0xd830297f, 0xd265c307),
+       PCMCIA_DEVICE_PROD_ID12("Matsushita Electric Industrial Co.,LTD.", "CF-VEL211", 0x44445376, 0x8ded41d4),
+       PCMCIA_DEVICE_PROD_ID12("MAXTECH", "PCN2000", 0x78d64bc0, 0xca0ca4b8),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC2-T", 0x481e0094, 0xa2eb0cf3),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC2-TX", 0x481e0094, 0x41a6916c),
+       PCMCIA_DEVICE_PROD_ID12("Microcom C.E.", "Travel Card LAN 10/100", 0x4b91cec7, 0xe70220d6),
+       PCMCIA_DEVICE_PROD_ID12("Microdyne", "NE4200", 0x2e6da59b, 0x0478e472),
+       PCMCIA_DEVICE_PROD_ID12("MIDORI ELEC.", "LT-PCMT", 0x648d55c1, 0xbde526c7),
+       PCMCIA_DEVICE_PROD_ID12("National Semiconductor", "InfoMover 4100", 0x36e1191f, 0x60c229b9),
+       PCMCIA_DEVICE_PROD_ID12("National Semiconductor", "InfoMover NE4100", 0x36e1191f, 0xa6617ec8),
+       PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J12", 0x18df0ba0, 0xbc912d76),
+       PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA410TX", 0x9aa79dc3, 0x60e5bc0e),
+       PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA411", 0x9aa79dc3, 0x40fad875),
+       PCMCIA_DEVICE_PROD_ID12("Network Everywhere", "Fast Ethernet 10/100 PC Card", 0x820a67b6, 0x31ed1a5f),
+       PCMCIA_DEVICE_PROD_ID12("NextCom K.K.", "Next Hawk", 0xaedaec74, 0xad050ef1),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "10/100Mbps Ethernet Card", 0x281f1c5d, 0x6e41773b),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet", 0x281f1c5d, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "ETHERNET", 0x281f1c5d, 0x3ff7175b),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet 10BaseT Card", 0x281f1c5d, 0x4de2f6c8),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet Card", 0x281f1c5d, 0x5e9d92c0),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet Combo card", 0x281f1c5d, 0x929c486c),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "ETHERNET V1.0", 0x281f1c5d, 0x4d8817c8),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEthernet", 0x281f1c5d, 0xfe871eeb),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast-Ethernet", 0x281f1c5d, 0x45f1f3b4),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FAST ETHERNET CARD", 0x281f1c5d, 0xec5dbca7),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA LAN", "Ethernet", 0x7500e246, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "LNT-10TN", 0x281f1c5d, 0xe707f641),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "UE2212", 0x281f1c5d, 0xbf17199b),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "    Ethernet NE2000 Compatible", 0x281f1c5d, 0x42d5d7e1),
+       PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10baseT 3.3V", 0xebf91155, 0x30074c80),
+       PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10BaseT 3.3V", 0xebf91155, 0x7f5a4f50),
+       PCMCIA_DEVICE_PROD_ID12("Psion Dacom", "Gold Card Ethernet", 0xf5f025c2, 0x3a30e110),
+       PCMCIA_DEVICE_PROD_ID12("=RELIA==", "Ethernet", 0xcdd0644a, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID12("RP", "1625B Ethernet NE2000 Compatible", 0xe3e66e22, 0xb96150df),
+       PCMCIA_DEVICE_PROD_ID12("RPTI", "EP400 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4a7e2ae0),
+       PCMCIA_DEVICE_PROD_ID12("RPTI", "EP401 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4bcbd7fd),
+       PCMCIA_DEVICE_PROD_ID12("RPTI LTD.", "EP400", 0xc53ac515, 0x81e39388),
+       PCMCIA_DEVICE_PROD_ID12("SCM", "Ethernet Combo card", 0xbdc3b102, 0x929c486c),
+       PCMCIA_DEVICE_PROD_ID12("Seiko Epson Corp.", "Ethernet", 0x09928730, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID12("SMC", "EZCard-10-PCMCIA", 0xc4f8b18b, 0xfb21d265),
+       PCMCIA_DEVICE_PROD_ID12("Socket Communications Inc", "Socket EA PCMCIA LAN Adapter Revision D", 0xc70a4760, 0x2ade483e),
+       PCMCIA_DEVICE_PROD_ID12("Socket Communications Inc", "Socket EA PCMCIA LAN Adapter Revision E", 0xc70a4760, 0x5dd978a8),
+       PCMCIA_DEVICE_PROD_ID12("TDK", "LAK-CD031 for PCMCIA", 0x1eae9475, 0x0ed386fa),
+       PCMCIA_DEVICE_PROD_ID12("Telecom Device K.K.", "SuperSocket RE450T", 0x466b05f0, 0x8b74bc4f),
+       PCMCIA_DEVICE_PROD_ID12("Telecom Device K.K.", "SuperSocket RE550T", 0x466b05f0, 0x33c8db2a),
+       PCMCIA_DEVICE_PROD_ID13("Hypertec",  "EP401", 0x8787bec7, 0xf6e4a31e),
+       PCMCIA_DEVICE_PROD_ID13("KingMax Technology Inc.", "Ethernet Card", 0x932b7189, 0x5e9d92c0),
+       PCMCIA_DEVICE_PROD_ID13("LONGSHINE", "EP401", 0xf866b0b0, 0xf6e4a31e),
+       PCMCIA_DEVICE_PROD_ID13("Xircom", "CFE-10", 0x2e3ee845, 0x22a49f89),
+       PCMCIA_DEVICE_PROD_ID1("CyQ've 10 Base-T LAN CARD", 0x94faf360),
+       PCMCIA_DEVICE_PROD_ID1("EP-210 PCMCIA LAN CARD.", 0x8850b4de),
+       PCMCIA_DEVICE_PROD_ID1("ETHER-C16", 0x06a8514f),
+       PCMCIA_DEVICE_PROD_ID1("IC-CARD", 0x60cb09a6),
+       PCMCIA_DEVICE_PROD_ID1("NE2000 Compatible", 0x75b8ad5a),
+       PCMCIA_DEVICE_PROD_ID2("EN-6200P2", 0xa996d078),
+       /* too generic! */
+       /* PCMCIA_DEVICE_PROD_ID12("PCMCIA", "10/100 Ethernet Card", 0x281f1c5d, 0x11b0ffc0), */
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "PCMLM28.cis"),
+       PCMCIA_MFC_DEVICE_CIS_PROD_ID12(0, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_PROD_ID4(0, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0175, 0x0000, "DP83903.cis"),
+       PCMCIA_DEVICE_CIS_MANF_CARD(0xc00f, 0x0002, "LA-PCM.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("KTI", "PE520 PLUS", 0xad180345, 0x9d58d392, "PE520.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("NDC", "Ethernet", 0x01c43ae1, 0x00b2e941, "NE2K.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("PMX   ", "PE-200", 0x34f3f1c8, 0x10b59f8c, "PE-200.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("TAMARACK", "Ethernet", 0xcf434fba, 0x00b2e941, "tamarack.cis"),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, pcnet_ids);
+
 static struct pcmcia_driver pcnet_driver = {
        .drv            = {
                .name   = "pcnet_cs",
@@ -1642,6 +1846,7 @@ static struct pcmcia_driver pcnet_driver = {
        .attach         = pcnet_attach,
        .detach         = pcnet_detach,
        .owner          = THIS_MODULE,
+       .id_table       = pcnet_ids,
 };
 
 static int __init init_pcnet_cs(void)
index 85a152173148c2f52f03aed39b99b07d9a8b6ac7..bc01c88c67093877d8bd9685ab45de1131fa2096 100644 (file)
@@ -127,6 +127,12 @@ struct smc_private {
     int                                rx_ovrn;
 };
 
+struct smc_cfg_mem {
+    tuple_t tuple;
+    cisparse_t parse;
+    u_char buf[255];
+};
+
 /* Special definitions for Megahertz multifunction cards */
 #define MEGAHERTZ_ISR          0x0380
 
@@ -498,14 +504,24 @@ static int mhz_mfc_config(dev_link_t *link)
 {
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
-    tuple_t tuple;
-    cisparse_t parse;
-    u_char buf[255];
-    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    struct smc_cfg_mem *cfg_mem;
+    tuple_t *tuple;
+    cisparse_t *parse;
+    cistpl_cftable_entry_t *cf;
+    u_char *buf;
     win_req_t req;
     memreq_t mem;
     int i, k;
 
+    cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
+    if (!cfg_mem)
+        return CS_OUT_OF_RESOURCE;
+
+    tuple = &cfg_mem->tuple;
+    parse = &cfg_mem->parse;
+    cf = &parse->cftable_entry;
+    buf = cfg_mem->buf;
+
     link->conf.Attributes |= CONF_ENABLE_SPKR;
     link->conf.Status = CCSR_AUDIO_ENA;
     link->irq.Attributes =
@@ -514,12 +530,12 @@ static int mhz_mfc_config(dev_link_t *link)
     link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
     link->io.NumPorts2 = 8;
 
-    tuple.Attributes = tuple.TupleOffset = 0;
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleDataMax = sizeof(buf);
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    tuple->Attributes = tuple->TupleOffset = 0;
+    tuple->TupleData = (cisdata_t *)buf;
+    tuple->TupleDataMax = 255;
+    tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
 
-    i = first_tuple(link->handle, &tuple, &parse);
+    i = first_tuple(link->handle, tuple, parse);
     /* The Megahertz combo cards have modem-like CIS entries, so
        we have to explicitly try a bunch of port combinations. */
     while (i == CS_SUCCESS) {
@@ -532,10 +548,10 @@ static int mhz_mfc_config(dev_link_t *link)
            if (i == CS_SUCCESS) break;
        }
        if (i == CS_SUCCESS) break;
-       i = next_tuple(link->handle, &tuple, &parse);
+       i = next_tuple(link->handle, tuple, parse);
     }
     if (i != CS_SUCCESS)
-       return i;
+       goto free_cfg_mem;
     dev->base_addr = link->io.BasePort1;
 
     /* Allocate a memory window, for accessing the ISR */
@@ -544,7 +560,7 @@ static int mhz_mfc_config(dev_link_t *link)
     req.AccessSpeed = 0;
     i = pcmcia_request_window(&link->handle, &req, &link->win);
     if (i != CS_SUCCESS)
-       return i;
+       goto free_cfg_mem;
     smc->base = ioremap(req.Base, req.Size);
     mem.CardOffset = mem.Page = 0;
     if (smc->manfid == MANFID_MOTOROLA)
@@ -556,6 +572,8 @@ static int mhz_mfc_config(dev_link_t *link)
        && (smc->cardid == PRODID_MEGAHERTZ_EM3288))
        mhz_3288_power(link);
 
+free_cfg_mem:
+    kfree(cfg_mem);
     return i;
 }
 
@@ -563,39 +581,61 @@ static int mhz_setup(dev_link_t *link)
 {
     client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
-    tuple_t tuple;
-    cisparse_t parse;
-    u_char buf[255], *station_addr;
+    struct smc_cfg_mem *cfg_mem;
+    tuple_t *tuple;
+    cisparse_t *parse;
+    u_char *buf, *station_addr;
+    int rc;
+
+    cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
+    if (!cfg_mem)
+       return -1;
+
+    tuple = &cfg_mem->tuple;
+    parse = &cfg_mem->parse;
+    buf = cfg_mem->buf;
 
-    tuple.Attributes = tuple.TupleOffset = 0;
-    tuple.TupleData = buf;
-    tuple.TupleDataMax = sizeof(buf);
+    tuple->Attributes = tuple->TupleOffset = 0;
+    tuple->TupleData = (cisdata_t *)buf;
+    tuple->TupleDataMax = 255;
 
     /* Read the station address from the CIS.  It is stored as the last
        (fourth) string in the Version 1 Version/ID tuple. */
-    tuple.DesiredTuple = CISTPL_VERS_1;
-    if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS)
-       return -1;
+    tuple->DesiredTuple = CISTPL_VERS_1;
+    if (first_tuple(handle, tuple, parse) != CS_SUCCESS) {
+       rc = -1;
+       goto free_cfg_mem;
+    }
     /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
-    if (next_tuple(handle, &tuple, &parse) != CS_SUCCESS)
-       first_tuple(handle, &tuple, &parse);
-    if (parse.version_1.ns > 3) {
-       station_addr = parse.version_1.str + parse.version_1.ofs[3];
-       if (cvt_ascii_address(dev, station_addr) == 0)
-           return 0;
+    if (next_tuple(handle, tuple, parse) != CS_SUCCESS)
+       first_tuple(handle, tuple, parse);
+    if (parse->version_1.ns > 3) {
+       station_addr = parse->version_1.str + parse->version_1.ofs[3];
+       if (cvt_ascii_address(dev, station_addr) == 0) {
+               rc = 0;
+               goto free_cfg_mem;
+       }
     }
 
     /* Another possibility: for the EM3288, in a special tuple */
-    tuple.DesiredTuple = 0x81;
-    if (pcmcia_get_first_tuple(handle, &tuple) != CS_SUCCESS)
-       return -1;
-    if (pcmcia_get_tuple_data(handle, &tuple) != CS_SUCCESS)
-       return -1;
+    tuple->DesiredTuple = 0x81;
+    if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) {
+       rc = -1;
+       goto free_cfg_mem;
+    }
+    if (pcmcia_get_tuple_data(handle, tuple) != CS_SUCCESS) {
+       rc = -1;
+       goto free_cfg_mem;
+    }
     buf[12] = '\0';
-    if (cvt_ascii_address(dev, buf) == 0)
-       return 0;
-
-    return -1;
+    if (cvt_ascii_address(dev, buf) == 0) {
+       rc = 0;
+       goto free_cfg_mem;
+   }
+    rc = -1;
+free_cfg_mem:
+   kfree(cfg_mem);
+   return rc;
 }
 
 /*======================================================================
@@ -665,19 +705,29 @@ static int mot_setup(dev_link_t *link)
 static int smc_config(dev_link_t *link)
 {
     struct net_device *dev = link->priv;
-    tuple_t tuple;
-    cisparse_t parse;
-    u_char buf[255];
-    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    struct smc_cfg_mem *cfg_mem;
+    tuple_t *tuple;
+    cisparse_t *parse;
+    cistpl_cftable_entry_t *cf;
+    u_char *buf;
     int i;
 
-    tuple.Attributes = tuple.TupleOffset = 0;
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleDataMax = sizeof(buf);
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
+    if (!cfg_mem)
+       return CS_OUT_OF_RESOURCE;
+
+    tuple = &cfg_mem->tuple;
+    parse = &cfg_mem->parse;
+    cf = &parse->cftable_entry;
+    buf = cfg_mem->buf;
+
+    tuple->Attributes = tuple->TupleOffset = 0;
+    tuple->TupleData = (cisdata_t *)buf;
+    tuple->TupleDataMax = 255;
+    tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
 
     link->io.NumPorts1 = 16;
-    i = first_tuple(link->handle, &tuple, &parse);
+    i = first_tuple(link->handle, tuple, parse);
     while (i != CS_NO_MORE_ITEMS) {
        if (i == CS_SUCCESS) {
            link->conf.ConfigIndex = cf->index;
@@ -686,10 +736,12 @@ static int smc_config(dev_link_t *link)
            i = pcmcia_request_io(link->handle, &link->io);
            if (i == CS_SUCCESS) break;
        }
-       i = next_tuple(link->handle, &tuple, &parse);
+       i = next_tuple(link->handle, tuple, parse);
     }
     if (i == CS_SUCCESS)
        dev->base_addr = link->io.BasePort1;
+
+    kfree(cfg_mem);
     return i;
 }
 
@@ -697,41 +749,58 @@ static int smc_setup(dev_link_t *link)
 {
     client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
-    tuple_t tuple;
-    cisparse_t parse;
+    struct smc_cfg_mem *cfg_mem;
+    tuple_t *tuple;
+    cisparse_t *parse;
     cistpl_lan_node_id_t *node_id;
-    u_char buf[255], *station_addr;
-    int i;
+    u_char *buf, *station_addr;
+    int i, rc;
+
+    cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
+    if (!cfg_mem)
+       return CS_OUT_OF_RESOURCE;
 
-    tuple.Attributes = tuple.TupleOffset = 0;
-    tuple.TupleData = buf;
-    tuple.TupleDataMax = sizeof(buf);
+    tuple = &cfg_mem->tuple;
+    parse = &cfg_mem->parse;
+    buf = cfg_mem->buf;
+
+    tuple->Attributes = tuple->TupleOffset = 0;
+    tuple->TupleData = (cisdata_t *)buf;
+    tuple->TupleDataMax = 255;
 
     /* Check for a LAN function extension tuple */
-    tuple.DesiredTuple = CISTPL_FUNCE;
-    i = first_tuple(handle, &tuple, &parse);
+    tuple->DesiredTuple = CISTPL_FUNCE;
+    i = first_tuple(handle, tuple, parse);
     while (i == CS_SUCCESS) {
-       if (parse.funce.type == CISTPL_FUNCE_LAN_NODE_ID)
+       if (parse->funce.type == CISTPL_FUNCE_LAN_NODE_ID)
            break;
-       i = next_tuple(handle, &tuple, &parse);
+       i = next_tuple(handle, tuple, parse);
     }
     if (i == CS_SUCCESS) {
-       node_id = (cistpl_lan_node_id_t *)parse.funce.data;
+       node_id = (cistpl_lan_node_id_t *)parse->funce.data;
        if (node_id->nb == 6) {
            for (i = 0; i < 6; i++)
                dev->dev_addr[i] = node_id->id[i];
-           return 0;
+           rc = 0;
+           goto free_cfg_mem;
        }
     }
     /* Try the third string in the Version 1 Version/ID tuple. */
-    tuple.DesiredTuple = CISTPL_VERS_1;
-    if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS)
-       return -1;
-    station_addr = parse.version_1.str + parse.version_1.ofs[2];
-    if (cvt_ascii_address(dev, station_addr) == 0)
-       return 0;
+    tuple->DesiredTuple = CISTPL_VERS_1;
+    if (first_tuple(handle, tuple, parse) != CS_SUCCESS) {
+       rc = -1;
+       goto free_cfg_mem;
+    }
+    station_addr = parse->version_1.str + parse->version_1.ofs[2];
+    if (cvt_ascii_address(dev, station_addr) == 0) {
+       rc = 0;
+       goto free_cfg_mem;
+    }
 
-    return -1;
+    rc = -1;
+free_cfg_mem:
+    kfree(cfg_mem);
+    return rc;
 }
 
 /*====================================================================*/
@@ -773,26 +842,36 @@ static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid)
 {
     client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
-    tuple_t tuple;
-    u_char buf[255];
-    int i;
+    struct smc_cfg_mem *cfg_mem;
+    tuple_t *tuple;
+    u_char *buf;
+    int i, rc;
+
+    cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
+    if (!cfg_mem)
+        return -1;
+
+    tuple = &cfg_mem->tuple;
+    buf = cfg_mem->buf;
 
-    tuple.Attributes = TUPLE_RETURN_COMMON;
-    tuple.TupleData = buf;
-    tuple.TupleDataMax = sizeof(buf);
-    tuple.TupleOffset = 0;
+    tuple->Attributes = TUPLE_RETURN_COMMON;
+    tuple->TupleData = (cisdata_t *)buf;
+    tuple->TupleDataMax = 255;
+    tuple->TupleOffset = 0;
 
     /* Read the station address from tuple 0x90, subtuple 0x04 */
-    tuple.DesiredTuple = 0x90;
-    i = pcmcia_get_first_tuple(handle, &tuple);
+    tuple->DesiredTuple = 0x90;
+    i = pcmcia_get_first_tuple(handle, tuple);
     while (i == CS_SUCCESS) {
-       i = pcmcia_get_tuple_data(handle, &tuple);
+       i = pcmcia_get_tuple_data(handle, tuple);
        if ((i != CS_SUCCESS) || (buf[0] == 0x04))
            break;
-       i = pcmcia_get_next_tuple(handle, &tuple);
+       i = pcmcia_get_next_tuple(handle, tuple);
+    }
+    if (i != CS_SUCCESS) {
+       rc = -1;
+       goto free_cfg_mem;
     }
-    if (i != CS_SUCCESS)
-       return -1;
     for (i = 0; i < 6; i++)
        dev->dev_addr[i] = buf[i+2];
 
@@ -814,8 +893,10 @@ static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid)
              inw(link->io.BasePort1 + OSITECH_AUI_PWR),
              inw(link->io.BasePort1 + OSITECH_RESET_ISR));
     }
-
-    return 0;
+    rc = 0;
+free_cfg_mem:
+   kfree(cfg_mem);
+   return rc;
 }
 
 /*======================================================================
@@ -887,9 +968,10 @@ static void smc91c92_config(dev_link_t *link)
     client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
-    tuple_t tuple;
-    cisparse_t parse;
-    u_short buf[32];
+    struct smc_cfg_mem *cfg_mem;
+    tuple_t *tuple;
+    cisparse_t *parse;
+    u_char *buf;
     char *name;
     int i, j, rev;
     kio_addr_t ioaddr;
@@ -897,21 +979,29 @@ static void smc91c92_config(dev_link_t *link)
 
     DEBUG(0, "smc91c92_config(0x%p)\n", link);
 
-    tuple.Attributes = tuple.TupleOffset = 0;
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleDataMax = sizeof(buf);
+    cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
+    if (!cfg_mem)
+       goto config_failed;
 
-    tuple.DesiredTuple = CISTPL_CONFIG;
-    i = first_tuple(handle, &tuple, &parse);
-    CS_EXIT_TEST(i, ParseTuple, config_failed);
-    link->conf.ConfigBase = parse.config.base;
-    link->conf.Present = parse.config.rmask[0];
+    tuple = &cfg_mem->tuple;
+    parse = &cfg_mem->parse;
+    buf = cfg_mem->buf;
 
-    tuple.DesiredTuple = CISTPL_MANFID;
-    tuple.Attributes = TUPLE_RETURN_COMMON;
-    if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
-       smc->manfid = parse.manfid.manf;
-       smc->cardid = parse.manfid.card;
+    tuple->Attributes = tuple->TupleOffset = 0;
+    tuple->TupleData = (cisdata_t *)buf;
+    tuple->TupleDataMax = 64;
+
+    tuple->DesiredTuple = CISTPL_CONFIG;
+    i = first_tuple(handle, tuple, parse);
+    CS_EXIT_TEST(i, ParseTuple, config_failed);
+    link->conf.ConfigBase = parse->config.base;
+    link->conf.Present = parse->config.rmask[0];
+
+    tuple->DesiredTuple = CISTPL_MANFID;
+    tuple->Attributes = TUPLE_RETURN_COMMON;
+    if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
+       smc->manfid = parse->manfid.manf;
+       smc->cardid = parse->manfid.card;
     }
 
     /* Configure card */
@@ -1046,7 +1136,7 @@ static void smc91c92_config(dev_link_t *link)
            printk(KERN_NOTICE "  No MII transceivers found!\n");
        }
     }
-
+    kfree(cfg_mem);
     return;
 
 config_undo:
@@ -1054,6 +1144,7 @@ config_undo:
 config_failed:                 /* CS_EXIT_TEST() calls jump to here... */
     smc91c92_release(link);
     link->state &= ~DEV_CONFIG_PENDING;
+    kfree(cfg_mem);
 
 } /* smc91c92_config */
 
@@ -2236,6 +2327,38 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
        return rc;
 }
 
+static struct pcmcia_device_id smc91c92_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+       PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020),
+       PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023),
+       PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb),
+       PCMCIA_DEVICE_PROD_ID12("ARGOSY", "Fast Ethernet PCCard", 0x78f308dc, 0xdcea68bc),
+       PCMCIA_DEVICE_PROD_ID12("dit Co., Ltd.", "PC Card-10/100BTX", 0xe59365c8, 0x6a2161d1),
+       PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L100C", 0x6a26d1cf, 0xc16ce9c5),
+       PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734e9),
+       PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953),
+       PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a),
+       PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+       PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xdcea68bc),
+       PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9),
+       PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0eeb2d),
+       /* These conflict with other cards! */
+       /* PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0100), */
+       /* PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids);
+
 static struct pcmcia_driver smc91c92_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -2243,6 +2366,7 @@ static struct pcmcia_driver smc91c92_cs_driver = {
        },
        .attach         = smc91c92_attach,
        .detach         = smc91c92_detach,
+       .id_table       = smc91c92_ids,
 };
 
 static int __init init_smc91c92_cs(void)
index 58177d67ea128e27ceaf615a1ea96da022386b7a..0cd225e1595c0d6e5d03ea06395e0c19cacce6f8 100644 (file)
@@ -1983,6 +1983,33 @@ do_stop(struct net_device *dev)
     return 0;
 }
 
+static struct pcmcia_device_id xirc2ps_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0089, 0x110a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0138, 0x110a),
+       PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
+       PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
+       PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
+       PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
+       PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Xircom", "CreditCard Ethernet", 0x2e3ee845, 0xc0e778c2),
+       PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x010a),
+       PCMCIA_DEVICE_PROD_ID13("Toshiba Information Systems", "TPCENET", 0x1b3b94fe, 0xf381c1a2),
+       PCMCIA_DEVICE_PROD_ID13("Xircom", "CE3-10/100", 0x2e3ee845, 0x0ec0ac37),
+       PCMCIA_DEVICE_PROD_ID13("Xircom", "PS-CE2-10", 0x2e3ee845, 0x947d9073),
+       PCMCIA_DEVICE_PROD_ID13("Xircom", "R2E-100BTX", 0x2e3ee845, 0x2464a6e3),
+       PCMCIA_DEVICE_PROD_ID13("Xircom", "RE-10", 0x2e3ee845, 0x3e08d609),
+       PCMCIA_DEVICE_PROD_ID13("Xircom", "XE2000", 0x2e3ee845, 0xf7188e46),
+       PCMCIA_DEVICE_PROD_ID12("Compaq", "Ethernet LAN Card", 0x54f7c49c, 0x9fd2f0a2),
+       PCMCIA_DEVICE_PROD_ID12("Compaq", "Netelligent 10/100 PC Card", 0x54f7c49c, 0xefe96769),
+       PCMCIA_DEVICE_PROD_ID12("Intel", "EtherExpress(TM) PRO/100 PC Card Mobile Adapter16", 0x816cc815, 0x174397db),
+       PCMCIA_DEVICE_PROD_ID12("Toshiba", "10/100 Ethernet PC Card", 0x44a09d9c, 0xb44deecf),
+       /* also matches CFE-10 cards! */
+       /* PCMCIA_DEVICE_MANF_CARD(0x0105, 0x010a), */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, xirc2ps_ids);
+
+
 static struct pcmcia_driver xirc2ps_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -1990,6 +2017,7 @@ static struct pcmcia_driver xirc2ps_cs_driver = {
        },
        .attach         = xirc2ps_attach,
        .detach         = xirc2ps_detach,
+       .id_table       = xirc2ps_ids,
 };
 
 static int __init
index 13f114876965ba1d26f3bc2c604037d409213fa5..113b68099216b4aeac8af443d690e21cd1c15cb4 100644 (file)
@@ -850,7 +850,7 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
     if ((!data) || (data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)))
     data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
 
-    schedule_timeout(data * HZ);
+    msleep_interruptible(data * 1000);
     del_timer_sync(&lp->blink_timer);
 
     /* Restore the original value of the bcrs */
@@ -1602,7 +1602,7 @@ pcnet32_init_ring(struct net_device *dev)
 
        rmb();
        if (lp->rx_dma_addr[i] == 0)
-           lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail,
+           lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->data,
                    PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
        lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]);
        lp->rx_ring[i].buf_length = le16_to_cpu(2-PKT_BUF_SZ);
@@ -1983,7 +1983,7 @@ pcnet32_rx(struct net_device *dev)
                        lp->rx_skbuff[entry] = newskb;
                        newskb->dev = dev;
                        lp->rx_dma_addr[entry] =
-                           pci_map_single(lp->pci_dev, newskb->tail,
+                           pci_map_single(lp->pci_dev, newskb->data,
                                    PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
                        lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]);
                        rx_in_place = 1;
@@ -2020,7 +2020,7 @@ pcnet32_rx(struct net_device *dev)
                                                PKT_BUF_SZ-2,
                                                PCI_DMA_FROMDEVICE);
                    eth_copy_and_sum(skb,
-                           (unsigned char *)(lp->rx_skbuff[entry]->tail),
+                           (unsigned char *)(lp->rx_skbuff[entry]->data),
                            pkt_len,0);
                    pci_dma_sync_single_for_device(lp->pci_dev,
                                                   lp->rx_dma_addr[entry],
index ce449fe90e6d66169a1e93399b75282b8c472b47..d5afe05cd8267de3b9e3e308f28bf711d5efc093 100644 (file)
@@ -1876,7 +1876,7 @@ static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
        skb_reserve(skb, NET_IP_ALIGN);
        *sk_buff = skb;
 
-       mapping = pci_map_single(pdev, skb->tail, rx_buf_sz,
+       mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
                                 PCI_DMA_FROMDEVICE);
 
        rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
@@ -2336,7 +2336,7 @@ static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
                skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
                if (skb) {
                        skb_reserve(skb, NET_IP_ALIGN);
-                       eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0);
+                       eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
                        *sk_buff = skb;
                        rtl8169_mark_to_asic(desc, rx_buf_sz);
                        ret = 0;
index 9c224eba057d527d8f1764fed8fef4a64398555e..ea638b162d3f09223cd16ca8b97f16073650f354 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -1698,11 +1699,9 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
 #else
                ba = &nic->ba[ring_no][block_no][off];
                skb_reserve(skb, BUF0_LEN);
-               tmp = (unsigned long) skb->data;
-               tmp += ALIGN_SIZE;
-               tmp &= ~ALIGN_SIZE;
-               skb->data = (void *) tmp;
-               skb->tail = (void *) tmp;
+               tmp = ((unsigned long) skb->data & ALIGN_SIZE);
+               if (tmp)
+                       skb_reserve(skb, (ALIGN_SIZE + 1) - tmp);
 
                memset(rxdp, 0, sizeof(RxD_t));
                rxdp->Buffer2_ptr = pci_map_single
@@ -4593,19 +4592,19 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
                return ret;
        }
 
-       if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
+       if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
                DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n");
                dma_flag = TRUE;
 
                if (pci_set_consistent_dma_mask
-                   (pdev, 0xffffffffffffffffULL)) {
+                   (pdev, DMA_64BIT_MASK)) {
                        DBG_PRINT(ERR_DBG,
                                  "Unable to obtain 64bit DMA for \
                                        consistent allocations\n");
                        pci_disable_device(pdev);
                        return -ENOMEM;
                }
-       } else if (!pci_set_dma_mask(pdev, 0xffffffffUL)) {
+       } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
                DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 32bit DMA\n");
        } else {
                pci_disable_device(pdev);
index e15369c8d1651dbd9d20ffa1724f29f47ce9e2e6..d6388e1533f09778578a0eee49dad0d3dbed8af2 100644 (file)
@@ -90,7 +90,6 @@ static int sb1000_close(struct net_device *dev);
 
 
 /* SB1000 hardware routines to be used during open/configuration phases */
-static inline void nicedelay(unsigned long usecs);
 static inline int card_wait_for_busy_clear(const int ioaddr[],
        const char* name);
 static inline int card_wait_for_ready(const int ioaddr[], const char* name,
@@ -254,13 +253,6 @@ static struct pnp_driver sb1000_driver = {
 
 static const int TimeOutJiffies = (875 * HZ) / 100;
 
-static inline void nicedelay(unsigned long usecs)
-{
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(HZ);
-       return;
-}
-
 /* Card Wait For Busy Clear (cannot be used during an interrupt) */
 static inline int
 card_wait_for_busy_clear(const int ioaddr[], const char* name)
@@ -475,7 +467,7 @@ sb1000_reset(const int ioaddr[], const char* name)
        udelay(1000);
        outb(0x0, port);
        inb(port);
-       nicedelay(60000);
+       ssleep(1);
        outb(0x4, port);
        inb(port);
        udelay(1000);
@@ -537,7 +529,7 @@ sb1000_activate(const int ioaddr[], const char* name)
        const unsigned char Command0[6] = {0x80, 0x11, 0x00, 0x00, 0x00, 0x00};
        const unsigned char Command1[6] = {0x80, 0x16, 0x00, 0x00, 0x00, 0x00};
 
-       nicedelay(50000);
+       ssleep(1);
        if ((status = card_send_command(ioaddr, name, Command0, st)))
                return status;
        if ((status = card_send_command(ioaddr, name, Command1, st)))
@@ -944,7 +936,7 @@ sb1000_open(struct net_device *dev)
        /* initialize sb1000 */
        if ((status = sb1000_reset(ioaddr, name)))
                return status;
-       nicedelay(200000);
+       ssleep(1);
        if ((status = sb1000_check_CRC(ioaddr, name)))
                return status;
 
index fd2e7c3749064b87be8dfbce76e849127948ad6b..7abd55a4fb21fecf9e0e6204fafb490117ca464a 100644 (file)
@@ -963,11 +963,11 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
        /*
         * Do not interrupt per DMA transfer.
         */
-       dsc->dscr_a = virt_to_phys(sb_new->tail) |
+       dsc->dscr_a = virt_to_phys(sb_new->data) |
                V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
                0;
 #else
-       dsc->dscr_a = virt_to_phys(sb_new->tail) |
+       dsc->dscr_a = virt_to_phys(sb_new->data) |
                V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
                M_DMA_DSCRA_INTERRUPT;
 #endif
index 3107aed0fb51958b01f7a860adc8d1771159adfc..23b713c700b3beb2e3db8aad2a1321254afae46e 100644 (file)
@@ -66,6 +66,7 @@
 #include <linux/ethtool.h>
 #include <linux/crc32.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/processor.h>      /* Processor type for cache alignment. */
 #include <asm/io.h>
@@ -93,8 +94,6 @@ static int sis900_debug = -1; /* Use SIS900_DEF_MSG as value */
 
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT  (4*HZ)
-/* SiS 900 is capable of 32 bits BM DMA */
-#define SIS900_DMA_MASK 0xffffffff
 
 enum {
        SIS_900 = 0,
@@ -414,7 +413,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
        ret = pci_enable_device(pci_dev);
        if(ret) return ret;
        
-       i = pci_set_dma_mask(pci_dev, SIS900_DMA_MASK);
+       i = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK);
        if(i){
                printk(KERN_ERR "sis900.c: architecture does not support"
                        "32bit PCI busmaster DMA\n");
@@ -1155,7 +1154,7 @@ sis900_init_rx_ring(struct net_device *net_dev)
                sis_priv->rx_skbuff[i] = skb;
                sis_priv->rx_ring[i].cmdsts = RX_BUF_SIZE;
                 sis_priv->rx_ring[i].bufptr = pci_map_single(sis_priv->pci_dev,
-                        skb->tail, RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                        skb->data, RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
        }
        sis_priv->dirty_rx = (unsigned int) (i - NUM_RX_DESC);
 
@@ -1777,7 +1776,7 @@ static int sis900_rx(struct net_device *net_dev)
                        sis_priv->rx_skbuff[entry] = skb;
                        sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
                        sis_priv->rx_ring[entry].bufptr = 
-                               pci_map_single(sis_priv->pci_dev, skb->tail
+                               pci_map_single(sis_priv->pci_dev, skb->data
                                        RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
                        sis_priv->dirty_rx++;
                }
@@ -1810,7 +1809,7 @@ static int sis900_rx(struct net_device *net_dev)
                        sis_priv->rx_skbuff[entry] = skb;
                        sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
                        sis_priv->rx_ring[entry].bufptr =
-                               pci_map_single(sis_priv->pci_dev, skb->tail,
+                               pci_map_single(sis_priv->pci_dev, skb->data,
                                        RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
                }
        }
index 1ccb2989001c4a46dcf28fbacfb06f320389089d..82570ec44d8eefea84aa2b7721ac9f3eafa7bd3e 100644 (file)
 #include       <linux/moduleparam.h>
 #include       <linux/init.h>
 #include       <linux/proc_fs.h>
+#include       <linux/dma-mapping.h>
 
 #include       "h/skdrv1st.h"
 #include       "h/skdrv2nd.h"
@@ -4912,8 +4913,8 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
                goto out;
  
        /* Configure DMA attributes. */
-       if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL) &&
-           pci_set_dma_mask(pdev, (u64) 0xffffffff))
+       if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) &&
+           pci_set_dma_mask(pdev, DMA_32BIT_MASK))
                goto out_disable_device;
 
 
index 6cfccfb7889f55db6e906bf4486cbbedd2565ffd..cb23580fcffa5894d1f10db8dce271575c7a1781 100644 (file)
@@ -6,8 +6,8 @@ obj-$(CONFIG_SKFP) += skfp.o
 
 skfp-objs :=  skfddi.o    hwmtm.o    fplustm.o  smt.o      cfm.o     \
               ecm.o       pcmplc.o   pmf.o      queue.o    rmt.o     \
-             smtdef.o    smtinit.o  smttimer.o srf.o      lnkstat.o \
-              smtparse.o  hwt.o      drvfbi.o   ess.o
+             smtdef.o    smtinit.o  smttimer.o srf.o      hwt.o     \
+             drvfbi.o   ess.o
 
 # NOTE:
 #   Compiling this driver produces some warnings (and some more are 
index 052e841ba187176fcb89d43f2775120e16f651e8..5b475833f64562d23177c5f2393a9a94c6327956 100644 (file)
@@ -105,8 +105,8 @@ extern int AIX_vpdReadByte() ;
 #endif
 
 
-/* Prototypes of local functions. */
-void smt_stop_watchdog(struct s_smc *smc);
+/* Prototype of a local function. */
+static void smt_stop_watchdog(struct s_smc *smc);
 
 #ifdef MCA
 static int read_card_id() ;
@@ -631,7 +631,7 @@ void plc_clear_irq(struct s_smc *smc, int p)
  *     LED_Y_OFF       just switch yellow LED off
  *     LED_Y_ON        just switch yello LED on
  */
-void led_indication(struct s_smc *smc, int led_event)
+static void led_indication(struct s_smc *smc, int led_event)
 {
        /* use smc->hw.mac_ring_is_up == TRUE 
         * as indication for Ring Operational
@@ -764,122 +764,6 @@ void llc_recover_tx(struct s_smc *smc)
 #endif
 }
 
-/*--------------------------- DMA init ----------------------------*/
-#ifdef ISA
-
-/*
- * init DMA
- */
-void init_dma(struct s_smc *smc, int dma)
-{
-       SK_UNUSED(smc) ;
-
-       /*
-        * set cascade mode,
-        * clear mask bit (enable DMA cannal)
-        */
-       if (dma > 3) {
-               outp(0xd6,(dma & 0x03) | 0xc0) ;
-               outp(0xd4, dma & 0x03) ;
-       }
-       else {
-               outp(0x0b,(dma & 0x03) | 0xc0) ;
-               outp(0x0a,dma & 0x03) ;
-       }
-}
-
-/*
- * disable DMA
- */
-void dis_dma(struct s_smc *smc, int dma)
-{
-       SK_UNUSED(smc) ;
-
-       /*
-        * set mask bit (disable DMA cannal)
-        */
-       if (dma > 3) {
-               outp(0xd4,(dma & 0x03) | 0x04) ;
-       }
-       else {
-               outp(0x0a,(dma & 0x03) | 0x04) ;
-       }
-}
-
-#endif /* ISA */
-
-#ifdef EISA
-
-/*arrays with io addresses of dma controller length and address registers*/
-static const int cntr[8] = { 0x001,0x003,0x005,0x007,0,0x0c6,0x0ca,0x0ce } ;
-static const int base[8] = { 0x000,0x002,0x004,0x006,0,0x0c4,0x0c8,0x0cc } ;
-static const int page[8] = { 0x087,0x083,0x081,0x082,0,0x08b,0x089,0x08a } ;
-
-void init_dma(struct s_smc *smc, int dma)
-{
-       /*
-        * extended mode register
-        * 32 bit IO
-        * type c
-        * TC output
-        * disable stop
-        */
-
-       /* mode read (write) demand */
-       smc->hw.dma_rmode = (dma & 3) | 0x08 | 0x0 ;
-       smc->hw.dma_wmode = (dma & 3) | 0x04 | 0x0 ;
-
-       /* 32 bit IO's, burst DMA mode (type "C") */
-       smc->hw.dma_emode = (dma & 3) | 0x08 | 0x30 ;
-
-       outp((dma < 4) ? 0x40b : 0x4d6,smc->hw.dma_emode) ;
-
-       /* disable chaining */
-       outp((dma < 4) ? 0x40a : 0x4d4,(dma&3)) ;
-
-       /*load dma controller addresses for fast access during set dma*/
-       smc->hw.dma_base_word_count = cntr[smc->hw.dma];
-       smc->hw.dma_base_address = base[smc->hw.dma];
-       smc->hw.dma_base_address_page = page[smc->hw.dma];
-
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
-       SK_UNUSED(smc) ;
-
-       outp((dma < 4) ? 0x0a : 0xd4,(dma&3)|4) ;/* mask bit */
-}
-#endif /* EISA */
-
-#ifdef MCA
-void init_dma(struct s_smc *smc, int dma)
-{
-       SK_UNUSED(smc) ;
-       SK_UNUSED(dma) ;
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
-       SK_UNUSED(smc) ;
-       SK_UNUSED(dma) ;
-}
-#endif
-
-#ifdef PCI
-void init_dma(struct s_smc *smc, int dma)
-{
-       SK_UNUSED(smc) ;
-       SK_UNUSED(dma) ;
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
-       SK_UNUSED(smc) ;
-       SK_UNUSED(dma) ;
-}
-#endif
-
 #ifdef MULT_OEM
 static int is_equal_num(char comp1[], char comp2[], int num)
 {
@@ -1407,7 +1291,7 @@ void smt_start_watchdog(struct s_smc *smc)
 #endif /* DEBUG */
 }
 
-void smt_stop_watchdog(struct s_smc *smc)
+static void smt_stop_watchdog(struct s_smc *smc)
 {
        SK_UNUSED(smc) ;        /* Make LINT happy. */
 #ifndef        DEBUG
@@ -1422,104 +1306,6 @@ void smt_stop_watchdog(struct s_smc *smc)
 }
 
 #ifdef PCI
-static char get_rom_byte(struct s_smc *smc, u_short addr)
-{
-       GET_PAGE(addr) ;
-       return (READ_PROM(ADDR(B2_FDP))) ;
-}
-
-/*
- * ROM image defines
- */
-#define        ROM_SIG_1       0
-#define ROM_SIG_2      1
-#define PCI_DATA_1     0x18
-#define PCI_DATA_2     0x19
-
-/*
- * PCI data structure defines
- */
-#define        VPD_DATA_1      0x08
-#define        VPD_DATA_2      0x09
-#define IMAGE_LEN_1    0x10
-#define IMAGE_LEN_2    0x11
-#define        CODE_TYPE       0x14
-#define        INDICATOR       0x15
-
-/*
- *     BEGIN_MANUAL_ENTRY(mac_drv_vpd_read)
- *     mac_drv_vpd_read(smc,buf,size,image)
- *
- * function    DOWNCALL        (FDDIWARE)
- *             reads the VPD data of the FPROM and writes it into the
- *             buffer
- *
- * para        buf     points to the buffer for the VPD data
- *     size    size of the VPD data buffer
- *     image   boot image; code type of the boot image
- *             image = 0       Intel x86, PC-AT compatible
- *                     1       OPENBOOT standard for PCI
- *                     2-FF    reserved
- *
- * returns     len     number of VPD data bytes read form the FPROM
- *             <0      number of read bytes
- *             >0      error: data invalid
- *
- *     END_MANUAL_ENTRY
- */
-int mac_drv_vpd_read(struct s_smc *smc, char *buf, int size, char image)
-{
-       u_short ibase ;
-       u_short pci_base ;
-       u_short vpd ;
-       int     len ;
-
-       len = 0 ;
-       ibase = 0 ;
-       /*
-        * as long images defined
-        */
-       while (get_rom_byte(smc,ibase+ROM_SIG_1) == 0x55 &&
-               (u_char) get_rom_byte(smc,ibase+ROM_SIG_2) == 0xaa) {
-               /*
-                * get the pointer to the PCI data structure
-                */
-               pci_base = ibase + get_rom_byte(smc,ibase+PCI_DATA_1) +
-                               (get_rom_byte(smc,ibase+PCI_DATA_2) << 8) ;
-
-               if (image == get_rom_byte(smc,pci_base+CODE_TYPE)) {
-                       /*
-                        * we have the right image, read the VPD data
-                        */
-                       vpd = ibase + get_rom_byte(smc,pci_base+VPD_DATA_1) +
-                               (get_rom_byte(smc,pci_base+VPD_DATA_2) << 8) ;
-                       if (vpd == ibase) {
-                               break ;         /* no VPD data */
-                       }
-                       for (len = 0; len < size; len++,buf++,vpd++) {
-                               *buf = get_rom_byte(smc,vpd) ;
-                       }
-                       break ;
-               }
-               else {
-                       /*
-                        * try the next image
-                        */
-                       if (get_rom_byte(smc,pci_base+INDICATOR) & 0x80) {
-                               break ;         /* this was the last image */
-                       }
-                       ibase = ibase + get_rom_byte(smc,ibase+IMAGE_LEN_1) +
-                               (get_rom_byte(smc,ibase+IMAGE_LEN_2) << 8) ;
-               }
-       }
-
-       return(len) ;
-}
-
-void mac_drv_pci_fix(struct s_smc *smc, u_long fix_value)
-{
-       smc->hw.pci_fix_value = fix_value ;
-}
 
 void mac_do_pci_fix(struct s_smc *smc)
 {
index fd39b4b2ef7da93caae56bc36691be161b9eaf5b..62b01328c496c4e3678bf8b5b7fe7e1950470895 100644 (file)
@@ -102,7 +102,7 @@ void ess_timer_poll(struct s_smc *smc);
 void ess_para_change(struct s_smc *smc);
 int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
                          int fs);
-int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead);
+static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead);
 
 
 /*
@@ -375,7 +375,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
  * determines the synchronous bandwidth, set the TSYNC register and the
  * mib variables SBAPayload, SBAOverhead and fddiMACT-NEG.
  */
-int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead)
+static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead)
 {
        /*
         * determine the synchronous bandwidth (sync_bw) in bytes per T-NEG,
index 76e78442fc2470a340628c71c9a1cb79e4903c9a..a2ed47f1cc709ec5b7243b5f04ffe2b5de8d96db 100644 (file)
@@ -1114,30 +1114,6 @@ void mac_clear_multicast(struct s_smc *smc)
        }
 }
 
-/*
-       BEGIN_MANUAL_ENTRY(if,func;others;2)
-
-       int mac_set_func_addr(smc,f_addr)
-       struct s_smc *smc ;
-       u_long f_addr ;
-
-Function       DOWNCALL        (SMT, fplustm.c)
-               Set a Token-Ring functional address, the address will
-               be activated after calling mac_update_multicast()
-
-Para   f_addr  functional bits in non-canonical format
-
-Returns        0: always success
-
-       END_MANUAL_ENTRY()
- */
-int mac_set_func_addr(struct s_smc *smc, u_long f_addr)
-{
-       smc->hw.fp.func_addr = f_addr ;
-       return(0) ;
-}
-
-
 /*
        BEGIN_MANUAL_ENTRY(if,func;others;2)
 
@@ -1202,52 +1178,6 @@ int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can)
        return(0) ;
 }
 
-/*
-       BEGIN_MANUAL_ENTRY(if,func;others;2)
-
-       void mac_del_multicast(smc,addr,can)
-       struct s_smc *smc ;
-       struct fddi_addr *addr ;
-       int can ;
-
-Function       DOWNCALL        (SMT, fplustm.c)
-               Delete an entry from the multicast table
-
-Para   addr    pointer to a multicast address
-       can     = 0:    the multicast address has the physical format
-               = 1:    the multicast address has the canonical format
-               | 0x80  permanent
-
-       END_MANUAL_ENTRY()
- */
-void mac_del_multicast(struct s_smc *smc, struct fddi_addr *addr, int can)
-{
-       SK_LOC_DECL(struct fddi_addr,own) ;
-       struct s_fpmc   *tb ;
-
-       if (!(tb = mac_get_mc_table(smc,addr,&own,1,can & ~0x80)))
-               return ;
-       /*
-        * permanent addresses must be deleted with perm bit
-        * and vice versa
-        */
-       if (( tb->perm &&  (can & 0x80)) ||
-           (!tb->perm && !(can & 0x80))) {
-               /*
-                * delete it
-                */
-               if (tb->n) {
-                       tb->n-- ;
-                       if (tb->perm) {
-                               smc->hw.fp.smt_slots_used-- ;
-                       }
-                       else {
-                               smc->hw.fp.os_slots_used-- ;
-                       }
-               }
-       }
-}
-
 /*
  * mode
  */
index 603982debc71e0690ae5d1254caf166d27d3de87..f2f771d8be76b3a207ff8282b91fd2a8f7331703 100644 (file)
@@ -507,7 +507,6 @@ void pcm_status_state(struct s_smc *smc, int np, int *type, int *state,
                      int *remote, int *mac);
 void plc_config_mux(struct s_smc *smc, int mux);
 void sm_lem_evaluate(struct s_smc *smc);
-void smt_clear_una_dna(struct s_smc *smc);
 void mac_update_counter(struct s_smc *smc);
 void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off);
 void sm_ma_control(struct s_smc *smc, int mode);
@@ -541,11 +540,9 @@ void smt_timer_poll(struct s_smc *smc);
 u_long smt_get_time(void);
 u_long smt_get_tid(struct s_smc *smc);
 void smt_timer_done(struct s_smc *smc);
-void smt_set_defaults(struct s_smc *smc);
 void smt_fixup_mib(struct s_smc *smc);
 void smt_reset_defaults(struct s_smc *smc, int level);
 void smt_agent_task(struct s_smc *smc);
-void smt_please_reconnect(struct s_smc *smc, int reconn_time);
 int smt_check_para(struct s_smc *smc, struct smt_header *sm,
                   const u_short list[]);
 void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr);
@@ -568,7 +565,6 @@ int pcm_get_s_port(struct s_smc *smc);
 int pcm_rooted_station(struct s_smc *smc);
 int cfm_get_mac_input(struct s_smc *smc);
 int cfm_get_mac_output(struct s_smc *smc);
-int port_to_mib(struct s_smc *smc, int p);
 int cem_build_path(struct s_smc *smc, char *to, int path_index);
 int sm_mac_get_tx_state(struct s_smc *smc);
 char *get_pcmstate(struct s_smc *smc, int np);
@@ -580,8 +576,6 @@ void smt_send_frame(struct s_smc *smc, SMbuf *mb, int fc, int local);
 void smt_set_timestamp(struct s_smc *smc, u_char *p);
 void mac_set_rx_mode(struct s_smc *smc,        int mode);
 int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can);
-int mac_set_func_addr(struct s_smc *smc, u_long f_addr);
-void mac_del_multicast(struct s_smc *smc, struct fddi_addr *addr, int can);
 void mac_update_multicast(struct s_smc *smc);
 void mac_clear_multicast(struct s_smc *smc);
 void set_formac_tsync(struct s_smc *smc, long sync_bw);
@@ -599,7 +593,6 @@ void plc_irq(struct s_smc *smc,     int np, unsigned int cmd);
 int smt_set_mac_opvalues(struct s_smc *smc);
 
 #ifdef TAG_MODE
-void mac_drv_pci_fix(struct s_smc *smc, u_long fix_value);
 void mac_do_pci_fix(struct s_smc *smc);
 void mac_drv_clear_tx_queue(struct s_smc *smc);
 void mac_drv_repair_descr(struct s_smc *smc);
index 4e360af07d779a73daf6b6f2f656e583225affd6..1a606d4bfe5e98253ff3b7f241de99887804ebee 100644 (file)
@@ -261,31 +261,6 @@ struct os_debug {
 #define        HWM_GET_CURR_TXD(smc,queue)     (struct s_smt_fp_txd volatile *)\
                                        (smc)->hw.fp.tx_q[queue].tx_curr_put
 
-/*
- *     BEGIN_MANUAL_ENTRY(HWM_TX_CHECK)
- *     void HWM_TX_CHECK(smc,frame_status,low_water)
- *
- * function    MACRO           (hardware module, hwmtm.h)
- *             This macro is invoked by the OS-specific before it left it's
- *             driver_send function. This macro calls mac_drv_clear_txd
- *             if the free TxDs of the current transmit queue is equal or
- *             lower than the given low water mark.
- *
- * para        frame_status    status of the frame, see design description
- *     low_water       low water mark of free TxD's
- *
- *     END_MANUAL_ENTRY
- */
-#ifndef HWM_NO_FLOW_CTL
-#define        HWM_TX_CHECK(smc,frame_status,low_water) {\
-       if ((low_water)>=(smc)->hw.fp.tx_q[(frame_status)&QUEUE_A0].tx_free) {\
-               mac_drv_clear_txd(smc) ;\
-       }\
-}
-#else
-#define        HWM_TX_CHECK(smc,frame_status,low_water)        mac_drv_clear_txd(smc)
-#endif
-
 /*
  *     BEGIN_MANUAL_ENTRY(HWM_GET_RX_FRAG_LEN)
  *     int HWM_GET_RX_FRAG_LEN(rxd)
index 5359eb53008dfe6c11b4435af515717672edca6e..763ca18cbea876f8e162f7e9c8bb1c98551a0483 100644 (file)
@@ -20,6 +20,8 @@
 // HWM (HardWare Module) Definitions
 // -----------------------
 
+#include <asm/byteorder.h>
+
 #ifdef __LITTLE_ENDIAN
 #define LITTLE_ENDIAN
 #else
index 18d429021edbbbe188b1dee75b79806804987a7f..438f424e63611ca73f372aa74207713507d34bb5 100644 (file)
@@ -86,6 +86,7 @@ static u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue);
 static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue);
 static SMbuf* get_llc_rx(struct s_smc *smc);
 static SMbuf* get_txd_mb(struct s_smc *smc);
+static void mac_drv_clear_txd(struct s_smc *smc);
 
 /*
        -------------------------------------------------------------
@@ -146,7 +147,6 @@ extern int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead,
 */
 void process_receive(struct s_smc *smc);
 void fddi_isr(struct s_smc *smc);
-void mac_drv_clear_txd(struct s_smc *smc);
 void smt_free_mbuf(struct s_smc *smc, SMbuf *mb);
 void init_driver_fplus(struct s_smc *smc);
 void mac_drv_rx_mode(struct s_smc *smc, int mode);
@@ -158,7 +158,6 @@ void hwm_tx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
 void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
                 int frame_status);
 
-int mac_drv_rx_frag(struct s_smc *smc, void far *virt, int len);
 int mac_drv_init(struct s_smc *smc);
 int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len,
                int frame_status);
@@ -1448,35 +1447,6 @@ void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
        NDD_TRACE("RHfE",r,AIX_REVERSE(r->rxd_rbadr),0) ;
 }
 
-#ifndef        NDIS_OS2
-/*
- *     BEGIN_MANUAL_ENTRY(mac_drv_rx_frag)
- *     int mac_drv_rx_frag(smc,virt,len)
- *
- * function    DOWNCALL        (hwmtm.c)
- *             mac_drv_rx_frag fills the fragment with a part of the frame.
- *
- * para        virt    the virtual address of the fragment
- *     len     the length in bytes of the fragment
- *
- * return 0:   success code, no errors possible
- *
- *     END_MANUAL_ENTRY
- */
-int mac_drv_rx_frag(struct s_smc *smc, void far *virt, int len)
-{
-       NDD_TRACE("RHSB",virt,len,smc->os.hwm.r.mb_pos) ;
-
-       DB_RX("receive from queue: len/virt: = %d/%x",len,virt,4) ;
-       memcpy((char far *)virt,smc->os.hwm.r.mb_pos,len) ;
-       smc->os.hwm.r.mb_pos += len ;
-
-       NDD_TRACE("RHSE",smc->os.hwm.r.mb_pos,0,0) ;
-       return(0) ;
-}
-#endif
-
-
 /*
  *     BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue)
  *
@@ -1978,7 +1948,7 @@ void smt_send_mbuf(struct s_smc *smc, SMbuf *mb, int fc)
  *
  *     END_MANUAL_ENTRY
  */
-void mac_drv_clear_txd(struct s_smc *smc)
+static void mac_drv_clear_txd(struct s_smc *smc)
 {
        struct s_smt_tx_queue *queue ;
        struct s_smt_fp_txd volatile *t1 ;
diff --git a/drivers/net/skfp/lnkstat.c b/drivers/net/skfp/lnkstat.c
deleted file mode 100644 (file)
index 00a2480..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/******************************************************************************
- *
- *     (C)Copyright 1998,1999 SysKonnect,
- *     a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- *     See the file "skfddi.c" for further information.
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     The information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-/*
-       IBM FDDI read error log function
-*/
-
-#include "h/types.h"
-#include "h/fddi.h"
-#include "h/smc.h"
-#include "h/lnkstat.h"
-
-#ifndef        lint
-static const char ID_sccs[] = "@(#)lnkstat.c   1.8 97/04/11 (C) SK " ;
-#endif
-
-#ifdef sun
-#define _far
-#endif
-
-#define EL_IS_OK(x,l)  ((((int)&(((struct s_error_log *)0)->x)) + \
-                       sizeof(er->x)) <= l)
-
-/*
-       BEGIN_MANUAL_ENTRY(if,func;others;11)
-
-       u_long smt_get_error_word(smc)
-       struct s_smc *smc ;
-
-Function       DOWNCALL        (SMT, lnkstat.c)
-               This functions returns the SMT error work for AIX events.
-
-Return smt_error_word  These bits are supported:
-
-               SMT_ERL_ALC     ==      [PS/PA].fddiPORTLerFlag
-               SMT_ERL_BLC     ==      [PB].fddiPORTLerFlag
-               SMT_ERL_NCC     ==      fddiMACNotCopiedFlag
-               SMT_ERL_FEC     ==      fddiMACFrameErrorFlag
-
-       END_MANUAL_ENTRY()
- */
-u_long smt_get_error_word(struct s_smc *smc)
-{
-       u_long  st;
-
-       /*
-        * smt error word low
-        */
-       st = 0 ;
-       if (smc->s.sas == SMT_SAS) {
-               if (smc->mib.p[PS].fddiPORTLerFlag)
-                       st |= SMT_ERL_ALC ;
-       }
-       else {
-               if (smc->mib.p[PA].fddiPORTLerFlag)
-                       st |= SMT_ERL_ALC ;
-               if (smc->mib.p[PB].fddiPORTLerFlag)
-                       st |= SMT_ERL_BLC ;
-       }
-       if (smc->mib.m[MAC0].fddiMACNotCopiedFlag)
-               st |= SMT_ERL_NCC ;             /* not copied condition */
-       if (smc->mib.m[MAC0].fddiMACFrameErrorFlag)
-               st |= SMT_ERL_FEC ;             /* frame error condition */
-
-       return st;
-}
-
-/*
-       BEGIN_MANUAL_ENTRY(if,func;others;11)
-
-       u_long smt_get_event_word(smc)
-       struct s_smc *smc ;
-
-Function       DOWNCALL        (SMT, lnkstat.c)
-               This functions returns the SMT event work for AIX events.
-
-Return smt_event_word  always 0
-
-       END_MANUAL_ENTRY()
- */
-u_long smt_get_event_word(struct s_smc *smc)
-{
-       return (u_long) 0;
-}
-
-/*
-       BEGIN_MANUAL_ENTRY(if,func;others;11)
-
-       u_long smt_get_port_event_word(smc)
-       struct s_smc *smc ;
-
-Function       DOWNCALL        (SMT, lnkstat.c)
-               This functions returns the SMT port event work for AIX events.
-
-Return smt_port_event_word     always 0
-
-       END_MANUAL_ENTRY()
- */
-u_long smt_get_port_event_word(struct s_smc *smc)
-{
-       return (u_long) 0;
-}
-
-/*
-       BEGIN_MANUAL_ENTRY(if,func;others;11)
-
-       u_long smt_read_errorlog(smc,p,len)
-       struct s_smc *smc ;
-       char _far *p ;
-       int len ;
-
-Function       DOWNCALL        (SMT, lnkstat.c)
-               This functions returns the SMT error log field for AIX events.
-
-Para   p       pointer to the error log field
-       len     len of the error log field
-
-Return len     used len of the error log field
-
-       END_MANUAL_ENTRY()
- */
-int smt_read_errorlog(struct s_smc *smc, char _far *p, int len)
-{
-       int                     i ;
-       int                     st ;
-       struct s_error_log _far *er ;
-
-       er = (struct s_error_log _far *) p ;
-       if (len > sizeof(struct s_error_log))
-               len = sizeof(struct s_error_log) ;
-       for (i = 0 ; i < len ; i++)
-               *p++ = 0 ;
-       /*
-        * set count
-        */
-       if (EL_IS_OK(set_count_high,len)) {
-               er->set_count_low = (u_short)smc->mib.fddiSMTSetCount.count ;
-               er->set_count_high =
-                       (u_short)(smc->mib.fddiSMTSetCount.count >> 16L) ;
-       }
-       /*
-        * aci
-        */
-       if (EL_IS_OK(aci_id_code,len)) {
-               er->aci_id_code = 0 ;
-       }
-       /*
-        * purge counter is missed frames; 16 bits only
-        */
-       if (EL_IS_OK(purge_frame_counter,len)) {
-               if (smc->mib.m[MAC0].fddiMACCopied_Ct > 0xffff)
-                       er->purge_frame_counter = 0xffff ;
-               else
-                       er->purge_frame_counter =
-                               (u_short)smc->mib.m[MAC0].fddiMACCopied_Ct ;
-       }
-       /*
-        * CMT and RMT state machines
-        */
-       if (EL_IS_OK(ecm_state,len))
-               er->ecm_state = smc->mib.fddiSMTECMState ;
-
-       if (EL_IS_OK(pcm_b_state,len)) {
-               if (smc->s.sas == SMT_SAS) {
-                       er->pcm_a_state = smc->y[PS].mib->fddiPORTPCMState ;
-                       er->pcm_b_state = 0 ;
-               }
-               else {
-                       er->pcm_a_state = smc->y[PA].mib->fddiPORTPCMState ;
-                       er->pcm_b_state = smc->y[PB].mib->fddiPORTPCMState ;
-               }
-       }
-       if (EL_IS_OK(cfm_state,len))
-               er->cfm_state = smc->mib.fddiSMTCF_State ;
-       if (EL_IS_OK(rmt_state,len))
-               er->rmt_state = smc->mib.m[MAC0].fddiMACRMTState ;
-
-       /*
-        * smt error word low (we only need the low order 16 bits.)
-        */
-
-       st = smt_get_error_word(smc) & 0xffff ;
-
-       if (EL_IS_OK(smt_error_low,len))
-               er->smt_error_low = st ;
-
-       if (EL_IS_OK(ucode_version_level,len))
-               er->ucode_version_level = 0x0101 ;
-       return(len) ;
-}
-
index 571f055c096bacca88967d49c88ba6446c426131..cd0aa4c151b092effd4dc5fb33d9c6473a85ef03 100644 (file)
@@ -1861,13 +1861,6 @@ void plc_irq(struct s_smc *smc, int np, unsigned int cmd)
 #endif
 }
 
-void pcm_set_lct_short(struct s_smc *smc, int n)
-{
-       if (n <= 0 || n > 1000)
-               return ;
-       smc->s.lct_short = n ;
-}
-
 #ifdef DEBUG
 /*
  * fill state struct
index f2b446d8b0bffc90407dbdaf3f85afc738956097..efc639c013fde5b0fc82d2e1fc2cb99ca13009d2 100644 (file)
@@ -36,12 +36,13 @@ static int smt_authorize(struct s_smc *smc, struct smt_header *sm);
 static int smt_check_set_count(struct s_smc *smc, struct smt_header *sm);
 static const struct s_p_tab* smt_get_ptab(u_short para);
 static int smt_mib_phys(struct s_smc *smc);
-int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index, int local,
-                int set);
+static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
+                       int local, int set);
 void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para,
                  int index, int local);
 static SMbuf *smt_build_pmf_response(struct s_smc *smc, struct smt_header *req,
                                     int set, int local);
+static int port_to_mib(struct s_smc *smc, int p);
 
 #define MOFFSS(e)      ((int)&(((struct fddi_mib *)0)->e))
 #define MOFFSA(e)      ((int) (((struct fddi_mib *)0)->e))
@@ -1078,8 +1079,8 @@ wrong_error:
 /*
  * set parameter
  */
-int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index, int local,
-                int set)
+static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
+                       int local, int set)
 {
 #define IFSET(x)       if (set) (x)
 
@@ -1549,7 +1550,7 @@ static int smt_mib_phys(struct s_smc *smc)
 #endif
 }
 
-int port_to_mib(struct s_smc *smc, int p)
+static int port_to_mib(struct s_smc *smc, int p)
 {
 #ifdef CONCENTRATOR
        SK_UNUSED(smc) ;
index c88aad6edd7456bc0af36d49644875b15b3c18e9..4b5ed2c63177ff991716885c843c4fe331e26eaf 100644 (file)
@@ -149,7 +149,6 @@ extern void hwm_rx_frag(struct s_smc *smc, char far * virt, u_long phys,
 extern void mac_drv_rx_mode(struct s_smc *smc, int mode);
 extern void mac_drv_clear_rx_queue(struct s_smc *smc);
 extern void enable_tx_irq(struct s_smc *smc, u_short queue);
-extern void mac_drv_clear_txd(struct s_smc *smc);
 
 static struct pci_device_id skfddi_pci_tbl[] = {
        { PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, PCI_ANY_ID, PCI_ANY_ID, },
index 71935eaf9d4eccd1cd30697459c261dabf9c583c..f17c05cbe44bf84a79eab3b4d3900369f9f8a706 100644 (file)
@@ -86,7 +86,7 @@ static void smt_send_sif_config(struct s_smc *smc, struct fddi_addr *dest,
 static void smt_send_sif_operation(struct s_smc *smc, struct fddi_addr *dest,
                                   u_long tid, int local);
 #ifdef LITTLE_ENDIAN
-static void smt_string_swap(void);
+static void smt_string_swap(char *data, const char *format, int len);
 #endif
 static void smt_add_frame_len(SMbuf *mb, int len);
 static void smt_fill_una(struct s_smc *smc, struct smt_p_una *una);
@@ -110,7 +110,7 @@ static void smt_fill_setcount(struct s_smc *smc, struct smt_p_setcount *setcount
 static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long seed,
                          int len);
 
-void smt_clear_una_dna(struct s_smc *smc);
+static void smt_clear_una_dna(struct s_smc *smc);
 static void smt_clear_old_una_dna(struct s_smc *smc);
 #ifdef CONCENTRATOR
 static int entity_to_index(void);
@@ -118,7 +118,7 @@ static int entity_to_index(void);
 static void update_dac(struct s_smc *smc, int report);
 static int div_ratio(u_long upper, u_long lower);
 #ifdef  USE_CAN_ADDR
-void   hwm_conv_can(struct s_smc *smc, char *data, int len);
+static void    hwm_conv_can(struct s_smc *smc, char *data, int len);
 #else
 #define                hwm_conv_can(smc,data,len)
 #endif
@@ -216,24 +216,6 @@ void smt_agent_task(struct s_smc *smc)
        DB_SMT("SMT agent task\n",0,0) ;
 }
 
-void smt_please_reconnect(struct s_smc *smc, int reconn_time)
-/* struct s_smc        *smc;  Pointer to SMT context */
-/* int reconn_time;    Wait for reconnect time in seconds */
-{
-       /*
-        * The please reconnect variable is used as a timer.
-        * It is decremented each time smt_event is called.
-        * This happens every second or when smt_force_irq is called.
-        * Note: smt_force_irq () is called on some packet receives and
-        *       when a multicast address is changed. Since nothing
-        *       is received during the disconnect and the multicast
-        *       address changes can be viewed as not very often and
-        *       the timer runs out close to its given value
-        *       (reconn_time).
-        */
-       smc->sm.please_reconnect = reconn_time ;
-}
-
 #ifndef SMT_REAL_TOKEN_CT
 void smt_emulate_token_ct(struct s_smc *smc, int mac_index)
 {
@@ -1574,7 +1556,7 @@ static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long see
  * clear DNA and UNA
  * called from CFM if configuration changes
  */
-void smt_clear_una_dna(struct s_smc *smc)
+static void smt_clear_una_dna(struct s_smc *smc)
 {
        smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ;
        smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ;
@@ -2057,31 +2039,11 @@ int smt_action(struct s_smc *smc, int class, int code, int index)
        return(0) ;
 }
 
-/*
- * change tneg
- *     set T_Req in MIB (Path Attribute)
- *     calculate new values for MAC
- *     if change required
- *             disconnect
- *             set reconnect
- *     end
- */
-void smt_change_t_neg(struct s_smc *smc, u_long tneg)
-{
-       smc->mib.a[PATH0].fddiPATHMaxT_Req = tneg ;
-
-       if (smt_set_mac_opvalues(smc)) {
-               RS_SET(smc,RS_EVENT) ;
-               smc->sm.please_reconnect = 1 ;
-               queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
-       }
-}
-
 /*
  * canonical conversion of <len> bytes beginning form *data
  */
 #ifdef  USE_CAN_ADDR
-void hwm_conv_can(struct s_smc *smc, char *data, int len)
+static void hwm_conv_can(struct s_smc *smc, char *data, int len)
 {
        int i ;
 
index 5a0c8db816d8194042ee3f2b667b9cafed8fb3d7..4e07ff7073f1141f209c0773f16c0972261c260a 100644 (file)
@@ -76,11 +76,6 @@ void smt_reset_defaults(struct s_smc *smc, int level);
 static void smt_init_mib(struct s_smc *smc, int level);
 static int set_min_max(int maxflag, u_long mib, u_long limit, u_long *oper);
 
-void smt_set_defaults(struct s_smc *smc)
-{
-       smt_reset_defaults(smc,0) ;
-}
-
 #define MS2BCLK(x)     ((x)*12500L)
 #define US2BCLK(x)     ((x)*1250L)
 
diff --git a/drivers/net/skfp/smtparse.c b/drivers/net/skfp/smtparse.c
deleted file mode 100644 (file)
index d5779e4..0000000
+++ /dev/null
@@ -1,467 +0,0 @@
-/******************************************************************************
- *
- *     (C)Copyright 1998,1999 SysKonnect,
- *     a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- *     See the file "skfddi.c" for further information.
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     The information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-
-/*
-       parser for SMT parameters
-*/
-
-#include "h/types.h"
-#include "h/fddi.h"
-#include "h/smc.h"
-#include "h/smt_p.h"
-
-#define KERNEL
-#include "h/smtstate.h"
-
-#ifndef        lint
-static const char ID_sccs[] = "@(#)smtparse.c  1.12 98/10/06 (C) SK " ;
-#endif
-
-#ifdef sun
-#define _far
-#endif
-
-/*
- * convert to BCLK units
- */
-#define MS2BCLK(x)      ((x)*12500L)
-#define US2BCLK(x)      ((x/10)*125L)
-
-/*
- * parameter table
- */
-static struct s_ptab {
-       char    *pt_name ;
-       u_short pt_num ;
-       u_short pt_type ;
-       u_long  pt_min ;
-       u_long  pt_max ;
-} ptab[] = {
-       { "PMFPASSWD",0,        0 } ,
-       { "USERDATA",1,         0 } ,
-       { "LERCUTOFFA",2,       1,      4,      15      } ,
-       { "LERCUTOFFB",3,       1,      4,      15      } ,
-       { "LERALARMA",4,        1,      4,      15      } ,
-       { "LERALARMB",5,        1,      4,      15      } ,
-       { "TMAX",6,             1,      5,      165     } ,
-       { "TMIN",7,             1,      5,      165     } ,
-       { "TREQ",8,             1,      5,      165     } ,
-       { "TVX",9,              1,      2500,   10000   } ,
-#ifdef ESS
-       { "SBAPAYLOAD",10,      1,      0,      1562    } ,
-       { "SBAOVERHEAD",11,     1,      50,     5000    } ,
-       { "MAXTNEG",12,         1,      5,      165     } ,
-       { "MINSEGMENTSIZE",13,  1,      0,      4478    } ,
-       { "SBACATEGORY",14,     1,      0,      0xffff  } ,
-       { "SYNCHTXMODE",15,     0 } ,
-#endif
-#ifdef SBA
-       { "SBACOMMAND",16,      0 } ,
-       { "SBAAVAILABLE",17,    1,      0,      100     } ,
-#endif
-       { NULL }
-} ;
-
-/* Define maximum string size for values and keybuffer */
-#define MAX_VAL        40
-
-/*
- * local function declarations
- */
-static u_long parse_num(int type, char _far *value, char *v, u_long mn,
-                       u_long mx, int scale);
-static int parse_word(char *buf, char _far *text);
-
-#ifdef SIM
-#define DB_MAIN(a,b,c) printf(a,b,c)
-#else
-#define DB_MAIN(a,b,c)
-#endif
-
-/*
- * BEGIN_MANUAL_ENTRY()
- *
- *     int smt_parse_arg(struct s_smc *,char _far *keyword,int type,
-               char _far *value)
- *
- *     parse SMT parameter
- *     *keyword
- *             pointer to keyword, must be \0, \n or \r terminated
- *     *value  pointer to value, either char * or u_long *
- *             if char *
- *                     pointer to value, must be \0, \n or \r terminated
- *             if u_long *
- *                     contains binary value
- *
- *     type    0: integer
- *             1: string
- *     return
- *             0       parameter parsed ok
- *             != 0    error
- *     NOTE:
- *             function can be called with DS != SS
- *
- *
- * END_MANUAL_ENTRY()
- */
-int smt_parse_arg(struct s_smc *smc, char _far *keyword, int type,
-                 char _far *value)
-{
-       char            keybuf[MAX_VAL+1];
-       char            valbuf[MAX_VAL+1];
-       char            c ;
-       char            *p ;
-       char            *v ;
-       char            *d ;
-       u_long          val = 0 ;
-       struct s_ptab   *pt ;
-       int             st ;
-       int             i ;
-
-       /*
-        * parse keyword
-        */
-       if ((st = parse_word(keybuf,keyword)))
-               return(st) ;
-       /*
-        * parse value if given as string
-        */
-       if (type == 1) {
-               if ((st = parse_word(valbuf,value)))
-                       return(st) ;
-       }
-       /*
-        * search in table
-        */
-       st = 0 ;
-       for (pt = ptab ; (v = pt->pt_name) ; pt++) {
-               for (p = keybuf ; (c = *p) ; p++,v++) {
-                       if (c != *v)
-                               break ;
-               }
-               if (!c && !*v)
-                       break ;
-       }
-       if (!v)
-               return(-1) ;
-#if    0
-       printf("=>%s<==>%s<=\n",pt->pt_name,valbuf) ;
-#endif
-       /*
-        * set value in MIB
-        */
-       if (pt->pt_type)
-               val = parse_num(type,value,valbuf,pt->pt_min,pt->pt_max,1) ;
-       switch (pt->pt_num) {
-       case 0 :
-               v = valbuf ;
-               d = (char *) smc->mib.fddiPRPMFPasswd ;
-               for (i = 0 ; i < (signed)sizeof(smc->mib.fddiPRPMFPasswd) ; i++)
-                       *d++ = *v++ ;
-               DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiPRPMFPasswd) ;
-               break ;
-       case 1 :
-               v = valbuf ;
-               d = (char *) smc->mib.fddiSMTUserData ;
-               for (i = 0 ; i < (signed)sizeof(smc->mib.fddiSMTUserData) ; i++)
-                       *d++ = *v++ ;
-               DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiSMTUserData) ;
-               break ;
-       case 2 :
-               smc->mib.p[PA].fddiPORTLer_Cutoff = (u_char) val ;
-               DB_MAIN("SET %s = %d\n",
-                       pt->pt_name,smc->mib.p[PA].fddiPORTLer_Cutoff) ;
-               break ;
-       case 3 :
-               smc->mib.p[PB].fddiPORTLer_Cutoff = (u_char) val ;
-               DB_MAIN("SET %s = %d\n",
-                       pt->pt_name,smc->mib.p[PB].fddiPORTLer_Cutoff) ;
-               break ;
-       case 4 :
-               smc->mib.p[PA].fddiPORTLer_Alarm = (u_char) val ;
-               DB_MAIN("SET %s = %d\n",
-                       pt->pt_name,smc->mib.p[PA].fddiPORTLer_Alarm) ;
-               break ;
-       case 5 :
-               smc->mib.p[PB].fddiPORTLer_Alarm = (u_char) val ;
-               DB_MAIN("SET %s = %d\n",
-                       pt->pt_name,smc->mib.p[PB].fddiPORTLer_Alarm) ;
-               break ;
-       case 6 :                        /* TMAX */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.a[PATH0].fddiPATHT_MaxLowerBound =
-                       (u_long) -MS2BCLK((long)val) ;
-               break ;
-       case 7 :                        /* TMIN */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.m[MAC0].fddiMACT_Min =
-                       (u_long) -MS2BCLK((long)val) ;
-               break ;
-       case 8 :                        /* TREQ */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.a[PATH0].fddiPATHMaxT_Req =
-                       (u_long) -MS2BCLK((long)val) ;
-               break ;
-       case 9 :                        /* TVX */
-               DB_MAIN("SET %s = %d \n",pt->pt_name,val) ;
-               smc->mib.a[PATH0].fddiPATHTVXLowerBound =
-                       (u_long) -US2BCLK((long)val) ;
-               break ;
-#ifdef ESS
-       case 10 :                       /* SBAPAYLOAD */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               if (smc->mib.fddiESSPayload != val) {
-                       smc->ess.raf_act_timer_poll = TRUE ;
-                       smc->mib.fddiESSPayload = val ;
-               }
-               break ;
-       case 11 :                       /* SBAOVERHEAD */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.fddiESSOverhead = val ;
-               break ;
-       case 12 :                       /* MAXTNEG */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.fddiESSMaxTNeg = (u_long) -MS2BCLK((long)val) ;
-               break ;
-       case 13 :                       /* MINSEGMENTSIZE */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.fddiESSMinSegmentSize = val ;
-               break ;
-       case 14 :                       /* SBACATEGORY */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.fddiESSCategory =
-                       (smc->mib.fddiESSCategory & 0xffff) |
-                       ((u_long)(val << 16)) ;
-               break ;
-       case 15 :                       /* SYNCHTXMODE */
-               /* do not use memcmp(valbuf,"ALL",3) because DS != SS */
-               if (valbuf[0] == 'A' && valbuf[1] == 'L' && valbuf[2] == 'L') {
-                       smc->mib.fddiESSSynchTxMode = TRUE ;
-                       DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
-               }
-               /* if (!memcmp(valbuf,"SPLIT",5)) { */
-               if (valbuf[0] == 'S' && valbuf[1] == 'P' && valbuf[2] == 'L' &&
-                       valbuf[3] == 'I' && valbuf[4] == 'T') {
-                       DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
-                       smc->mib.fddiESSSynchTxMode = FALSE ;
-               }
-               break ;
-#endif
-#ifdef SBA
-       case 16 :                       /* SBACOMMAND */
-               /* if (!memcmp(valbuf,"START",5)) { */
-               if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'A' &&
-                       valbuf[3] == 'R' && valbuf[4] == 'T') {
-                       DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
-                       smc->mib.fddiSBACommand = SB_START ;
-               }
-               /* if (!memcmp(valbuf,"STOP",4)) { */
-               if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'O' &&
-                       valbuf[3] == 'P') {
-                       DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
-                       smc->mib.fddiSBACommand = SB_STOP ;
-               }
-               break ;
-       case 17 :                       /* SBAAVAILABLE */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.fddiSBAAvailable = (u_char) val ;
-               break ;
-#endif
-       }
-       return(0) ;
-}
-
-static int parse_word(char *buf, char _far *text)
-{
-       char            c ;
-       char            *p ;
-       int             p_len ;
-       int             quote ;
-       int             i ;
-       int             ok ;
-
-       /*
-        * skip leading white space
-        */
-       p = buf ;
-       for (i = 0 ; i < MAX_VAL ; i++)
-               *p++ = 0 ;
-       p = buf ;
-       p_len = 0 ;
-       ok = 0 ;
-       while ( (c = *text++) && (c != '\n') && (c != '\r')) {
-               if ((c != ' ') && (c != '\t')) {
-                       ok = 1 ;
-                       break ;
-               }
-       }
-       if (!ok)
-               return(-1) ;
-       if (c == '"') {
-               quote = 1 ;
-       }
-       else {
-               quote = 0 ;
-               text-- ;
-       }
-       /*
-        * parse valbuf
-        */
-       ok = 0 ;
-       while (!ok && p_len < MAX_VAL-1 && (c = *text++) && (c != '\n')
-               && (c != '\r')) {
-               switch (quote) {
-               case 0 :
-                       if ((c == ' ') || (c == '\t') || (c == '=')) {
-                               ok = 1 ;
-                               break ;
-                       }
-                       *p++ = c ;
-                       p_len++ ;
-                       break ;
-               case 2 :
-                       *p++ = c ;
-                       p_len++ ;
-                       quote = 1 ;
-                       break ;
-               case 1 :
-                       switch (c) {
-                       case '"' :
-                               ok = 1 ;
-                               break ;
-                       case '\\' :
-                               quote = 2 ;
-                               break ;
-                       default :
-                               *p++ = c ;
-                               p_len++ ;
-                       }
-               }
-       }
-       *p++ = 0 ;
-       for (p = buf ; (c = *p) ; p++) {
-               if (c >= 'a' && c <= 'z')
-                       *p = c + 'A' - 'a' ;
-       }
-       return(0) ;
-}
-
-static u_long parse_num(int type, char _far *value, char *v, u_long mn,
-                       u_long mx, int scale)
-{
-       u_long  x = 0 ;
-       char    c ;
-
-       if (type == 0) {                /* integer */
-               u_long _far     *l ;
-               u_long          u1 ;
-
-               l = (u_long _far *) value ;
-               u1 = *l ;
-               /*
-                * if the value is negative take the lower limit
-                */
-               if ((long)u1 < 0) {
-                       if (- ((long)u1) > (long) mx) {
-                               u1 = 0 ;
-                       }
-                       else {
-                               u1 = (u_long) - ((long)u1) ;
-                       }
-               }
-               x = u1 ;
-       }
-       else {                          /* string */
-               int     sign = 0 ;
-
-               if (*v == '-') {
-                       sign = 1 ;
-               }
-               while ((c = *v++) && (c >= '0') && (c <= '9')) {
-                       x = x * 10 + c - '0' ;
-               }
-               if (scale == 10) {
-                       x *= 10 ;
-                       if (c == '.') {
-                               if ((c = *v++) && (c >= '0') && (c <= '9')) {
-                                       x += c - '0' ;
-                               }
-                       }
-               }
-               if (sign)
-                       x = (u_long) - ((long)x) ;
-       }
-       /*
-        * if the value is negative
-        *      and the absolute value is outside the limits
-        *              take the lower limit
-        *      else
-        *              take the absoute value
-        */
-       if ((long)x < 0) {
-               if (- ((long)x) > (long) mx) {
-                       x = 0 ;
-               }
-               else {
-                       x = (u_long) - ((long)x) ;
-               }
-       }
-       if (x < mn)
-               return(mn) ;
-       else if (x > mx)
-               return(mx) ;
-       return(x) ;
-}
-
-#if 0
-struct s_smc   SMC ;
-main()
-{
-       char    *p ;
-       char    *v ;
-       char    buf[100] ;
-       int     toggle = 0 ;
-
-       while (gets(buf)) {
-               p = buf ;
-               while (*p && ((*p == ' ') || (*p == '\t')))
-                       p++ ;
-
-               while (*p && ((*p != ' ') && (*p != '\t')))
-                       p++ ;
-
-               v = p ;
-               while (*v && ((*v == ' ') || (*v == '\t')))
-                       v++ ;
-               if ((*v >= '0') && (*v <= '9')) {
-                       toggle = !toggle ;
-                       if (toggle) {
-                               u_long  l ;
-                               l = atol(v) ;
-                               smt_parse_arg(&SMC,buf,0,(char _far *)&l) ;
-                       }
-                       else
-                               smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
-               }
-               else {
-                       smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
-               }
-       }
-       exit(0) ;
-}
-#endif
-
index 30e8d589d167b58684ac6e786dc546991ac75d30..3dbb1cb09ed823d99c669a409f17f0b42570059b 100644 (file)
@@ -7,7 +7,7 @@
  * of the original driver such as link fail-over and link management because
  * those should be done at higher levels.
  *
- * Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org>
+ * Copyright (C) 2004, 2005 Stephen Hemminger <shemminger@osdl.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
 #include "skge.h"
 
 #define DRV_NAME               "skge"
-#define DRV_VERSION            "0.6"
+#define DRV_VERSION            "0.7"
 #define PFX                    DRV_NAME " "
 
 #define DEFAULT_TX_RING_SIZE   128
 #define DEFAULT_RX_RING_SIZE   512
 #define MAX_TX_RING_SIZE       1024
 #define MAX_RX_RING_SIZE       4096
+#define RX_COPY_THRESHOLD      128
+#define RX_BUF_SIZE            1536
 #define PHY_RETRIES            1000
 #define ETH_JUMBO_MTU          9000
 #define TX_WATCHDOG            (5 * HZ)
 #define NAPI_WEIGHT            64
 #define BLINK_HZ               (HZ/4)
-#define LINK_POLL_HZ           (HZ/10)
 
 MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
 MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
@@ -70,28 +71,17 @@ module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
 static const struct pci_device_id skge_id_table[] = {
-       { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940,
-         PCI_ANY_ID, PCI_ANY_ID },
-       { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B,
-         PCI_ANY_ID, PCI_ANY_ID },
-       { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE,
-         PCI_ANY_ID, PCI_ANY_ID },
-       { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU,
-         PCI_ANY_ID, PCI_ANY_ID },
-       { PCI_VENDOR_ID_SYSKONNECT, 0x9E00, /* SK-9Exx  */
-         PCI_ANY_ID, PCI_ANY_ID },
-       { PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T,
-         PCI_ANY_ID, PCI_ANY_ID },
-       { PCI_VENDOR_ID_MARVELL, 0x4320, /* Gigabit Ethernet Controller */
-         PCI_ANY_ID, PCI_ANY_ID },
-       { PCI_VENDOR_ID_MARVELL, 0x5005, /* Marvell (11ab), Belkin */
-         PCI_ANY_ID, PCI_ANY_ID },
-       { PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD,
-         PCI_ANY_ID, PCI_ANY_ID },
-       { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032,
-         PCI_ANY_ID, PCI_ANY_ID },
-       { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064,
-         PCI_ANY_ID, PCI_ANY_ID },
+       { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940) },
+       { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B) },
+       { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) },
+       { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) },
+       { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, /* SK-9Exx  */
+       { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), },
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) },
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */
+       { PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) },
+       { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032) },
+       { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064) },
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, skge_id_table);
@@ -99,19 +89,22 @@ MODULE_DEVICE_TABLE(pci, skge_id_table);
 static int skge_up(struct net_device *dev);
 static int skge_down(struct net_device *dev);
 static void skge_tx_clean(struct skge_port *skge);
-static void skge_xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
-static void skge_gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
 static void genesis_get_stats(struct skge_port *skge, u64 *data);
 static void yukon_get_stats(struct skge_port *skge, u64 *data);
 static void yukon_init(struct skge_hw *hw, int port);
 static void yukon_reset(struct skge_hw *hw, int port);
 static void genesis_mac_init(struct skge_hw *hw, int port);
 static void genesis_reset(struct skge_hw *hw, int port);
+static void genesis_link_up(struct skge_port *skge);
 
+/* Avoid conditionals by using array */
 static const int txqaddr[] = { Q_XA1, Q_XA2 };
 static const int rxqaddr[] = { Q_R1, Q_R2 };
 static const u32 rxirqmask[] = { IS_R1_F, IS_R2_F };
 static const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F };
+static const u32 portirqmask[] = { IS_PORT_1, IS_PORT_2 };
 
 /* Don't need to look at whole 16K.
  * last interesting register is descriptor poll timer.
@@ -154,7 +147,7 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs,
 static int wol_supported(const struct skge_hw *hw)
 {
        return !((hw->chip_id == CHIP_ID_GENESIS ||
-                 (hw->chip_id == CHIP_ID_YUKON && chip_rev(hw) == 0)));
+                 (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)));
 }
 
 static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -170,7 +163,7 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        struct skge_port *skge = netdev_priv(dev);
        struct skge_hw *hw = skge->hw;
 
-       if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
+       if (wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
                return -EOPNOTSUPP;
 
        if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw))
@@ -190,6 +183,36 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        return 0;
 }
 
+/* Determine supported/adverised modes based on hardware.
+ * Note: ethtoool ADVERTISED_xxx == SUPPORTED_xxx
+ */
+static u32 skge_supported_modes(const struct skge_hw *hw)
+{
+       u32 supported;
+
+       if (iscopper(hw)) {
+               supported = SUPPORTED_10baseT_Half
+                       | SUPPORTED_10baseT_Full
+                       | SUPPORTED_100baseT_Half
+                       | SUPPORTED_100baseT_Full
+                       | SUPPORTED_1000baseT_Half
+                       | SUPPORTED_1000baseT_Full
+                       | SUPPORTED_Autoneg| SUPPORTED_TP;
+
+               if (hw->chip_id == CHIP_ID_GENESIS)
+                       supported &= ~(SUPPORTED_10baseT_Half
+                                            | SUPPORTED_10baseT_Full
+                                            | SUPPORTED_100baseT_Half
+                                            | SUPPORTED_100baseT_Full);
+
+               else if (hw->chip_id == CHIP_ID_YUKON)
+                       supported &= ~SUPPORTED_1000baseT_Half;
+       } else
+               supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE
+                       | SUPPORTED_Autoneg;
+
+       return supported;
+}
 
 static int skge_get_settings(struct net_device *dev,
                             struct ethtool_cmd *ecmd)
@@ -198,38 +221,13 @@ static int skge_get_settings(struct net_device *dev,
        struct skge_hw *hw = skge->hw;
 
        ecmd->transceiver = XCVR_INTERNAL;
+       ecmd->supported = skge_supported_modes(hw);
 
        if (iscopper(hw)) {
-               if (hw->chip_id == CHIP_ID_GENESIS)
-                       ecmd->supported = SUPPORTED_1000baseT_Full
-                               | SUPPORTED_1000baseT_Half
-                               | SUPPORTED_Autoneg | SUPPORTED_TP;
-               else {
-                       ecmd->supported = SUPPORTED_10baseT_Half
-                               | SUPPORTED_10baseT_Full
-                               | SUPPORTED_100baseT_Half
-                               | SUPPORTED_100baseT_Full
-                               | SUPPORTED_1000baseT_Half
-                               | SUPPORTED_1000baseT_Full
-                               | SUPPORTED_Autoneg| SUPPORTED_TP;
-
-                       if (hw->chip_id == CHIP_ID_YUKON)
-                               ecmd->supported &= ~SUPPORTED_1000baseT_Half;
-
-                       else if (hw->chip_id == CHIP_ID_YUKON_FE)
-                               ecmd->supported &= ~(SUPPORTED_1000baseT_Half
-                                                    | SUPPORTED_1000baseT_Full);
-               }
-
                ecmd->port = PORT_TP;
                ecmd->phy_address = hw->phy_addr;
-       } else {
-               ecmd->supported = SUPPORTED_1000baseT_Full
-                       | SUPPORTED_FIBRE
-                       | SUPPORTED_Autoneg;
-
+       } else
                ecmd->port = PORT_FIBRE;
-       }
 
        ecmd->advertising = skge->advertising;
        ecmd->autoneg = skge->autoneg;
@@ -238,65 +236,57 @@ static int skge_get_settings(struct net_device *dev,
        return 0;
 }
 
-static u32 skge_modes(const struct skge_hw *hw)
-{
-       u32 modes = ADVERTISED_Autoneg
-               | ADVERTISED_1000baseT_Full | ADVERTISED_1000baseT_Half
-               | ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half
-               | ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half;
-
-       if (iscopper(hw)) {
-               modes |= ADVERTISED_TP;
-               switch(hw->chip_id) {
-               case CHIP_ID_GENESIS:
-                       modes &= ~(ADVERTISED_100baseT_Full
-                                  | ADVERTISED_100baseT_Half
-                                  | ADVERTISED_10baseT_Full
-                                  | ADVERTISED_10baseT_Half);
-                       break;
-
-               case CHIP_ID_YUKON:
-                       modes &= ~ADVERTISED_1000baseT_Half;
-                       break;
-
-               case CHIP_ID_YUKON_FE:
-                       modes &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
-                       break;
-               }
-       } else {
-               modes |= ADVERTISED_FIBRE;
-               modes &= ~ADVERTISED_1000baseT_Half;
-       }
-       return modes;
-}
-
 static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
        struct skge_port *skge = netdev_priv(dev);
        const struct skge_hw *hw = skge->hw;
+       u32 supported = skge_supported_modes(hw);
 
        if (ecmd->autoneg == AUTONEG_ENABLE) {
-               if (ecmd->advertising & skge_modes(hw))
-                       return -EINVAL;
+               ecmd->advertising = supported;
+               skge->duplex = -1;
+               skge->speed = -1;
        } else {
+               u32 setting;
+
                switch(ecmd->speed) {
                case SPEED_1000:
-                       if (hw->chip_id == CHIP_ID_YUKON_FE)
+                       if (ecmd->duplex == DUPLEX_FULL)
+                               setting = SUPPORTED_1000baseT_Full;
+                       else if (ecmd->duplex == DUPLEX_HALF)
+                               setting = SUPPORTED_1000baseT_Half;
+                       else
                                return -EINVAL;
                        break;
                case SPEED_100:
+                       if (ecmd->duplex == DUPLEX_FULL)
+                               setting = SUPPORTED_100baseT_Full;
+                       else if (ecmd->duplex == DUPLEX_HALF)
+                               setting = SUPPORTED_100baseT_Half;
+                       else
+                               return -EINVAL;
+                       break;
+
                case SPEED_10:
-                       if (iscopper(hw) || hw->chip_id == CHIP_ID_GENESIS)
+                       if (ecmd->duplex == DUPLEX_FULL)
+                               setting = SUPPORTED_10baseT_Full;
+                       else if (ecmd->duplex == DUPLEX_HALF)
+                               setting = SUPPORTED_10baseT_Half;
+                       else
                                return -EINVAL;
                        break;
                default:
                        return -EINVAL;
                }
+
+               if ((setting & supported) == 0)
+                       return -EINVAL;
+
+               skge->speed = ecmd->speed;
+               skge->duplex = ecmd->duplex;
        }
 
        skge->autoneg = ecmd->autoneg;
-       skge->speed = ecmd->speed;
-       skge->duplex = ecmd->duplex;
        skge->advertising = ecmd->advertising;
 
        if (netif_running(dev)) {
@@ -393,7 +383,7 @@ static void skge_get_strings(struct net_device *dev, u32 stringset, u8 *data)
 {
        int i;
 
-       switch(stringset) {
+       switch (stringset) {
        case ETH_SS_STATS:
                for (i = 0; i < ARRAY_SIZE(skge_stats); i++)
                        memcpy(data + i * ETH_GSTRING_LEN,
@@ -511,14 +501,6 @@ static int skge_set_rx_csum(struct net_device *dev, u32 data)
        return 0;
 }
 
-/* Only Yukon II supports TSO (not implemented yet) */
-static int skge_set_tso(struct net_device *dev, u32 data)
-{
-       if (data)
-               return -EOPNOTSUPP;
-       return 0;
-}
-
 static void skge_get_pauseparam(struct net_device *dev,
                                struct ethtool_pauseparam *ecmd)
 {
@@ -540,9 +522,9 @@ static int skge_set_pauseparam(struct net_device *dev,
        skge->autoneg = ecmd->autoneg;
        if (ecmd->rx_pause && ecmd->tx_pause)
                skge->flow_control = FLOW_MODE_SYMMETRIC;
-       else if(ecmd->rx_pause && !ecmd->tx_pause)
+       else if (ecmd->rx_pause && !ecmd->tx_pause)
                skge->flow_control = FLOW_MODE_REM_SEND;
-       else if(!ecmd->rx_pause && ecmd->tx_pause)
+       else if (!ecmd->rx_pause && ecmd->tx_pause)
                skge->flow_control = FLOW_MODE_LOC_SEND;
        else
                skge->flow_control = FLOW_MODE_NONE;
@@ -559,8 +541,6 @@ static inline u32 hwkhz(const struct skge_hw *hw)
 {
        if (hw->chip_id == CHIP_ID_GENESIS)
                return 53215; /* or:  53.125 MHz */
-       else if (hw->chip_id == CHIP_ID_YUKON_EC)
-               return 125000; /* or: 125.000 MHz */
        else
                return 78215; /* or:  78.125 MHz */
 }
@@ -643,30 +623,18 @@ static int skge_set_coalesce(struct net_device *dev,
 static void skge_led_on(struct skge_hw *hw, int port)
 {
        if (hw->chip_id == CHIP_ID_GENESIS) {
-               skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_ON);
+               skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON);
                skge_write8(hw, B0_LED, LED_STAT_ON);
 
-               skge_write8(hw, SKGEMAC_REG(port, RX_LED_TST), LED_T_ON);
-               skge_write32(hw, SKGEMAC_REG(port, RX_LED_VAL), 100);
-               skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_START);
+               skge_write8(hw, SK_REG(port, RX_LED_TST), LED_T_ON);
+               skge_write32(hw, SK_REG(port, RX_LED_VAL), 100);
+               skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
 
-               switch (hw->phy_type) {
-               case SK_PHY_BCOM:
-                       skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL,
-                                         PHY_B_PEC_LED_ON);
-                       break;
-               case SK_PHY_LONE:
-                       skge_xm_phy_write(hw, port, PHY_LONE_LED_CFG,
-                                         0x0800);
-                       break;
-               default:
-                       skge_write8(hw, SKGEMAC_REG(port, TX_LED_TST), LED_T_ON);
-                       skge_write32(hw, SKGEMAC_REG(port, TX_LED_VAL), 100);
-                       skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_START);
-               }
+               /* For Broadcom Phy only */
+               xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
        } else {
-               skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
-               skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER,
+               gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
+               gm_phy_write(hw, port, PHY_MARV_LED_OVER,
                                  PHY_M_LED_MO_DUP(MO_LED_ON)  |
                                  PHY_M_LED_MO_10(MO_LED_ON)   |
                                  PHY_M_LED_MO_100(MO_LED_ON)  |
@@ -678,28 +646,17 @@ static void skge_led_on(struct skge_hw *hw, int port)
 static void skge_led_off(struct skge_hw *hw, int port)
 {
        if (hw->chip_id == CHIP_ID_GENESIS) {
-               skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_OFF);
+               skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
                skge_write8(hw, B0_LED, LED_STAT_OFF);
 
-               skge_write32(hw, SKGEMAC_REG(port, RX_LED_VAL), 0);
-               skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_T_OFF);
+               skge_write32(hw, SK_REG(port, RX_LED_VAL), 0);
+               skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF);
 
-               switch (hw->phy_type) {
-               case SK_PHY_BCOM:
-                       skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL,
-                                         PHY_B_PEC_LED_OFF);
-                       break;
-               case SK_PHY_LONE:
-                       skge_xm_phy_write(hw, port, PHY_LONE_LED_CFG,
-                                         PHY_L_LC_LEDT);
-                       break;
-               default:
-                       skge_write32(hw, SKGEMAC_REG(port, TX_LED_VAL), 0);
-                       skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_T_OFF);
-               }
+               /* Broadcom only */
+               xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
        } else {
-               skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
-               skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER,
+               gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
+               gm_phy_write(hw, port, PHY_MARV_LED_OVER,
                                  PHY_M_LED_MO_DUP(MO_LED_OFF)  |
                                  PHY_M_LED_MO_10(MO_LED_OFF)   |
                                  PHY_M_LED_MO_100(MO_LED_OFF)  |
@@ -730,7 +687,7 @@ static int skge_phys_id(struct net_device *dev, u32 data)
 {
        struct skge_port *skge = netdev_priv(dev);
 
-       if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+       if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
                data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
 
        /* start blinking */
@@ -763,8 +720,6 @@ static struct ethtool_ops skge_ethtool_ops = {
        .set_pauseparam = skge_set_pauseparam,
        .get_coalesce   = skge_get_coalesce,
        .set_coalesce   = skge_set_coalesce,
-       .get_tso        = ethtool_op_get_tso,
-       .set_tso        = skge_set_tso,
        .get_sg         = ethtool_op_get_sg,
        .set_sg         = skge_set_sg,
        .get_tx_csum    = ethtool_op_get_tx_csum,
@@ -793,6 +748,7 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base)
 
        for (i = 0, e = ring->start, d = vaddr; i < ring->count; i++, e++, d++) {
                e->desc = d;
+               e->skb = NULL;
                if (i == ring->count - 1) {
                        e->next = ring->start;
                        d->next_offset = base;
@@ -806,24 +762,23 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base)
        return 0;
 }
 
-/* Setup buffer for receiving */
-static inline int skge_rx_alloc(struct skge_port *skge,
-                               struct skge_element *e)
+static struct sk_buff *skge_rx_alloc(struct net_device *dev, unsigned int size)
 {
-       unsigned long bufsize = skge->netdev->mtu + ETH_HLEN; /* VLAN? */
-       struct skge_rx_desc *rd = e->desc;
-       struct sk_buff *skb;
-       u64 map;
+       struct sk_buff *skb = dev_alloc_skb(size);
 
-       skb = dev_alloc_skb(bufsize + NET_IP_ALIGN);
-       if (unlikely(!skb)) {
-               printk(KERN_DEBUG PFX "%s: out of memory for receive\n",
-                      skge->netdev->name);
-               return -ENOMEM;
+       if (likely(skb)) {
+               skb->dev = dev;
+               skb_reserve(skb, NET_IP_ALIGN);
        }
+       return skb;
+}
 
-       skb->dev = skge->netdev;
-       skb_reserve(skb, NET_IP_ALIGN);
+/* Allocate and setup a new buffer for receiving */
+static void skge_rx_setup(struct skge_port *skge, struct skge_element *e,
+                         struct sk_buff *skb, unsigned int bufsize)
+{
+       struct skge_rx_desc *rd = e->desc;
+       u64 map;
 
        map = pci_map_single(skge->hw->pdev, skb->data, bufsize,
                             PCI_DMA_FROMDEVICE);
@@ -841,55 +796,69 @@ static inline int skge_rx_alloc(struct skge_port *skge,
        rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize;
        pci_unmap_addr_set(e, mapaddr, map);
        pci_unmap_len_set(e, maplen, bufsize);
-       return 0;
 }
 
-/* Free all unused buffers in receive ring, assumes receiver stopped */
+/* Resume receiving using existing skb,
+ * Note: DMA address is not changed by chip.
+ *      MTU not changed while receiver active.
+ */
+static void skge_rx_reuse(struct skge_element *e, unsigned int size)
+{
+       struct skge_rx_desc *rd = e->desc;
+
+       rd->csum2 = 0;
+       rd->csum2_start = ETH_HLEN;
+
+       wmb();
+
+       rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | size;
+}
+
+
+/* Free all  buffers in receive ring, assumes receiver stopped */
 static void skge_rx_clean(struct skge_port *skge)
 {
        struct skge_hw *hw = skge->hw;
        struct skge_ring *ring = &skge->rx_ring;
        struct skge_element *e;
 
-       for (e = ring->to_clean; e != ring->to_use; e = e->next) {
+       e = ring->start;
+       do {
                struct skge_rx_desc *rd = e->desc;
                rd->control = 0;
-
-               pci_unmap_single(hw->pdev,
-                                pci_unmap_addr(e, mapaddr),
-                                pci_unmap_len(e, maplen),
-                                PCI_DMA_FROMDEVICE);
-               dev_kfree_skb(e->skb);
-               e->skb = NULL;
-       }
-       ring->to_clean = e;
+               if (e->skb) {
+                       pci_unmap_single(hw->pdev,
+                                        pci_unmap_addr(e, mapaddr),
+                                        pci_unmap_len(e, maplen),
+                                        PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb(e->skb);
+                       e->skb = NULL;
+               }
+       } while ((e = e->next) != ring->start);
 }
 
+
 /* Allocate buffers for receive ring
- * For receive: to_use   is refill location
- *              to_clean is next received frame.
- *
- * if (to_use == to_clean)
- *      then ring all frames in ring need buffers
- * if (to_use->next == to_clean)
- *      then ring all frames in ring have buffers
+ * For receive:  to_clean is next received frame.
  */
 static int skge_rx_fill(struct skge_port *skge)
 {
        struct skge_ring *ring = &skge->rx_ring;
        struct skge_element *e;
-       int ret = 0;
+       unsigned int bufsize = skge->rx_buf_size;
 
-       for (e = ring->to_use; e->next != ring->to_clean; e = e->next) {
-               if (skge_rx_alloc(skge, e)) {
-                       ret = 1;
-                       break;
-               }
+       e = ring->start;
+       do {
+               struct sk_buff *skb = skge_rx_alloc(skge->netdev, bufsize);
 
-       }
-       ring->to_use = e;
+               if (!skb)
+                       return -ENOMEM;
+
+               skge_rx_setup(skge, e, skb, bufsize);
+       } while ( (e = e->next) != ring->start);
 
-       return ret;
+       ring->to_clean = ring->start;
+       return 0;
 }
 
 static void skge_link_up(struct skge_port *skge)
@@ -919,50 +888,50 @@ static void skge_link_down(struct skge_port *skge)
                printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name);
 }
 
-static u16 skge_xm_phy_read(struct skge_hw *hw, int port,  u16 reg)
+static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg)
 {
        int i;
        u16 v;
 
-       skge_xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
-       v = skge_xm_read16(hw, port, XM_PHY_DATA);
-       if (hw->phy_type != SK_PHY_XMAC) {
-               for (i = 0; i < PHY_RETRIES; i++) {
-                       udelay(1);
-                       if (skge_xm_read16(hw, port, XM_MMU_CMD)
-                           & XM_MMU_PHY_RDY)
-                               goto ready;
-               }
+       xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
+       v = xm_read16(hw, port, XM_PHY_DATA);
 
-               printk(KERN_WARNING PFX "%s: phy read timed out\n",
-                      hw->dev[port]->name);
-               return 0;
-       ready:
-               v = skge_xm_read16(hw, port, XM_PHY_DATA);
+       /* Need to wait for external PHY */
+       for (i = 0; i < PHY_RETRIES; i++) {
+               udelay(1);
+               if (xm_read16(hw, port, XM_MMU_CMD)
+                   & XM_MMU_PHY_RDY)
+                       goto ready;
        }
 
+       printk(KERN_WARNING PFX "%s: phy read timed out\n",
+              hw->dev[port]->name);
+       return 0;
+ ready:
+       v = xm_read16(hw, port, XM_PHY_DATA);
+
        return v;
 }
 
-static void skge_xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
 {
        int i;
 
-       skge_xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
+       xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
        for (i = 0; i < PHY_RETRIES; i++) {
-               if (!(skge_xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
+               if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
                        goto ready;
-               cpu_relax();
+               udelay(1);
        }
        printk(KERN_WARNING PFX "%s: phy write failed to come ready\n",
               hw->dev[port]->name);
 
 
  ready:
-       skge_xm_write16(hw, port, XM_PHY_DATA, val);
+       xm_write16(hw, port, XM_PHY_DATA, val);
        for (i = 0; i < PHY_RETRIES; i++) {
                udelay(1);
-               if (!(skge_xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
+               if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
                        return;
        }
        printk(KERN_WARNING PFX "%s: phy write timed out\n",
@@ -999,34 +968,112 @@ static void genesis_init(struct skge_hw *hw)
 
 static void genesis_reset(struct skge_hw *hw, int port)
 {
-       int i;
-       u64 zero = 0;
+       const u8 zero[8]  = { 0 };
 
        /* reset the statistics module */
-       skge_xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT);
-       skge_xm_write16(hw, port, XM_IMSK, 0xffff);     /* disable XMAC IRQs */
-       skge_xm_write32(hw, port, XM_MODE, 0);          /* clear Mode Reg */
-       skge_xm_write16(hw, port, XM_TX_CMD, 0);        /* reset TX CMD Reg */
-       skge_xm_write16(hw, port, XM_RX_CMD, 0);        /* reset RX CMD Reg */
+       xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT);
+       xm_write16(hw, port, XM_IMSK, 0xffff);  /* disable XMAC IRQs */
+       xm_write32(hw, port, XM_MODE, 0);               /* clear Mode Reg */
+       xm_write16(hw, port, XM_TX_CMD, 0);     /* reset TX CMD Reg */
+       xm_write16(hw, port, XM_RX_CMD, 0);     /* reset RX CMD Reg */
 
-       /* disable all PHY IRQs */
-       if  (hw->phy_type == SK_PHY_BCOM)
-               skge_xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
+       /* disable Broadcom PHY IRQ */
+       xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
 
-       skge_xm_outhash(hw, port, XM_HSM, (u8 *) &zero);
-       for (i = 0; i < 15; i++)
-               skge_xm_outaddr(hw, port, XM_EXM(i), (u8 *) &zero);
-       skge_xm_outhash(hw, port, XM_SRC_CHK, (u8 *) &zero);
+       xm_outhash(hw, port, XM_HSM, zero);
 }
 
 
-static void genesis_mac_init(struct skge_hw *hw, int port)
+/* Convert mode to MII values  */
+static const u16 phy_pause_map[] = {
+       [FLOW_MODE_NONE] =      0,
+       [FLOW_MODE_LOC_SEND] =  PHY_AN_PAUSE_ASYM,
+       [FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP,
+       [FLOW_MODE_REM_SEND]  = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM,
+};
+
+
+/* Check status of Broadcom phy link */
+static void bcom_check_link(struct skge_hw *hw, int port)
 {
-       struct skge_port *skge = netdev_priv(hw->dev[port]);
+       struct net_device *dev = hw->dev[port];
+       struct skge_port *skge = netdev_priv(dev);
+       u16 status;
+
+       /* read twice because of latch */
+       (void) xm_phy_read(hw, port, PHY_BCOM_STAT);
+       status = xm_phy_read(hw, port, PHY_BCOM_STAT);
+
+       pr_debug("bcom_check_link status=0x%x\n", status);
+
+       if ((status & PHY_ST_LSYNC) == 0) {
+               u16 cmd = xm_read16(hw, port, XM_MMU_CMD);
+               cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+               xm_write16(hw, port, XM_MMU_CMD, cmd);
+               /* dummy read to ensure writing */
+               (void) xm_read16(hw, port, XM_MMU_CMD);
+
+               if (netif_carrier_ok(dev))
+                       skge_link_down(skge);
+       } else {
+               if (skge->autoneg == AUTONEG_ENABLE &&
+                   (status & PHY_ST_AN_OVER)) {
+                       u16 lpa = xm_phy_read(hw, port, PHY_BCOM_AUNE_LP);
+                       u16 aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
+
+                       if (lpa & PHY_B_AN_RF) {
+                               printk(KERN_NOTICE PFX "%s: remote fault\n",
+                                      dev->name);
+                               return;
+                       }
+
+                       /* Check Duplex mismatch */
+                       switch(aux & PHY_B_AS_AN_RES_MSK) {
+                       case PHY_B_RES_1000FD:
+                               skge->duplex = DUPLEX_FULL;
+                               break;
+                       case PHY_B_RES_1000HD:
+                               skge->duplex = DUPLEX_HALF;
+                               break;
+                       default:
+                               printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
+                                      dev->name);
+                               return;
+                       }
+
+
+                       /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+                       switch (aux & PHY_B_AS_PAUSE_MSK) {
+                       case PHY_B_AS_PAUSE_MSK:
+                               skge->flow_control = FLOW_MODE_SYMMETRIC;
+                               break;
+                       case PHY_B_AS_PRR:
+                               skge->flow_control = FLOW_MODE_REM_SEND;
+                               break;
+                       case PHY_B_AS_PRT:
+                               skge->flow_control = FLOW_MODE_LOC_SEND;
+                               break;
+                       default:
+                               skge->flow_control = FLOW_MODE_NONE;
+                       }
+
+                       skge->speed = SPEED_1000;
+               }
+
+               if (!netif_carrier_ok(dev))
+                       genesis_link_up(skge);
+       }
+}
+
+/* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional
+ * Phy on for 100 or 10Mbit operation
+ */
+static void bcom_phy_init(struct skge_port *skge, int jumbo)
+{
+       struct skge_hw *hw = skge->hw;
+       int port = skge->port;
        int i;
-       u32 r;
-       u16 id1;
-       u16 ctrl1, ctrl2, ctrl3, ctrl4, ctrl5;
+       u16 id1, r, ext, ctl;
 
        /* magic workaround patterns for Broadcom */
        static const struct {
@@ -1042,16 +1089,120 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
                { 0x17, 0x0013 }, { 0x15, 0x0A04 }, { 0x18, 0x0420 },
        };
 
+       pr_debug("bcom_phy_init\n");
+
+       /* read Id from external PHY (all have the same address) */
+       id1 = xm_phy_read(hw, port, PHY_XMAC_ID1);
+
+       /* Optimize MDIO transfer by suppressing preamble. */
+       r = xm_read16(hw, port, XM_MMU_CMD);
+       r |=  XM_MMU_NO_PRE;
+       xm_write16(hw, port, XM_MMU_CMD,r);
+
+       switch(id1) {
+       case PHY_BCOM_ID1_C0:
+               /*
+                * Workaround BCOM Errata for the C0 type.
+                * Write magic patterns to reserved registers.
+                */
+               for (i = 0; i < ARRAY_SIZE(C0hack); i++)
+                       xm_phy_write(hw, port,
+                                    C0hack[i].reg, C0hack[i].val);
+
+               break;
+       case PHY_BCOM_ID1_A1:
+               /*
+                * Workaround BCOM Errata for the A1 type.
+                * Write magic patterns to reserved registers.
+                */
+               for (i = 0; i < ARRAY_SIZE(A1hack); i++)
+                       xm_phy_write(hw, port,
+                                    A1hack[i].reg, A1hack[i].val);
+               break;
+       }
+
+       /*
+        * Workaround BCOM Errata (#10523) for all BCom PHYs.
+        * Disable Power Management after reset.
+        */
+       r = xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL);
+       r |= PHY_B_AC_DIS_PM;
+       xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r);
+
+       /* Dummy read */
+       xm_read16(hw, port, XM_ISRC);
+
+       ext = PHY_B_PEC_EN_LTR; /* enable tx led */
+       ctl = PHY_CT_SP1000;    /* always 1000mbit */
+
+       if (skge->autoneg == AUTONEG_ENABLE) {
+               /*
+                * Workaround BCOM Errata #1 for the C5 type.
+                * 1000Base-T Link Acquisition Failure in Slave Mode
+                * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
+                */
+               u16 adv = PHY_B_1000C_RD;
+               if (skge->advertising & ADVERTISED_1000baseT_Half)
+                       adv |= PHY_B_1000C_AHD;
+               if (skge->advertising & ADVERTISED_1000baseT_Full)
+                       adv |= PHY_B_1000C_AFD;
+               xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, adv);
+
+               ctl |= PHY_CT_ANE | PHY_CT_RE_CFG;
+       } else {
+               if (skge->duplex == DUPLEX_FULL)
+                       ctl |= PHY_CT_DUP_MD;
+               /* Force to slave */
+               xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, PHY_B_1000C_MSE);
+       }
+
+       /* Set autonegotiation pause parameters */
+       xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV,
+                    phy_pause_map[skge->flow_control] | PHY_AN_CSMA);
+
+       /* Handle Jumbo frames */
+       if (jumbo) {
+               xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
+                            PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK);
+
+               ext |= PHY_B_PEC_HIGH_LA;
+
+       }
+
+       xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ext);
+       xm_phy_write(hw, port, PHY_BCOM_CTRL, ctl);
+
+       /* Use link status change interrrupt */
+       xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
+
+       bcom_check_link(hw, port);
+}
+
+static void genesis_mac_init(struct skge_hw *hw, int port)
+{
+       struct net_device *dev = hw->dev[port];
+       struct skge_port *skge = netdev_priv(dev);
+       int jumbo = hw->dev[port]->mtu > ETH_DATA_LEN;
+       int i;
+       u32 r;
+       const u8 zero[6]  = { 0 };
+
+       /* Clear MIB counters */
+       xm_write16(hw, port, XM_STAT_CMD,
+                       XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+       /* Clear two times according to Errata #3 */
+       xm_write16(hw, port, XM_STAT_CMD,
+                       XM_SC_CLR_RXC | XM_SC_CLR_TXC);
 
        /* initialize Rx, Tx and Link LED */
-       skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_ON);
-       skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON);
+       skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON);
+       skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON);
 
-       skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_START);
-       skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_START);
+       skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
+       skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START);
 
        /* Unreset the XMAC. */
-       skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+       skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
 
        /*
         * Perform additional initialization for external PHYs,
@@ -1059,67 +1210,56 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
         * GMII mode.
         */
        spin_lock_bh(&hw->phy_lock);
-       if (hw->phy_type != SK_PHY_XMAC) {
-               /* Take PHY out of reset. */
-               r = skge_read32(hw, B2_GP_IO);
-               if (port == 0)
-                       r |= GP_DIR_0|GP_IO_0;
-               else
-                       r |= GP_DIR_2|GP_IO_2;
-
-               skge_write32(hw, B2_GP_IO, r);
-               skge_read32(hw, B2_GP_IO);
-
-               /* Enable GMII mode on the XMAC. */
-               skge_xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
-
-               id1 = skge_xm_phy_read(hw, port, PHY_XMAC_ID1);
-
-               /* Optimize MDIO transfer by suppressing preamble. */
-               skge_xm_write16(hw, port, XM_MMU_CMD,
-                               skge_xm_read16(hw, port, XM_MMU_CMD)
-                               | XM_MMU_NO_PRE);
-
-               if (id1 == PHY_BCOM_ID1_C0) {
-                       /*
-                        * Workaround BCOM Errata for the C0 type.
-                        * Write magic patterns to reserved registers.
-                        */
-                       for (i = 0; i < ARRAY_SIZE(C0hack); i++)
-                               skge_xm_phy_write(hw, port,
-                                         C0hack[i].reg, C0hack[i].val);
-
-               } else if (id1 == PHY_BCOM_ID1_A1) {
-                       /*
-                        * Workaround BCOM Errata for the A1 type.
-                        * Write magic patterns to reserved registers.
-                        */
-                       for (i = 0; i < ARRAY_SIZE(A1hack); i++)
-                               skge_xm_phy_write(hw, port,
-                                         A1hack[i].reg, A1hack[i].val);
-               }
+       /* Take external Phy out of reset */
+       r = skge_read32(hw, B2_GP_IO);
+       if (port == 0)
+               r |= GP_DIR_0|GP_IO_0;
+       else
+               r |= GP_DIR_2|GP_IO_2;
 
-               /*
-                * Workaround BCOM Errata (#10523) for all BCom PHYs.
-                * Disable Power Management after reset.
-                */
-               r = skge_xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL);
-               skge_xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r | PHY_B_AC_DIS_PM);
-       }
+       skge_write32(hw, B2_GP_IO, r);
+       skge_read32(hw, B2_GP_IO);
+       spin_unlock_bh(&hw->phy_lock);
 
-       /* Dummy read */
-       skge_xm_read16(hw, port, XM_ISRC);
+       /* Enable GMII interfac */
+       xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
+
+       bcom_phy_init(skge, jumbo);
+
+       /* Set Station Address */
+       xm_outaddr(hw, port, XM_SA, dev->dev_addr);
+
+       /* We don't use match addresses so clear */
+       for (i = 1; i < 16; i++)
+               xm_outaddr(hw, port, XM_EXM(i), zero);
 
-       r = skge_xm_read32(hw, port, XM_MODE);
-       skge_xm_write32(hw, port, XM_MODE, r|XM_MD_CSA);
+       /* configure Rx High Water Mark (XM_RX_HI_WM) */
+       xm_write16(hw, port, XM_RX_HI_WM, 1450);
 
        /* We don't need the FCS appended to the packet. */
-       r = skge_xm_read16(hw, port, XM_RX_CMD);
-       skge_xm_write16(hw, port, XM_RX_CMD, r | XM_RX_STRIP_FCS);
+       r = XM_RX_LENERR_OK | XM_RX_STRIP_FCS;
+       if (jumbo)
+               r |= XM_RX_BIG_PK_OK;
+
+       if (skge->duplex == DUPLEX_HALF) {
+               /*
+                * If in manual half duplex mode the other side might be in
+                * full duplex mode, so ignore if a carrier extension is not seen
+                * on frames received
+                */
+               r |= XM_RX_DIS_CEXT;
+       }
+       xm_write16(hw, port, XM_RX_CMD, r);
+
 
        /* We want short frames padded to 60 bytes. */
-       r = skge_xm_read16(hw, port, XM_TX_CMD);
-       skge_xm_write16(hw, port, XM_TX_CMD, r | XM_TX_AUTO_PAD);
+       xm_write16(hw, port, XM_TX_CMD, XM_TX_AUTO_PAD);
+
+       /*
+        * Bump up the transmit threshold. This helps hold off transmit
+        * underruns when we're blasting traffic from both ports at once.
+        */
+       xm_write16(hw, port, XM_TX_THR, 512);
 
        /*
         * Enable the reception of all error frames. This is is
@@ -1135,19 +1275,22 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
         * case the XMAC will start transfering frames out of the
         * RX FIFO as soon as the FIFO threshold is reached.
         */
-       r = skge_xm_read32(hw, port, XM_MODE);
-       skge_xm_write32(hw, port, XM_MODE,
-                    XM_MD_RX_CRCE|XM_MD_RX_LONG|XM_MD_RX_RUNT|
-                    XM_MD_RX_ERR|XM_MD_RX_IRLE);
+       xm_write32(hw, port, XM_MODE, XM_DEF_MODE);
 
-       skge_xm_outaddr(hw, port, XM_SA, hw->dev[port]->dev_addr);
-       skge_xm_outaddr(hw, port, XM_EXM(0), hw->dev[port]->dev_addr);
 
        /*
-        * Bump up the transmit threshold. This helps hold off transmit
-        * underruns when we're blasting traffic from both ports at once.
+        * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK)
+        *      - Enable all bits excepting 'Octets Rx OK Low CntOv'
+        *        and 'Octets Rx OK Hi Cnt Ov'.
         */
-       skge_xm_write16(hw, port, XM_TX_THR, 512);
+       xm_write32(hw, port, XM_RX_EV_MSK, XMR_DEF_MSK);
+
+       /*
+        * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK)
+        *      - Enable all bits excepting 'Octets Tx OK Low CntOv'
+        *        and 'Octets Tx OK Hi Cnt Ov'.
+        */
+       xm_write32(hw, port, XM_TX_EV_MSK, XMT_DEF_MSK);
 
        /* Configure MAC arbiter */
        skge_write16(hw, B3_MA_TO_CTRL, MA_RST_CLR);
@@ -1164,137 +1307,30 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
        skge_write8(hw, B3_MA_RCINI_TX2, 0);
 
        /* Configure Rx MAC FIFO */
-       skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_RST_CLR);
-       skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_ENA_TIM_PAT);
-       skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
+       skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_RST_CLR);
+       skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_TIM_PAT);
+       skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
 
        /* Configure Tx MAC FIFO */
-       skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_RST_CLR);
-       skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
-       skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
+       skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_CLR);
+       skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
+       skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
 
-       if (hw->dev[port]->mtu > ETH_DATA_LEN) {
+       if (jumbo) {
                /* Enable frame flushing if jumbo frames used */
-               skge_write16(hw, SKGEMAC_REG(port,RX_MFF_CTRL1), MFF_ENA_FLUSH);
+               skge_write16(hw, SK_REG(port,RX_MFF_CTRL1), MFF_ENA_FLUSH);
        } else {
                /* enable timeout timers if normal frames */
                skge_write16(hw, B3_PA_CTRL,
-                            port == 0 ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2);
+                            (port == 0) ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2);
        }
-
-
-       r = skge_xm_read16(hw, port, XM_RX_CMD);
-       if (hw->dev[port]->mtu > ETH_DATA_LEN)
-               skge_xm_write16(hw, port, XM_RX_CMD, r | XM_RX_BIG_PK_OK);
-       else
-               skge_xm_write16(hw, port, XM_RX_CMD, r & ~(XM_RX_BIG_PK_OK));
-
-       switch (hw->phy_type) {
-       case SK_PHY_XMAC:
-               if (skge->autoneg == AUTONEG_ENABLE) {
-                       ctrl1 = PHY_X_AN_FD | PHY_X_AN_HD;
-
-                       switch (skge->flow_control) {
-                       case FLOW_MODE_NONE:
-                               ctrl1 |= PHY_X_P_NO_PAUSE;
-                               break;
-                       case FLOW_MODE_LOC_SEND:
-                               ctrl1 |= PHY_X_P_ASYM_MD;
-                               break;
-                       case FLOW_MODE_SYMMETRIC:
-                               ctrl1 |= PHY_X_P_SYM_MD;
-                               break;
-                       case FLOW_MODE_REM_SEND:
-                               ctrl1 |= PHY_X_P_BOTH_MD;
-                               break;
-                       }
-
-                       skge_xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl1);
-                       ctrl2 = PHY_CT_ANE | PHY_CT_RE_CFG;
-               } else {
-                       ctrl2 = 0;
-                       if (skge->duplex == DUPLEX_FULL)
-                               ctrl2 |= PHY_CT_DUP_MD;
-               }
-
-               skge_xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl2);
-               break;
-
-       case SK_PHY_BCOM:
-               ctrl1 = PHY_CT_SP1000;
-               ctrl2 = 0;
-               ctrl3 = PHY_SEL_TYPE;
-               ctrl4 = PHY_B_PEC_EN_LTR;
-               ctrl5 = PHY_B_AC_TX_TST;
-
-               if (skge->autoneg == AUTONEG_ENABLE) {
-                       /*
-                        * Workaround BCOM Errata #1 for the C5 type.
-                        * 1000Base-T Link Acquisition Failure in Slave Mode
-                        * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
-                        */
-                       ctrl2 |= PHY_B_1000C_RD;
-                       if (skge->advertising & ADVERTISED_1000baseT_Half)
-                               ctrl2 |= PHY_B_1000C_AHD;
-                       if (skge->advertising & ADVERTISED_1000baseT_Full)
-                               ctrl2 |= PHY_B_1000C_AFD;
-
-                       /* Set Flow-control capabilities */
-                       switch (skge->flow_control) {
-                       case FLOW_MODE_NONE:
-                               ctrl3 |= PHY_B_P_NO_PAUSE;
-                               break;
-                       case FLOW_MODE_LOC_SEND:
-                               ctrl3 |= PHY_B_P_ASYM_MD;
-                               break;
-                       case FLOW_MODE_SYMMETRIC:
-                               ctrl3 |= PHY_B_P_SYM_MD;
-                               break;
-                       case FLOW_MODE_REM_SEND:
-                               ctrl3 |= PHY_B_P_BOTH_MD;
-                               break;
-                       }
-
-                       /* Restart Auto-negotiation */
-                       ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
-               } else {
-                       if (skge->duplex == DUPLEX_FULL)
-                               ctrl1 |= PHY_CT_DUP_MD;
-
-                       ctrl2 |= PHY_B_1000C_MSE;       /* set it to Slave */
-               }
-
-               skge_xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, ctrl2);
-               skge_xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV, ctrl3);
-
-               if (skge->netdev->mtu > ETH_DATA_LEN) {
-                       ctrl4 |= PHY_B_PEC_HIGH_LA;
-                       ctrl5 |= PHY_B_AC_LONG_PACK;
-
-                       skge_xm_phy_write(hw, port,PHY_BCOM_AUX_CTRL, ctrl5);
-               }
-
-               skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ctrl4);
-               skge_xm_phy_write(hw, port, PHY_BCOM_CTRL, ctrl1);
-               break;
-       }
-       spin_unlock_bh(&hw->phy_lock);
-
-       /* Clear MIB counters */
-       skge_xm_write16(hw, port, XM_STAT_CMD,
-                       XM_SC_CLR_RXC | XM_SC_CLR_TXC);
-       /* Clear two times according to Errata #3 */
-       skge_xm_write16(hw, port, XM_STAT_CMD,
-                       XM_SC_CLR_RXC | XM_SC_CLR_TXC);
-
-       /* Start polling for link status */
-       mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
 }
 
 static void genesis_stop(struct skge_port *skge)
 {
        struct skge_hw *hw = skge->hw;
        int port = skge->port;
+       u32 reg;
 
        /* Clear Tx packet arbiter timeout IRQ */
        skge_write16(hw, B3_PA_CTRL,
@@ -1304,33 +1340,30 @@ static void genesis_stop(struct skge_port *skge)
         * If the transfer stucks at the MAC the STOP command will not
         * terminate if we don't flush the XMAC's transmit FIFO !
         */
-       skge_xm_write32(hw, port, XM_MODE,
-                       skge_xm_read32(hw, port, XM_MODE)|XM_MD_FTF);
+       xm_write32(hw, port, XM_MODE,
+                       xm_read32(hw, port, XM_MODE)|XM_MD_FTF);
 
 
        /* Reset the MAC */
-       skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
+       skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
 
        /* For external PHYs there must be special handling */
-       if (hw->phy_type != SK_PHY_XMAC) {
-               u32 reg = skge_read32(hw, B2_GP_IO);
-
-               if (port == 0) {
-                       reg |= GP_DIR_0;
-                       reg &= ~GP_IO_0;
-               } else {
-                       reg |= GP_DIR_2;
-                       reg &= ~GP_IO_2;
-               }
-               skge_write32(hw, B2_GP_IO, reg);
-               skge_read32(hw, B2_GP_IO);
+       reg = skge_read32(hw, B2_GP_IO);
+       if (port == 0) {
+               reg |= GP_DIR_0;
+               reg &= ~GP_IO_0;
+       } else {
+               reg |= GP_DIR_2;
+               reg &= ~GP_IO_2;
        }
+       skge_write32(hw, B2_GP_IO, reg);
+       skge_read32(hw, B2_GP_IO);
 
-       skge_xm_write16(hw, port, XM_MMU_CMD,
-                       skge_xm_read16(hw, port, XM_MMU_CMD)
+       xm_write16(hw, port, XM_MMU_CMD,
+                       xm_read16(hw, port, XM_MMU_CMD)
                        & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
 
-       skge_xm_read16(hw, port, XM_MMU_CMD);
+       xm_read16(hw, port, XM_MMU_CMD);
 }
 
 
@@ -1341,11 +1374,11 @@ static void genesis_get_stats(struct skge_port *skge, u64 *data)
        int i;
        unsigned long timeout = jiffies + HZ;
 
-       skge_xm_write16(hw, port,
+       xm_write16(hw, port,
                        XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC);
 
        /* wait for update to complete */
-       while (skge_xm_read16(hw, port, XM_STAT_CMD)
+       while (xm_read16(hw, port, XM_STAT_CMD)
               & (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) {
                if (time_after(jiffies, timeout))
                        break;
@@ -1353,68 +1386,60 @@ static void genesis_get_stats(struct skge_port *skge, u64 *data)
        }
 
        /* special case for 64 bit octet counter */
-       data[0] = (u64) skge_xm_read32(hw, port, XM_TXO_OK_HI) << 32
-               | skge_xm_read32(hw, port, XM_TXO_OK_LO);
-       data[1] = (u64) skge_xm_read32(hw, port, XM_RXO_OK_HI) << 32
-               | skge_xm_read32(hw, port, XM_RXO_OK_LO);
+       data[0] = (u64) xm_read32(hw, port, XM_TXO_OK_HI) << 32
+               | xm_read32(hw, port, XM_TXO_OK_LO);
+       data[1] = (u64) xm_read32(hw, port, XM_RXO_OK_HI) << 32
+               | xm_read32(hw, port, XM_RXO_OK_LO);
 
        for (i = 2; i < ARRAY_SIZE(skge_stats); i++)
-               data[i] = skge_xm_read32(hw, port, skge_stats[i].xmac_offset);
+               data[i] = xm_read32(hw, port, skge_stats[i].xmac_offset);
 }
 
 static void genesis_mac_intr(struct skge_hw *hw, int port)
 {
        struct skge_port *skge = netdev_priv(hw->dev[port]);
-       u16 status = skge_xm_read16(hw, port, XM_ISRC);
-
-       pr_debug("genesis_intr status %x\n", status);
-       if (hw->phy_type == SK_PHY_XMAC) {
-               /* LInk down, start polling for state change */
-               if (status & XM_IS_INP_ASS) {
-                       skge_xm_write16(hw, port, XM_IMSK,
-                                       skge_xm_read16(hw, port, XM_IMSK) | XM_IS_INP_ASS);
-                       mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
-               }
-               else if (status & XM_IS_AND)
-                       mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
-       }
+       u16 status = xm_read16(hw, port, XM_ISRC);
+
+       if (netif_msg_intr(skge))
+               printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n",
+                      skge->netdev->name, status);
 
        if (status & XM_IS_TXF_UR) {
-               skge_xm_write32(hw, port, XM_MODE, XM_MD_FTF);
+               xm_write32(hw, port, XM_MODE, XM_MD_FTF);
                ++skge->net_stats.tx_fifo_errors;
        }
        if (status & XM_IS_RXF_OV) {
-               skge_xm_write32(hw, port, XM_MODE, XM_MD_FRF);
+               xm_write32(hw, port, XM_MODE, XM_MD_FRF);
                ++skge->net_stats.rx_fifo_errors;
        }
 }
 
-static void skge_gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
 {
        int i;
 
-       skge_gma_write16(hw, port, GM_SMI_DATA, val);
-       skge_gma_write16(hw, port, GM_SMI_CTRL,
+       gma_write16(hw, port, GM_SMI_DATA, val);
+       gma_write16(hw, port, GM_SMI_CTRL,
                         GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg));
        for (i = 0; i < PHY_RETRIES; i++) {
                udelay(1);
 
-               if (!(skge_gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
+               if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
                        break;
        }
 }
 
-static u16 skge_gm_phy_read(struct skge_hw *hw, int port, u16 reg)
+static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg)
 {
        int i;
 
-       skge_gma_write16(hw, port, GM_SMI_CTRL,
+       gma_write16(hw, port, GM_SMI_CTRL,
                         GM_SMI_CT_PHY_AD(hw->phy_addr)
                         | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD);
 
        for (i = 0; i < PHY_RETRIES; i++) {
                udelay(1);
-               if (skge_gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL)
+               if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL)
                        goto ready;
        }
 
@@ -1422,24 +1447,7 @@ static u16 skge_gm_phy_read(struct skge_hw *hw, int port, u16 reg)
               hw->dev[port]->name);
        return 0;
  ready:
-       return skge_gma_read16(hw, port, GM_SMI_DATA);
-}
-
-static void genesis_link_down(struct skge_port *skge)
-{
-       struct skge_hw *hw = skge->hw;
-       int port = skge->port;
-
-       pr_debug("genesis_link_down\n");
-
-       skge_xm_write16(hw, port, XM_MMU_CMD,
-                       skge_xm_read16(hw, port, XM_MMU_CMD)
-                       & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
-
-       /* dummy read to ensure writing */
-       (void) skge_xm_read16(hw, port, XM_MMU_CMD);
-
-       skge_link_down(skge);
+       return gma_read16(hw, port, GM_SMI_DATA);
 }
 
 static void genesis_link_up(struct skge_port *skge)
@@ -1450,7 +1458,7 @@ static void genesis_link_up(struct skge_port *skge)
        u32 mode, msk;
 
        pr_debug("genesis_link_up\n");
-       cmd = skge_xm_read16(hw, port, XM_MMU_CMD);
+       cmd = xm_read16(hw, port, XM_MMU_CMD);
 
        /*
         * enabling pause frame reception is required for 1000BT
@@ -1458,14 +1466,15 @@ static void genesis_link_up(struct skge_port *skge)
         */
        if (skge->flow_control == FLOW_MODE_NONE ||
            skge->flow_control == FLOW_MODE_LOC_SEND)
+               /* Disable Pause Frame Reception */
                cmd |= XM_MMU_IGN_PF;
        else
                /* Enable Pause Frame Reception */
                cmd &= ~XM_MMU_IGN_PF;
 
-       skge_xm_write16(hw, port, XM_MMU_CMD, cmd);
+       xm_write16(hw, port, XM_MMU_CMD, cmd);
 
-       mode = skge_xm_read32(hw, port, XM_MODE);
+       mode = xm_read32(hw, port, XM_MODE);
        if (skge->flow_control == FLOW_MODE_SYMMETRIC ||
            skge->flow_control == FLOW_MODE_LOC_SEND) {
                /*
@@ -1479,10 +1488,10 @@ static void genesis_link_up(struct skge_port *skge)
                /* XM_PAUSE_DA = '010000C28001' (default) */
                /* XM_MAC_PTIME = 0xffff (maximum) */
                /* remember this value is defined in big endian (!) */
-               skge_xm_write16(hw, port, XM_MAC_PTIME, 0xffff);
+               xm_write16(hw, port, XM_MAC_PTIME, 0xffff);
 
                mode |= XM_PAUSE_MODE;
-               skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
+               skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
        } else {
                /*
                 * disable pause frame generation is required for 1000BT
@@ -1491,125 +1500,68 @@ static void genesis_link_up(struct skge_port *skge)
                /* Disable Pause Mode in Mode Register */
                mode &= ~XM_PAUSE_MODE;
 
-               skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
+               skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
        }
 
-       skge_xm_write32(hw, port, XM_MODE, mode);
+       xm_write32(hw, port, XM_MODE, mode);
 
        msk = XM_DEF_MSK;
-       if (hw->phy_type != SK_PHY_XMAC)
-               msk |= XM_IS_INP_ASS;   /* disable GP0 interrupt bit */
+       /* disable GP0 interrupt bit for external Phy */
+       msk |= XM_IS_INP_ASS;
 
-       skge_xm_write16(hw, port, XM_IMSK, msk);
-       skge_xm_read16(hw, port, XM_ISRC);
+       xm_write16(hw, port, XM_IMSK, msk);
+       xm_read16(hw, port, XM_ISRC);
 
        /* get MMU Command Reg. */
-       cmd = skge_xm_read16(hw, port, XM_MMU_CMD);
-       if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL)
+       cmd = xm_read16(hw, port, XM_MMU_CMD);
+       if (skge->duplex == DUPLEX_FULL)
                cmd |= XM_MMU_GMII_FD;
 
-       if (hw->phy_type == SK_PHY_BCOM) {
-               /*
-                * Workaround BCOM Errata (#10523) for all BCom Phys
-                * Enable Power Management after link up
-                */
-               skge_xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
-                                 skge_xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
-                                 & ~PHY_B_AC_DIS_PM);
-               skge_xm_phy_write(hw, port, PHY_BCOM_INT_MASK,
-                                 PHY_B_DEF_MSK);
-       }
+       /*
+        * Workaround BCOM Errata (#10523) for all BCom Phys
+        * Enable Power Management after link up
+        */
+       xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
+                    xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
+                    & ~PHY_B_AC_DIS_PM);
+       xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
 
        /* enable Rx/Tx */
-       skge_xm_write16(hw, port, XM_MMU_CMD,
+       xm_write16(hw, port, XM_MMU_CMD,
                        cmd | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
        skge_link_up(skge);
 }
 
 
-static void genesis_bcom_intr(struct skge_port *skge)
+static inline void bcom_phy_intr(struct skge_port *skge)
 {
        struct skge_hw *hw = skge->hw;
        int port = skge->port;
-       u16 stat = skge_xm_phy_read(hw, port, PHY_BCOM_INT_STAT);
+       u16 isrc;
+
+       isrc = xm_phy_read(hw, port, PHY_BCOM_INT_STAT);
+       if (netif_msg_intr(skge))
+               printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x\n",
+                      skge->netdev->name, isrc);
 
-       pr_debug("genesis_bcom intr stat=%x\n", stat);
+       if (isrc & PHY_B_IS_PSE)
+               printk(KERN_ERR PFX "%s: uncorrectable pair swap error\n",
+                      hw->dev[port]->name);
 
        /* Workaround BCom Errata:
         *      enable and disable loopback mode if "NO HCD" occurs.
         */
-       if (stat & PHY_B_IS_NO_HDCL) {
-               u16 ctrl = skge_xm_phy_read(hw, port, PHY_BCOM_CTRL);
-               skge_xm_phy_write(hw, port, PHY_BCOM_CTRL,
+       if (isrc & PHY_B_IS_NO_HDCL) {
+               u16 ctrl = xm_phy_read(hw, port, PHY_BCOM_CTRL);
+               xm_phy_write(hw, port, PHY_BCOM_CTRL,
                                  ctrl | PHY_CT_LOOP);
-               skge_xm_phy_write(hw, port, PHY_BCOM_CTRL,
+               xm_phy_write(hw, port, PHY_BCOM_CTRL,
                                  ctrl & ~PHY_CT_LOOP);
        }
 
-       stat = skge_xm_phy_read(hw, port, PHY_BCOM_STAT);
-       if (stat & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) {
-               u16 aux = skge_xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
-               if ( !(aux & PHY_B_AS_LS) && netif_carrier_ok(skge->netdev))
-                       genesis_link_down(skge);
-
-               else if (stat & PHY_B_IS_LST_CHANGE) {
-                       if (aux & PHY_B_AS_AN_C) {
-                               switch (aux & PHY_B_AS_AN_RES_MSK) {
-                               case PHY_B_RES_1000FD:
-                                       skge->duplex = DUPLEX_FULL;
-                                       break;
-                               case PHY_B_RES_1000HD:
-                                       skge->duplex = DUPLEX_HALF;
-                                       break;
-                               }
-
-                               switch (aux & PHY_B_AS_PAUSE_MSK) {
-                               case PHY_B_AS_PAUSE_MSK:
-                                       skge->flow_control = FLOW_MODE_SYMMETRIC;
-                                       break;
-                               case PHY_B_AS_PRR:
-                                       skge->flow_control = FLOW_MODE_REM_SEND;
-                                       break;
-                               case PHY_B_AS_PRT:
-                                       skge->flow_control = FLOW_MODE_LOC_SEND;
-                                       break;
-                               default:
-                                       skge->flow_control = FLOW_MODE_NONE;
-                               }
-                               skge->speed = SPEED_1000;
-                       }
-                       genesis_link_up(skge);
-               }
-               else
-                       mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
-       }
-}
+       if (isrc & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+               bcom_check_link(hw, port);
 
-/* Perodic poll of phy status to check for link transistion  */
-static void skge_link_timer(unsigned long __arg)
-{
-       struct skge_port *skge = (struct skge_port *) __arg;
-       struct skge_hw *hw = skge->hw;
-       int port = skge->port;
-
-       if (hw->chip_id != CHIP_ID_GENESIS || !netif_running(skge->netdev))
-               return;
-
-       spin_lock_bh(&hw->phy_lock);
-       if (hw->phy_type == SK_PHY_BCOM)
-               genesis_bcom_intr(skge);
-       else {
-               int i;
-               for (i = 0; i < 3; i++)
-                       if (skge_xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)
-                               break;
-
-               if (i == 3)
-                       mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
-               else
-                       genesis_link_up(skge);
-       }
-       spin_unlock_bh(&hw->phy_lock);
 }
 
 /* Marvell Phy Initailization */
@@ -1621,31 +1573,27 @@ static void yukon_init(struct skge_hw *hw, int port)
 
        pr_debug("yukon_init\n");
        if (skge->autoneg == AUTONEG_ENABLE) {
-               u16 ectrl = skge_gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
+               u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
 
                ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
                          PHY_M_EC_MAC_S_MSK);
                ectrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ);
 
-               /* on PHY 88E1111 there is a change for downshift control */
-               if (hw->chip_id == CHIP_ID_YUKON_EC)
-                       ectrl |= PHY_M_EC_M_DSC_2(0) | PHY_M_EC_DOWN_S_ENA;
-               else
-                       ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
+               ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
 
-               skge_gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl);
+               gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl);
        }
 
-       ctrl = skge_gm_phy_read(hw, port, PHY_MARV_CTRL);
+       ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL);
        if (skge->autoneg == AUTONEG_DISABLE)
                ctrl &= ~PHY_CT_ANE;
 
        ctrl |= PHY_CT_RESET;
-       skge_gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+       gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
 
        ctrl = 0;
        ct1000 = 0;
-       adv = PHY_SEL_TYPE;
+       adv = PHY_AN_CSMA;
 
        if (skge->autoneg == AUTONEG_ENABLE) {
                if (iscopper(hw)) {
@@ -1661,41 +1609,12 @@ static void yukon_init(struct skge_hw *hw, int port)
                                adv |= PHY_M_AN_10_FD;
                        if (skge->advertising & ADVERTISED_10baseT_Half)
                                adv |= PHY_M_AN_10_HD;
-
-                       /* Set Flow-control capabilities */
-                       switch (skge->flow_control) {
-                       case FLOW_MODE_NONE:
-                               adv |= PHY_B_P_NO_PAUSE;
-                               break;
-                       case FLOW_MODE_LOC_SEND:
-                               adv |= PHY_B_P_ASYM_MD;
-                               break;
-                       case FLOW_MODE_SYMMETRIC:
-                               adv |= PHY_B_P_SYM_MD;
-                               break;
-                       case FLOW_MODE_REM_SEND:
-                               adv |= PHY_B_P_BOTH_MD;
-                               break;
-                       }
-               } else {        /* special defines for FIBER (88E1011S only) */
+               } else  /* special defines for FIBER (88E1011S only) */
                        adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
 
-                       /* Set Flow-control capabilities */
-                       switch (skge->flow_control) {
-                       case FLOW_MODE_NONE:
-                               adv |= PHY_M_P_NO_PAUSE_X;
-                               break;
-                       case FLOW_MODE_LOC_SEND:
-                               adv |= PHY_M_P_ASYM_MD_X;
-                               break;
-                       case FLOW_MODE_SYMMETRIC:
-                               adv |= PHY_M_P_SYM_MD_X;
-                               break;
-                       case FLOW_MODE_REM_SEND:
-                               adv |= PHY_M_P_BOTH_MD_X;
-                               break;
-                       }
-               }
+               /* Set Flow-control capabilities */
+               adv |= phy_pause_map[skge->flow_control];
+
                /* Restart Auto-negotiation */
                ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
        } else {
@@ -1717,36 +1636,23 @@ static void yukon_init(struct skge_hw *hw, int port)
                ctrl |= PHY_CT_RESET;
        }
 
-       if (hw->chip_id != CHIP_ID_YUKON_FE)
-               skge_gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
+       gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
 
-       skge_gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
-       skge_gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+       gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
+       gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
 
        /* Setup Phy LED's */
        ledctrl = PHY_M_LED_PULS_DUR(PULS_170MS);
        ledover = 0;
 
-       if (hw->chip_id == CHIP_ID_YUKON_FE) {
-               /* on 88E3082 these bits are at 11..9 (shifted left) */
-               ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) << 1;
-
-               skge_gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR,
-                                 ((skge_gm_phy_read(hw, port, PHY_MARV_FE_LED_PAR)
-
-                                   & ~PHY_M_FELP_LED1_MSK)
-                                  | PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_ACT_BL)));
-       } else {
-               /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */
-               ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL;
+       ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL;
 
-               /* turn off the Rx LED (LED_RX) */
-               ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
-       }
+       /* turn off the Rx LED (LED_RX) */
+       ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
 
        /* disable blink mode (LED_DUPLEX) on collisions */
        ctrl |= PHY_M_LEDC_DP_CTRL;
-       skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
+       gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
 
        if (skge->autoneg == AUTONEG_DISABLE || skge->speed == SPEED_100) {
                /* turn on 100 Mbps LED (LED_LINK100) */
@@ -1754,25 +1660,25 @@ static void yukon_init(struct skge_hw *hw, int port)
        }
 
        if (ledover)
-               skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
+               gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
 
        /* Enable phy interrupt on autonegotiation complete (or link up) */
        if (skge->autoneg == AUTONEG_ENABLE)
-               skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL);
+               gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL);
        else
-               skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+               gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
 }
 
 static void yukon_reset(struct skge_hw *hw, int port)
 {
-       skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);/* disable PHY IRQs */
-       skge_gma_write16(hw, port, GM_MC_ADDR_H1, 0);   /* clear MC hash */
-       skge_gma_write16(hw, port, GM_MC_ADDR_H2, 0);
-       skge_gma_write16(hw, port, GM_MC_ADDR_H3, 0);
-       skge_gma_write16(hw, port, GM_MC_ADDR_H4, 0);
+       gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);/* disable PHY IRQs */
+       gma_write16(hw, port, GM_MC_ADDR_H1, 0);        /* clear MC hash */
+       gma_write16(hw, port, GM_MC_ADDR_H2, 0);
+       gma_write16(hw, port, GM_MC_ADDR_H3, 0);
+       gma_write16(hw, port, GM_MC_ADDR_H4, 0);
 
-       skge_gma_write16(hw, port, GM_RX_CTRL,
-                        skge_gma_read16(hw, port, GM_RX_CTRL)
+       gma_write16(hw, port, GM_RX_CTRL,
+                        gma_read16(hw, port, GM_RX_CTRL)
                         | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
 }
 
@@ -1785,17 +1691,17 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
 
        /* WA code for COMA mode -- set PHY reset */
        if (hw->chip_id == CHIP_ID_YUKON_LITE &&
-           chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+           hw->chip_rev == CHIP_REV_YU_LITE_A3)
                skge_write32(hw, B2_GP_IO,
                             (skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9));
 
        /* hard reset */
-       skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), GPC_RST_SET);
-       skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_RST_SET);
+       skge_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
+       skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET);
 
        /* WA code for COMA mode -- clear PHY reset */
        if (hw->chip_id == CHIP_ID_YUKON_LITE &&
-           chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+           hw->chip_rev == CHIP_REV_YU_LITE_A3)
                skge_write32(hw, B2_GP_IO,
                             (skge_read32(hw, B2_GP_IO) | GP_DIR_9)
                             & ~GP_IO_9);
@@ -1806,13 +1712,13 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
        reg |= iscopper(hw) ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB;
 
        /* Clear GMC reset */
-       skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), reg | GPC_RST_SET);
-       skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), reg | GPC_RST_CLR);
-       skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR);
+       skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_SET);
+       skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_CLR);
+       skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR);
        if (skge->autoneg == AUTONEG_DISABLE) {
                reg = GM_GPCR_AU_ALL_DIS;
-               skge_gma_write16(hw, port, GM_GP_CTRL,
-                                skge_gma_read16(hw, port, GM_GP_CTRL) | reg);
+               gma_write16(hw, port, GM_GP_CTRL,
+                                gma_read16(hw, port, GM_GP_CTRL) | reg);
 
                switch (skge->speed) {
                case SPEED_1000:
@@ -1828,7 +1734,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
                reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL;
        switch (skge->flow_control) {
        case FLOW_MODE_NONE:
-               skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+               skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
                reg |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
                break;
        case FLOW_MODE_LOC_SEND:
@@ -1836,7 +1742,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
                reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
        }
 
-       skge_gma_write16(hw, port, GM_GP_CTRL, reg);
+       gma_write16(hw, port, GM_GP_CTRL, reg);
        skge_read16(hw, GMAC_IRQ_SRC);
 
        spin_lock_bh(&hw->phy_lock);
@@ -1844,25 +1750,25 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
        spin_unlock_bh(&hw->phy_lock);
 
        /* MIB clear */
-       reg = skge_gma_read16(hw, port, GM_PHY_ADDR);
-       skge_gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR);
+       reg = gma_read16(hw, port, GM_PHY_ADDR);
+       gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR);
 
        for (i = 0; i < GM_MIB_CNT_SIZE; i++)
-               skge_gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i);
-       skge_gma_write16(hw, port, GM_PHY_ADDR, reg);
+               gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i);
+       gma_write16(hw, port, GM_PHY_ADDR, reg);
 
        /* transmit control */
-       skge_gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF));
+       gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF));
 
        /* receive control reg: unicast + multicast + no FCS  */
-       skge_gma_write16(hw, port, GM_RX_CTRL,
+       gma_write16(hw, port, GM_RX_CTRL,
                         GM_RXCR_UCF_ENA | GM_RXCR_CRC_DIS | GM_RXCR_MCF_ENA);
 
        /* transmit flow control */
-       skge_gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff);
+       gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff);
 
        /* transmit parameter */
-       skge_gma_write16(hw, port, GM_TX_PARAM,
+       gma_write16(hw, port, GM_TX_PARAM,
                         TX_JAM_LEN_VAL(TX_JAM_LEN_DEF) |
                         TX_JAM_IPG_VAL(TX_JAM_IPG_DEF) |
                         TX_IPG_JAM_DATA(TX_IPG_JAM_DEF));
@@ -1872,33 +1778,33 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
        if (hw->dev[port]->mtu > 1500)
                reg |= GM_SMOD_JUMBO_ENA;
 
-       skge_gma_write16(hw, port, GM_SERIAL_MODE, reg);
+       gma_write16(hw, port, GM_SERIAL_MODE, reg);
 
        /* physical address: used for pause frames */
-       skge_gm_set_addr(hw, port, GM_SRC_ADDR_1L, addr);
+       gma_set_addr(hw, port, GM_SRC_ADDR_1L, addr);
        /* virtual address for data */
-       skge_gm_set_addr(hw, port, GM_SRC_ADDR_2L, addr);
+       gma_set_addr(hw, port, GM_SRC_ADDR_2L, addr);
 
        /* enable interrupt mask for counter overflows */
-       skge_gma_write16(hw, port, GM_TX_IRQ_MSK, 0);
-       skge_gma_write16(hw, port, GM_RX_IRQ_MSK, 0);
-       skge_gma_write16(hw, port, GM_TR_IRQ_MSK, 0);
+       gma_write16(hw, port, GM_TX_IRQ_MSK, 0);
+       gma_write16(hw, port, GM_RX_IRQ_MSK, 0);
+       gma_write16(hw, port, GM_TR_IRQ_MSK, 0);
 
        /* Initialize Mac Fifo */
 
        /* Configure Rx MAC FIFO */
-       skge_write16(hw, SKGEMAC_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK);
+       skge_write16(hw, SK_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK);
        reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
        if (hw->chip_id == CHIP_ID_YUKON_LITE &&
-           chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+           hw->chip_rev == CHIP_REV_YU_LITE_A3)
                reg &= ~GMF_RX_F_FL_ON;
-       skge_write8(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
-       skge_write16(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), reg);
-       skge_write16(hw, SKGEMAC_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF);
+       skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
+       skge_write16(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
+       skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF);
 
        /* Configure Tx MAC FIFO */
-       skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
-       skge_write16(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
+       skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
+       skge_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
 }
 
 static void yukon_stop(struct skge_port *skge)
@@ -1907,19 +1813,19 @@ static void yukon_stop(struct skge_port *skge)
        int port = skge->port;
 
        if (hw->chip_id == CHIP_ID_YUKON_LITE &&
-           chip_rev(hw) == CHIP_REV_YU_LITE_A3) {
+           hw->chip_rev == CHIP_REV_YU_LITE_A3) {
                skge_write32(hw, B2_GP_IO,
                             skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9);
        }
 
-       skge_gma_write16(hw, port, GM_GP_CTRL,
-                        skge_gma_read16(hw, port, GM_GP_CTRL)
+       gma_write16(hw, port, GM_GP_CTRL,
+                        gma_read16(hw, port, GM_GP_CTRL)
                         & ~(GM_GPCR_RX_ENA|GM_GPCR_RX_ENA));
-       skge_gma_read16(hw, port, GM_GP_CTRL);
+       gma_read16(hw, port, GM_GP_CTRL);
 
        /* set GPHY Control reset */
-       skge_gma_write32(hw, port, GPHY_CTRL, GPC_RST_SET);
-       skge_gma_write32(hw, port, GMAC_CTRL, GMC_RST_SET);
+       gma_write32(hw, port, GPHY_CTRL, GPC_RST_SET);
+       gma_write32(hw, port, GMAC_CTRL, GMC_RST_SET);
 }
 
 static void yukon_get_stats(struct skge_port *skge, u64 *data)
@@ -1928,39 +1834,40 @@ static void yukon_get_stats(struct skge_port *skge, u64 *data)
        int port = skge->port;
        int i;
 
-       data[0] = (u64) skge_gma_read32(hw, port, GM_TXO_OK_HI) << 32
-               | skge_gma_read32(hw, port, GM_TXO_OK_LO);
-       data[1] = (u64) skge_gma_read32(hw, port, GM_RXO_OK_HI) << 32
-               | skge_gma_read32(hw, port, GM_RXO_OK_LO);
+       data[0] = (u64) gma_read32(hw, port, GM_TXO_OK_HI) << 32
+               | gma_read32(hw, port, GM_TXO_OK_LO);
+       data[1] = (u64) gma_read32(hw, port, GM_RXO_OK_HI) << 32
+               | gma_read32(hw, port, GM_RXO_OK_LO);
 
        for (i = 2; i < ARRAY_SIZE(skge_stats); i++)
-               data[i] = skge_gma_read32(hw, port,
+               data[i] = gma_read32(hw, port,
                                          skge_stats[i].gma_offset);
 }
 
 static void yukon_mac_intr(struct skge_hw *hw, int port)
 {
-       struct skge_port *skge = netdev_priv(hw->dev[port]);
-       u8 status = skge_read8(hw, SKGEMAC_REG(port, GMAC_IRQ_SRC));
+       struct net_device *dev = hw->dev[port];
+       struct skge_port *skge = netdev_priv(dev);
+       u8 status = skge_read8(hw, SK_REG(port, GMAC_IRQ_SRC));
+
+       if (netif_msg_intr(skge))
+               printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n",
+                      dev->name, status);
 
-       pr_debug("yukon_intr status %x\n", status);
        if (status & GM_IS_RX_FF_OR) {
                ++skge->net_stats.rx_fifo_errors;
-               skge_gma_write8(hw, port, RX_GMF_CTRL_T, GMF_CLI_RX_FO);
+               gma_write8(hw, port, RX_GMF_CTRL_T, GMF_CLI_RX_FO);
        }
        if (status & GM_IS_TX_FF_UR) {
                ++skge->net_stats.tx_fifo_errors;
-               skge_gma_write8(hw, port, TX_GMF_CTRL_T, GMF_CLI_TX_FU);
+               gma_write8(hw, port, TX_GMF_CTRL_T, GMF_CLI_TX_FU);
        }
 
 }
 
 static u16 yukon_speed(const struct skge_hw *hw, u16 aux)
 {
-       if (hw->chip_id == CHIP_ID_YUKON_FE)
-               return (aux & PHY_M_PS_SPEED_100) ? SPEED_100 : SPEED_10;
-
-       switch(aux & PHY_M_PS_SPEED_MSK) {
+       switch (aux & PHY_M_PS_SPEED_MSK) {
        case PHY_M_PS_SPEED_1000:
                return SPEED_1000;
        case PHY_M_PS_SPEED_100:
@@ -1981,15 +1888,15 @@ static void yukon_link_up(struct skge_port *skge)
        /* Enable Transmit FIFO Underrun */
        skge_write8(hw, GMAC_IRQ_MSK, GMAC_DEF_MSK);
 
-       reg = skge_gma_read16(hw, port, GM_GP_CTRL);
+       reg = gma_read16(hw, port, GM_GP_CTRL);
        if (skge->duplex == DUPLEX_FULL || skge->autoneg == AUTONEG_ENABLE)
                reg |= GM_GPCR_DUP_FULL;
 
        /* enable Rx/Tx */
        reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
-       skge_gma_write16(hw, port, GM_GP_CTRL, reg);
+       gma_write16(hw, port, GM_GP_CTRL, reg);
 
-       skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+       gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
        skge_link_up(skge);
 }
 
@@ -1999,16 +1906,15 @@ static void yukon_link_down(struct skge_port *skge)
        int port = skge->port;
 
        pr_debug("yukon_link_down\n");
-       skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);
-       skge_gm_phy_write(hw, port, GM_GP_CTRL,
-                         skge_gm_phy_read(hw, port, GM_GP_CTRL)
+       gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);
+       gm_phy_write(hw, port, GM_GP_CTRL,
+                         gm_phy_read(hw, port, GM_GP_CTRL)
                          & ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA));
 
-       if (hw->chip_id != CHIP_ID_YUKON_FE &&
-           skge->flow_control == FLOW_MODE_REM_SEND) {
+       if (skge->flow_control == FLOW_MODE_REM_SEND) {
                /* restore Asymmetric Pause bit */
-               skge_gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
-                                 skge_gm_phy_read(hw, port,
+               gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
+                                 gm_phy_read(hw, port,
                                                   PHY_MARV_AUNE_ADV)
                                  | PHY_M_AN_ASP);
 
@@ -2027,20 +1933,21 @@ static void yukon_phy_intr(struct skge_port *skge)
        const char *reason = NULL;
        u16 istatus, phystat;
 
-       istatus = skge_gm_phy_read(hw, port, PHY_MARV_INT_STAT);
-       phystat = skge_gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
-       pr_debug("yukon phy intr istat=%x phy_stat=%x\n", istatus, phystat);
+       istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT);
+       phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
+
+       if (netif_msg_intr(skge))
+               printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x 0x%x\n",
+                      skge->netdev->name, istatus, phystat);
 
        if (istatus & PHY_M_IS_AN_COMPL) {
-               if (skge_gm_phy_read(hw, port, PHY_MARV_AUNE_LP)
+               if (gm_phy_read(hw, port, PHY_MARV_AUNE_LP)
                    & PHY_M_AN_RF) {
                        reason = "remote fault";
                        goto failed;
                }
 
-               if (!(hw->chip_id == CHIP_ID_YUKON_FE || hw->chip_id == CHIP_ID_YUKON_EC)
-                   && (skge_gm_phy_read(hw, port, PHY_MARV_1000T_STAT)
-                       & PHY_B_1000S_MSF)) {
+               if (gm_phy_read(hw, port, PHY_MARV_1000T_STAT) & PHY_B_1000S_MSF) {
                        reason = "master/slave fault";
                        goto failed;
                }
@@ -2054,10 +1961,6 @@ static void yukon_phy_intr(struct skge_port *skge)
                        ? DUPLEX_FULL : DUPLEX_HALF;
                skge->speed = yukon_speed(hw, phystat);
 
-               /* Tx & Rx Pause Enabled bits are at 9..8 */
-               if (hw->chip_id == CHIP_ID_YUKON_XL)
-                       phystat >>= 6;
-
                /* We are using IEEE 802.3z/D5.0 Table 37-4 */
                switch (phystat & PHY_M_PS_PAUSE_MSK) {
                case PHY_M_PS_PAUSE_MSK:
@@ -2075,9 +1978,9 @@ static void yukon_phy_intr(struct skge_port *skge)
 
                if (skge->flow_control == FLOW_MODE_NONE ||
                    (skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF))
-                       skge_write8(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+                       skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
                else
-                       skge_write8(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
+                       skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
                yukon_link_up(skge);
                return;
        }
@@ -2161,6 +2064,12 @@ static int skge_up(struct net_device *dev)
        if (netif_msg_ifup(skge))
                printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
 
+       if (dev->mtu > RX_BUF_SIZE)
+               skge->rx_buf_size = dev->mtu + ETH_HLEN + NET_IP_ALIGN;
+       else
+               skge->rx_buf_size = RX_BUF_SIZE;
+
+
        rx_size = skge->rx_ring.count * sizeof(struct skge_rx_desc);
        tx_size = skge->tx_ring.count * sizeof(struct skge_tx_desc);
        skge->mem_size = tx_size + rx_size;
@@ -2173,7 +2082,8 @@ static int skge_up(struct net_device *dev)
        if ((err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma)))
                goto free_pci_mem;
 
-       if (skge_rx_fill(skge))
+       err = skge_rx_fill(skge);
+       if (err)
                goto free_rx_ring;
 
        if ((err = skge_ring_alloc(&skge->tx_ring, skge->mem + rx_size,
@@ -2182,6 +2092,10 @@ static int skge_up(struct net_device *dev)
 
        skge->tx_avail = skge->tx_ring.count - 1;
 
+       /* Enable IRQ from port */
+       hw->intr_mask |= portirqmask[port];
+       skge_write32(hw, B0_IMSK, hw->intr_mask);
+
        /* Initialze MAC */
        if (hw->chip_id == CHIP_ID_GENESIS)
                genesis_mac_init(hw, port);
@@ -2189,7 +2103,7 @@ static int skge_up(struct net_device *dev)
                yukon_mac_init(hw, port);
 
        /* Configure RAMbuffers */
-       chunk = hw->ram_size / (isdualport(hw) ? 4 : 2);
+       chunk = hw->ram_size / ((hw->ports + 1)*2);
        ram_addr = hw->ram_offset + 2 * chunk * port;
 
        skge_ramset(hw, rxqaddr[port], ram_addr, chunk);
@@ -2227,7 +2141,6 @@ static int skge_down(struct net_device *dev)
        netif_stop_queue(dev);
 
        del_timer_sync(&skge->led_blink);
-       del_timer_sync(&skge->link_check);
 
        /* Stop transmitter */
        skge_write8(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_STOP);
@@ -2240,12 +2153,12 @@ static int skge_down(struct net_device *dev)
                yukon_stop(skge);
 
        /* Disable Force Sync bit and Enable Alloc bit */
-       skge_write8(hw, SKGEMAC_REG(port, TXA_CTRL),
+       skge_write8(hw, SK_REG(port, TXA_CTRL),
                    TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
 
        /* Stop Interval Timer and Limit Counter of Tx Arbiter */
-       skge_write32(hw, SKGEMAC_REG(port, TXA_ITI_INI), 0L);
-       skge_write32(hw, SKGEMAC_REG(port, TXA_LIM_INI), 0L);
+       skge_write32(hw, SK_REG(port, TXA_ITI_INI), 0L);
+       skge_write32(hw, SK_REG(port, TXA_LIM_INI), 0L);
 
        /* Reset PCI FIFO */
        skge_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_SET_RESET);
@@ -2260,13 +2173,13 @@ static int skge_down(struct net_device *dev)
        skge_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_SET_RESET);
 
        if (hw->chip_id == CHIP_ID_GENESIS) {
-               skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_RST_SET);
-               skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_RST_SET);
-               skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_STOP);
-               skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_STOP);
+               skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_SET);
+               skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_RST_SET);
+               skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_STOP);
+               skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_STOP);
        } else {
-               skge_write8(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
-               skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
+               skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
+               skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
        }
 
        /* turn off led's */
@@ -2299,10 +2212,10 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
 
        local_irq_save(flags);
        if (!spin_trylock(&skge->tx_lock)) {
-               /* Collision - tell upper layer to requeue */ 
-               local_irq_restore(flags); 
-               return NETDEV_TX_LOCKED; 
-       } 
+               /* Collision - tell upper layer to requeue */
+               local_irq_restore(flags);
+               return NETDEV_TX_LOCKED;
+       }
 
        if (unlikely(skge->tx_avail < skb_shinfo(skb)->nr_frags +1)) {
                netif_stop_queue(dev);
@@ -2333,7 +2246,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
                 * does.  Looks like hardware is wrong?
                 */
                if (ip->protocol == IPPROTO_UDP
-                   && chip_rev(hw) == 0 && hw->chip_id == CHIP_ID_YUKON)
+                   && hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON)
                        control = BMU_TCP_CHECK;
                else
                        control = BMU_UDP_CHECK;
@@ -2394,6 +2307,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
 
 static inline void skge_tx_free(struct skge_hw *hw, struct skge_element *e)
 {
+       /* This ring element can be skb or fragment */
        if (e->skb) {
                pci_unmap_single(hw->pdev,
                               pci_unmap_addr(e, mapaddr),
@@ -2438,16 +2352,17 @@ static void skge_tx_timeout(struct net_device *dev)
 static int skge_change_mtu(struct net_device *dev, int new_mtu)
 {
        int err = 0;
+       int running = netif_running(dev);
 
-       if(new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
+       if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
                return -EINVAL;
 
-       dev->mtu = new_mtu;
 
-       if (netif_running(dev)) {
+       if (running)
                skge_down(dev);
+       dev->mtu = new_mtu;
+       if (running)
                skge_up(dev);
-       }
 
        return err;
 }
@@ -2462,7 +2377,9 @@ static void genesis_set_multicast(struct net_device *dev)
        u32 mode;
        u8 filter[8];
 
-       mode = skge_xm_read32(hw, port, XM_MODE);
+       pr_debug("genesis_set_multicast flags=%x count=%d\n", dev->flags, dev->mc_count);
+
+       mode = xm_read32(hw, port, XM_MODE);
        mode |= XM_MD_ENA_HASH;
        if (dev->flags & IFF_PROMISC)
                mode |= XM_MD_ENA_PROM;
@@ -2473,17 +2390,16 @@ static void genesis_set_multicast(struct net_device *dev)
                memset(filter, 0xff, sizeof(filter));
        else {
                memset(filter, 0, sizeof(filter));
-               for(i = 0; list && i < count; i++, list = list->next) {
-                       u32 crc = crc32_le(~0, list->dmi_addr, ETH_ALEN);
-                       u8 bit = 63 - (crc & 63);
-
+               for (i = 0; list && i < count; i++, list = list->next) {
+                       u32 crc, bit;
+                       crc = ether_crc_le(ETH_ALEN, list->dmi_addr);
+                       bit = ~crc & 0x3f;
                        filter[bit/8] |= 1 << (bit%8);
                }
        }
 
-       skge_xm_outhash(hw, port, XM_HSM, filter);
-
-       skge_xm_write32(hw, port, XM_MODE, mode);
+       xm_write32(hw, port, XM_MODE, mode);
+       xm_outhash(hw, port, XM_HSM, filter);
 }
 
 static void yukon_set_multicast(struct net_device *dev)
@@ -2497,7 +2413,7 @@ static void yukon_set_multicast(struct net_device *dev)
 
        memset(filter, 0, sizeof(filter));
 
-       reg = skge_gma_read16(hw, port, GM_RX_CTRL);
+       reg = gma_read16(hw, port, GM_RX_CTRL);
        reg |= GM_RXCR_UCF_ENA;
 
        if (dev->flags & IFF_PROMISC)           /* promiscious */
@@ -2510,23 +2426,23 @@ static void yukon_set_multicast(struct net_device *dev)
                int i;
                reg |= GM_RXCR_MCF_ENA;
 
-               for(i = 0; list && i < dev->mc_count; i++, list = list->next) {
+               for (i = 0; list && i < dev->mc_count; i++, list = list->next) {
                        u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f;
                        filter[bit/8] |= 1 << (bit%8);
                }
        }
 
 
-       skge_gma_write16(hw, port, GM_MC_ADDR_H1,
+       gma_write16(hw, port, GM_MC_ADDR_H1,
                         (u16)filter[0] | ((u16)filter[1] << 8));
-       skge_gma_write16(hw, port, GM_MC_ADDR_H2,
+       gma_write16(hw, port, GM_MC_ADDR_H2,
                         (u16)filter[2] | ((u16)filter[3] << 8));
-       skge_gma_write16(hw, port, GM_MC_ADDR_H3,
+       gma_write16(hw, port, GM_MC_ADDR_H3,
                         (u16)filter[4] | ((u16)filter[5] << 8));
-       skge_gma_write16(hw, port, GM_MC_ADDR_H4,
+       gma_write16(hw, port, GM_MC_ADDR_H4,
                         (u16)filter[6] | ((u16)filter[7] << 8));
 
-       skge_gma_write16(hw, port, GM_RX_CTRL, reg);
+       gma_write16(hw, port, GM_RX_CTRL, reg);
 }
 
 static inline int bad_phy_status(const struct skge_hw *hw, u32 status)
@@ -2545,28 +2461,76 @@ static void skge_rx_error(struct skge_port *skge, int slot,
                printk(KERN_DEBUG PFX "%s: rx err, slot %d control 0x%x status 0x%x\n",
                       skge->netdev->name, slot, control, status);
 
-       if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
-           || (control & BMU_BBC) > skge->netdev->mtu + VLAN_ETH_HLEN)
+       if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF))
                skge->net_stats.rx_length_errors++;
-       else {
-               if (skge->hw->chip_id == CHIP_ID_GENESIS) {
-                       if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR))
-                               skge->net_stats.rx_length_errors++;
-                       if (status & XMR_FS_FRA_ERR)
-                               skge->net_stats.rx_frame_errors++;
-                       if (status & XMR_FS_FCS_ERR)
-                               skge->net_stats.rx_crc_errors++;
-               } else {
-                       if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE))
-                               skge->net_stats.rx_length_errors++;
-                       if (status & GMR_FS_FRAGMENT)
-                               skge->net_stats.rx_frame_errors++;
-                       if (status & GMR_FS_CRC_ERR)
-                               skge->net_stats.rx_crc_errors++;
+       else if (skge->hw->chip_id == CHIP_ID_GENESIS) {
+               if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR))
+                       skge->net_stats.rx_length_errors++;
+               if (status & XMR_FS_FRA_ERR)
+                       skge->net_stats.rx_frame_errors++;
+               if (status & XMR_FS_FCS_ERR)
+                       skge->net_stats.rx_crc_errors++;
+       } else {
+               if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE))
+                       skge->net_stats.rx_length_errors++;
+               if (status & GMR_FS_FRAGMENT)
+                       skge->net_stats.rx_frame_errors++;
+               if (status & GMR_FS_CRC_ERR)
+                       skge->net_stats.rx_crc_errors++;
+       }
+}
+
+/* Get receive buffer from descriptor.
+ * Handles copy of small buffers and reallocation failures
+ */
+static inline struct sk_buff *skge_rx_get(struct skge_port *skge,
+                                         struct skge_element *e,
+                                         unsigned int len)
+{
+       struct sk_buff *nskb, *skb;
+
+       if (len < RX_COPY_THRESHOLD) {
+               nskb = skge_rx_alloc(skge->netdev, len + NET_IP_ALIGN);
+               if (unlikely(!nskb))
+                       return NULL;
+
+               pci_dma_sync_single_for_cpu(skge->hw->pdev,
+                                           pci_unmap_addr(e, mapaddr),
+                                           len, PCI_DMA_FROMDEVICE);
+               memcpy(nskb->data, e->skb->data, len);
+               pci_dma_sync_single_for_device(skge->hw->pdev,
+                                              pci_unmap_addr(e, mapaddr),
+                                              len, PCI_DMA_FROMDEVICE);
+
+               if (skge->rx_csum) {
+                       struct skge_rx_desc *rd = e->desc;
+                       nskb->csum = le16_to_cpu(rd->csum2);
+                       nskb->ip_summed = CHECKSUM_HW;
                }
+               skge_rx_reuse(e, skge->rx_buf_size);
+               return nskb;
+       } else {
+               nskb = skge_rx_alloc(skge->netdev, skge->rx_buf_size);
+               if (unlikely(!nskb))
+                       return NULL;
+
+               pci_unmap_single(skge->hw->pdev,
+                                pci_unmap_addr(e, mapaddr),
+                                pci_unmap_len(e, maplen),
+                                PCI_DMA_FROMDEVICE);
+               skb = e->skb;
+               if (skge->rx_csum) {
+                       struct skge_rx_desc *rd = e->desc;
+                       skb->csum = le16_to_cpu(rd->csum2);
+                       skb->ip_summed = CHECKSUM_HW;
+               }
+
+               skge_rx_setup(skge, e, nskb, skge->rx_buf_size);
+               return skb;
        }
 }
 
+
 static int skge_poll(struct net_device *dev, int *budget)
 {
        struct skge_port *skge = netdev_priv(dev);
@@ -2575,13 +2539,12 @@ static int skge_poll(struct net_device *dev, int *budget)
        struct skge_element *e;
        unsigned int to_do = min(dev->quota, *budget);
        unsigned int work_done = 0;
-       int done;
-       static const u32 irqmask[] = { IS_PORT_1, IS_PORT_2 };
 
-       for (e = ring->to_clean; e != ring->to_use && work_done < to_do;
-            e = e->next) {
+       pr_debug("skge_poll\n");
+
+       for (e = ring->to_clean; work_done < to_do; e = e->next) {
                struct skge_rx_desc *rd = e->desc;
-               struct sk_buff *skb = e->skb;
+               struct sk_buff *skb;
                u32 control, len, status;
 
                rmb();
@@ -2590,19 +2553,12 @@ static int skge_poll(struct net_device *dev, int *budget)
                        break;
 
                len = control & BMU_BBC;
-               e->skb = NULL;
-
-               pci_unmap_single(hw->pdev,
-                                pci_unmap_addr(e, mapaddr),
-                                pci_unmap_len(e, maplen),
-                                PCI_DMA_FROMDEVICE);
-
                status = rd->status;
-               if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
-                    || len > dev->mtu + VLAN_ETH_HLEN
-                    || bad_phy_status(hw, status)) {
+
+               if (unlikely((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
+                            || bad_phy_status(hw, status))) {
                        skge_rx_error(skge, e - ring->start, control, status);
-                       dev_kfree_skb(skb);
+                       skge_rx_reuse(e, skge->rx_buf_size);
                        continue;
                }
 
@@ -2610,43 +2566,37 @@ static int skge_poll(struct net_device *dev, int *budget)
                    printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n",
                           dev->name, e - ring->start, rd->status, len);
 
-               skb_put(skb, len);
-               skb->protocol = eth_type_trans(skb, dev);
-
-               if (skge->rx_csum) {
-                       skb->csum = le16_to_cpu(rd->csum2);
-                       skb->ip_summed = CHECKSUM_HW;
-               }
+               skb = skge_rx_get(skge, e, len);
+               if (likely(skb)) {
+                       skb_put(skb, len);
+                       skb->protocol = eth_type_trans(skb, dev);
 
-               dev->last_rx = jiffies;
-               netif_receive_skb(skb);
+                       dev->last_rx = jiffies;
+                       netif_receive_skb(skb);
 
-               ++work_done;
+                       ++work_done;
+               } else
+                       skge_rx_reuse(e, skge->rx_buf_size);
        }
        ring->to_clean = e;
 
-       *budget -= work_done;
-       dev->quota -= work_done;
-       done = work_done < to_do;
-
-       if (skge_rx_fill(skge))
-               done = 0;
-
        /* restart receiver */
        wmb();
        skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR),
                    CSR_START | CSR_IRQ_CL_F);
 
-       if (done) {
-               local_irq_disable();
-               hw->intr_mask |= irqmask[skge->port];
-               /* Order is important since data can get interrupted */
-               skge_write32(hw, B0_IMSK, hw->intr_mask);
-               __netif_rx_complete(dev);
-               local_irq_enable();
-       }
+       *budget -= work_done;
+       dev->quota -= work_done;
 
-       return !done;
+       if (work_done >=  to_do)
+               return 1; /* not done */
+
+       local_irq_disable();
+       __netif_rx_complete(dev);
+       hw->intr_mask |= portirqmask[skge->port];
+       skge_write32(hw, B0_IMSK, hw->intr_mask);
+       local_irq_enable();
+       return 0;
 }
 
 static inline void skge_tx_intr(struct net_device *dev)
@@ -2657,7 +2607,7 @@ static inline void skge_tx_intr(struct net_device *dev)
        struct skge_element *e;
 
        spin_lock(&skge->tx_lock);
-       for(e = ring->to_clean; e != ring->to_use; e = e->next) {
+       for (e = ring->to_clean; e != ring->to_use; e = e->next) {
                struct skge_tx_desc *td = e->desc;
                u32 control;
 
@@ -2690,12 +2640,12 @@ static void skge_mac_parity(struct skge_hw *hw, int port)
               : (port == 0 ? "(port A)": "(port B"));
 
        if (hw->chip_id == CHIP_ID_GENESIS)
-               skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1),
+               skge_write16(hw, SK_REG(port, TX_MFF_CTRL1),
                             MFF_CLR_PERR);
        else
                /* HW-Bug #8: cleared by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE */
-               skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T),
-                           (hw->chip_id == CHIP_ID_YUKON && chip_rev(hw) == 0)
+               skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T),
+                           (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)
                            ? GMF_CLI_TX_FC : GMF_CLI_TX_PE);
 }
 
@@ -2703,16 +2653,16 @@ static void skge_pci_clear(struct skge_hw *hw)
 {
        u16 status;
 
-       status = skge_read16(hw, SKGEPCI_REG(PCI_STATUS));
+       pci_read_config_word(hw->pdev, PCI_STATUS, &status);
        skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-       skge_write16(hw, SKGEPCI_REG(PCI_STATUS),
-                    status | PCI_STATUS_ERROR_BITS);
+       pci_write_config_word(hw->pdev, PCI_STATUS,
+                             status | PCI_STATUS_ERROR_BITS);
        skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
 }
 
 static void skge_mac_intr(struct skge_hw *hw, int port)
 {
-       if (hw->chip_id == CHIP_ID_GENESIS) 
+       if (hw->chip_id == CHIP_ID_GENESIS)
                genesis_mac_intr(hw, port);
        else
                yukon_mac_intr(hw, port);
@@ -2726,9 +2676,9 @@ static void skge_error_irq(struct skge_hw *hw)
        if (hw->chip_id == CHIP_ID_GENESIS) {
                /* clear xmac errors */
                if (hwstatus & (IS_NO_STAT_M1|IS_NO_TIST_M1))
-                       skge_write16(hw, SKGEMAC_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT);
+                       skge_write16(hw, SK_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT);
                if (hwstatus & (IS_NO_STAT_M2|IS_NO_TIST_M2))
-                       skge_write16(hw, SKGEMAC_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT);
+                       skge_write16(hw, SK_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT);
        } else {
                /* Timestamp (unused) overflow */
                if (hwstatus & IS_IRQ_TIST_OV)
@@ -2803,8 +2753,8 @@ static void skge_extirq(unsigned long data)
 
                        if (hw->chip_id != CHIP_ID_GENESIS)
                                yukon_phy_intr(skge);
-                       else if (hw->phy_type == SK_PHY_BCOM)
-                               genesis_bcom_intr(skge);
+                       else
+                               bcom_phy_intr(skge);
                }
        }
        spin_unlock(&hw->phy_lock);
@@ -2824,19 +2774,14 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
                return IRQ_NONE;
 
        status &= hw->intr_mask;
-
-       if ((status & IS_R1_F) && netif_rx_schedule_prep(hw->dev[0])) {
-               status &= ~IS_R1_F;
+       if (status & IS_R1_F) {
                hw->intr_mask &= ~IS_R1_F;
-               skge_write32(hw, B0_IMSK, hw->intr_mask);
-               __netif_rx_schedule(hw->dev[0]);
+               netif_rx_schedule(hw->dev[0]);
        }
 
-       if ((status & IS_R2_F) && netif_rx_schedule_prep(hw->dev[1])) {
-               status &= ~IS_R2_F;
+       if (status & IS_R2_F) {
                hw->intr_mask &= ~IS_R2_F;
-               skge_write32(hw, B0_IMSK, hw->intr_mask);
-               __netif_rx_schedule(hw->dev[1]);
+               netif_rx_schedule(hw->dev[1]);
        }
 
        if (status & IS_XA1_F)
@@ -2845,9 +2790,27 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
        if (status & IS_XA2_F)
                skge_tx_intr(hw->dev[1]);
 
+       if (status & IS_PA_TO_RX1) {
+               struct skge_port *skge = netdev_priv(hw->dev[0]);
+               ++skge->net_stats.rx_over_errors;
+               skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX1);
+       }
+
+       if (status & IS_PA_TO_RX2) {
+               struct skge_port *skge = netdev_priv(hw->dev[1]);
+               ++skge->net_stats.rx_over_errors;
+               skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX2);
+       }
+
+       if (status & IS_PA_TO_TX1)
+               skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX1);
+
+       if (status & IS_PA_TO_TX2)
+               skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX2);
+
        if (status & IS_MAC1)
                skge_mac_intr(hw, 0);
-       
+
        if (status & IS_MAC2)
                skge_mac_intr(hw, 1);
 
@@ -2859,8 +2822,7 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
                tasklet_schedule(&hw->ext_tasklet);
        }
 
-       if (status)
-               skge_write32(hw, B0_IMSK, hw->intr_mask);
+       skge_write32(hw, B0_IMSK, hw->intr_mask);
 
        return IRQ_HANDLED;
 }
@@ -2904,9 +2866,6 @@ static const struct {
        { CHIP_ID_YUKON,         "Yukon" },
        { CHIP_ID_YUKON_LITE,    "Yukon-Lite"},
        { CHIP_ID_YUKON_LP,      "Yukon-LP"},
-       { CHIP_ID_YUKON_XL,      "Yukon-2 XL"},
-       { CHIP_ID_YUKON_EC,      "YUKON-2 EC"},
-       { CHIP_ID_YUKON_FE,      "YUKON-2 FE"},
 };
 
 static const char *skge_board_name(const struct skge_hw *hw)
@@ -2930,8 +2889,8 @@ static const char *skge_board_name(const struct skge_hw *hw)
 static int skge_reset(struct skge_hw *hw)
 {
        u16 ctst;
-       u8 t8;
-       int i, ports;
+       u8 t8, mac_cfg;
+       int i;
 
        ctst = skge_read16(hw, B0_CTST);
 
@@ -2952,12 +2911,9 @@ static int skge_reset(struct skge_hw *hw)
        hw->phy_type = skge_read8(hw, B2_E_1) & 0xf;
        hw->pmd_type = skge_read8(hw, B2_PMD_TYP);
 
-       switch(hw->chip_id) {
+       switch (hw->chip_id) {
        case CHIP_ID_GENESIS:
                switch (hw->phy_type) {
-               case SK_PHY_XMAC:
-                       hw->phy_addr = PHY_ADDR_XMAC;
-                       break;
                case SK_PHY_BCOM:
                        hw->phy_addr = PHY_ADDR_BCOM;
                        break;
@@ -2986,8 +2942,9 @@ static int skge_reset(struct skge_hw *hw)
                return -EOPNOTSUPP;
        }
 
-       hw->mac_cfg = skge_read8(hw, B2_MAC_CFG);
-       ports = isdualport(hw) ? 2 : 1;
+       mac_cfg = skge_read8(hw, B2_MAC_CFG);
+       hw->ports = (mac_cfg & CFG_SNG_MAC) ? 1 : 2;
+       hw->chip_rev = (mac_cfg & CFG_CHIP_R_MSK) >> 4;
 
        /* read the adapters RAM size */
        t8 = skge_read8(hw, B2_E_0);
@@ -3010,9 +2967,9 @@ static int skge_reset(struct skge_hw *hw)
                /* switch power to VCC (WA for VAUX problem) */
                skge_write8(hw, B0_POWER_CTRL,
                            PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
-               for (i = 0; i < ports; i++) {
-                       skge_write16(hw, SKGEMAC_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
-                       skge_write16(hw, SKGEMAC_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
+               for (i = 0; i < hw->ports; i++) {
+                       skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
+                       skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
                }
        }
 
@@ -3022,8 +2979,8 @@ static int skge_reset(struct skge_hw *hw)
        skge_write8(hw, B0_LED, LED_STAT_ON);
 
        /* enable the Tx Arbiters */
-       for (i = 0; i < ports; i++)
-               skge_write8(hw, SKGEMAC_REG(i, TXA_CTRL), TXA_ENA_ARB);
+       for (i = 0; i < hw->ports; i++)
+               skge_write8(hw, SK_REG(i, TXA_CTRL), TXA_ENA_ARB);
 
        /* Initialize ram interface */
        skge_write16(hw, B3_RI_CTRL, RI_RST_CLR);
@@ -3050,16 +3007,14 @@ static int skge_reset(struct skge_hw *hw)
        skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100));
        skge_write32(hw, B2_IRQM_CTRL, TIM_START);
 
-       hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1;
-       if (isdualport(hw))
-               hw->intr_mask |= IS_PORT_2;
+       hw->intr_mask = IS_HW_ERR | IS_EXT_REG;
        skge_write32(hw, B0_IMSK, hw->intr_mask);
 
        if (hw->chip_id != CHIP_ID_GENESIS)
                skge_write8(hw, GMAC_IRQ_MSK, 0);
 
        spin_lock_bh(&hw->phy_lock);
-       for (i = 0; i < ports; i++) {
+       for (i = 0; i < hw->ports; i++) {
                if (hw->chip_id == CHIP_ID_GENESIS)
                        genesis_reset(hw, i);
                else
@@ -3071,7 +3026,8 @@ static int skge_reset(struct skge_hw *hw)
 }
 
 /* Initialize network device */
-static struct net_device *skge_devinit(struct skge_hw *hw, int port)
+static struct net_device *skge_devinit(struct skge_hw *hw, int port,
+                                      int highmem)
 {
        struct skge_port *skge;
        struct net_device *dev = alloc_etherdev(sizeof(*skge));
@@ -3104,6 +3060,8 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port)
 #endif
        dev->irq = hw->pdev->irq;
        dev->features = NETIF_F_LLTX;
+       if (highmem)
+               dev->features |= NETIF_F_HIGHDMA;
 
        skge = netdev_priv(dev);
        skge->netdev = dev;
@@ -3117,7 +3075,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port)
        skge->flow_control = FLOW_MODE_SYMMETRIC;
        skge->duplex = -1;
        skge->speed = -1;
-       skge->advertising = skge_modes(hw);
+       skge->advertising = skge_supported_modes(hw);
 
        hw->dev[port] = dev;
 
@@ -3125,10 +3083,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port)
 
        spin_lock_init(&skge->tx_lock);
 
-       init_timer(&skge->link_check);
-       skge->link_check.function = skge_link_timer;
-       skge->link_check.data = (unsigned long) skge;
-
        init_timer(&skge->led_blink);
        skge->led_blink.function = skge_blink_timer;
        skge->led_blink.data = (unsigned long) skge;
@@ -3232,14 +3186,11 @@ static int __devinit skge_probe(struct pci_dev *pdev,
 
        printk(KERN_INFO PFX "addr 0x%lx irq %d chip %s rev %d\n",
               pci_resource_start(pdev, 0), pdev->irq,
-              skge_board_name(hw), chip_rev(hw));
+              skge_board_name(hw), hw->chip_rev);
 
-       if ((dev = skge_devinit(hw, 0)) == NULL)
+       if ((dev = skge_devinit(hw, 0, using_dac)) == NULL)
                goto err_out_led_off;
 
-       if (using_dac)
-               dev->features |= NETIF_F_HIGHDMA;
-
        if ((err = register_netdev(dev))) {
                printk(KERN_ERR PFX "%s: cannot register net device\n",
                       pci_name(pdev));
@@ -3248,10 +3199,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
 
        skge_show_addr(dev);
 
-       if (isdualport(hw) && (dev1 = skge_devinit(hw, 1))) {
-               if (using_dac)
-                       dev1->features |= NETIF_F_HIGHDMA;
-
+       if (hw->ports > 1 && (dev1 = skge_devinit(hw, 1, using_dac))) {
                if (register_netdev(dev1) == 0)
                        skge_show_addr(dev1);
                else {
@@ -3288,7 +3236,7 @@ static void __devexit skge_remove(struct pci_dev *pdev)
        struct skge_hw *hw  = pci_get_drvdata(pdev);
        struct net_device *dev0, *dev1;
 
-       if(!hw)
+       if (!hw)
                return;
 
        if ((dev1 = hw->dev[1]))
@@ -3316,7 +3264,7 @@ static int skge_suspend(struct pci_dev *pdev, u32 state)
        struct skge_hw *hw  = pci_get_drvdata(pdev);
        int i, wol = 0;
 
-       for(i = 0; i < 2; i++) {
+       for (i = 0; i < 2; i++) {
                struct net_device *dev = hw->dev[i];
 
                if (dev) {
@@ -3349,11 +3297,11 @@ static int skge_resume(struct pci_dev *pdev)
 
        skge_reset(hw);
 
-       for(i = 0; i < 2; i++) {
+       for (i = 0; i < 2; i++) {
                struct net_device *dev = hw->dev[i];
                if (dev) {
                        netif_device_attach(dev);
-                       if(netif_running(dev))
+                       if (netif_running(dev))
                                skge_up(dev);
                }
        }
index 36c62b68fab4f8a5185ccb8eb4ef2a5fa0d91122..14d0cc01fb9a7ee90abae1648ee7a79746928f0a 100644 (file)
@@ -7,31 +7,6 @@
 /* PCI config registers */
 #define PCI_DEV_REG1   0x40
 #define PCI_DEV_REG2   0x44
-#ifndef PCI_VPD
-#define PCI_VPD                0x50
-#endif
-
-/*     PCI_OUR_REG_2           32 bit  Our Register 2 */
-enum {
-       PCI_VPD_WR_THR  = 0xff<<24, /* Bit 31..24:      VPD Write Threshold */
-       PCI_DEV_SEL     = 0x7f<<17, /* Bit 23..17:      EEPROM Device Select */
-       PCI_VPD_ROM_SZ  = 7   <<14, /* Bit 16..14:      VPD ROM Size    */
-                                   /* Bit 13..12:      reserved        */
-       PCI_EN_DUMMY_RD = 1<<3, /* Enable Dummy Read */
-       PCI_REV_DESC    = 1<<2, /* Reverse Desc. Bytes */
-       PCI_USEDATA64   = 1<<0, /* Use 64Bit Data bus ext */
-};
-
-/*     PCI_VPD_ADR_REG         16 bit  VPD Address Register */
-enum {
-       PCI_VPD_FLAG    = 1<<15,  /* starts VPD rd/wr cycle */
-       PCI_VPD_ADR_MSK =0x7fffL, /* Bit 14.. 0:        VPD Address Mask */
-       VPD_RES_ID      = 0x82,
-       VPD_RES_READ    = 0x90,
-       VPD_RES_WRITE   = 0x81,
-       VPD_RES_END     = 0x78,
-};
-
 
 #define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \
                               PCI_STATUS_SIG_SYSTEM_ERROR | \
@@ -39,7 +14,6 @@ enum {
                               PCI_STATUS_REC_TARGET_ABORT | \
                               PCI_STATUS_PARITY)
 
-
 enum csr_regs {
        B0_RAP  = 0x0000,
        B0_CTST = 0x0004,
@@ -229,8 +203,11 @@ enum {
        IS_XA2_F        = 1<<1,         /* Q_XA2 End of Frame */
        IS_XA2_C        = 1<<0,         /* Q_XA2 Encoding Error */
 
-       IS_PORT_1       = IS_XA1_F| IS_R1_F| IS_MAC1,
-       IS_PORT_2       = IS_XA2_F| IS_R2_F| IS_MAC2,
+       IS_TO_PORT1     = IS_PA_TO_RX1 | IS_PA_TO_TX1,
+       IS_TO_PORT2     = IS_PA_TO_RX2 | IS_PA_TO_TX2,
+
+       IS_PORT_1       = IS_XA1_F| IS_R1_F | IS_TO_PORT1 | IS_MAC1,
+       IS_PORT_2       = IS_XA2_F| IS_R2_F | IS_TO_PORT2 | IS_MAC2,
 };
 
 
@@ -288,14 +265,6 @@ enum {
        CHIP_REV_YU_LITE_A3  = 7,       /* Chip Rev. for YUKON-Lite A3 */
 };
 
-/*     B2_LD_TEST               8 bit  EPROM loader test register */
-enum {
-       LD_T_ON         = 1<<3, /* Loader Test mode on */
-       LD_T_OFF        = 1<<2, /* Loader Test mode off */
-       LD_T_STEP       = 1<<1, /* Decrement FPROM addr. Counter */
-       LD_START        = 1<<0, /* Start loading FPROM */
-};
-
 /*     B2_TI_CTRL               8 bit  Timer control */
 /*     B2_IRQM_CTRL     8 bit  IRQ Moderation Timer Control */
 enum {
@@ -313,16 +282,6 @@ enum {
        TIM_T_STEP      = 1<<0, /* Test step */
 };
 
-/*     B28_DPT_INI     32 bit  Descriptor Poll Timer Init Val */
-/*     B28_DPT_VAL     32 bit  Descriptor Poll Timer Curr Val */
-/*     B28_DPT_CTRL     8 bit  Descriptor Poll Timer Ctrl Reg */
-enum {
-       DPT_MSK = 0x00ffffffL,  /* Bit 23.. 0:  Desc Poll Timer Bits */
-
-       DPT_START       = 1<<1, /* Start Descriptor Poll Timer */
-       DPT_STOP        = 1<<0, /* Stop  Descriptor Poll Timer */
-};
-
 /*     B2_GP_IO                32 bit  General Purpose I/O Register */
 enum {
        GP_DIR_9 = 1<<25, /* IO_9 direct, 0=In/1=Out */
@@ -348,30 +307,6 @@ enum {
        GP_IO_0 = 1<<0, /* IO_0 pin */
 };
 
-/* Rx/Tx Path related Arbiter Test Registers */
-/*     B3_MA_TO_TEST   16 bit  MAC Arbiter Timeout Test Reg */
-/*     B3_MA_RC_TEST   16 bit  MAC Arbiter Recovery Test Reg */
-/*     B3_PA_TEST              16 bit  Packet Arbiter Test Register */
-/*                     Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */
-enum {
-       TX2_T_EV        = 1<<15,/* TX2 Timeout/Recv Event occured */
-       TX2_T_ON        = 1<<14,/* TX2 Timeout/Recv Timer Test On */
-       TX2_T_OFF       = 1<<13,/* TX2 Timeout/Recv Timer Tst Off */
-       TX2_T_STEP      = 1<<12,/* TX2 Timeout/Recv Timer Step */
-       TX1_T_EV        = 1<<11,/* TX1 Timeout/Recv Event occured */
-       TX1_T_ON        = 1<<10,/* TX1 Timeout/Recv Timer Test On */
-       TX1_T_OFF       = 1<<9, /* TX1 Timeout/Recv Timer Tst Off */
-       TX1_T_STEP      = 1<<8, /* TX1 Timeout/Recv Timer Step */
-       RX2_T_EV        = 1<<7, /* RX2 Timeout/Recv Event occured */
-       RX2_T_ON        = 1<<6, /* RX2 Timeout/Recv Timer Test On */
-       RX2_T_OFF       = 1<<5, /* RX2 Timeout/Recv Timer Tst Off */
-       RX2_T_STEP      = 1<<4, /* RX2 Timeout/Recv Timer Step */
-       RX1_T_EV        = 1<<3, /* RX1 Timeout/Recv Event occured */
-       RX1_T_ON        = 1<<2, /* RX1 Timeout/Recv Timer Test On */
-       RX1_T_OFF       = 1<<1, /* RX1 Timeout/Recv Timer Tst Off */
-       RX1_T_STEP      = 1<<0, /* RX1 Timeout/Recv Timer Step */
-};
-
 /* Descriptor Bit Definition */
 /*     TxCtrl          Transmit Buffer Control Field */
 /*     RxCtrl          Receive  Buffer Control Field */
@@ -428,14 +363,6 @@ enum {
        RI_RST_SET      = 1<<0, /* Set   RAM Interface Reset */
 };
 
-/*     B3_RI_TEST               8 bit  RAM Iface Test Register */
-enum {
-       RI_T_EV = 1<<3, /* Timeout Event occured */
-       RI_T_ON = 1<<2, /* Timeout Timer Test On */
-       RI_T_OFF        = 1<<1, /* Timeout Timer Test Off */
-       RI_T_STEP       = 1<<0, /* Timeout Timer Step */
-};
-
 /* MAC Arbiter Registers */
 /*     B3_MA_TO_CTRL   16 bit  MAC Arbiter Timeout Ctrl Reg */
 enum {
@@ -452,19 +379,6 @@ enum {
 #define SK_PKT_TO_MAX  0xffff          /* Maximum value */
 #define SK_RI_TO_53    36              /* RAM interface timeout */
 
-
-/*     B3_MA_RC_CTRL   16 bit  MAC Arbiter Recovery Ctrl Reg */
-enum {
-       MA_ENA_REC_TX2  = 1<<7, /* Enable  Recovery Timer TX2 */
-       MA_DIS_REC_TX2  = 1<<6, /* Disable Recovery Timer TX2 */
-       MA_ENA_REC_TX1  = 1<<5, /* Enable  Recovery Timer TX1 */
-       MA_DIS_REC_TX1  = 1<<4, /* Disable Recovery Timer TX1 */
-       MA_ENA_REC_RX2  = 1<<3, /* Enable  Recovery Timer RX2 */
-       MA_DIS_REC_RX2  = 1<<2, /* Disable Recovery Timer RX2 */
-       MA_ENA_REC_RX1  = 1<<1, /* Enable  Recovery Timer RX1 */
-       MA_DIS_REC_RX1  = 1<<0, /* Disable Recovery Timer RX1 */
-};
-
 /* Packet Arbiter Registers */
 /*     B3_PA_CTRL              16 bit  Packet Arbiter Ctrl Register */
 enum {
@@ -488,7 +402,7 @@ enum {
                                                PA_ENA_TO_TX1 | PA_ENA_TO_TX2)
 
 
-/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() to access */
 /*     TXA_ITI_INI             32 bit  Tx Arb Interval Timer Init Val */
 /*     TXA_ITI_VAL             32 bit  Tx Arb Interval Timer Value */
 /*     TXA_LIM_INI             32 bit  Tx Arb Limit Counter Init Val */
@@ -511,7 +425,7 @@ enum {
 /*
  *     Bank 4 - 5
  */
-/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() to access */
 enum {
        TXA_ITI_INI     = 0x0200,/* 32 bit      Tx Arb Interval Timer Init Val*/
        TXA_ITI_VAL     = 0x0204,/* 32 bit      Tx Arb Interval Timer Value */
@@ -537,7 +451,7 @@ enum {
 
 /* Queue Register Offsets, use Q_ADDR() to access */
 enum {
-       B8_Q_REGS = 0x0400, /* base of Queue registers */       
+       B8_Q_REGS = 0x0400, /* base of Queue registers */
        Q_D     = 0x00, /* 8*32 bit     Current Descriptor */
        Q_DA_L  = 0x20, /* 32 bit       Current Descriptor Address Low dWord */
        Q_DA_H  = 0x24, /* 32 bit       Current Descriptor Address High dWord */
@@ -618,8 +532,7 @@ enum {
 enum {
        PHY_ADDR_XMAC   = 0<<8,
        PHY_ADDR_BCOM   = 1<<8,
-       PHY_ADDR_LONE   = 3<<8,
-       PHY_ADDR_NAT    = 0<<8,
+
 /* GPHY address (bits 15..11 of SMI control reg) */
        PHY_ADDR_MARV   = 0,
 };
@@ -986,7 +899,7 @@ enum {
        LINKLED_BLINK_OFF    = 0x10,
        LINKLED_BLINK_ON     = 0x20,
 };
-       
+
 /* GMAC and GPHY Control Registers (YUKON only) */
 enum {
        GMAC_CTRL       = 0x0f00,/* 32 bit      GMAC Control Reg */
@@ -1151,54 +1064,6 @@ enum {
        PHY_MARV_FE_SPEC_2      = 0x1c,/* 16 bit r/w    Specific Control Reg. 2 */
 };
 
-/* Level One-PHY Registers, indirect addressed over XMAC */
-enum {
-       PHY_LONE_CTRL           = 0x00,/* 16 bit r/w    PHY Control Register */
-       PHY_LONE_STAT           = 0x01,/* 16 bit r/o    PHY Status Register */
-       PHY_LONE_ID0            = 0x02,/* 16 bit r/o    PHY ID0 Register */
-       PHY_LONE_ID1            = 0x03,/* 16 bit r/o    PHY ID1 Register */
-       PHY_LONE_AUNE_ADV       = 0x04,/* 16 bit r/w    Auto-Neg. Advertisement */
-       PHY_LONE_AUNE_LP        = 0x05,/* 16 bit r/o    Link Part Ability Reg */
-       PHY_LONE_AUNE_EXP       = 0x06,/* 16 bit r/o    Auto-Neg. Expansion Reg */
-       PHY_LONE_NEPG           = 0x07,/* 16 bit r/w    Next Page Register */
-       PHY_LONE_NEPG_LP        = 0x08,/* 16 bit r/o    Next Page Link Partner */
-       /* Level One-specific registers */
-       PHY_LONE_1000T_CTRL     = 0x09,/* 16 bit r/w    1000Base-T Control Reg */
-       PHY_LONE_1000T_STAT     = 0x0a,/* 16 bit r/o    1000Base-T Status Reg */
-       PHY_LONE_EXT_STAT       = 0x0f,/* 16 bit r/o    Extended Status Reg */
-       PHY_LONE_PORT_CFG       = 0x10,/* 16 bit r/w    Port Configuration Reg*/
-       PHY_LONE_Q_STAT         = 0x11,/* 16 bit r/o    Quick Status Reg */
-       PHY_LONE_INT_ENAB       = 0x12,/* 16 bit r/w    Interrupt Enable Reg */
-       PHY_LONE_INT_STAT       = 0x13,/* 16 bit r/o    Interrupt Status Reg */
-       PHY_LONE_LED_CFG        = 0x14,/* 16 bit r/w    LED Configuration Reg */
-       PHY_LONE_PORT_CTRL      = 0x15,/* 16 bit r/w    Port Control Reg */
-       PHY_LONE_CIM            = 0x16,/* 16 bit r/o    CIM Reg */
-};
-
-/* National-PHY Registers, indirect addressed over XMAC */
-enum {
-       PHY_NAT_CTRL            = 0x00,/* 16 bit r/w    PHY Control Register */
-       PHY_NAT_STAT            = 0x01,/* 16 bit r/w    PHY Status Register */
-       PHY_NAT_ID0             = 0x02,/* 16 bit r/o    PHY ID0 Register */
-       PHY_NAT_ID1             = 0x03,/* 16 bit r/o    PHY ID1 Register */
-       PHY_NAT_AUNE_ADV        = 0x04,/* 16 bit r/w    Auto-Neg. Advertisement */
-       PHY_NAT_AUNE_LP         = 0x05,/* 16 bit r/o    Link Partner Ability Reg */
-       PHY_NAT_AUNE_EXP        = 0x06,/* 16 bit r/o    Auto-Neg. Expansion Reg */
-       PHY_NAT_NEPG            = 0x07,/* 16 bit r/w    Next Page Register */
-       PHY_NAT_NEPG_LP         = 0x08,/* 16 bit r/o    Next Page Link Partner Reg */
-       /* National-specific registers */
-       PHY_NAT_1000T_CTRL      = 0x09,/* 16 bit r/w    1000Base-T Control Reg */
-       PHY_NAT_1000T_STAT      = 0x0a,/* 16 bit r/o    1000Base-T Status Reg */
-       PHY_NAT_EXT_STAT        = 0x0f,/* 16 bit r/o    Extended Status Register */
-       PHY_NAT_EXT_CTRL1       = 0x10,/* 16 bit r/o    Extended Control Reg1 */
-       PHY_NAT_Q_STAT1         = 0x11,/* 16 bit r/o    Quick Status Reg1 */
-       PHY_NAT_10B_OP          = 0x12,/* 16 bit r/o    10Base-T Operations Reg */
-       PHY_NAT_EXT_CTRL2       = 0x13,/* 16 bit r/o    Extended Control Reg1 */
-       PHY_NAT_Q_STAT2         = 0x14,/* 16 bit r/o    Quick Status Reg2 */
-
-       PHY_NAT_PHY_ADDR        = 0x19,/* 16 bit r/o    PHY Address Register */
-};
-
 enum {
        PHY_CT_RESET    = 1<<15, /* Bit 15: (sc)        clear all PHY related regs */
        PHY_CT_LOOP     = 1<<14, /* Bit 14:     enable Loopback over PHY */
@@ -1253,8 +1118,29 @@ enum {
        PHY_MARV_ID1_Y2 = 0x0C91, /* Yukon-2 (PHY 88E1112) */
 };
 
+/* Advertisement register bits */
 enum {
        PHY_AN_NXT_PG   = 1<<15, /* Bit 15:     Request Next Page */
+       PHY_AN_ACK      = 1<<14, /* Bit 14:     (ro) Acknowledge Received */
+       PHY_AN_RF       = 1<<13, /* Bit 13:     Remote Fault Bits */
+
+       PHY_AN_PAUSE_ASYM = 1<<11,/* Bit 11:    Try for asymmetric */
+       PHY_AN_PAUSE_CAP = 1<<10, /* Bit 10:    Try for pause */
+       PHY_AN_100BASE4 = 1<<9, /* Bit 9:       Try for 100mbps 4k packets */
+       PHY_AN_100FULL  = 1<<8, /* Bit 8:       Try for 100mbps full-duplex */
+       PHY_AN_100HALF  = 1<<7, /* Bit 7:       Try for 100mbps half-duplex */
+       PHY_AN_10FULL   = 1<<6, /* Bit 6:       Try for 10mbps full-duplex */
+       PHY_AN_10HALF   = 1<<5, /* Bit 5:       Try for 10mbps half-duplex */
+       PHY_AN_CSMA     = 1<<0, /* Bit 0:       Only selector supported */
+       PHY_AN_SEL      = 0x1f, /* Bit 4..0:    Selector Field, 00001=Ethernet*/
+       PHY_AN_FULL     = PHY_AN_100FULL | PHY_AN_10FULL | PHY_AN_CSMA,
+       PHY_AN_ALL      = PHY_AN_10HALF | PHY_AN_10FULL |
+                         PHY_AN_100HALF | PHY_AN_100FULL,
+};
+
+/* Xmac Specific */
+enum {
+       PHY_X_AN_NXT_PG = 1<<15, /* Bit 15:     Request Next Page */
        PHY_X_AN_ACK    = 1<<14, /* Bit 14:     (ro) Acknowledge Received */
        PHY_X_AN_RFB    = 3<<12,/* Bit 13..12:  Remote Fault Bits */
 
@@ -1263,82 +1149,6 @@ enum {
        PHY_X_AN_FD     = 1<<5, /* Bit  5:      Full Duplex */
 };
 
-enum {
-       PHY_B_AN_RF     = 1<<13, /* Bit 13:     Remote Fault */
-
-       PHY_B_AN_ASP    = 1<<11, /* Bit 11:     Asymmetric Pause */
-       PHY_B_AN_PC     = 1<<10, /* Bit 10:     Pause Capable */
-       PHY_B_AN_SEL    = 0x1f, /* Bit 4..0:    Selector Field, 00001=Ethernet*/
-};
-
-enum {
-       PHY_L_AN_RF     = 1<<13, /* Bit 13:     Remote Fault */
-                                                               /* Bit 12:      reserved */
-       PHY_L_AN_ASP    = 1<<11, /* Bit 11:     Asymmetric Pause */
-       PHY_L_AN_PC     = 1<<10, /* Bit 10:     Pause Capable */
-
-       PHY_L_AN_SEL    = 0x1f, /* Bit 4..0:    Selector Field, 00001=Ethernet*/
-};
-
-/*  PHY_NAT_AUNE_ADV   16 bit r/w      Auto-Negotiation Advertisement */
-/*  PHY_NAT_AUNE_LP    16 bit r/o      Link Partner Ability Reg *****/
-/*  PHY_AN_NXT_PG      (see XMAC) Bit 15:      Request Next Page */
-enum {
-       PHY_N_AN_RF     = 1<<13, /* Bit 13:     Remote Fault */
-
-       PHY_N_AN_100F   = 1<<11, /* Bit 11:     100Base-T2 FD Support */
-       PHY_N_AN_100H   = 1<<10, /* Bit 10:     100Base-T2 HD Support */
-
-       PHY_N_AN_SEL    = 0x1f, /* Bit 4..0:    Selector Field, 00001=Ethernet*/
-};
-
-/* field type definition for PHY_x_AN_SEL */
-enum {
-       PHY_SEL_TYPE     = 1,   /* 00001 = Ethernet */
-};
-
-enum {
-       PHY_ANE_LP_NP   = 1<<3, /* Bit  3:      Link Partner can Next Page */
-       PHY_ANE_LOC_NP  = 1<<2, /* Bit  2:      Local PHY can Next Page */
-       PHY_ANE_RX_PG   = 1<<1, /* Bit  1:      Page Received */
-};
-
-enum {
-       PHY_ANE_PAR_DF  = 1<<4, /* Bit  4:      Parallel Detection Fault */
-
-       PHY_ANE_LP_CAP  = 1<<0, /* Bit  0:      Link Partner Auto-Neg. Cap. */  
-};
-
-enum {
-       PHY_NP_MORE     = 1<<15, /* Bit 15:     More, Next Pages to follow */
-       PHY_NP_ACK1     = 1<<14, /* Bit 14: (ro)        Ack1, for receiving a message */
-       PHY_NP_MSG_VAL  = 1<<13, /* Bit 13:     Message Page valid */
-       PHY_NP_ACK2     = 1<<12, /* Bit 12:     Ack2, comply with msg content */
-       PHY_NP_TOG      = 1<<11, /* Bit 11:     Toggle Bit, ensure sync */
-       PHY_NP_MSG      = 0x07ff, /* Bit 10..0: Message from/to Link Partner */
-};
-
-enum {
-       PHY_X_EX_FD     = 1<<15, /* Bit 15:     Device Supports Full Duplex */
-       PHY_X_EX_HD     = 1<<14, /* Bit 14:     Device Supports Half Duplex */
-};
-
-enum {
-       PHY_X_RS_PAUSE  = 3<<7,/* Bit  8..7:    selected Pause Mode */
-       PHY_X_RS_HD     = 1<<6, /* Bit  6:      Half Duplex Mode selected */
-       PHY_X_RS_FD     = 1<<5, /* Bit  5:      Full Duplex Mode selected */
-       PHY_X_RS_ABLMIS = 1<<4, /* Bit  4:      duplex or pause cap mismatch */
-       PHY_X_RS_PAUMIS = 1<<3, /* Bit  3:      pause capability mismatch */
-};
-
-/** Remote Fault Bits (PHY_X_AN_RFB) encoding  */
-enum {
-       X_RFB_OK        = 0<<12,/* Bit 13..12   No errors, Link OK */
-       X_RFB_LF        = 1<<12, /* Bit 13..12  Link Failure */
-       X_RFB_OFF       = 2<<12,/* Bit 13..12   Offline */
-       X_RFB_AN_ERR    = 3<<12,/* Bit 13..12   Auto-Negotiation Error */
-};
-
 /* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */
 enum {
        PHY_X_P_NO_PAUSE        = 0<<7,/* Bit  8..7:    no Pause Mode */
@@ -1418,6 +1228,16 @@ enum {
        PHY_B_PES_MLT3_ER       = 1<<0, /* Bit  0:      MLT3 code Error */
 };
 
+/*  PHY_BCOM_AUNE_ADV  16 bit r/w      Auto-Negotiation Advertisement *****/
+/*  PHY_BCOM_AUNE_LP   16 bit r/o      Link Partner Ability Reg *****/
+enum {
+       PHY_B_AN_RF     = 1<<13, /* Bit 13:     Remote Fault */
+
+       PHY_B_AN_ASP    = 1<<11, /* Bit 11:     Asymmetric Pause */
+       PHY_B_AN_PC     = 1<<10, /* Bit 10:     Pause Capable */
+};
+
+
 /*****  PHY_BCOM_FC_CTR                16 bit r/w      False Carrier Counter *****/
 enum {
        PHY_B_FC_CTR    = 0xff, /* Bit  7..0:   False Carrier Counter */
@@ -1478,7 +1298,9 @@ enum {
        PHY_B_IS_LST_CHANGE     = 1<<1, /* Bit  1:      Link Status Changed */
        PHY_B_IS_CRC_ER = 1<<0, /* Bit  0:      CRC Error */
 };
-#define PHY_B_DEF_MSK  (~(PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+#define PHY_B_DEF_MSK  \
+       (~(PHY_B_IS_PSE | PHY_B_IS_AN_PR | PHY_B_IS_DUP_CHANGE | \
+           PHY_B_IS_LSP_CHANGE | PHY_B_IS_LST_CHANGE))
 
 /* Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */
 enum {
@@ -1495,166 +1317,6 @@ enum {
        PHY_B_RES_1000HD        = 6<<8,/* Bit 10..8:    1000Base-T Half Dup. */
 };
 
-/*
- * Level One-Specific
- */
-/*****  PHY_LONE_1000T_CTRL    16 bit r/w      1000Base-T Control Reg *****/
-enum {
-       PHY_L_1000C_TEST        = 7<<13,/* Bit 15..13:  Test Modes */
-       PHY_L_1000C_MSE = 1<<12, /* Bit 12:     Master/Slave Enable */
-       PHY_L_1000C_MSC = 1<<11, /* Bit 11:     M/S Configuration */
-       PHY_L_1000C_RD  = 1<<10, /* Bit 10:     Repeater/DTE */
-       PHY_L_1000C_AFD = 1<<9, /* Bit  9:      Advertise Full Duplex */
-       PHY_L_1000C_AHD = 1<<8, /* Bit  8:      Advertise Half Duplex */
-};
-
-/*****  PHY_LONE_1000T_STAT    16 bit r/o      1000Base-T Status Reg *****/
-enum {
-       PHY_L_1000S_MSF = 1<<15, /* Bit 15:     Master/Slave Fault */
-       PHY_L_1000S_MSR = 1<<14, /* Bit 14:     Master/Slave Result */
-       PHY_L_1000S_LRS = 1<<13, /* Bit 13:     Local Receiver Status */
-       PHY_L_1000S_RRS = 1<<12, /* Bit 12:     Remote Receiver Status */
-       PHY_L_1000S_LP_FD = 1<<11, /* Bit 11:   Link Partner can FD */
-       PHY_L_1000S_LP_HD = 1<<10, /* Bit 10:   Link Partner can HD */
-
-       PHY_L_1000S_IEC  = 0xff, /* Bit  7..0:  Idle Error Count */
-
-/*****  PHY_LONE_EXT_STAT      16 bit r/o      Extended Status Register *****/
-       PHY_L_ES_X_FD_CAP = 1<<15, /* Bit 15:   1000Base-X FD capable */
-       PHY_L_ES_X_HD_CAP = 1<<14, /* Bit 14:   1000Base-X HD capable */
-       PHY_L_ES_T_FD_CAP = 1<<13, /* Bit 13:   1000Base-T FD capable */
-       PHY_L_ES_T_HD_CAP = 1<<12, /* Bit 12:   1000Base-T HD capable */
-};
-
-/*****  PHY_LONE_PORT_CFG      16 bit r/w      Port Configuration Reg *****/
-enum {
-       PHY_L_PC_REP_MODE       = 1<<15, /* Bit 15:     Repeater Mode */
-
-       PHY_L_PC_TX_DIS = 1<<13, /* Bit 13:     Tx output Disabled */
-       PHY_L_PC_BY_SCR = 1<<12, /* Bit 12:     Bypass Scrambler */
-       PHY_L_PC_BY_45  = 1<<11, /* Bit 11:     Bypass 4B5B-Decoder */
-       PHY_L_PC_JAB_DIS        = 1<<10, /* Bit 10:     Jabber Disabled */
-       PHY_L_PC_SQE    = 1<<9, /* Bit  9:      Enable Heartbeat */
-       PHY_L_PC_TP_LOOP        = 1<<8, /* Bit  8:      TP Loopback */
-       PHY_L_PC_SSS    = 1<<7, /* Bit  7:      Smart Speed Selection */
-       PHY_L_PC_FIFO_SIZE      = 1<<6, /* Bit  6:      FIFO Size */
-       PHY_L_PC_PRE_EN = 1<<5, /* Bit  5:      Preamble Enable */
-       PHY_L_PC_CIM    = 1<<4, /* Bit  4:      Carrier Integrity Mon */
-       PHY_L_PC_10_SER = 1<<3, /* Bit  3:      Use Serial Output */
-       PHY_L_PC_ANISOL = 1<<2, /* Bit  2:      Unisolate Port */
-       PHY_L_PC_TEN_BIT        = 1<<1, /* Bit  1:      10bit iface mode on */
-       PHY_L_PC_ALTCLOCK       = 1<<0, /* Bit  0: (ro) ALTCLOCK Mode on */
-};
-
-/*****  PHY_LONE_Q_STAT                16 bit r/o      Quick Status Reg *****/
-enum {
-       PHY_L_QS_D_RATE = 3<<14,/* Bit 15..14:  Data Rate */
-       PHY_L_QS_TX_STAT        = 1<<13, /* Bit 13:     Transmitting */
-       PHY_L_QS_RX_STAT        = 1<<12, /* Bit 12:     Receiving */
-       PHY_L_QS_COL_STAT       = 1<<11, /* Bit 11:     Collision */
-       PHY_L_QS_L_STAT = 1<<10, /* Bit 10:     Link is up */
-       PHY_L_QS_DUP_MOD        = 1<<9, /* Bit  9:      Full/Half Duplex */
-       PHY_L_QS_AN     = 1<<8, /* Bit  8:      AutoNeg is On */
-       PHY_L_QS_AN_C   = 1<<7, /* Bit  7:      AN is Complete */
-       PHY_L_QS_LLE    = 7<<4,/* Bit  6..4:    Line Length Estim. */
-       PHY_L_QS_PAUSE  = 1<<3, /* Bit  3:      LP advertised Pause */
-       PHY_L_QS_AS_PAUSE       = 1<<2, /* Bit  2:      LP adv. asym. Pause */
-       PHY_L_QS_ISOLATE        = 1<<1, /* Bit  1:      CIM Isolated */
-       PHY_L_QS_EVENT  = 1<<0, /* Bit  0:      Event has occurred */
-};
-
-/*****  PHY_LONE_INT_ENAB      16 bit r/w      Interrupt Enable Reg *****/
-/*****  PHY_LONE_INT_STAT      16 bit r/o      Interrupt Status Reg *****/
-enum {
-       PHY_L_IS_AN_F   = 1<<13, /* Bit 13:     Auto-Negotiation fault */
-       PHY_L_IS_CROSS  = 1<<11, /* Bit 11:     Crossover used */
-       PHY_L_IS_POL    = 1<<10, /* Bit 10:     Polarity correct. used */
-       PHY_L_IS_SS     = 1<<9, /* Bit  9:      Smart Speed Downgrade */
-       PHY_L_IS_CFULL  = 1<<8, /* Bit  8:      Counter Full */
-       PHY_L_IS_AN_C   = 1<<7, /* Bit  7:      AutoNeg Complete */
-       PHY_L_IS_SPEED  = 1<<6, /* Bit  6:      Speed Changed */
-       PHY_L_IS_DUP    = 1<<5, /* Bit  5:      Duplex Changed */
-       PHY_L_IS_LS     = 1<<4, /* Bit  4:      Link Status Changed */
-       PHY_L_IS_ISOL   = 1<<3, /* Bit  3:      Isolate Occured */
-       PHY_L_IS_MDINT  = 1<<2, /* Bit  2: (ro) STAT: MII Int Pending */
-       PHY_L_IS_INTEN  = 1<<1, /* Bit  1:      ENAB: Enable IRQs */
-       PHY_L_IS_FORCE  = 1<<0, /* Bit  0:      ENAB: Force Interrupt */
-};
-
-/* int. mask */
-#define PHY_L_DEF_MSK  (PHY_L_IS_LS | PHY_L_IS_ISOL | PHY_L_IS_INTEN)
-
-/*****  PHY_LONE_LED_CFG       16 bit r/w      LED Configuration Reg *****/
-enum {
-       PHY_L_LC_LEDC   = 3<<14,/* Bit 15..14:  Col/Blink/On/Off */
-       PHY_L_LC_LEDR   = 3<<12,/* Bit 13..12:  Rx/Blink/On/Off */
-       PHY_L_LC_LEDT   = 3<<10,/* Bit 11..10:  Tx/Blink/On/Off */
-       PHY_L_LC_LEDG   = 3<<8,/* Bit  9..8:    Giga/Blink/On/Off */
-       PHY_L_LC_LEDS   = 3<<6,/* Bit  7..6:    10-100/Blink/On/Off */
-       PHY_L_LC_LEDL   = 3<<4,/* Bit  5..4:    Link/Blink/On/Off */
-       PHY_L_LC_LEDF   = 3<<2,/* Bit  3..2:    Duplex/Blink/On/Off */
-       PHY_L_LC_PSTRECH= 1<<1, /* Bit  1:      Strech LED Pulses */
-       PHY_L_LC_FREQ   = 1<<0, /* Bit  0:      30/100 ms */
-};
-
-/*****  PHY_LONE_PORT_CTRL     16 bit r/w      Port Control Reg *****/
-enum {
-       PHY_L_PC_TX_TCLK = 1<<15, /* Bit 15:    Enable TX_TCLK */
-       PHY_L_PC_ALT_NP  = 1<<13, /* Bit 14:    Alternate Next Page */
-       PHY_L_PC_GMII_ALT= 1<<12, /* Bit 13:    Alternate GMII driver */
-       PHY_L_PC_TEN_CRS = 1<<10, /* Bit 10:    Extend CRS*/
-};
-
-/*****  PHY_LONE_CIM           16 bit r/o      CIM Reg *****/
-enum {
-       PHY_L_CIM_ISOL      = 0xff<<8,/* Bit 15..8:     Isolate Count */
-       PHY_L_CIM_FALSE_CAR = 0xff,   /* Bit  7..0:     False Carrier Count */
-};
-
-/*
- * Pause Bits (PHY_L_AN_ASP and PHY_L_AN_PC) encoding
- */
-enum {
-       PHY_L_P_NO_PAUSE= 0<<10,/* Bit 11..10:  no Pause Mode */
-       PHY_L_P_SYM_MD  = 1<<10, /* Bit 11..10: symmetric Pause Mode */
-       PHY_L_P_ASYM_MD = 2<<10,/* Bit 11..10:  asymmetric Pause Mode */
-       PHY_L_P_BOTH_MD = 3<<10,/* Bit 11..10:  both Pause Mode */
-};
-
-/*
- * National-Specific
- */
-/*****  PHY_NAT_1000T_CTRL     16 bit r/w      1000Base-T Control Reg *****/
-enum {
-       PHY_N_1000C_TEST= 7<<13,/* Bit 15..13:  Test Modes */
-       PHY_N_1000C_MSE = 1<<12, /* Bit 12:     Master/Slave Enable */
-       PHY_N_1000C_MSC = 1<<11, /* Bit 11:     M/S Configuration */
-       PHY_N_1000C_RD  = 1<<10, /* Bit 10:     Repeater/DTE */
-       PHY_N_1000C_AFD = 1<<9, /* Bit  9:      Advertise Full Duplex */
-       PHY_N_1000C_AHD = 1<<8, /* Bit  8:      Advertise Half Duplex */
-       PHY_N_1000C_APC = 1<<7, /* Bit  7:      Asymmetric Pause Cap. */};
-
-
-/*****  PHY_NAT_1000T_STAT     16 bit r/o      1000Base-T Status Reg *****/
-enum {
-       PHY_N_1000S_MSF = 1<<15, /* Bit 15:     Master/Slave Fault */
-       PHY_N_1000S_MSR = 1<<14, /* Bit 14:     Master/Slave Result */
-       PHY_N_1000S_LRS = 1<<13, /* Bit 13:     Local Receiver Status */
-       PHY_N_1000S_RRS = 1<<12, /* Bit 12:     Remote Receiver Status*/
-       PHY_N_1000S_LP_FD= 1<<11, /* Bit 11:    Link Partner can FD */
-       PHY_N_1000S_LP_HD= 1<<10, /* Bit 10:    Link Partner can HD */
-       PHY_N_1000C_LP_APC= 1<<9, /* Bit  9:    LP Asym. Pause Cap. */
-       PHY_N_1000S_IEC = 0xff, /* Bit  7..0:   Idle Error Count */
-};
-
-/*****  PHY_NAT_EXT_STAT       16 bit r/o      Extended Status Register *****/
-enum {
-       PHY_N_ES_X_FD_CAP= 1<<15, /* Bit 15:    1000Base-X FD capable */
-       PHY_N_ES_X_HD_CAP= 1<<14, /* Bit 14:    1000Base-X HD capable */
-       PHY_N_ES_T_FD_CAP= 1<<13, /* Bit 13:    1000Base-T FD capable */
-       PHY_N_ES_T_HD_CAP= 1<<12, /* Bit 12:    1000Base-T HD capable */
-};
-
 /** Marvell-Specific */
 enum {
        PHY_M_AN_NXT_PG = 1<<15, /* Request Next Page */
@@ -1718,7 +1380,7 @@ enum {
        PHY_M_PC_EN_DET_PLUS    = 3<<8, /* Energy Detect Plus (Mode 2) */
 };
 
-#define PHY_M_PC_MDI_XMODE(x)  (((x)<<5) & PHY_M_PC_MDIX_MSK)  
+#define PHY_M_PC_MDI_XMODE(x)  (((x)<<5) & PHY_M_PC_MDIX_MSK)
 
 enum {
        PHY_M_PC_MAN_MDI        = 0, /* 00 = Manual MDI configuration */
@@ -2105,7 +1767,7 @@ enum {
        GM_GPSR_FC_RX_DIS       = 1<<2, /* Bit  2:      Rx Flow-Control Mode Disabled */
        GM_GPSR_PROM_EN         = 1<<1, /* Bit  1:      Promiscuous Mode Enabled */
 };
-       
+
 /*     GM_GP_CTRL      16 bit r/w      General Purpose Control Register */
 enum {
        GM_GPCR_PROM_ENA        = 1<<14,        /* Bit 14:      Enable Promiscuous Mode */
@@ -2127,7 +1789,7 @@ enum {
 
 #define GM_GPCR_SPEED_1000     (GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100)
 #define GM_GPCR_AU_ALL_DIS     (GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS|GM_GPCR_AU_SPD_DIS)
-       
+
 /*     GM_TX_CTRL                      16 bit r/w      Transmit Control Register */
 enum {
        GM_TXCR_FORCE_JAM       = 1<<15, /* Bit 15:     Force Jam / Flow-Control */
@@ -2138,7 +1800,7 @@ enum {
 
 #define TX_COL_THR(x)          (((x)<<10) & GM_TXCR_COL_THR_MSK)
 #define TX_COL_DEF             0x04
-       
+
 /*     GM_RX_CTRL                      16 bit r/w      Receive Control Register */
 enum {
        GM_RXCR_UCF_ENA = 1<<15, /* Bit 15:     Enable Unicast filtering */
@@ -2146,7 +1808,7 @@ enum {
        GM_RXCR_CRC_DIS = 1<<13, /* Bit 13:     Remove 4-byte CRC */
        GM_RXCR_PASS_FC = 1<<12, /* Bit 12:     Pass FC packets to FIFO */
 };
-       
+
 /*     GM_TX_PARAM             16 bit r/w      Transmit Parameter Register */
 enum {
        GM_TXPA_JAMLEN_MSK      = 0x03<<14,     /* Bit 15..14:  Jam Length */
@@ -2171,7 +1833,7 @@ enum {
        GM_SMOD_JUMBO_ENA       = 1<<8, /* Bit  8:      Enable Jumbo (Max. Frame Len) */
         GM_SMOD_IPG_MSK        = 0x1f  /* Bit 4..0:    Inter-Packet Gap (IPG) */
 };
-       
+
 #define DATA_BLIND_VAL(x)      (((x)<<11) & GM_SMOD_DATABL_MSK)
 #define DATA_BLIND_DEF         0x04
 
@@ -2186,7 +1848,7 @@ enum {
        GM_SMI_CT_RD_VAL        = 1<<4, /* Bit  4:      Read Valid (Read completed) */
        GM_SMI_CT_BUSY          = 1<<3, /* Bit  3:      Busy (Operation in progress) */
 };
-       
+
 #define GM_SMI_CT_PHY_AD(x)    (((x)<<11) & GM_SMI_CT_PHY_A_MSK)
 #define GM_SMI_CT_REG_AD(x)    (((x)<<6) & GM_SMI_CT_REG_A_MSK)
 
@@ -2195,7 +1857,7 @@ enum {
        GM_PAR_MIB_CLR  = 1<<5, /* Bit  5:      Set MIB Clear Counter Mode */
        GM_PAR_MIB_TST  = 1<<4, /* Bit  4:      MIB Load Counter (Test Mode) */
 };
-       
+
 /* Receive Frame Status Encoding */
 enum {
        GMR_FS_LEN      = 0xffff<<16, /* Bit 31..16:    Rx Frame Length */
@@ -2217,12 +1879,12 @@ enum {
 /*
  * GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR)
  */
-       GMR_FS_ANY_ERR  = GMR_FS_CRC_ERR | GMR_FS_LONG_ERR | 
-                         GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC | 
+       GMR_FS_ANY_ERR  = GMR_FS_CRC_ERR | GMR_FS_LONG_ERR |
+                         GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC |
                          GMR_FS_JABBER,
 /* Rx GMAC FIFO Flush Mask (default) */
        RX_FF_FL_DEF_MSK = GMR_FS_CRC_ERR | GMR_FS_RX_FF_OV |GMR_FS_MII_ERR |
-                          GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_UN_SIZE | 
+                          GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_UN_SIZE |
                           GMR_FS_JABBER,
 };
 
@@ -2540,10 +2202,6 @@ enum {
 };
 
 
-/*     XM_PHY_ADDR     16 bit r/w      PHY Address Register */
-#define XM_PHY_ADDR_SZ 0x1f    /* Bit  4..0:   PHY Address bits */
-
-
 /*     XM_GP_PORT      32 bit r/w      General Purpose Port Register */
 enum {
        XM_GP_ANIP      = 1<<6, /* Bit  6: (ro) Auto-Neg. in progress */
@@ -2662,8 +2320,8 @@ enum {
 };
 
 #define XM_PAUSE_MODE  (XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I)
-#define XM_DEF_MODE            (XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\
-                               XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA | XM_MD_CAA)
+#define XM_DEF_MODE    (XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\
+                        XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA)
 
 /*     XM_STAT_CMD     16 bit r/w      Statistics Command Register */
 enum {
@@ -2793,28 +2451,20 @@ struct skge_hw {
        u32                  intr_mask;
        struct net_device    *dev[2];
 
-       u8                   mac_cfg;
        u8                   chip_id;
+       u8                   chip_rev;
        u8                   phy_type;
        u8                   pmd_type;
        u16                  phy_addr;
+       u8                   ports;
 
        u32                  ram_size;
        u32                  ram_offset;
-       
+
        struct tasklet_struct ext_tasklet;
        spinlock_t           phy_lock;
 };
 
-static inline int isdualport(const struct skge_hw *hw)
-{
-       return !(hw->mac_cfg & CFG_SNG_MAC);
-}
-
-static inline u8 chip_rev(const struct skge_hw *hw)
-{
-       return (hw->mac_cfg & CFG_CHIP_R_MSK) >> 4;
-}
 
 static inline int iscopper(const struct skge_hw *hw)
 {
@@ -2827,7 +2477,7 @@ enum {
        FLOW_MODE_REM_SEND      = 2, /* Symmetric or just remote */
        FLOW_MODE_SYMMETRIC     = 3, /* Both stations may send PAUSE */
 };
-       
+
 struct skge_port {
        u32                  msg_enable;
        struct skge_hw       *hw;
@@ -2853,8 +2503,8 @@ struct skge_port {
        void                 *mem;      /* PCI memory for rings */
        dma_addr_t           dma;
        unsigned long        mem_size;
+       unsigned int         rx_buf_size;
 
-       struct timer_list    link_check;
        struct timer_list    led_blink;
 };
 
@@ -2863,7 +2513,6 @@ struct skge_port {
 static inline u32 skge_read32(const struct skge_hw *hw, int reg)
 {
        return readl(hw->regs + reg);
-
 }
 
 static inline u16 skge_read16(const struct skge_hw *hw, int reg)
@@ -2892,114 +2541,87 @@ static inline void skge_write8(const struct skge_hw *hw, int reg, u8 val)
 }
 
 /* MAC Related Registers inside the device. */
-#define SKGEMAC_REG(port,reg)  (((port)<<7)+(reg))
-
-/* PCI config space can be accessed via memory mapped space */
-#define SKGEPCI_REG(reg) ((reg)+ 0x380)
-
-#define SKGEXM_REG(port, reg) \
+#define SK_REG(port,reg)       (((port)<<7)+(reg))
+#define SK_XMAC_REG(port, reg) \
        ((BASE_XMAC_1 + (port) * (BASE_XMAC_2 - BASE_XMAC_1)) | (reg) << 1)
 
-static inline u32 skge_xm_read32(const struct skge_hw *hw, int port, int reg)
-{
-       return skge_read32(hw, SKGEXM_REG(port,reg));
-}
-
-static inline u16 skge_xm_read16(const struct skge_hw *hw, int port, int reg)
+static inline u32 xm_read32(const struct skge_hw *hw, int port, int reg)
 {
-       return skge_read16(hw, SKGEXM_REG(port,reg));
+       u32 v;
+       v = skge_read16(hw, SK_XMAC_REG(port, reg));
+       v |= (u32)skge_read16(hw, SK_XMAC_REG(port, reg+2)) << 16;
+       return v;
 }
 
-static inline u8 skge_xm_read8(const struct skge_hw *hw, int port, int reg)
+static inline u16 xm_read16(const struct skge_hw *hw, int port, int reg)
 {
-       return skge_read8(hw, SKGEXM_REG(port,reg));
+       return skge_read16(hw, SK_XMAC_REG(port,reg));
 }
 
-static inline void skge_xm_write32(const struct skge_hw *hw, int port, int r, u32 v)
+static inline void xm_write32(const struct skge_hw *hw, int port, int r, u32 v)
 {
-       skge_write32(hw, SKGEXM_REG(port,r), v);
+       skge_write16(hw, SK_XMAC_REG(port,r), v & 0xffff);
+       skge_write16(hw, SK_XMAC_REG(port,r+2), v >> 16);
 }
 
-static inline void skge_xm_write16(const struct skge_hw *hw, int port, int r, u16 v)
+static inline void xm_write16(const struct skge_hw *hw, int port, int r, u16 v)
 {
-       skge_write16(hw, SKGEXM_REG(port,r), v);
+       skge_write16(hw, SK_XMAC_REG(port,r), v);
 }
 
-static inline void skge_xm_write8(const struct skge_hw *hw, int port, int r, u8 v)
-{
-       skge_write8(hw, SKGEXM_REG(port,r), v);
-}
-
-static inline void skge_xm_outhash(const struct skge_hw *hw, int port, int reg,
+static inline void xm_outhash(const struct skge_hw *hw, int port, int reg,
                                   const u8 *hash)
 {
-       skge_xm_write16(hw, port, reg, 
-                       (u16)hash[0] | ((u16)hash[1] << 8));
-       skge_xm_write16(hw, port, reg+2, 
-                       (u16)hash[2] | ((u16)hash[3] << 8));
-       skge_xm_write16(hw, port, reg+4, 
-                       (u16)hash[4] | ((u16)hash[5] << 8));
-       skge_xm_write16(hw, port, reg+6, 
-                       (u16)hash[6] | ((u16)hash[7] << 8));
+       xm_write16(hw, port, reg,   (u16)hash[0] | ((u16)hash[1] << 8));
+       xm_write16(hw, port, reg+2, (u16)hash[2] | ((u16)hash[3] << 8));
+       xm_write16(hw, port, reg+4, (u16)hash[4] | ((u16)hash[5] << 8));
+       xm_write16(hw, port, reg+6, (u16)hash[6] | ((u16)hash[7] << 8));
 }
 
-static inline void skge_xm_outaddr(const struct skge_hw *hw, int port, int reg,
+static inline void xm_outaddr(const struct skge_hw *hw, int port, int reg,
                                   const u8 *addr)
 {
-       skge_xm_write16(hw, port, reg, 
-                       (u16)addr[0] | ((u16)addr[1] << 8));
-       skge_xm_write16(hw, port, reg, 
-                       (u16)addr[2] | ((u16)addr[3] << 8));
-       skge_xm_write16(hw, port, reg, 
-                       (u16)addr[4] | ((u16)addr[5] << 8));
+       xm_write16(hw, port, reg,   (u16)addr[0] | ((u16)addr[1] << 8));
+       xm_write16(hw, port, reg+2, (u16)addr[2] | ((u16)addr[3] << 8));
+       xm_write16(hw, port, reg+4, (u16)addr[4] | ((u16)addr[5] << 8));
 }
 
+#define SK_GMAC_REG(port,reg) \
+       (BASE_GMAC_1 + (port) * (BASE_GMAC_2-BASE_GMAC_1) + (reg))
 
-#define SKGEGMA_REG(port,reg) \
-       ((reg) + BASE_GMAC_1 + \
-        (port) * (BASE_GMAC_2-BASE_GMAC_1))
-
-static inline u16 skge_gma_read16(const struct skge_hw *hw, int port, int reg)
+static inline u16 gma_read16(const struct skge_hw *hw, int port, int reg)
 {
-       return skge_read16(hw, SKGEGMA_REG(port,reg));
+       return skge_read16(hw, SK_GMAC_REG(port,reg));
 }
 
-static inline u32 skge_gma_read32(const struct skge_hw *hw, int port, int reg)
+static inline u32 gma_read32(const struct skge_hw *hw, int port, int reg)
 {
-       return (u32) skge_read16(hw, SKGEGMA_REG(port,reg))
-               | ((u32)skge_read16(hw, SKGEGMA_REG(port,reg+4)) << 16);
+       return (u32) skge_read16(hw, SK_GMAC_REG(port,reg))
+               | ((u32)skge_read16(hw, SK_GMAC_REG(port,reg+4)) << 16);
 }
 
-static inline u8 skge_gma_read8(const struct skge_hw *hw, int port, int reg)
+static inline void gma_write16(const struct skge_hw *hw, int port, int r, u16 v)
 {
-       return skge_read8(hw, SKGEGMA_REG(port,reg));
+       skge_write16(hw, SK_GMAC_REG(port,r), v);
 }
 
-static inline void skge_gma_write16(const struct skge_hw *hw, int port, int r, u16 v)
+static inline void gma_write32(const struct skge_hw *hw, int port, int r, u32 v)
 {
-       skge_write16(hw, SKGEGMA_REG(port,r), v);
+       skge_write16(hw, SK_GMAC_REG(port, r), (u16) v);
+       skge_write32(hw, SK_GMAC_REG(port, r+4), (u16)(v >> 16));
 }
 
-static inline void skge_gma_write32(const struct skge_hw *hw, int port, int r, u32 v)
+static inline void gma_write8(const struct skge_hw *hw, int port, int r, u8 v)
 {
-       skge_write16(hw, SKGEGMA_REG(port, r), (u16) v);
-       skge_write32(hw, SKGEGMA_REG(port, r+4), (u16)(v >> 16));
+       skge_write8(hw, SK_GMAC_REG(port,r), v);
 }
 
-static inline void skge_gma_write8(const struct skge_hw *hw, int port, int r, u8 v)
-{
-       skge_write8(hw, SKGEGMA_REG(port,r), v);
-}
-
-static inline void skge_gm_set_addr(struct skge_hw *hw, int port, int reg,
+static inline void gma_set_addr(struct skge_hw *hw, int port, int reg,
                                    const u8 *addr)
 {
-       skge_gma_write16(hw, port, reg,
-                        (u16) addr[0] | ((u16) addr[1] << 8));
-       skge_gma_write16(hw, port, reg+4,
-                        (u16) addr[2] | ((u16) addr[3] << 8));
-       skge_gma_write16(hw, port, reg+8,
-                        (u16) addr[4] | ((u16) addr[5] << 8));
+       gma_write16(hw, port, reg,  (u16) addr[0] | ((u16) addr[1] << 8));
+       gma_write16(hw, port, reg+4,(u16) addr[2] | ((u16) addr[3] << 8));
+       gma_write16(hw, port, reg+8,(u16) addr[4] | ((u16) addr[5] << 8));
 }
-               
+
 #endif
index 19112712daf03ccab4eee49fa32063dbba5e0e84..404ea4297e32796e28a8fbb8a5e5a49fc203e6fc 100644 (file)
@@ -74,6 +74,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/if_arp.h>
 #include <linux/if_slip.h>
+#include <linux/delay.h>
 #include <linux/init.h>
 #include "slip.h"
 #ifdef CONFIG_INET
@@ -198,18 +199,12 @@ err_exit:
 static void
 sl_free_bufs(struct slip *sl)
 {
-       void * tmp;
-
        /* Free all SLIP frame buffers. */
-       tmp = xchg(&sl->rbuff, NULL);
-       kfree(tmp);
-       tmp = xchg(&sl->xbuff, NULL);
-       kfree(tmp);
+       kfree(xchg(&sl->rbuff, NULL));
+       kfree(xchg(&sl->xbuff, NULL));
 #ifdef SL_INCLUDE_CSLIP
-       tmp = xchg(&sl->cbuff, NULL);
-       kfree(tmp);
-       if ((tmp = xchg(&sl->slcomp, NULL)) != NULL)
-               slhc_free(tmp);
+       kfree(xchg(&sl->cbuff, NULL));
+       slhc_free(xchg(&sl->slcomp, NULL));
 #endif
 }
 
@@ -1389,10 +1384,8 @@ static void __exit slip_exit(void)
        /* First of all: check for active disciplines and hangup them.
         */
        do {
-               if (busy) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(HZ / 10);
-               }
+               if (busy)
+                       msleep_interruptible(100);
 
                busy = 0;
                for (i = 0; i < slip_maxdev; i++) {
index 990201f42ba04453a71f80e9cc5aefc931370d12..f00c476064f0421041c6e7bb643faacbc06fa0e4 100644 (file)
@@ -49,7 +49,6 @@
 #include <asm/system.h>
 
 #include "8390.h"
-#include "smc-mca.h"
 
 #define DRV_NAME "smc-mca"
 
@@ -100,6 +99,63 @@ module_param_array(ultra_irq, int, NULL, 0);
 MODULE_PARM_DESC(ultra_io, "SMC Ultra/EtherEZ MCA I/O base address(es)");
 MODULE_PARM_DESC(ultra_irq, "SMC Ultra/EtherEZ MCA IRQ number(s)");
 
+static const struct {
+  unsigned int base_addr;
+} addr_table[] = {
+    { 0x0800 },
+    { 0x1800 },
+    { 0x2800 },
+    { 0x3800 },
+    { 0x4800 },
+    { 0x5800 },
+    { 0x6800 },
+    { 0x7800 },
+    { 0x8800 },
+    { 0x9800 },
+    { 0xa800 },
+    { 0xb800 },
+    { 0xc800 },
+    { 0xd800 },
+    { 0xe800 },
+    { 0xf800 }
+};
+
+#define MEM_MASK 64
+
+static const struct {
+  unsigned char mem_index;
+  unsigned long mem_start;
+  unsigned char num_pages;
+} mem_table[] = {
+    { 16, 0x0c0000, 40 },
+    { 18, 0x0c4000, 40 },
+    { 20, 0x0c8000, 40 },
+    { 22, 0x0cc000, 40 },
+    { 24, 0x0d0000, 40 },
+    { 26, 0x0d4000, 40 },
+    { 28, 0x0d8000, 40 },
+    { 30, 0x0dc000, 40 },
+    {144, 0xfc0000, 40 },
+    {148, 0xfc8000, 40 },
+    {154, 0xfd0000, 40 },
+    {156, 0xfd8000, 40 },
+    {  0, 0x0c0000, 20 },
+    {  1, 0x0c2000, 20 },
+    {  2, 0x0c4000, 20 },
+    {  3, 0x0c6000, 20 }
+};
+
+#define IRQ_MASK 243
+static const struct {
+   unsigned char new_irq;
+   unsigned char old_irq;
+} irq_table[] = {
+   {  3,  3 },
+   {  4,  4 },
+   { 10, 10 },
+   { 14, 15 }
+};
+
 static short smc_mca_adapter_ids[] __initdata = {
        0x61c8,
        0x61c9,
@@ -126,7 +182,7 @@ static char *smc_mca_adapter_names[] __initdata = {
 
 static int ultra_found = 0;
 
-int __init ultramca_probe(struct device *gen_dev)
+static int __init ultramca_probe(struct device *gen_dev)
 {
        unsigned short ioaddr;
        struct net_device *dev;
diff --git a/drivers/net/smc-mca.h b/drivers/net/smc-mca.h
deleted file mode 100644 (file)
index ac50117..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * djweis weisd3458@uni.edu
- * most of this file was taken from ps2esdi.h
- */
-
-struct {
-  unsigned int base_addr;
-} addr_table[] = {
-    { 0x0800 },
-    { 0x1800 },
-    { 0x2800 },
-    { 0x3800 },
-    { 0x4800 },
-    { 0x5800 },
-    { 0x6800 },
-    { 0x7800 },
-    { 0x8800 },
-    { 0x9800 },
-    { 0xa800 },
-    { 0xb800 },
-    { 0xc800 },
-    { 0xd800 },
-    { 0xe800 },
-    { 0xf800 }
-};
-
-#define MEM_MASK 64
-
-struct {
-  unsigned char mem_index;
-  unsigned long mem_start;
-  unsigned char num_pages;
-} mem_table[] = {
-    { 16, 0x0c0000, 40 },
-    { 18, 0x0c4000, 40 },
-    { 20, 0x0c8000, 40 },
-    { 22, 0x0cc000, 40 },
-    { 24, 0x0d0000, 40 },
-    { 26, 0x0d4000, 40 },
-    { 28, 0x0d8000, 40 },
-    { 30, 0x0dc000, 40 },
-    {144, 0xfc0000, 40 },
-    {148, 0xfc8000, 40 },
-    {154, 0xfd0000, 40 },
-    {156, 0xfd8000, 40 },
-    {  0, 0x0c0000, 20 },
-    {  1, 0x0c2000, 20 },
-    {  2, 0x0c4000, 20 },
-    {  3, 0x0c6000, 20 }
-};
-
-#define IRQ_MASK 243
-struct {
-   unsigned char new_irq;
-   unsigned char old_irq;
-} irq_table[] = {
-   {  3,  3 },
-   {  4,  4 },
-   { 10, 10 },
-   { 14, 15 }
-};
index b564c677c6d25542a75a06a21e4d13f9adc0851f..6d9dae60a697050c1d7d1e8f4665420f0ac65074 100644 (file)
@@ -194,12 +194,7 @@ struct net_device * __init ultra_probe(int unit)
        err = do_ultra_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -325,6 +320,9 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr)
 #endif
        NS8390_init(dev, 0);
 
+       retval = register_netdev(dev);
+       if (retval)
+               goto out;
        return 0;
 out:
        release_region(ioaddr, ULTRA_IO_EXTENT);
@@ -583,11 +581,8 @@ init_module(void)
                dev->irq = irq[this_dev];
                dev->base_addr = io[this_dev];
                if (do_ultra_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_ultra[found++] = dev;
-                               continue;
-                       }
-                       cleanup_card(dev);
+                       dev_ultra[found++] = dev;
+                       continue;
                }
                free_netdev(dev);
                printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]);
index fd80048f7f7ac6f98e09bf6e0456448e7688ccea..1438fdd20826487a0d8d0535143f484b1111a3be 100644 (file)
@@ -315,15 +315,25 @@ static void smc_reset(struct net_device *dev)
        struct smc_local *lp = netdev_priv(dev);
        void __iomem *ioaddr = lp->base;
        unsigned int ctl, cfg;
+       struct sk_buff *pending_skb;
 
        DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
 
-       /* Disable all interrupts */
+       /* Disable all interrupts, block TX tasklet */
        spin_lock(&lp->lock);
        SMC_SELECT_BANK(2);
        SMC_SET_INT_MASK(0);
+       pending_skb = lp->pending_tx_skb;
+       lp->pending_tx_skb = NULL;
        spin_unlock(&lp->lock);
 
+       /* free any pending tx skb */
+       if (pending_skb) {
+               dev_kfree_skb(pending_skb);
+               lp->stats.tx_errors++;
+               lp->stats.tx_aborted_errors++;
+       }
+
        /*
         * This resets the registers mostly to defaults, but doesn't
         * affect EEPROM.  That seems unnecessary
@@ -389,14 +399,6 @@ static void smc_reset(struct net_device *dev)
        SMC_SELECT_BANK(2);
        SMC_SET_MMU_CMD(MC_RESET);
        SMC_WAIT_MMU_BUSY();
-
-       /* clear anything saved */
-       if (lp->pending_tx_skb != NULL) {
-               dev_kfree_skb (lp->pending_tx_skb);
-               lp->pending_tx_skb = NULL;
-               lp->stats.tx_errors++;
-               lp->stats.tx_aborted_errors++;
-       }
 }
 
 /*
@@ -440,6 +442,7 @@ static void smc_shutdown(struct net_device *dev)
 {
        struct smc_local *lp = netdev_priv(dev);
        void __iomem *ioaddr = lp->base;
+       struct sk_buff *pending_skb;
 
        DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
 
@@ -447,7 +450,11 @@ static void smc_shutdown(struct net_device *dev)
        spin_lock(&lp->lock);
        SMC_SELECT_BANK(2);
        SMC_SET_INT_MASK(0);
+       pending_skb = lp->pending_tx_skb;
+       lp->pending_tx_skb = NULL;
        spin_unlock(&lp->lock);
+       if (pending_skb)
+               dev_kfree_skb(pending_skb);
 
        /* and tell the card to stay away from that nasty outside world */
        SMC_SELECT_BANK(0);
@@ -627,7 +634,12 @@ static void smc_hardware_send_pkt(unsigned long data)
        }
 
        skb = lp->pending_tx_skb;
+       if (unlikely(!skb)) {
+               smc_special_unlock(&lp->lock);
+               return;
+       }
        lp->pending_tx_skb = NULL;
+
        packet_no = SMC_GET_AR();
        if (unlikely(packet_no & AR_FAILED)) {
                printk("%s: Memory allocation failed.\n", dev->name);
@@ -702,7 +714,6 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
 
        BUG_ON(lp->pending_tx_skb != NULL);
-       lp->pending_tx_skb = skb;
 
        /*
         * The MMU wants the number of pages to be the number of 256 bytes
@@ -718,7 +729,6 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
        if (unlikely(numPages > 7)) {
                printk("%s: Far too big packet error.\n", dev->name);
-               lp->pending_tx_skb = NULL;
                lp->stats.tx_errors++;
                lp->stats.tx_dropped++;
                dev_kfree_skb(skb);
@@ -745,6 +755,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        smc_special_unlock(&lp->lock);
 
+       lp->pending_tx_skb = skb;
        if (!poll_count) {
                /* oh well, wait until the chip finds memory later */
                netif_stop_queue(dev);
@@ -1062,7 +1073,7 @@ static void smc_phy_powerdown(struct net_device *dev)
           above). linkwatch_event() also wants the netlink semaphore.
        */
        while(lp->work_pending)
-               schedule();
+               yield();
 
        bmcr = smc_phy_read(dev, phy, MII_BMCR);
        smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN);
@@ -1606,14 +1617,8 @@ static int smc_close(struct net_device *dev)
 
        /* clear everything */
        smc_shutdown(dev);
-
+       tasklet_kill(&lp->tx_task);
        smc_phy_powerdown(dev);
-
-       if (lp->pending_tx_skb) {
-               dev_kfree_skb(lp->pending_tx_skb);
-               lp->pending_tx_skb = NULL;
-       }
-
        return 0;
 }
 
@@ -1993,7 +1998,7 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
        if (retval)
                goto err_out;
 
-       set_irq_type(dev->irq, IRQT_RISING);
+       set_irq_type(dev->irq, SMC_IRQ_TRIGGER_TYPE);
 
 #ifdef SMC_USE_PXA_DMA
        {
index 946528e6b742000523f6991cf7925f2c123a3b24..7089d86e857a6d0dbf62ad48742265fea34aa8f5 100644 (file)
@@ -182,6 +182,16 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 #define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
 #define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
 
+#include <asm/mach-types.h>
+#include <asm/arch/cpu.h>
+
+#define        SMC_IRQ_TRIGGER_TYPE (( \
+                  machine_is_omap_h2() \
+               || machine_is_omap_h3() \
+               || (machine_is_omap_innovator() && !cpu_is_omap150()) \
+       ) ? IRQT_FALLING : IRQT_RISING)
+
+
 #elif  defined(CONFIG_SH_SH4202_MICRODEV)
 
 #define SMC_CAN_USE_8BIT       0
@@ -300,6 +310,9 @@ static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l)
 
 #endif
 
+#ifndef        SMC_IRQ_TRIGGER_TYPE
+#define        SMC_IRQ_TRIGGER_TYPE    IRQT_RISING
+#endif
 
 #ifdef SMC_USE_PXA_DMA
 /*
index 12e2b6826fa3768e2c72ee9afd92bc0bee6b2e5d..88b89dc95c77c8b2643745bf06618c6e2742ccf8 100644 (file)
@@ -1286,7 +1286,7 @@ static void init_ring(struct net_device *dev)
                np->rx_info[i].skb = skb;
                if (skb == NULL)
                        break;
-               np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+               np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
                skb->dev = dev;                 /* Mark as being used by this device. */
                /* Grrr, we cannot offset to correctly align the IP header. */
                np->rx_ring[i].rxaddr = cpu_to_dma(np->rx_info[i].mapping | RxDescValid);
@@ -1572,7 +1572,7 @@ static int __netdev_rx(struct net_device *dev, int *quota)
                        pci_dma_sync_single_for_cpu(np->pci_dev,
                                                    np->rx_info[entry].mapping,
                                                    pkt_len, PCI_DMA_FROMDEVICE);
-                       eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0);
+                       eth_copy_and_sum(skb, np->rx_info[entry].skb->data, pkt_len, 0);
                        pci_dma_sync_single_for_device(np->pci_dev,
                                                       np->rx_info[entry].mapping,
                                                       pkt_len, PCI_DMA_FROMDEVICE);
@@ -1696,7 +1696,7 @@ static void refill_rx_ring(struct net_device *dev)
                        if (skb == NULL)
                                break;  /* Better luck next round. */
                        np->rx_info[entry].mapping =
-                               pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+                               pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
                        skb->dev = dev; /* Mark as being used by this device. */
                        np->rx_ring[entry].rxaddr =
                                cpu_to_dma(np->rx_info[entry].mapping | RxDescValid);
index 08cb7177a17598cbb9eb236531a18891a9ab8c64..d500a5771dbc5c05f5f03428b71f58e21b96530f 100644 (file)
@@ -1028,7 +1028,7 @@ static void init_ring(struct net_device *dev)
                skb->dev = dev;         /* Mark as being used by this device. */
                skb_reserve(skb, 2);    /* 16 byte align the IP header. */
                np->rx_ring[i].frag[0].addr = cpu_to_le32(
-                       pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz,
+                       pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz,
                                PCI_DMA_FROMDEVICE));
                np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag);
        }
@@ -1341,7 +1341,7 @@ static void rx_poll(unsigned long data)
                                                            np->rx_buf_sz,
                                                            PCI_DMA_FROMDEVICE);
 
-                               eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
+                               eth_copy_and_sum(skb, np->rx_skbuff[entry]->data, pkt_len, 0);
                                pci_dma_sync_single_for_device(np->pci_dev,
                                                               desc->frag[0].addr,
                                                               np->rx_buf_sz,
@@ -1400,7 +1400,7 @@ static void refill_rx (struct net_device *dev)
                        skb->dev = dev;         /* Mark as being used by this device. */
                        skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
                        np->rx_ring[entry].frag[0].addr = cpu_to_le32(
-                               pci_map_single(np->pci_dev, skb->tail,
+                               pci_map_single(np->pci_dev, skb->data,
                                        np->rx_buf_sz, PCI_DMA_FROMDEVICE));
                }
                /* Perhaps we need not reset this field. */
index 5cd50fd53c1251fd8ba9a68a700ca28d96fcc897..1f5655655c40185091146461789f0a08ab7c5282 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
@@ -2989,10 +2990,10 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
         */
        if (pdev->vendor == PCI_VENDOR_ID_SUN &&
            pdev->device == PCI_DEVICE_ID_SUN_GEM &&
-           !pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL)) {
+           !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
                pci_using_dac = 1;
        } else {
-               err = pci_set_dma_mask(pdev, (u64) 0xffffffff);
+               err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
                if (err) {
                        printk(KERN_ERR PFX "No usable DMA configuration, "
                               "aborting.\n");
index a0b8848049c9ede346a9160c370d0b1df49c2798..7e371b1209a1a4b3578b80f0d7bb33d2a6d2697c 100644 (file)
@@ -66,8 +66,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.31"
-#define DRV_MODULE_RELDATE     "June 8, 2005"
+#define DRV_MODULE_VERSION     "3.32"
+#define DRV_MODULE_RELDATE     "June 24, 2005"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -337,12 +337,10 @@ static struct {
 static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
 {
        if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&tp->indirect_lock, flags);
+               spin_lock_bh(&tp->indirect_lock);
                pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);
                pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
-               spin_unlock_irqrestore(&tp->indirect_lock, flags);
+               spin_unlock_bh(&tp->indirect_lock);
        } else {
                writel(val, tp->regs + off);
                if ((tp->tg3_flags & TG3_FLAG_5701_REG_WRITE_BUG) != 0)
@@ -353,12 +351,10 @@ static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
 static void _tw32_flush(struct tg3 *tp, u32 off, u32 val)
 {
        if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&tp->indirect_lock, flags);
+               spin_lock_bh(&tp->indirect_lock);
                pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);
                pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
-               spin_unlock_irqrestore(&tp->indirect_lock, flags);
+               spin_unlock_bh(&tp->indirect_lock);
        } else {
                void __iomem *dest = tp->regs + off;
                writel(val, dest);
@@ -398,28 +394,24 @@ static inline void _tw32_tx_mbox(struct tg3 *tp, u32 off, u32 val)
 
 static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&tp->indirect_lock, flags);
+       spin_lock_bh(&tp->indirect_lock);
        pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
        pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
 
        /* Always leave this as zero. */
        pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
-       spin_unlock_irqrestore(&tp->indirect_lock, flags);
+       spin_unlock_bh(&tp->indirect_lock);
 }
 
 static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&tp->indirect_lock, flags);
+       spin_lock_bh(&tp->indirect_lock);
        pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
        pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
 
        /* Always leave this as zero. */
        pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
-       spin_unlock_irqrestore(&tp->indirect_lock, flags);
+       spin_unlock_bh(&tp->indirect_lock);
 }
 
 static void tg3_disable_ints(struct tg3 *tp)
@@ -438,12 +430,14 @@ static inline void tg3_cond_int(struct tg3 *tp)
 
 static void tg3_enable_ints(struct tg3 *tp)
 {
+       tp->irq_sync = 0;
+       wmb();
+
        tw32(TG3PCI_MISC_HOST_CTRL,
             (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
        tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
                     (tp->last_tag << 24));
        tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
-
        tg3_cond_int(tp);
 }
 
@@ -492,6 +486,7 @@ static void tg3_restart_ints(struct tg3 *tp)
 
 static inline void tg3_netif_stop(struct tg3 *tp)
 {
+       tp->dev->trans_start = jiffies; /* prevent tx timeout */
        netif_poll_disable(tp->dev);
        netif_tx_disable(tp->dev);
 }
@@ -504,7 +499,8 @@ static inline void tg3_netif_start(struct tg3 *tp)
         * (such as after tg3_init_hw)
         */
        netif_poll_enable(tp->dev);
-       tg3_cond_int(tp);
+       tp->hw_status->status |= SD_STATUS_UPDATED;
+       tg3_enable_ints(tp);
 }
 
 static void tg3_switch_clocks(struct tg3 *tp)
@@ -2578,7 +2574,7 @@ static void tg3_tx(struct tg3 *tp)
                        sw_idx = NEXT_TX(sw_idx);
                }
 
-               dev_kfree_skb_irq(skb);
+               dev_kfree_skb(skb);
        }
 
        tp->tx_cons = sw_idx;
@@ -2884,11 +2880,8 @@ static int tg3_poll(struct net_device *netdev, int *budget)
 {
        struct tg3 *tp = netdev_priv(netdev);
        struct tg3_hw_status *sblk = tp->hw_status;
-       unsigned long flags;
        int done;
 
-       spin_lock_irqsave(&tp->lock, flags);
-
        /* handle link change and other phy events */
        if (!(tp->tg3_flags &
              (TG3_FLAG_USE_LINKCHG_REG |
@@ -2896,7 +2889,9 @@ static int tg3_poll(struct net_device *netdev, int *budget)
                if (sblk->status & SD_STATUS_LINK_CHG) {
                        sblk->status = SD_STATUS_UPDATED |
                                (sblk->status & ~SD_STATUS_LINK_CHG);
+                       spin_lock(&tp->lock);
                        tg3_setup_phy(tp, 0);
+                       spin_unlock(&tp->lock);
                }
        }
 
@@ -2907,8 +2902,6 @@ static int tg3_poll(struct net_device *netdev, int *budget)
                spin_unlock(&tp->tx_lock);
        }
 
-       spin_unlock_irqrestore(&tp->lock, flags);
-
        /* run RX thread, within the bounds set by NAPI.
         * All RX "locking" is done by ensuring outside
         * code synchronizes with dev->poll()
@@ -2929,19 +2922,54 @@ static int tg3_poll(struct net_device *netdev, int *budget)
        if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
                tp->last_tag = sblk->status_tag;
        rmb();
+       sblk->status &= ~SD_STATUS_UPDATED;
 
        /* if no more work, tell net stack and NIC we're done */
        done = !tg3_has_work(tp);
        if (done) {
-               spin_lock_irqsave(&tp->lock, flags);
-               __netif_rx_complete(netdev);
+               spin_lock(&tp->lock);
+               netif_rx_complete(netdev);
                tg3_restart_ints(tp);
-               spin_unlock_irqrestore(&tp->lock, flags);
+               spin_unlock(&tp->lock);
        }
 
        return (done ? 0 : 1);
 }
 
+static void tg3_irq_quiesce(struct tg3 *tp)
+{
+       BUG_ON(tp->irq_sync);
+
+       tp->irq_sync = 1;
+       smp_mb();
+
+       synchronize_irq(tp->pdev->irq);
+}
+
+static inline int tg3_irq_sync(struct tg3 *tp)
+{
+       return tp->irq_sync;
+}
+
+/* Fully shutdown all tg3 driver activity elsewhere in the system.
+ * If irq_sync is non-zero, then the IRQ handler must be synchronized
+ * with as well.  Most of the time, this is not necessary except when
+ * shutting down the device.
+ */
+static inline void tg3_full_lock(struct tg3 *tp, int irq_sync)
+{
+       if (irq_sync)
+               tg3_irq_quiesce(tp);
+       spin_lock_bh(&tp->lock);
+       spin_lock(&tp->tx_lock);
+}
+
+static inline void tg3_full_unlock(struct tg3 *tp)
+{
+       spin_unlock(&tp->tx_lock);
+       spin_unlock_bh(&tp->lock);
+}
+
 /* MSI ISR - No need to check for interrupt sharing and no need to
  * flush status block and interrupt mailbox. PCI ordering rules
  * guarantee that MSI will arrive after the status block.
@@ -2951,9 +2979,6 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs)
        struct net_device *dev = dev_id;
        struct tg3 *tp = netdev_priv(dev);
        struct tg3_hw_status *sblk = tp->hw_status;
-       unsigned long flags;
-
-       spin_lock_irqsave(&tp->lock, flags);
 
        /*
         * Writing any value to intr-mbox-0 clears PCI INTA# and
@@ -2964,6 +2989,9 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs)
         */
        tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
        tp->last_tag = sblk->status_tag;
+       rmb();
+       if (tg3_irq_sync(tp))
+               goto out;
        sblk->status &= ~SD_STATUS_UPDATED;
        if (likely(tg3_has_work(tp)))
                netif_rx_schedule(dev);         /* schedule NAPI poll */
@@ -2972,9 +3000,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs)
                tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
                             tp->last_tag << 24);
        }
-
-       spin_unlock_irqrestore(&tp->lock, flags);
-
+out:
        return IRQ_RETVAL(1);
 }
 
@@ -2983,11 +3009,8 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        struct net_device *dev = dev_id;
        struct tg3 *tp = netdev_priv(dev);
        struct tg3_hw_status *sblk = tp->hw_status;
-       unsigned long flags;
        unsigned int handled = 1;
 
-       spin_lock_irqsave(&tp->lock, flags);
-
        /* In INTx mode, it is possible for the interrupt to arrive at
         * the CPU before the status block posted prior to the interrupt.
         * Reading the PCI State register will confirm whether the
@@ -3004,6 +3027,8 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                 */
                tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
                             0x00000001);
+               if (tg3_irq_sync(tp))
+                       goto out;
                sblk->status &= ~SD_STATUS_UPDATED;
                if (likely(tg3_has_work(tp)))
                        netif_rx_schedule(dev);         /* schedule NAPI poll */
@@ -3018,9 +3043,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        } else {        /* shared interrupt */
                handled = 0;
        }
-
-       spin_unlock_irqrestore(&tp->lock, flags);
-
+out:
        return IRQ_RETVAL(handled);
 }
 
@@ -3029,11 +3052,8 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *r
        struct net_device *dev = dev_id;
        struct tg3 *tp = netdev_priv(dev);
        struct tg3_hw_status *sblk = tp->hw_status;
-       unsigned long flags;
        unsigned int handled = 1;
 
-       spin_lock_irqsave(&tp->lock, flags);
-
        /* In INTx mode, it is possible for the interrupt to arrive at
         * the CPU before the status block posted prior to the interrupt.
         * Reading the PCI State register will confirm whether the
@@ -3051,6 +3071,9 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *r
                tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
                             0x00000001);
                tp->last_tag = sblk->status_tag;
+               rmb();
+               if (tg3_irq_sync(tp))
+                       goto out;
                sblk->status &= ~SD_STATUS_UPDATED;
                if (likely(tg3_has_work(tp)))
                        netif_rx_schedule(dev);         /* schedule NAPI poll */
@@ -3065,9 +3088,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *r
        } else {        /* shared interrupt */
                handled = 0;
        }
-
-       spin_unlock_irqrestore(&tp->lock, flags);
-
+out:
        return IRQ_RETVAL(handled);
 }
 
@@ -3106,8 +3127,7 @@ static void tg3_reset_task(void *_data)
 
        tg3_netif_stop(tp);
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, 1);
 
        restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER;
        tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER;
@@ -3117,8 +3137,7 @@ static void tg3_reset_task(void *_data)
 
        tg3_netif_start(tp);
 
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
 
        if (restart_timer)
                mod_timer(&tp->timer, jiffies + 1);
@@ -3224,39 +3243,21 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        unsigned int i;
        u32 len, entry, base_flags, mss;
        int would_hit_hwbug;
-       unsigned long flags;
 
        len = skb_headlen(skb);
 
        /* No BH disabling for tx_lock here.  We are running in BH disabled
         * context and TX reclaim runs via tp->poll inside of a software
-        * interrupt.  Rejoice!
-        *
-        * Actually, things are not so simple.  If we are to take a hw
-        * IRQ here, we can deadlock, consider:
-        *
-        *       CPU1           CPU2
-        *   tg3_start_xmit
-        *   take tp->tx_lock
-        *                      tg3_timer
-        *                      take tp->lock
-        *   tg3_interrupt
-        *   spin on tp->lock
-        *                      spin on tp->tx_lock
-        *
-        * So we really do need to disable interrupts when taking
-        * tx_lock here.
+        * interrupt.  Furthermore, IRQ processing runs lockless so we have
+        * no IRQ context deadlocks to worry about either.  Rejoice!
         */
-       local_irq_save(flags);
-       if (!spin_trylock(&tp->tx_lock)) { 
-               local_irq_restore(flags);
+       if (!spin_trylock(&tp->tx_lock))
                return NETDEV_TX_LOCKED; 
-       } 
 
        /* This is a hard error, log it. */
        if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
                netif_stop_queue(dev);
-               spin_unlock_irqrestore(&tp->tx_lock, flags);
+               spin_unlock(&tp->tx_lock);
                printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
                       dev->name);
                return NETDEV_TX_BUSY;
@@ -3421,7 +3422,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 out_unlock:
        mmiowb();
-       spin_unlock_irqrestore(&tp->tx_lock, flags);
+       spin_unlock(&tp->tx_lock);
 
        dev->trans_start = jiffies;
 
@@ -3455,8 +3456,8 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
        }
 
        tg3_netif_stop(tp);
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+
+       tg3_full_lock(tp, 1);
 
        tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
 
@@ -3466,8 +3467,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 
        tg3_netif_start(tp);
 
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
 
        return 0;
 }
@@ -5088,9 +5088,9 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
 
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
-       spin_lock_irq(&tp->lock);
+       spin_lock_bh(&tp->lock);
        __tg3_set_mac_addr(tp);
-       spin_unlock_irq(&tp->lock);
+       spin_unlock_bh(&tp->lock);
 
        return 0;
 }
@@ -5727,9 +5727,6 @@ static int tg3_reset_hw(struct tg3 *tp)
 
        tg3_write_sig_post_reset(tp, RESET_KIND_INIT);
 
-       if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)
-               tg3_enable_ints(tp);
-
        return 0;
 }
 
@@ -5802,10 +5799,8 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp)
 static void tg3_timer(unsigned long __opaque)
 {
        struct tg3 *tp = (struct tg3 *) __opaque;
-       unsigned long flags;
 
-       spin_lock_irqsave(&tp->lock, flags);
-       spin_lock(&tp->tx_lock);
+       spin_lock(&tp->lock);
 
        if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
                /* All of this garbage is because when using non-tagged
@@ -5822,8 +5817,7 @@ static void tg3_timer(unsigned long __opaque)
 
                if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
                        tp->tg3_flags2 |= TG3_FLG2_RESTART_TIMER;
-                       spin_unlock(&tp->tx_lock);
-                       spin_unlock_irqrestore(&tp->lock, flags);
+                       spin_unlock(&tp->lock);
                        schedule_work(&tp->reset_task);
                        return;
                }
@@ -5891,8 +5885,7 @@ static void tg3_timer(unsigned long __opaque)
                tp->asf_counter = tp->asf_multiplier;
        }
 
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irqrestore(&tp->lock, flags);
+       spin_unlock(&tp->lock);
 
        tp->timer.expires = jiffies + tp->timer_offset;
        add_timer(&tp->timer);
@@ -6007,14 +6000,12 @@ static int tg3_test_msi(struct tg3 *tp)
        /* Need to reset the chip because the MSI cycle may have terminated
         * with Master Abort.
         */
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, 1);
 
        tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
        err = tg3_init_hw(tp);
 
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
 
        if (err)
                free_irq(tp->pdev->irq, dev);
@@ -6027,14 +6018,12 @@ static int tg3_open(struct net_device *dev)
        struct tg3 *tp = netdev_priv(dev);
        int err;
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, 0);
 
        tg3_disable_ints(tp);
        tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
 
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
 
        /* The placement of this call is tied
         * to the setup and use of Host TX descriptors.
@@ -6081,8 +6070,7 @@ static int tg3_open(struct net_device *dev)
                return err;
        }
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, 0);
 
        err = tg3_init_hw(tp);
        if (err) {
@@ -6106,8 +6094,7 @@ static int tg3_open(struct net_device *dev)
                tp->timer.function = tg3_timer;
        }
 
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
 
        if (err) {
                free_irq(tp->pdev->irq, dev);
@@ -6123,8 +6110,7 @@ static int tg3_open(struct net_device *dev)
                err = tg3_test_msi(tp);
 
                if (err) {
-                       spin_lock_irq(&tp->lock);
-                       spin_lock(&tp->tx_lock);
+                       tg3_full_lock(tp, 0);
 
                        if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
                                pci_disable_msi(tp->pdev);
@@ -6134,22 +6120,19 @@ static int tg3_open(struct net_device *dev)
                        tg3_free_rings(tp);
                        tg3_free_consistent(tp);
 
-                       spin_unlock(&tp->tx_lock);
-                       spin_unlock_irq(&tp->lock);
+                       tg3_full_unlock(tp);
 
                        return err;
                }
        }
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, 0);
 
        add_timer(&tp->timer);
        tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
        tg3_enable_ints(tp);
 
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
 
        netif_start_queue(dev);
 
@@ -6395,8 +6378,7 @@ static int tg3_close(struct net_device *dev)
 
        del_timer_sync(&tp->timer);
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, 1);
 #if 0
        tg3_dump_state(tp);
 #endif
@@ -6410,8 +6392,7 @@ static int tg3_close(struct net_device *dev)
                  TG3_FLAG_GOT_SERDES_FLOWCTL);
        netif_carrier_off(tp->dev);
 
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
 
        free_irq(tp->pdev->irq, dev);
        if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
@@ -6448,16 +6429,15 @@ static unsigned long calc_crc_errors(struct tg3 *tp)
        if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
            (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
             GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
-               unsigned long flags;
                u32 val;
 
-               spin_lock_irqsave(&tp->lock, flags);
+               spin_lock_bh(&tp->lock);
                if (!tg3_readphy(tp, 0x1e, &val)) {
                        tg3_writephy(tp, 0x1e, val | 0x8000);
                        tg3_readphy(tp, 0x14, &val);
                } else
                        val = 0;
-               spin_unlock_irqrestore(&tp->lock, flags);
+               spin_unlock_bh(&tp->lock);
 
                tp->phy_crc_errors += val;
 
@@ -6719,11 +6699,9 @@ static void tg3_set_rx_mode(struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, 0);
        __tg3_set_rx_mode(dev);
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
 }
 
 #define TG3_REGDUMP_LEN                (32 * 1024)
@@ -6745,8 +6723,7 @@ static void tg3_get_regs(struct net_device *dev,
 
        memset(p, 0, TG3_REGDUMP_LEN);
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, 0);
 
 #define __GET_REG32(reg)       (*(p)++ = tr32(reg))
 #define GET_REG32_LOOP(base,len)               \
@@ -6796,8 +6773,7 @@ do {      p = (u32 *)(orig_p + (reg));            \
 #undef GET_REG32_LOOP
 #undef GET_REG32_1
 
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
 }
 
 static int tg3_get_eeprom_len(struct net_device *dev)
@@ -6973,8 +6949,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                        return -EINVAL;
        }
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, 0);
 
        tp->link_config.autoneg = cmd->autoneg;
        if (cmd->autoneg == AUTONEG_ENABLE) {
@@ -6990,8 +6965,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        if (netif_running(dev))
                tg3_setup_phy(tp, 1);
 
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
   
        return 0;
 }
@@ -7027,12 +7001,12 @@ static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
            !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP))
                return -EINVAL;
   
-       spin_lock_irq(&tp->lock);
+       spin_lock_bh(&tp->lock);
        if (wol->wolopts & WAKE_MAGIC)
                tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
        else
                tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
-       spin_unlock_irq(&tp->lock);
+       spin_unlock_bh(&tp->lock);
   
        return 0;
 }
@@ -7072,7 +7046,7 @@ static int tg3_nway_reset(struct net_device *dev)
        if (!netif_running(dev))
                return -EAGAIN;
 
-       spin_lock_irq(&tp->lock);
+       spin_lock_bh(&tp->lock);
        r = -EINVAL;
        tg3_readphy(tp, MII_BMCR, &bmcr);
        if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
@@ -7080,7 +7054,7 @@ static int tg3_nway_reset(struct net_device *dev)
                tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART);
                r = 0;
        }
-       spin_unlock_irq(&tp->lock);
+       spin_unlock_bh(&tp->lock);
   
        return r;
 }
@@ -7102,17 +7076,19 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *
 static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 {
        struct tg3 *tp = netdev_priv(dev);
+       int irq_sync = 0;
   
        if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) ||
            (ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
            (ering->tx_pending > TG3_TX_RING_SIZE - 1))
                return -EINVAL;
   
-       if (netif_running(dev))
+       if (netif_running(dev)) {
                tg3_netif_stop(tp);
+               irq_sync = 1;
+       }
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, irq_sync);
   
        tp->rx_pending = ering->rx_pending;
 
@@ -7128,8 +7104,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
                tg3_netif_start(tp);
        }
 
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
   
        return 0;
 }
@@ -7146,12 +7121,15 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam
 static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
 {
        struct tg3 *tp = netdev_priv(dev);
+       int irq_sync = 0;
   
-       if (netif_running(dev))
+       if (netif_running(dev)) {
                tg3_netif_stop(tp);
+               irq_sync = 1;
+       }
+
+       tg3_full_lock(tp, irq_sync);
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
        if (epause->autoneg)
                tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
        else
@@ -7170,8 +7148,8 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
                tg3_init_hw(tp);
                tg3_netif_start(tp);
        }
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+
+       tg3_full_unlock(tp);
   
        return 0;
 }
@@ -7192,12 +7170,12 @@ static int tg3_set_rx_csum(struct net_device *dev, u32 data)
                return 0;
        }
   
-       spin_lock_irq(&tp->lock);
+       spin_lock_bh(&tp->lock);
        if (data)
                tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
        else
                tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
-       spin_unlock_irq(&tp->lock);
+       spin_unlock_bh(&tp->lock);
   
        return 0;
 }
@@ -7606,8 +7584,6 @@ static int tg3_test_loopback(struct tg3 *tp)
 
        tg3_abort_hw(tp, 1);
 
-       /* Clearing this flag to keep interrupts disabled */
-       tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
        tg3_reset_hw(tp);
 
        mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
@@ -7716,11 +7692,14 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                data[1] = 1;
        }
        if (etest->flags & ETH_TEST_FL_OFFLINE) {
-               if (netif_running(dev))
+               int irq_sync = 0;
+
+               if (netif_running(dev)) {
                        tg3_netif_stop(tp);
+                       irq_sync = 1;
+               }
 
-               spin_lock_irq(&tp->lock);
-               spin_lock(&tp->tx_lock);
+               tg3_full_lock(tp, irq_sync);
 
                tg3_halt(tp, RESET_KIND_SUSPEND, 1);
                tg3_nvram_lock(tp);
@@ -7742,14 +7721,14 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                        data[4] = 1;
                }
 
-               spin_unlock(&tp->tx_lock);
-               spin_unlock_irq(&tp->lock);
+               tg3_full_unlock(tp);
+
                if (tg3_test_interrupt(tp) != 0) {
                        etest->flags |= ETH_TEST_FL_FAILED;
                        data[5] = 1;
                }
-               spin_lock_irq(&tp->lock);
-               spin_lock(&tp->tx_lock);
+
+               tg3_full_lock(tp, 0);
 
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
                if (netif_running(dev)) {
@@ -7757,8 +7736,8 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                        tg3_init_hw(tp);
                        tg3_netif_start(tp);
                }
-               spin_unlock(&tp->tx_lock);
-               spin_unlock_irq(&tp->lock);
+
+               tg3_full_unlock(tp);
        }
 }
 
@@ -7779,9 +7758,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
                        break;                  /* We have no PHY */
 
-               spin_lock_irq(&tp->lock);
+               spin_lock_bh(&tp->lock);
                err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval);
-               spin_unlock_irq(&tp->lock);
+               spin_unlock_bh(&tp->lock);
 
                data->val_out = mii_regval;
 
@@ -7795,9 +7774,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                if (!capable(CAP_NET_ADMIN))
                        return -EPERM;
 
-               spin_lock_irq(&tp->lock);
+               spin_lock_bh(&tp->lock);
                err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in);
-               spin_unlock_irq(&tp->lock);
+               spin_unlock_bh(&tp->lock);
 
                return err;
 
@@ -7813,28 +7792,24 @@ static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
 {
        struct tg3 *tp = netdev_priv(dev);
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, 0);
 
        tp->vlgrp = grp;
 
        /* Update RX_MODE_KEEP_VLAN_TAG bit in RX_MODE register. */
        __tg3_set_rx_mode(dev);
 
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
 }
 
 static void tg3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 {
        struct tg3 *tp = netdev_priv(dev);
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, 0);
        if (tp->vlgrp)
                tp->vlgrp->vlan_devices[vid] = NULL;
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
 }
 #endif
 
@@ -10165,24 +10140,19 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
 
        del_timer_sync(&tp->timer);
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, 1);
        tg3_disable_ints(tp);
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
 
        netif_device_detach(dev);
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, 0);
        tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
 
        err = tg3_set_power_state(tp, pci_choose_state(pdev, state));
        if (err) {
-               spin_lock_irq(&tp->lock);
-               spin_lock(&tp->tx_lock);
+               tg3_full_lock(tp, 0);
 
                tg3_init_hw(tp);
 
@@ -10192,8 +10162,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
                netif_device_attach(dev);
                tg3_netif_start(tp);
 
-               spin_unlock(&tp->tx_lock);
-               spin_unlock_irq(&tp->lock);
+               tg3_full_unlock(tp);
        }
 
        return err;
@@ -10216,20 +10185,16 @@ static int tg3_resume(struct pci_dev *pdev)
 
        netif_device_attach(dev);
 
-       spin_lock_irq(&tp->lock);
-       spin_lock(&tp->tx_lock);
+       tg3_full_lock(tp, 0);
 
        tg3_init_hw(tp);
 
        tp->timer.expires = jiffies + tp->timer_offset;
        add_timer(&tp->timer);
 
-       tg3_enable_ints(tp);
-
        tg3_netif_start(tp);
 
-       spin_unlock(&tp->tx_lock);
-       spin_unlock_irq(&tp->lock);
+       tg3_full_unlock(tp);
 
        return 0;
 }
index 993f84c93dc41df662f0864e4a6bfb556051512e..99c5f9675a560f06ee89a8f11e1e7cf787cea366 100644 (file)
@@ -2006,17 +2006,31 @@ struct tg3_ethtool_stats {
 struct tg3 {
        /* begin "general, frequently-used members" cacheline section */
 
+       /* If the IRQ handler (which runs lockless) needs to be
+        * quiesced, the following bitmask state is used.  The
+        * SYNC flag is set by non-IRQ context code to initiate
+        * the quiescence.
+        *
+        * When the IRQ handler notices that SYNC is set, it
+        * disables interrupts and returns.
+        *
+        * When all outstanding IRQ handlers have returned after
+        * the SYNC flag has been set, the setter can be assured
+        * that interrupts will no longer get run.
+        *
+        * In this way all SMP driver locks are never acquired
+        * in hw IRQ context, only sw IRQ context or lower.
+        */
+       unsigned int                    irq_sync;
+
        /* SMP locking strategy:
         *
         * lock: Held during all operations except TX packet
         *       processing.
         *
-        * tx_lock: Held during tg3_start_xmit{,_4gbug} and tg3_tx
+        * tx_lock: Held during tg3_start_xmit and tg3_tx
         *
-        * If you want to shut up all asynchronous processing you must
-        * acquire both locks, 'lock' taken before 'tx_lock'.  IRQs must
-        * be disabled to take 'lock' but only softirq disabling is
-        * necessary for acquisition of 'tx_lock'.
+        * Both of these locks are to be held with BH safety.
         */
        spinlock_t                      lock;
        spinlock_t                      indirect_lock;
index cf31c0629852732defbf52d5ae4537325d1fc7e4..942fae0f2130227794dfcd17d7ccfdeaee63d655 100644 (file)
 #include <linux/ioport.h>
 #include <linux/eisa.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
@@ -566,7 +567,7 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
 
                priv->adapter = &board_info[ent->driver_data];
 
-               rc = pci_set_dma_mask(pdev, 0xFFFFFFFF);
+               rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
                if (rc) {
                        printk(KERN_ERR "TLAN: No suitable PCI mapping available.\n");
                        goto err_out_free_dev;
index 0d1dcf421771f64970ce4b8746d4c5f4acc59f8d..41e0cd8f478670215bfa71792cecc00625500ee8 100644 (file)
@@ -276,7 +276,8 @@ static void  xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value)
        return ; 
 }
  
-int __devinit xl_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 
+static int __devinit xl_probe(struct pci_dev *pdev,
+                             const struct pci_device_id *ent) 
 {
        struct net_device *dev ; 
        struct xl_private *xl_priv ; 
index 81354afa3d34072c349913bf5c9a7d908932a383..0400c029c077d8c29e46cb67a92df4f5a7d175de 100644 (file)
@@ -22,7 +22,7 @@
 
 static int mc_size = 24880 ; 
 
-u8 microcode[] = { 
+static const u8 microcode[] = { 
  0xfe,0x3a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
index bd4a2bccf867f31cf9261d80e39853eff8df321d..87103c400999dea48045e60fc8fb62311c39294c 100644 (file)
@@ -468,14 +468,3 @@ static void __exit abyss_rmmod (void)
 module_init(abyss_init);
 module_exit(abyss_rmmod);
 
-\f
-/*
- * Local variables:
- *  compile-command: "gcc -DMODVERSIONS  -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c abyss.c"
- *  alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c abyss.c"
- *  c-set-style "K&R"
- *  c-indent-level: 8
- *  c-basic-offset: 8
- *  tab-width: 8
- * End:
- */
index 3873917a9c227e8cd3a8667b9ad134f767751161..e7b001017b9a18dd5184f95604f14b6cfb7b6773 100644 (file)
@@ -151,7 +151,7 @@ static char version[] __initdata =
 
 /* this allows displaying full adapter information */
 
-char *channel_def[] __devinitdata = { "ISA", "MCA", "ISA P&P" };
+static char *channel_def[] __devinitdata = { "ISA", "MCA", "ISA P&P" };
 
 static char pcchannelid[] __devinitdata = {
        0x05, 0x00, 0x04, 0x09,
@@ -171,7 +171,7 @@ static char mcchannelid[] __devinitdata =  {
        0x03, 0x08, 0x02, 0x00
 };
 
-char __devinit *adapter_def(char type)
+static char __devinit *adapter_def(char type)
 {
        switch (type) {
        case 0xF: return "PC Adapter | PC Adapter II | Adapter/A";
@@ -184,7 +184,7 @@ char __devinit *adapter_def(char type)
 
 #define TRC_INIT 0x01          /*  Trace initialization & PROBEs */
 #define TRC_INITV 0x02         /*  verbose init trace points     */
-unsigned char ibmtr_debug_trace = 0;
+static unsigned char ibmtr_debug_trace = 0;
 
 static int     ibmtr_probe(struct net_device *dev);
 static int     ibmtr_probe1(struct net_device *dev, int ioaddr);
@@ -192,20 +192,20 @@ static unsigned char get_sram_size(struct tok_info *adapt_info);
 static int     trdev_init(struct net_device *dev);
 static int     tok_open(struct net_device *dev);
 static int     tok_init_card(struct net_device *dev);
-void           tok_open_adapter(unsigned long dev_addr);
+static void    tok_open_adapter(unsigned long dev_addr);
 static void    open_sap(unsigned char type, struct net_device *dev);
 static void    tok_set_multicast_list(struct net_device *dev);
 static int     tok_send_packet(struct sk_buff *skb, struct net_device *dev);
 static int     tok_close(struct net_device *dev);
-irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void    initial_tok_int(struct net_device *dev);
 static void    tr_tx(struct net_device *dev);
 static void    tr_rx(struct net_device *dev);
-void           ibmtr_reset_timer(struct timer_list*tmr,struct net_device *dev);
+static void    ibmtr_reset_timer(struct timer_list*tmr,struct net_device *dev);
 static void    tok_rerun(unsigned long dev_addr);
-void           ibmtr_readlog(struct net_device *dev);
+static void    ibmtr_readlog(struct net_device *dev);
 static struct  net_device_stats *tok_get_stats(struct net_device *dev);
-int            ibmtr_change_mtu(struct net_device *dev, int mtu);
+static int     ibmtr_change_mtu(struct net_device *dev, int mtu);
 static void    find_turbo_adapters(int *iolist);
 
 static int ibmtr_portlist[IBMTR_MAX_ADAPTERS+1] __devinitdata = {
@@ -928,7 +928,7 @@ static int tok_open(struct net_device *dev)
 #define DLC_MAX_SAP_OFST        32
 #define DLC_MAX_STA_OFST        33
 
-void tok_open_adapter(unsigned long dev_addr)
+static void tok_open_adapter(unsigned long dev_addr)
 {
        struct net_device *dev = (struct net_device *) dev_addr;
        struct tok_info *ti;
@@ -1099,7 +1099,7 @@ static void __iomem *map_address(struct tok_info *ti, unsigned index, __u8 *page
        return ti->sram_virt + index;
 }
 
-void dir_open_adapter (struct net_device *dev)
+static void dir_open_adapter (struct net_device *dev)
 {
         struct tok_info *ti = (struct tok_info *) dev->priv;
         unsigned char ret_code;
@@ -1172,7 +1172,7 @@ void dir_open_adapter (struct net_device *dev)
 
 /******************************************************************************/
 
-irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        unsigned char status;
        /*  unsigned char status_even ; */
@@ -1840,7 +1840,7 @@ static void tr_rx(struct net_device *dev)
 
 /*****************************************************************************/
 
-void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev)
+static void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev)
 {
        tmr->expires = jiffies + TR_RETRY_INTERVAL;
        tmr->data = (unsigned long) dev;
@@ -1872,7 +1872,7 @@ void tok_rerun(unsigned long dev_addr){
 
 /*****************************************************************************/
 
-void ibmtr_readlog(struct net_device *dev)
+static void ibmtr_readlog(struct net_device *dev)
 {
        struct tok_info *ti;
 
@@ -1905,7 +1905,7 @@ static struct net_device_stats *tok_get_stats(struct net_device *dev)
 
 /*****************************************************************************/
 
-int ibmtr_change_mtu(struct net_device *dev, int mtu)
+static int ibmtr_change_mtu(struct net_device *dev, int mtu)
 {
        struct tok_info *ti = (struct tok_info *) dev->priv;
 
index 99e0b03b69a81b318d78251f74cb18c13abea0f9..97712c3c4e07f4ccfa34b18377e065f781e5726d 100644 (file)
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/spinlock.h>
 #include <linux/version.h>
 #include <linux/bitops.h>
@@ -257,7 +258,7 @@ static int __devinit streamer_init_one(struct pci_dev *pdev,
 #endif
 #endif
 
-       rc = pci_set_dma_mask(pdev, 0xFFFFFFFFULL);
+       rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
        if (rc) {
                printk(KERN_ERR "%s: No suitable PCI mapping available.\n",
                                dev->name);
@@ -454,8 +455,7 @@ static int streamer_reset(struct net_device *dev)
        writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL);
        t = jiffies;
        /* Hold soft reset bit for a while */
-       current->state = TASK_UNINTERRUPTIBLE;
-       schedule_timeout(HZ);
+       ssleep(1);
        
        writew(readw(streamer_mmio + BCTL) & ~BCTL_SOFTRESET,
               streamer_mmio + BCTL);
@@ -511,8 +511,7 @@ static int streamer_reset(struct net_device *dev)
        writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
 
        while (!((readw(streamer_mmio + SISR)) & SISR_SRB_REPLY)) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(HZ/10);
+               msleep_interruptible(100);
                if (jiffies - t > 40 * HZ) {
                        printk(KERN_ERR
                               "IBM PCI tokenring card not responding\n");
index cfae2bbf2167a333b5ca548fd7c0153cfca46c16..659cbdbef7f380e4299f44a6cd157bca53cc6eb6 100644 (file)
@@ -625,7 +625,7 @@ static int madgemc_chipset_init(struct net_device *dev)
 /*
  * Disable the board, and put back into power-up state.
  */
-void madgemc_chipset_close(struct net_device *dev)
+static void madgemc_chipset_close(struct net_device *dev)
 {
        /* disable interrupts */
        madgemc_setint(dev, 0);
@@ -786,15 +786,3 @@ module_exit(madgemc_exit);
 
 MODULE_LICENSE("GPL");
 
-\f
-/*
- * Local variables:
- *  compile-command: "gcc -DMODVERSIONS  -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c madgemc.c"
- *  alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c madgemc.c"
- *  c-set-style "K&R"
- *  c-indent-level: 8
- *  c-basic-offset: 8
- *  tab-width: 8
- * End:
- */
-
index 675b063508e37a8b66117594b4c50c3f66cfbadd..40ad0fde28afc071fdf48562350d6c04a9fd1e35 100644 (file)
@@ -419,14 +419,3 @@ void cleanup_module(void)
 }
 #endif /* MODULE */
 
-\f
-/*
- * Local variables:
- *  compile-command: "gcc -DMODVERSIONS  -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c proteon.c"
- *  alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c proteon.c"
- *  c-set-style "K&R"
- *  c-indent-level: 8
- *  c-basic-offset: 8
- *  tab-width: 8
- * End:
- */
index 3fab54a264666572a76c96f5c86a8baed22baa6e..f26796e2d0e5f4cb0ee2a4a74872779d7d625fca 100644 (file)
@@ -429,14 +429,3 @@ void cleanup_module(void)
 }
 #endif /* MODULE */
 
-\f
-/*
- * Local variables:
- *  compile-command: "gcc -DMODVERSIONS  -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c skisa.c"
- *  alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c skisa.c"
- *  c-set-style "K&R"
- *  c-indent-level: 8
- *  c-basic-offset: 8
- *  tab-width: 8
- * End:
- */
index 5c8aeacb831863ec40b68648d47c2e8d1ff3c2e8..67d2b596ce22ec7df5757cc83772688e42afb668 100644 (file)
@@ -77,7 +77,7 @@ static int ringspeed;
 
 /* SMC Name of the Adapter. */
 static char smctr_name[] = "SMC TokenCard";
-char *smctr_model = "Unknown";
+static char *smctr_model = "Unknown";
 
 /* Use 0 for production, 1 for verification, 2 for debug, and
  * 3 for very verbose debug.
index 53f2cbc817c9d4d37bd23b946507013250a4d954..48994b043b7cf0e06e29b2f4424257edfae107b5 100644 (file)
@@ -21,7 +21,7 @@
 
 #if defined(CONFIG_SMCTR) || defined(CONFIG_SMCTR_MODULE)
 
-unsigned char smctr_code[] = {
+static const unsigned char smctr_code[] = {
        0x0BC, 0x01D, 0x012, 0x03B, 0x063, 0x0B4, 0x0E9, 0x000,
        0x000, 0x01F, 0x000, 0x001, 0x001, 0x000, 0x002, 0x005,
        0x001, 0x000, 0x006, 0x003, 0x001, 0x000, 0x004, 0x009,
index df43b449e42924870cfbf97605b3ab72aa1ae900..5e0b0ce98ed7fbe44383c604171bfeaa30b1d6d9 100644 (file)
@@ -2379,7 +2379,7 @@ EXPORT_SYMBOL(tmsdev_init);
 EXPORT_SYMBOL(tmsdev_term);
 EXPORT_SYMBOL(tms380tr_wait);
 
-struct module *TMS380_module = NULL;
+static struct module *TMS380_module = NULL;
 
 int init_module(void)
 {
@@ -2397,14 +2397,3 @@ void cleanup_module(void)
 
 MODULE_LICENSE("GPL");
 
-\f
-/*
- * Local variables:
- *  compile-command: "gcc -DMODVERSIONS  -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tms380tr.c"
- *  alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tms380tr.c"
- *  c-set-style "K&R"
- *  c-indent-level: 8
- *  c-basic-offset: 8
- *  tab-width: 8
- * End:
- */
index 37ddb5c2bec3352edbf09e01b2a255a6d4c6f98b..2e18c0a464828f60960b30c48b1d8873cb28b513 100644 (file)
@@ -254,14 +254,3 @@ static void __exit tms_pci_rmmod (void)
 module_init(tms_pci_init);
 module_exit(tms_pci_rmmod);
 
-\f
-/*
- * Local variables:
- *  compile-command: "gcc -DMODVERSIONS  -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tmspci.c"
- *  alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tmspci.c"
- *  c-set-style "K&R"
- *  c-indent-level: 8
- *  c-basic-offset: 8
- *  tab-width: 8
- * End:
- */
index dd357dd8c370282f6533fec7417b89b5f9a9f390..fc353e348f9aeaab909b216d8301706d014178af 100644 (file)
@@ -446,13 +446,13 @@ static void de_rx (struct de_private *de)
 
                        mapping =
                        de->rx_skb[rx_tail].mapping =
-                               pci_map_single(de->pdev, copy_skb->tail,
+                               pci_map_single(de->pdev, copy_skb->data,
                                               buflen, PCI_DMA_FROMDEVICE);
                        de->rx_skb[rx_tail].skb = copy_skb;
                } else {
                        pci_dma_sync_single_for_cpu(de->pdev, mapping, len, PCI_DMA_FROMDEVICE);
                        skb_reserve(copy_skb, RX_OFFSET);
-                       memcpy(skb_put(copy_skb, len), skb->tail, len);
+                       memcpy(skb_put(copy_skb, len), skb->data, len);
 
                        pci_dma_sync_single_for_device(de->pdev, mapping, len, PCI_DMA_FROMDEVICE);
 
@@ -1269,7 +1269,7 @@ static int de_refill_rx (struct de_private *de)
                skb->dev = de->dev;
 
                de->rx_skb[i].mapping = pci_map_single(de->pdev,
-                       skb->tail, de->rx_buf_sz, PCI_DMA_FROMDEVICE);
+                       skb->data, de->rx_buf_sz, PCI_DMA_FROMDEVICE);
                de->rx_skb[i].skb = skb;
 
                de->rx_ring[i].opts1 = cpu_to_le32(DescOwn);
index e25f33df223ea48e4ca4a9a71a3859c36c5f17d9..74e9075d9c48edee4d5c908849025d8dfe2cb169 100644 (file)
@@ -78,6 +78,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -354,7 +355,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
        SET_MODULE_OWNER(dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
 
-       if (pci_set_dma_mask(pdev, 0xffffffff)) {
+       if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
                printk(KERN_WARNING DRV_NAME ": 32-bit PCI DMA not available.\n");
                err = -ENODEV;
                goto err_out_free;
@@ -743,11 +744,6 @@ static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        DMFE_DBUG(0, "dmfe_interrupt()", 0);
 
-       if (!dev) {
-               DMFE_DBUG(1, "dmfe_interrupt() without DEVICE arg", 0);
-               return IRQ_NONE;
-       }
-
        spin_lock_irqsave(&db->lock, flags);
 
        /* Got DM910X status */
@@ -949,8 +945,8 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
 
                                /* Received Packet CRC check need or not */
                                if ( (db->dm910x_chk_mode & 1) &&
-                                       (cal_CRC(skb->tail, rxlen, 1) !=
-                                       (*(u32 *) (skb->tail+rxlen) ))) { /* FIXME (?) */
+                                       (cal_CRC(skb->data, rxlen, 1) !=
+                                       (*(u32 *) (skb->data+rxlen) ))) { /* FIXME (?) */
                                        /* Found a error received packet */
                                        dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
                                        db->dm910x_chk_mode = 3;
@@ -963,7 +959,7 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
                                                /* size less than COPY_SIZE, allocate a rxlen SKB */
                                                skb->dev = dev;
                                                skb_reserve(skb, 2); /* 16byte align */
-                                               memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->tail, rxlen);
+                                               memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->data, rxlen);
                                                dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
                                        } else {
                                                skb->dev = dev;
@@ -1256,7 +1252,7 @@ static void dmfe_reuse_skb(struct dmfe_board_info *db, struct sk_buff * skb)
 
        if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) {
                rxptr->rx_skb_ptr = skb;
-               rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
+               rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->data, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
                wmb();
                rxptr->rdes0 = cpu_to_le32(0x80000000);
                db->rx_avail_cnt++;
@@ -1467,7 +1463,7 @@ static void allocate_rx_buffer(struct dmfe_board_info *db)
                if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL )
                        break;
                rxptr->rx_skb_ptr = skb; /* FIXME (?) */
-               rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
+               rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->data, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
                wmb();
                rxptr->rdes0 = cpu_to_le32(0x80000000);
                rxptr = rxptr->next_rx_desc;
@@ -1806,7 +1802,7 @@ static void dmfe_parse_srom(struct dmfe_board_info * db)
        if ( ( (int) srom[18] & 0xff) == SROM_V41_CODE) {
                /* SROM V4.01 */
                /* Get NIC support media mode */
-               db->NIC_capability = le16_to_cpup(srom + 34);
+               db->NIC_capability = le16_to_cpup((__le16 *)srom + 34/2);
                db->PHY_reg4 = 0;
                for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) {
                        switch( db->NIC_capability & tmp_reg ) {
@@ -1818,7 +1814,8 @@ static void dmfe_parse_srom(struct dmfe_board_info * db)
                }
 
                /* Media Mode Force or not check */
-               dmfe_mode = le32_to_cpup(srom + 34) & le32_to_cpup(srom + 36);
+               dmfe_mode = le32_to_cpup((__le32 *)srom + 34/4) &
+                               le32_to_cpup((__le32 *)srom + 36/4);
                switch(dmfe_mode) {
                case 0x4: dmfe_media_mode = DMFE_100MHF; break; /* 100MHF */
                case 0x2: dmfe_media_mode = DMFE_10MFD; break;  /* 10MFD */
index ac5bf49ff60f6bcd77a385f3755fb4da16527766..fbd9ab60b0525a2402c464ee40036bfee511fbb0 100644 (file)
@@ -63,6 +63,22 @@ static struct eeprom_fixup eeprom_fixups[] __devinitdata = {
         */
        { 0x1e00, 0x0000, 0x000b, 0x8f01, 0x0103, 0x0300, 0x0821, 0x000, 0x0001, 0x0000, 0x01e1 }
   },
+  {"Cobalt Microserver", 0, 0x10, 0xE0, {0x1e00, /* 0 == controller #, 1e == offset    */
+                                        0x0000, /* 0 == high offset, 0 == gap          */
+                                        0x0800, /* Default Autoselect                  */
+                                        0x8001, /* 1 leaf, extended type, bogus len    */
+                                        0x0003, /* Type 3 (MII), PHY #0                */
+                                        0x0400, /* 0 init instr, 4 reset instr         */
+                                        0x0801, /* Set control mode, GP0 output        */
+                                        0x0000, /* Drive GP0 Low (RST is active low)   */
+                                        0x0800, /* control mode, GP0 input (undriven)  */
+                                        0x0000, /* clear control mode                  */
+                                        0x7800, /* 100TX FDX + HDX, 10bT FDX + HDX     */
+                                        0x01e0, /* Advertise all above                 */
+                                        0x5000, /* FDX all above                       */
+                                        0x1800, /* Set fast TTM in 100bt modes         */
+                                        0x0000, /* PHY cannot be unplugged             */
+  }},
   {NULL}};
 
 
index afb5cda9d8e1e32ed17424bfa0749f492470712f..bb3558164a5b09b8155eb2f2c04e20742187ff9a 100644 (file)
@@ -78,7 +78,7 @@ int tulip_refill_rx(struct net_device *dev)
                        if (skb == NULL)
                                break;
 
-                       mapping = pci_map_single(tp->pdev, skb->tail, PKT_BUF_SZ,
+                       mapping = pci_map_single(tp->pdev, skb->data, PKT_BUF_SZ,
                                                 PCI_DMA_FROMDEVICE);
                        tp->rx_buffers[entry].mapping = mapping;
 
@@ -199,12 +199,12 @@ int tulip_poll(struct net_device *dev, int *budget)
                                                                   tp->rx_buffers[entry].mapping,
                                                                   pkt_len, PCI_DMA_FROMDEVICE);
 #if ! defined(__alpha__)
-                                       eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail,
+                                       eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->data,
                                                         pkt_len, 0);
                                        skb_put(skb, pkt_len);
 #else
                                        memcpy(skb_put(skb, pkt_len),
-                                              tp->rx_buffers[entry].skb->tail,
+                                              tp->rx_buffers[entry].skb->data,
                                               pkt_len);
 #endif
                                        pci_dma_sync_single_for_device(tp->pdev,
@@ -423,12 +423,12 @@ static int tulip_rx(struct net_device *dev)
                                                            tp->rx_buffers[entry].mapping,
                                                            pkt_len, PCI_DMA_FROMDEVICE);
 #if ! defined(__alpha__)
-                               eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail,
+                               eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->data,
                                                 pkt_len, 0);
                                skb_put(skb, pkt_len);
 #else
                                memcpy(skb_put(skb, pkt_len),
-                                      tp->rx_buffers[entry].skb->tail,
+                                      tp->rx_buffers[entry].skb->data,
                                       pkt_len);
 #endif
                                pci_dma_sync_single_for_device(tp->pdev,
index 919c40cd635cbb9a0286f0486e706a0c5e1aeb16..e26c31f944bf1622f8eb77933ac6623de6056cfe 100644 (file)
@@ -400,6 +400,9 @@ void tulip_select_media(struct net_device *dev, int startup)
        }
 
        tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
+
+       mdelay(1);
+
        return;
 }
 
index e0ae3ed6e5785832794a8cb32dec13d1d592f5cc..d45d8f56e5b4a3df298aa6ae3b42b602db2f5b55 100644 (file)
@@ -242,6 +242,7 @@ static struct pci_device_id tulip_pci_tbl[] = {
        { 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X },      /* ALi 1563 integrated ethernet */
        { 0x10b9, 0x5263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X },      /* ALi 1563 integrated ethernet */
        { 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* 3Com 3CSOHO100B-TX */
+       { 0x14ea, 0xab08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* Planex FNW-3602-TX */
        { } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
@@ -624,7 +625,7 @@ static void tulip_init_ring(struct net_device *dev)
                tp->rx_buffers[i].skb = skb;
                if (skb == NULL)
                        break;
-               mapping = pci_map_single(tp->pdev, skb->tail,
+               mapping = pci_map_single(tp->pdev, skb->data,
                                         PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
                tp->rx_buffers[i].mapping = mapping;
                skb->dev = dev;                 /* Mark as being used by this device. */
@@ -1514,8 +1515,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
                     (PCI_SLOT(pdev->devfn) == 12))) {
                        /* Cobalt MAC address in first EEPROM locations. */
                        sa_offset = 0;
-                       /* No media table either */
-                       tp->flags &= ~HAS_MEDIA_TABLE;
+                      /* Ensure our media table fixup get's applied */
+                      memcpy(ee_data + 16, ee_data, 8);
                }
 #endif
 #ifdef CONFIG_GSC
@@ -1756,11 +1757,19 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
 
-       if (dev && netif_running (dev) && netif_device_present (dev)) {
-               netif_device_detach (dev);
-               tulip_down (dev);
-               /* pci_power_off(pdev, -1); */
-       }
+       if (!dev)
+               return -EINVAL;
+
+       if (netif_running(dev))
+               tulip_down(dev);
+
+       netif_device_detach(dev);
+       free_irq(dev->irq, dev);
+
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
        return 0;
 }
 
@@ -1768,15 +1777,26 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
 static int tulip_resume(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
+       int retval;
 
-       if (dev && netif_running (dev) && !netif_device_present (dev)) {
-#if 1
-               pci_enable_device (pdev);
-#endif
-               /* pci_power_on(pdev); */
-               tulip_up (dev);
-               netif_device_attach (dev);
+       if (!dev)
+               return -EINVAL;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+
+       pci_enable_device(pdev);
+
+       if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))) {
+               printk (KERN_ERR "tulip: request_irq failed in resume\n");
+               return retval;
        }
+
+       netif_device_attach(dev);
+
+       if (netif_running(dev))
+               tulip_up(dev);
+
        return 0;
 }
 
index caff2f5901657a1533b7e83e177d43bae2cccc51..5b1af3986abf533eae23e5384287bc9c1804b7e0 100644 (file)
@@ -121,6 +121,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
@@ -394,7 +395,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
 
        irq = pdev->irq;
 
-       if (pci_set_dma_mask(pdev,0xFFFFffff)) {
+       if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
                printk(KERN_WARNING "Winbond-840: Device %s disabled due to DMA limitations.\n",
                       pci_name(pdev));
                return -EIO;
@@ -848,7 +849,7 @@ static void init_rxtx_rings(struct net_device *dev)
                if (skb == NULL)
                        break;
                skb->dev = dev;                 /* Mark as being used by this device. */
-               np->rx_addr[i] = pci_map_single(np->pci_dev,skb->tail,
+               np->rx_addr[i] = pci_map_single(np->pci_dev,skb->data,
                                        skb->len,PCI_DMA_FROMDEVICE);
 
                np->rx_ring[i].buffer1 = np->rx_addr[i];
@@ -1268,7 +1269,7 @@ static int netdev_rx(struct net_device *dev)
                                pci_dma_sync_single_for_cpu(np->pci_dev,np->rx_addr[entry],
                                                            np->rx_skbuff[entry]->len,
                                                            PCI_DMA_FROMDEVICE);
-                               eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
+                               eth_copy_and_sum(skb, np->rx_skbuff[entry]->data, pkt_len, 0);
                                skb_put(skb, pkt_len);
                                pci_dma_sync_single_for_device(np->pci_dev,np->rx_addr[entry],
                                                               np->rx_skbuff[entry]->len,
@@ -1314,7 +1315,7 @@ static int netdev_rx(struct net_device *dev)
                                break;                  /* Better luck next round. */
                        skb->dev = dev;                 /* Mark as being used by this device. */
                        np->rx_addr[entry] = pci_map_single(np->pci_dev,
-                                                       skb->tail,
+                                                       skb->data,
                                                        skb->len, PCI_DMA_FROMDEVICE);
                        np->rx_ring[entry].buffer1 = np->rx_addr[entry];
                }
index b8a9b395c5ea17a5b842646e64f89e5e9faf78b2..887d7245fe7b436231eee334d6aefc1f7de969c6 100644 (file)
@@ -899,7 +899,7 @@ static void xircom_init_ring(struct net_device *dev)
                        break;
                skb->dev = dev;                 /* Mark as being used by this device. */
                tp->rx_ring[i].status = Rx0DescOwned;   /* Owned by Xircom chip */
-               tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail);
+               tp->rx_ring[i].buffer1 = virt_to_bus(skb->data);
        }
        tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 
@@ -1291,7 +1291,7 @@ xircom_rx(struct net_device *dev)
                        if (skb == NULL)
                                break;
                        skb->dev = dev;                 /* Mark as being used by this device. */
-                       tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail);
+                       tp->rx_ring[entry].buffer1 = virt_to_bus(skb->data);
                        work_done++;
                }
                tp->rx_ring[entry].status = Rx0DescOwned;
index 8f3392989a06e83188a1323341d04ff3f4176bca..0b5ca25379634cc9e49f8ca63c3132151e7a531b 100644 (file)
@@ -1661,7 +1661,7 @@ typhoon_alloc_rx_skb(struct typhoon *tp, u32 idx)
 #endif
 
        skb->dev = tp->dev;
-       dma_addr = pci_map_single(tp->pdev, skb->tail,
+       dma_addr = pci_map_single(tp->pdev, skb->data,
                                  PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 
        /* Since no card does 64 bit DAC, the high bits will never
@@ -1721,7 +1721,7 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready,
                        pci_dma_sync_single_for_cpu(tp->pdev, dma_addr,
                                                    PKT_BUF_SZ,
                                                    PCI_DMA_FROMDEVICE);
-                       eth_copy_and_sum(new_skb, skb->tail, pkt_len, 0);
+                       eth_copy_and_sum(new_skb, skb->data, pkt_len, 0);
                        pci_dma_sync_single_for_device(tp->pdev, dma_addr,
                                                       PKT_BUF_SZ,
                                                       PCI_DMA_FROMDEVICE);
index 7b57d552094a4270d653595c5de2ac75f5e05192..fc7738ffbfffeb1ffd17c7724426169b65531372 100644 (file)
@@ -186,6 +186,7 @@ static const int multicast_filter_limit = 32;
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
@@ -506,7 +507,7 @@ static struct net_device_stats *rhine_get_stats(struct net_device *dev);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static struct ethtool_ops netdev_ethtool_ops;
 static int  rhine_close(struct net_device *dev);
-static void rhine_shutdown (struct device *gdev);
+static void rhine_shutdown (struct pci_dev *pdev);
 
 #define RHINE_WAIT_FOR(condition) do {                                 \
        int i=1024;                                                     \
@@ -740,7 +741,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
                goto err_out;
 
        /* this should always be supported */
-       rc = pci_set_dma_mask(pdev, 0xffffffff);
+       rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
        if (rc) {
                printk(KERN_ERR "32-bit PCI DMA addresses not supported by "
                       "the card!?\n");
@@ -989,7 +990,7 @@ static void alloc_rbufs(struct net_device *dev)
                skb->dev = dev;                 /* Mark as being used by this device. */
 
                rp->rx_skbuff_dma[i] =
-                       pci_map_single(rp->pdev, skb->tail, rp->rx_buf_sz,
+                       pci_map_single(rp->pdev, skb->data, rp->rx_buf_sz,
                                       PCI_DMA_FROMDEVICE);
 
                rp->rx_ring[i].addr = cpu_to_le32(rp->rx_skbuff_dma[i]);
@@ -1397,7 +1398,7 @@ static void rhine_tx(struct net_device *dev)
        while (rp->dirty_tx != rp->cur_tx) {
                txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status);
                if (debug > 6)
-                       printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n",
+                       printk(KERN_DEBUG "Tx scavenge %d status %8.8x.\n",
                               entry, txstatus);
                if (txstatus & DescOwn)
                        break;
@@ -1468,7 +1469,7 @@ static void rhine_rx(struct net_device *dev)
                int data_size = desc_status >> 16;
 
                if (debug > 4)
-                       printk(KERN_DEBUG " rhine_rx() status is %8.8x.\n",
+                       printk(KERN_DEBUG "rhine_rx() status is %8.8x.\n",
                               desc_status);
                if (--boguscnt < 0)
                        break;
@@ -1486,7 +1487,7 @@ static void rhine_rx(struct net_device *dev)
                        } else if (desc_status & RxErr) {
                                /* There was a error. */
                                if (debug > 2)
-                                       printk(KERN_DEBUG " rhine_rx() Rx "
+                                       printk(KERN_DEBUG "rhine_rx() Rx "
                                               "error was %8.8x.\n",
                                               desc_status);
                                rp->stats.rx_errors++;
@@ -1517,7 +1518,7 @@ static void rhine_rx(struct net_device *dev)
                                                            PCI_DMA_FROMDEVICE);
 
                                eth_copy_and_sum(skb,
-                                                rp->rx_skbuff[entry]->tail,
+                                                rp->rx_skbuff[entry]->data,
                                                 pkt_len, 0);
                                skb_put(skb, pkt_len);
                                pci_dma_sync_single_for_device(rp->pdev,
@@ -1560,7 +1561,7 @@ static void rhine_rx(struct net_device *dev)
                                break;  /* Better luck next round. */
                        skb->dev = dev; /* Mark as being used by this device. */
                        rp->rx_skbuff_dma[entry] =
-                               pci_map_single(rp->pdev, skb->tail,
+                               pci_map_single(rp->pdev, skb->data,
                                               rp->rx_buf_sz,
                                               PCI_DMA_FROMDEVICE);
                        rp->rx_ring[entry].addr = cpu_to_le32(rp->rx_skbuff_dma[entry]);
@@ -1894,9 +1895,8 @@ static void __devexit rhine_remove_one(struct pci_dev *pdev)
        pci_set_drvdata(pdev, NULL);
 }
 
-static void rhine_shutdown (struct device *gendev)
+static void rhine_shutdown (struct pci_dev *pdev)
 {
-       struct pci_dev *pdev = to_pci_dev(gendev);
        struct net_device *dev = pci_get_drvdata(pdev);
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
@@ -1955,7 +1955,7 @@ static int rhine_suspend(struct pci_dev *pdev, pm_message_t state)
        pci_save_state(pdev);
 
        spin_lock_irqsave(&rp->lock, flags);
-       rhine_shutdown(&pdev->dev);
+       rhine_shutdown(pdev);
        spin_unlock_irqrestore(&rp->lock, flags);
 
        free_irq(dev->irq, dev);
@@ -2009,9 +2009,7 @@ static struct pci_driver rhine_driver = {
        .suspend        = rhine_suspend,
        .resume         = rhine_resume,
 #endif /* CONFIG_PM */
-       .driver = {
-               .shutdown = rhine_shutdown,
-       }
+       .shutdown =     rhine_shutdown,
 };
 
 
index 15e710283493fa672e3a408b36171675e77b81f4..abc5cee6eedc28d87f8d75e13b1ccb1b7268b074 100644 (file)
@@ -1335,7 +1335,7 @@ static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size,
                        if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN)
                                skb_reserve(new_skb, 2);
 
-                       memcpy(new_skb->data, rx_skb[0]->tail, pkt_size);
+                       memcpy(new_skb->data, rx_skb[0]->data, pkt_size);
                        *rx_skb = new_skb;
                        ret = 0;
                }
@@ -1456,9 +1456,9 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
         *      Do the gymnastics to get the buffer head for data at
         *      64byte alignment.
         */
-       skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->tail & 63);
+       skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63);
        rd_info->skb->dev = vptr->dev;
-       rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->tail, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE);
+       rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE);
        
        /*
         *      Fill in the descriptor to match
index 66b94668ddd8a69241d2535ce4726cc74f4d92f2..18c27e1e78840b7832eb4a0d069039843da95be0 100644 (file)
@@ -435,7 +435,7 @@ config VENDOR_SANGOMA
          the driver to support.
 
          If you have one or more of these cards, say M to this option;
-         and read <file:Documentation/networking/wanpipe.txt>.
+         and read <file:Documentation/networking/wan-router.txt>.
 
          To compile this driver as a module, choose M here: the
          module will be called wanpipe.
index 7575b799ce5368751c76323e61107d8766df2400..7217d44e885404ca310571dc246121ba0ab9d4b5 100644 (file)
@@ -981,6 +981,7 @@ fst_issue_cmd(struct fst_port_info *port, unsigned short cmd)
        /* Wait for any previous command to complete */
        while (mbval > NAK) {
                spin_unlock_irqrestore(&card->card_lock, flags);
+               set_current_state(TASK_UNINTERRUPTIBLE);
                schedule_timeout(1);
                spin_lock_irqsave(&card->card_lock, flags);
 
index c1b6896d70072d3ff12014883598ca69808fe862..87496843681a874d463b6aaa5ae56a73cb548ab6 100644 (file)
@@ -72,7 +72,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
        }
        skb_reserve(skb, 4);
        cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0);
-       data = (cisco_packet*)skb->tail;
+       data = (cisco_packet*)skb->data;
 
        data->type = htonl(type);
        data->par1 = htonl(par1);
index 1e7b47704ad9e15a3c64e47e7374c449bf9b7e79..9c1e10602f2b3ddbf1ae364021d27edab6323bad 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/netdevice.h>
 #include <linux/hdlc.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <asm/io.h>
 #include <asm/delay.h>
 
@@ -624,8 +625,8 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
        /* FIXME when PCI/DMA subsystems are fixed.
           We set both dma_mask and consistent_dma_mask back to 32 bits
           to indicate the card can do 32-bit DMA addressing */
-       if (pci_set_consistent_dma_mask(pdev, 0xFFFFFFFF) ||
-           pci_set_dma_mask(pdev, 0xFFFFFFFF)) {
+       if (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK) ||
+           pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
                printk(KERN_ERR "wanXL: No usable DMA configuration\n");
                wanxl_pci_remove_one(pdev);
                return -EIO;
index 1f05d9bd05e40b30b80bfaa7c33e4b1a68f6ae14..b03feae459fcf335db90ca08d7d8506b64c86779 100644 (file)
@@ -149,12 +149,7 @@ struct net_device * __init wd_probe(int unit)
        err = do_wd_probe(dev);
        if (err)
                goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
        return dev;
-out1:
-       cleanup_card(dev);
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -164,6 +159,7 @@ out:
 static int __init wd_probe1(struct net_device *dev, int ioaddr)
 {
        int i;
+       int err;
        int checksum = 0;
        int ancient = 0;                        /* An old card without config registers. */
        int word16 = 0;                         /* 0 = 8 bit, 1 = 16 bit */
@@ -356,7 +352,10 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
                outb(inb(ioaddr+4)|0x80, ioaddr+4);
 #endif
 
-       return 0;
+       err = register_netdev(dev);
+       if (err)
+               free_irq(dev->irq, dev);
+       return err;
 }
 
 static int
@@ -527,11 +526,8 @@ init_module(void)
                dev->mem_start = mem[this_dev];
                dev->mem_end = mem_end[this_dev];
                if (do_wd_probe(dev) == 0) {
-                       if (register_netdev(dev) == 0) {
-                               dev_wd[found++] = dev;
-                               continue;
-                       }
-                       cleanup_card(dev);
+                       dev_wd[found++] = dev;
+                       continue;
                }
                free_netdev(dev);
                printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]);
index fb10a2db63ad018623c2781be4da42db970cf434..c12648d8192b7dd7df2ffbbe7bbb68ccd87a30cb 100644 (file)
@@ -900,7 +900,7 @@ typedef struct aironet_ioctl {
        unsigned char __user *data;     // d-data
 } aironet_ioctl;
 
-static char *swversion = "2.1";
+static char swversion[] = "2.1";
 #endif /* CISCO_EXT */
 
 #define NUM_MODULES       2
@@ -1209,7 +1209,7 @@ struct airo_info {
        unsigned char           __iomem *pciaux;
        unsigned char           *shared;
        dma_addr_t              shared_dma;
-       int                     power;
+       pm_message_t            power;
        SsidRid                 *SSID;
        APListRid               *APList;
 #define        PCI_SHARED_LEN          2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
@@ -2918,7 +2918,7 @@ static int airo_thread(void *data) {
                        flush_signals(current);
 
                /* make swsusp happy with our thread */
-               try_to_freeze(PF_FREEZE);
+               try_to_freeze();
 
                if (test_bit(JOB_DIE, &ai->flags))
                        break;
@@ -5499,9 +5499,9 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        cmd.cmd=HOSTSLEEP;
        issuecommand(ai, &cmd, &rsp);
 
-       pci_enable_wake(pdev, state, 1);
+       pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
        pci_save_state(pdev);
-       return pci_set_power_state(pdev, state);
+       return pci_set_power_state(pdev, pci_choose_state(pdev, state));
 }
 
 static int airo_pci_resume(struct pci_dev *pdev)
@@ -5512,7 +5512,7 @@ static int airo_pci_resume(struct pci_dev *pdev)
 
        pci_set_power_state(pdev, 0);
        pci_restore_state(pdev);
-       pci_enable_wake(pdev, ai->power, 0);
+       pci_enable_wake(pdev, pci_choose_state(pdev, ai->power), 0);
 
        if (ai->power > 1) {
                reset_card(dev, 0);
@@ -5541,7 +5541,7 @@ static int airo_pci_resume(struct pci_dev *pdev)
        }
        writeConfigRid(ai, 0);
        enable_MAC(ai, &rsp, 0);
-       ai->power = 0;
+       ai->power = PMSG_ON;
        netif_device_attach(dev);
        netif_wake_queue(dev);
        enable_interrupts(ai);
index fbf53af6cda4c519f2d81b86cd57b44713d9ec0d..f10a9523034a650c9a43c9b2c330e89478db449d 100644 (file)
@@ -559,6 +559,15 @@ static int airo_event(event_t event, int priority,
        return 0;
 } /* airo_event */
 
+static struct pcmcia_device_id airo_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a),
+       PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0005),
+       PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0007),
+       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0007),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, airo_ids);
+
 static struct pcmcia_driver airo_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -566,6 +575,7 @@ static struct pcmcia_driver airo_driver = {
        },
        .attach         = airo_attach,
        .detach         = airo_detach,
+       .id_table       = airo_ids,
 };
 
 static int airo_cs_init(void)
index 4f304c6e693a79b0ab4c6de51c77da89d6620a04..0e1ac338cac1a7283e46d4b7145ce7864550edfc 100644 (file)
@@ -33,8 +33,6 @@ static int arlan_EEPROM_bad;
 
 #ifdef ARLAN_DEBUGGING
 
-static int arlan_entry_debug;
-static int arlan_exit_debug;
 static int testMemory = testMemoryUNKNOWN;
 static int irq = irqUNKNOWN;
 static int txScrambled = 1;
@@ -43,15 +41,13 @@ static int mdebug;
 module_param(irq, int, 0);
 module_param(mdebug, int, 0);
 module_param(testMemory, int, 0);
-module_param(arlan_entry_debug, int, 0);
-module_param(arlan_exit_debug, int, 0);
 module_param(txScrambled, int, 0);
 MODULE_PARM_DESC(irq, "(unused)");
 MODULE_PARM_DESC(testMemory, "(unused)");
 MODULE_PARM_DESC(mdebug, "Arlan multicast debugging (0-1)");
 #endif
 
-module_param(arlan_debug, int, 0);
+module_param_named(debug, arlan_debug, int, 0);
 module_param(spreadingCode, int, 0);
 module_param(channelNumber, int, 0);
 module_param(channelSet, int, 0);
@@ -63,17 +59,19 @@ module_param(keyStart, int, 0);
 module_param(tx_delay_ms, int, 0);
 module_param(retries, int, 0);
 module_param(tx_queue_len, int, 0);
-module_param(arlan_EEPROM_bad, int, 0);
-MODULE_PARM_DESC(arlan_debug, "Arlan debug enable (0-1)");
+module_param_named(EEPROM_bad, arlan_EEPROM_bad, int, 0);
+MODULE_PARM_DESC(debug, "Arlan debug enable (0-1)");
 MODULE_PARM_DESC(retries, "Arlan maximum packet retransmisions");
 #ifdef ARLAN_ENTRY_EXIT_DEBUGGING
-MODULE_PARM_DESC(arlan_entry_debug, "Arlan driver function entry debugging");
-MODULE_PARM_DESC(arlan_exit_debug, "Arlan driver function exit debugging");
-MODULE_PARM_DESC(arlan_entry_and_exit_debug, "Arlan driver function entry and exit debugging");
-#else
-MODULE_PARM_DESC(arlan_entry_debug, "(ignored)");
-MODULE_PARM_DESC(arlan_exit_debug, "(ignored)");
-MODULE_PARM_DESC(arlan_entry_and_exit_debug, "(ignored)");
+static int arlan_entry_debug;
+static int arlan_exit_debug;
+static int arlan_entry_and_exit_debug;
+module_param_named(entry_debug, arlan_entry_debug, int, 0);
+module_param_named(exit_debug, arlan_exit_debug, int, 0);
+module_param_named(entry_and_exit_debug, arlan_entry_and_exit_debug, int, 0);
+MODULE_PARM_DESC(entry_debug, "Arlan driver function entry debugging");
+MODULE_PARM_DESC(exit_debug, "Arlan driver function exit debugging");
+MODULE_PARM_DESC(entry_and_exit_debug, "Arlan driver function entry and exit debugging");
 #endif
 
 struct arlan_conf_stru arlan_conf[MAX_ARLANS];
index a4ed28d9c7837227774c1d629a3a638989a8ac07..86379d4998ac7930d47afe98b7288eb09f938ba8 100644 (file)
@@ -646,6 +646,27 @@ static int atmel_event(event_t event, int priority,
 } /* atmel_event */
 
 /*====================================================================*/
+static struct pcmcia_device_id atmel_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0620),
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0696),
+       PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3302),
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0007),
+       PCMCIA_DEVICE_PROD_ID12("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9),
+       PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f),
+       PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C504", 0xabda4164, 0x5040670a),
+       PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f),
+       PCMCIA_DEVICE_PROD_ID12("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5),
+       PCMCIA_DEVICE_PROD_ID12("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b),
+       PCMCIA_DEVICE_PROD_ID12("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6),
+       PCMCIA_DEVICE_PROD_ID12("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68),
+       PCMCIA_DEVICE_PROD_ID12("SMC", "2632W", 0xc4f8b18b, 0x30f38774),
+       PCMCIA_DEVICE_PROD_ID12("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377),
+       PCMCIA_DEVICE_PROD_ID12("Wireless", "PC", 0xa407ecdd, 0x556e4d7e),
+       PCMCIA_DEVICE_PROD_ID12("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, atmel_ids);
+
 static struct pcmcia_driver atmel_driver = {
         .owner          = THIS_MODULE,
         .drv            = {
@@ -653,6 +674,7 @@ static struct pcmcia_driver atmel_driver = {
         },
         .attach         = atmel_attach,
         .detach         = atmel_detach,
+       .id_table       = atmel_ids,
 };
 
 static int atmel_cs_init(void)
index 382241e7edbbc6e331bd82f70e4f8c6349ef11b1..e12bd75b269493de8fe19f800202ec42a0d96c1e 100644 (file)
@@ -1668,6 +1668,12 @@ static int netwave_close(struct net_device *dev) {
     return 0;
 }
 
+static struct pcmcia_device_id netwave_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("Xircom", "CreditCard Netwave", 0x2e3ee845, 0x54e28a28),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, netwave_ids);
+
 static struct pcmcia_driver netwave_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -1675,6 +1681,7 @@ static struct pcmcia_driver netwave_driver = {
        },
        .attach         = netwave_attach,
        .detach         = netwave_detach,
+       .id_table       = netwave_ids,
 };
 
 static int __init init_netwave_cs(void)
index b1078baa1d5e3851804b12509222407283b753d2..aabcdc2be05ea925fee9d685bbc4d38bcd8c5e0f 100644 (file)
  * under either the MPL or the GPL.  */
 
 /*
- * v0.01 -> v0.02 - 21/3/2001 - Jean II
- *     o Allow to use regular ethX device name instead of dldwdX
- *     o Warning on IBSS with ESSID=any for firmware 6.06
- *     o Put proper range.throughput values (optimistic)
- *     o IWSPY support (IOCTL and stat gather in Rx path)
- *     o Allow setting frequency in Ad-Hoc mode
- *     o Disable WEP setting if !has_wep to work on old firmware
- *     o Fix txpower range
- *     o Start adding support for Samsung/Compaq firmware
- *
- * v0.02 -> v0.03 - 23/3/2001 - Jean II
- *     o Start adding Symbol support - need to check all that
- *     o Fix Prism2/Symbol WEP to accept 128 bits keys
- *     o Add Symbol WEP (add authentication type)
- *     o Add Prism2/Symbol rate
- *     o Add PM timeout (holdover duration)
- *     o Enable "iwconfig eth0 key off" and friends (toggle flags)
- *     o Enable "iwconfig eth0 power unicast/all" (toggle flags)
- *     o Try with an Intel card. It report firmware 1.01, behave like
- *       an antiquated firmware, however on windows it says 2.00. Yuck !
- *     o Workaround firmware bug in allocate buffer (Intel 1.01)
- *     o Finish external renaming to orinoco...
- *     o Testing with various Wavelan firmwares
- *
- * v0.03 -> v0.04 - 30/3/2001 - Jean II
- *     o Update to Wireless 11 -> add retry limit/lifetime support
- *     o Tested with a D-Link DWL 650 card, fill in firmware support
- *     o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot)
- *     o Fixed the Prism2 WEP bugs that I introduced in v0.03 :-(
- *       It works on D-Link *only* after a tcpdump. Weird...
- *       And still doesn't work on Intel card. Grrrr...
- *     o Update the mode after a setport3
- *     o Add preamble setting for Symbol cards (not yet enabled)
- *     o Don't complain as much about Symbol cards...
- *
- * v0.04 -> v0.04b - 22/4/2001 - David Gibson
- *      o Removed the 'eth' parameter - always use ethXX as the
- *        interface name instead of dldwdXX.  The other was racy
- *        anyway.
- *     o Clean up RID definitions in hermes.h, other cleanups
- *
- * v0.04b -> v0.04c - 24/4/2001 - Jean II
- *     o Tim Hurley <timster AT seiki.bliztech.com> reported a D-Link card
- *       with vendor 02 and firmware 0.08. Added in the capabilities...
- *     o Tested Lucent firmware 7.28, everything works...
- *
- * v0.04c -> v0.05 - 3/5/2001 - Benjamin Herrenschmidt
- *     o Spin-off Pcmcia code. This file is renamed orinoco.c,
- *       and orinoco_cs.c now contains only the Pcmcia specific stuff
- *     o Add Airport driver support on top of orinoco.c (see airport.c)
- *
- * v0.05 -> v0.05a - 4/5/2001 - Jean II
- *     o Revert to old Pcmcia code to fix breakage of Ben's changes...
- *
- * v0.05a -> v0.05b - 4/5/2001 - Jean II
- *     o add module parameter 'ignore_cis_vcc' for D-Link @ 5V
- *     o D-Link firmware doesn't support multicast. We just print a few
- *       error messages, but otherwise everything works...
- *     o For David : set/getport3 works fine, just upgrade iwpriv...
- *
- * v0.05b -> v0.05c - 5/5/2001 - Benjamin Herrenschmidt
- *     o Adapt airport.c to latest changes in orinoco.c
- *     o Remove deferred power enabling code
- *
- * v0.05c -> v0.05d - 5/5/2001 - Jean II
- *     o Workaround to SNAP decapsulate frame from Linksys AP
- *       original patch from : Dong Liu <dliu AT research.bell-labs.com>
- *       (note : the memcmp bug was mine - fixed)
- *     o Remove set_retry stuff, no firmware support it (bloat--).
- *
- * v0.05d -> v0.06 - 25/5/2001 - Jean II
- *             Original patch from "Hong Lin" <alin AT redhat.com>,
- *             "Ian Kinner" <ikinner AT redhat.com>
- *             and "David Smith" <dsmith AT redhat.com>
- *     o Init of priv->tx_rate_ctrl in firmware specific section.
- *     o Prism2/Symbol rate, upto should be 0xF and not 0x15. Doh !
- *     o Spectrum card always need cor_reset (for every reset)
- *     o Fix cor_reset to not lose bit 7 in the register
- *     o flush_stale_links to remove zombie Pcmcia instances
- *     o Ack previous hermes event before reset
- *             Me (with my little hands)
- *     o Allow orinoco.c to call cor_reset via priv->card_reset_handler
- *     o Add priv->need_card_reset to toggle this feature
- *     o Fix various buglets when setting WEP in Symbol firmware
- *       Now, encryption is fully functional on Symbol cards. Youpi !
- *
- * v0.06 -> v0.06b - 25/5/2001 - Jean II
- *     o IBSS on Symbol use port_mode = 4. Please don't ask...
- *
- * v0.06b -> v0.06c - 29/5/2001 - Jean II
- *     o Show first spy address in /proc/net/wireless for IBSS mode as well
- *
- * v0.06c -> v0.06d - 6/7/2001 - David Gibson
- *      o Change a bunch of KERN_INFO messages to KERN_DEBUG, as per Linus'
- *        wishes to reduce the number of unnecessary messages.
- *     o Removed bogus message on CRC error.
- *     o Merged fixes for v0.08 Prism 2 firmware from William Waghorn
- *       <willwaghorn AT yahoo.co.uk>
- *     o Slight cleanup/re-arrangement of firmware detection code.
- *
- * v0.06d -> v0.06e - 1/8/2001 - David Gibson
- *     o Removed some redundant global initializers (orinoco_cs.c).
- *     o Added some module metadata
- *
- * v0.06e -> v0.06f - 14/8/2001 - David Gibson
- *     o Wording fix to license
- *     o Added a 'use_alternate_encaps' module parameter for APs which need an
- *       oui of 00:00:00.  We really need a better way of handling this, but
- *       the module flag is better than nothing for now.
- *
- * v0.06f -> v0.07 - 20/8/2001 - David Gibson
- *     o Removed BAP error retries from hermes_bap_seek().  For Tx we now
- *       let the upper layers handle the retry, we retry explicitly in the
- *       Rx path, but don't make as much noise about it.
- *     o Firmware detection cleanups.
- *
- * v0.07 -> v0.07a - 1/10/3001 - Jean II
- *     o Add code to read Symbol firmware revision, inspired by latest code
- *       in Spectrum24 by Lee John Keyser-Allen - Thanks Lee !
- *     o Thanks to Jared Valentine <hidden AT xmission.com> for "providing" me
- *       a 3Com card with a recent firmware, fill out Symbol firmware
- *       capabilities of latest rev (2.20), as well as older Symbol cards.
- *     o Disable Power Management in newer Symbol firmware, the API 
- *       has changed (documentation needed).
- *
- * v0.07a -> v0.08 - 3/10/2001 - David Gibson
- *     o Fixed a possible buffer overrun found by the Stanford checker (in
- *       dldwd_ioctl_setiwencode()).  Can only be called by root anyway, so not
- *       a big problem.
- *     o Turned has_big_wep on for Intersil cards.  That's not true for all of
- *       them but we should at least let the capable ones try.
- *     o Wait for BUSY to clear at the beginning of hermes_bap_seek().  I
- *       realized that my assumption that the driver's serialization
- *       would prevent the BAP being busy on entry was possibly false, because
- *       things other than seeks may make the BAP busy.
- *     o Use "alternate" (oui 00:00:00) encapsulation by default.
- *       Setting use_old_encaps will mimic the old behaviour, but I think we
- *       will be able to eliminate this.
- *     o Don't try to make __initdata const (the version string).  This can't
- *       work because of the way the __initdata sectioning works.
- *     o Added MODULE_LICENSE tags.
- *     o Support for PLX (transparent PCMCIA->PCI bridge) cards.
- *     o Changed to using the new type-fascist min/max.
- *
- * v0.08 -> v0.08a - 9/10/2001 - David Gibson
- *     o Inserted some missing acknowledgements/info into the Changelog.
- *     o Fixed some bugs in the normalization of signal level reporting.
- *     o Fixed bad bug in WEP key handling on Intersil and Symbol firmware,
- *       which led to an instant crash on big-endian machines.
- *
- * v0.08a -> v0.08b - 20/11/2001 - David Gibson
- *     o Lots of cleanup and bugfixes in orinoco_plx.c
- *     o Cleanup to handling of Tx rate setting.
- *     o Removed support for old encapsulation method.
- *     o Removed old "dldwd" names.
- *     o Split RID constants into a new file hermes_rid.h
- *     o Renamed RID constants to match linux-wlan-ng and prism2.o
- *     o Bugfixes in hermes.c
- *     o Poke the PLX's INTCSR register, so it actually starts
- *       generating interrupts.  These cards might actually work now.
- *     o Update to wireless extensions v12 (Jean II)
- *     o Support for tallies and inquire command (Jean II)
- *     o Airport updates for newer PPC kernels (BenH)
- *
- * v0.08b -> v0.09 - 21/12/2001 - David Gibson
- *     o Some new PCI IDs for PLX cards.
- *     o Removed broken attempt to do ALLMULTI reception.  Just use
- *       promiscuous mode instead
- *     o Preliminary work for list-AP (Jean II)
- *     o Airport updates from (BenH)
- *     o Eliminated racy hw_ready stuff
- *     o Fixed generation of fake events in irq handler.  This should
- *       finally kill the EIO problems (Jean II & dgibson)
- *     o Fixed breakage of bitrate set/get on Agere firmware (Jean II)
- *
- * v0.09 -> v0.09a - 2/1/2002 - David Gibson
- *     o Fixed stupid mistake in multicast list handling, triggering
- *       a BUG()
- *
- * v0.09a -> v0.09b - 16/1/2002 - David Gibson
- *     o Fixed even stupider mistake in new interrupt handling, which
- *       seriously broke things on big-endian machines.
- *     o Removed a bunch of redundant includes and exports.
- *     o Removed a redundant MOD_{INC,DEC}_USE_COUNT pair in airport.c
- *     o Don't attempt to do hardware level multicast reception on
- *       Intersil firmware, just go promisc instead.
- *     o Typo fixed in hermes_issue_cmd()
- *     o Eliminated WIRELESS_SPY #ifdefs
- *     o Status code reported on Tx exceptions
- *     o Moved netif_wake_queue() from ALLOC interrupts to TX and TXEXC
- *       interrupts, which should fix the timeouts we're seeing.
- *
- * v0.09b -> v0.10 - 25 Feb 2002 - David Gibson
- *     o Removed nested structures used for header parsing, so the
- *       driver should now work without hackery on ARM
- *     o Fix for WEP handling on Intersil (Hawk Newton)
- *     o Eliminated the /proc/hermes/ethXX/regs debugging file.  It
- *       was never very useful.
- *     o Make Rx errors less noisy.
- *
- * v0.10 -> v0.11 - 5 Apr 2002 - David Gibson
- *     o Laid the groundwork in hermes.[ch] for devices which map
- *       into PCI memory space rather than IO space.
- *     o Fixed bug in multicast handling (cleared multicast list when
- *       leaving promiscuous mode).
- *     o Relegated Tx error messages to debug.
- *     o Cleaned up / corrected handling of allocation lengths.
- *     o Set OWNSSID in IBSS mode for WinXP interoperability (jimc).
- *     o Change to using alloc_etherdev() for structure allocations. 
- *     o Check for and drop undersized packets.
- *     o Fixed a race in stopping/waking the queue.  This should fix
- *       the timeout problems (Pavel Roskin)
- *     o Reverted to netif_wake_queue() on the ALLOC event.
- *     o Fixes for recent Symbol firmwares which lack AP density
- *       (Pavel Roskin).
- *
- * v0.11 -> v0.11a - 29 Apr 2002 - David Gibson
- *     o Handle different register spacing, necessary for Prism 2.5
- *       PCI adaptors (Steve Hill).
- *     o Cleaned up initialization of card structures in orinoco_cs
- *       and airport.  Removed card->priv field.
- *     o Make response structure optional for hermes_docmd_wait()
- *       Pavel Roskin)
- *     o Added PCI id for Nortel emobility to orinoco_plx.c.
- *     o Cleanup to handling of Symbol's allocation bug. (Pavel Roskin)
- *     o Cleanups to firmware capability detection.
- *     o Arrange for orinoco_pci.c to override firmware detection.
- *       We should be able to support the PCI Intersil cards now.
- *     o Cleanup handling of reset_cor and hard_reset (Pavel Roskin).
- *     o Remove erroneous use of USER_BAP in the TxExc handler (Jouni
- *       Malinen).
- *     o Makefile changes for better integration into David Hinds
- *       pcmcia-cs package.
- *
- * v0.11a -> v0.11b - 1 May 2002 - David Gibson
- *     o Better error reporting in orinoco_plx_init_one()
- *     o Fixed multiple bad kfree() bugs introduced by the
- *       alloc_orinocodev() changes.
- *
- * v0.11b -> v0.12 - 19 Jun 2002 - David Gibson
- *     o Support changing the MAC address.
- *     o Correct display of Intersil firmware revision numbers.
- *     o Entirely revised locking scheme.  Should be both simpler and
- *        better.
- *     o Merged some common code in orinoco_plx, orinoco_pci and
- *       airport by creating orinoco_default_{open,stop,reset}()
- *       which are used as the dev->open, dev->stop, priv->reset
- *       callbacks if none are specified when alloc_orinocodev() is
- *       called.
- *     o Removed orinoco_plx_interrupt() and orinoco_pci_interrupt().
- *       They didn't do anything.
- *
- * v0.12 -> v0.12a - 4 Jul 2002 - David Gibson
- *     o Some rearrangement of code.
- *     o Numerous fixups to locking and rest handling, particularly
- *       for PCMCIA.
- *     o This allows open and stop net_device methods to be in
- *       orinoco.c now, rather than in the init modules.
- *     o In orinoco_cs.c link->priv now points to the struct
- *       net_device not to the struct orinoco_private.
- *     o Added a check for undersized SNAP frames, which could cause
- *       crashes.
- *
- * v0.12a -> v0.12b - 11 Jul 2002 - David Gibson
- *     o Fix hw->num_init testing code, so num_init is actually
- *       incremented.
- *     o Fix very stupid bug in orinoco_cs which broke compile with
- *       CONFIG_SMP.
- *     o Squashed a warning.
- *
- * v0.12b -> v0.12c - 26 Jul 2002 - David Gibson
- *     o Change to C9X style designated initializers.
- *     o Add support for 3Com AirConnect PCI.
- *     o No longer ignore the hard_reset argument to
- *       alloc_orinocodev().  Oops.
- *
- * v0.12c -> v0.13beta1 - 13 Sep 2002 - David Gibson
- *     o Revert the broken 0.12* locking scheme and go to a new yet
- *       simpler scheme.
- *     o Do firmware resets only in orinoco_init() and when waking
- *       the card from hard sleep.
- *
- * v0.13beta1 -> v0.13 - 27 Sep 2002 - David Gibson
- *     o Re-introduced full resets (via schedule_task()) on Tx
- *       timeout.
- *
- * v0.13 -> v0.13a - 30 Sep 2002 - David Gibson
- *     o Minor cleanups to info frame handling.  Add basic support
- *       for linkstatus info frames.
- *     o Include required kernel headers in orinoco.h, to avoid
- *       compile problems.
- *
- * v0.13a -> v0.13b - 10 Feb 2003 - David Gibson
- *     o Implemented hard reset for Airport cards
- *     o Experimental suspend/resume implementation for orinoco_pci
- *     o Abolished /proc debugging support, replaced with a debugging
- *       iwpriv.  Now it's ugly and simple instead of ugly and complex.
- *     o Bugfix in hermes.c if the firmware returned a record length
- *       of 0, we could go clobbering memory.
- *     o Bugfix in orinoco_stop() - it used to fail if hw_unavailable
- *       was set, which was usually true on PCMCIA hot removes.
- *     o Track LINKSTATUS messages, silently drop Tx packets before
- *       we are connected (avoids confusing the firmware), and only
- *       give LINKSTATUS printk()s if the status has changed.
- *
- * v0.13b -> v0.13c - 11 Mar 2003 - David Gibson
- *     o Cleanup: use dev instead of priv in various places.
- *     o Bug fix: Don't ReleaseConfiguration on RESET_PHYSICAL event
- *       if we're in the middle of a (driver initiated) hard reset.
- *     o Bug fix: ETH_ZLEN is supposed to include the header
- *       (Dionysus Blazakis & Manish Karir)
- *     o Convert to using workqueues instead of taskqueues (and
- *       backwards compatibility macros for pre 2.5.41 kernels).
- *     o Drop redundant (I think...) MOD_{INC,DEC}_USE_COUNT in
- *       airport.c
- *     o New orinoco_tmd.c init module from Joerg Dorchain for
- *       TMD7160 based PCI to PCMCIA bridges (similar to
- *       orinoco_plx.c).
- *
- * v0.13c -> v0.13d - 22 Apr 2003 - David Gibson
- *     o Make hw_unavailable a counter, rather than just a flag, this
- *       is necessary to avoid some races (such as a card being
- *       removed in the middle of orinoco_reset().
- *     o Restore Release/RequestConfiguration in the PCMCIA event handler
- *       when dealing with a driver initiated hard reset.  This is
- *       necessary to prevent hangs due to a spurious interrupt while
- *       the reset is in progress.
- *     o Clear the 802.11 header when transmitting, even though we
- *       don't use it.  This fixes a long standing bug on some
- *       firmwares, which seem to get confused if that isn't done.
- *     o Be less eager to de-encapsulate SNAP frames, only do so if
- *       the OUI is 00:00:00 or 00:00:f8, leave others alone.  The old
- *       behaviour broke CDP (Cisco Discovery Protocol).
- *     o Use dev instead of priv for free_irq() as well as
- *       request_irq() (oops).
- *     o Attempt to reset rather than giving up if we get too many
- *       IRQs.
- *     o Changed semantics of __orinoco_down() so it can be called
- *       safely with hw_unavailable set.  It also now clears the
- *       linkstatus (since we're going to have to reassociate).
- *
- * v0.13d -> v0.13e - 12 May 2003 - David Gibson
- *     o Support for post-2.5.68 return values from irq handler.
- *     o Fixed bug where underlength packets would be double counted
- *       in the rx_dropped statistics.
- *     o Provided a module parameter to suppress linkstatus messages.
- *
- * v0.13e -> v0.14alpha1 - 30 Sep 2003 - David Gibson
- *     o Replaced priv->connected logic with netif_carrier_on/off()
- *       calls.
- *     o Remove has_ibss_any and never set the CREATEIBSS RID when
- *       the ESSID is empty.  Too many firmwares break if we do.
- *     o 2.6 merges: Replace pdev->slot_name with pci_name(), remove
- *       __devinitdata from PCI ID tables, use free_netdev().
- *     o Enabled shared-key authentication for Agere firmware (from
- *       Robert J. Moore <Robert.J.Moore AT allanbank.com>
- *     o Move netif_wake_queue() (back) to the Tx completion from the
- *       ALLOC event.  This seems to prevent/mitigate the rolling
- *       error -110 problems at least on some Intersil firmwares.
- *       Theoretically reduces performance, but I can't measure it.
- *       Patch from Andrew Tridgell <tridge AT samba.org>
- *
- * v0.14alpha1 -> v0.14alpha2 - 20 Oct 2003 - David Gibson
- *     o Correctly turn off shared-key authentication when requested
- *       (bugfix from Robert J. Moore).
- *     o Correct airport sleep interfaces for current 2.6 kernels.
- *     o Add code for key change without disabling/enabling the MAC
- *       port.  This is supposed to allow 802.1x to work sanely, but
- *       doesn't seem to yet.
- *
  * TODO
- *     o New wireless extensions API (patch from Moustafa
- *       Youssef, updated by Jim Carter and Pavel Roskin).
  *     o Handle de-encapsulation within network layer, provide 802.11
  *       headers (patch from Thomas 'Dent' Mirlacher)
- *     o RF monitor mode support
  *     o Fix possible races in SPY handling.
  *     o Disconnect wireless extensions from fundamental configuration.
  *     o (maybe) Software WEP support (patch from Stano Meduna).
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
+#include <linux/ethtool.h>
 #include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -496,6 +126,10 @@ static int ignore_disconnect; /* = 0 */
 module_param(ignore_disconnect, int, 0644);
 MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer");
 
+static int force_monitor; /* = 0 */
+module_param(force_monitor, int, 0644);
+MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
+
 /********************************************************************/
 /* Compile time configuration and compatibility stuff               */
 /********************************************************************/
@@ -511,6 +145,10 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
 /* Internal constants                                               */
 /********************************************************************/
 
+/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
+static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+#define ENCAPS_OVERHEAD                (sizeof(encaps_hdr) + 2)
+
 #define ORINOCO_MIN_MTU                256
 #define ORINOCO_MAX_MTU                (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
 
@@ -537,6 +175,11 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
                                 | HERMES_EV_WTERR | HERMES_EV_INFO \
                                 | HERMES_EV_INFDROP )
 
+#define MAX_RID_LEN 1024
+
+static const struct iw_handler_def orinoco_handler_def;
+static struct ethtool_ops orinoco_ethtool_ops;
+
 /********************************************************************/
 /* Data tables                                                      */
 /********************************************************************/
@@ -571,26 +214,45 @@ static struct {
 /* Data types                                                       */
 /********************************************************************/
 
-struct header_struct {
-       /* 802.3 */
-       u8 dest[ETH_ALEN];
-       u8 src[ETH_ALEN];
-       u16 len;
-       /* 802.2 */
+/* Used in Event handling.
+ * We avoid nested structres as they break on ARM -- Moustafa */
+struct hermes_tx_descriptor_802_11 {
+       /* hermes_tx_descriptor */
+       u16 status;
+       u16 reserved1;
+       u16 reserved2;
+       u32 sw_support;
+       u8 retry_count;
+       u8 tx_rate;
+       u16 tx_control;
+
+       /* ieee802_11_hdr */
+       u16 frame_ctl;
+       u16 duration_id;
+       u8 addr1[ETH_ALEN];
+       u8 addr2[ETH_ALEN];
+       u8 addr3[ETH_ALEN];
+       u16 seq_ctl;
+       u8 addr4[ETH_ALEN];
+       u16 data_len;
+
+       /* ethhdr */
+       unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
+       unsigned char   h_source[ETH_ALEN];     /* source ether addr    */
+       unsigned short  h_proto;                /* packet type ID field */
+
+       /* p8022_hdr */
        u8 dsap;
        u8 ssap;
        u8 ctrl;
-       /* SNAP */
        u8 oui[3];
+
        u16 ethertype;
 } __attribute__ ((packed));
 
-/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
-u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
-
-#define ENCAPS_OVERHEAD                (sizeof(encaps_hdr) + 2)
-
+/* Rx frame header except compatibility 802.3 header */
 struct hermes_rx_descriptor {
+       /* Control */
        u16 status;
        u32 time;
        u8 silence;
@@ -598,13 +260,24 @@ struct hermes_rx_descriptor {
        u8 rate;
        u8 rxflow;
        u32 reserved;
+
+       /* 802.11 header */
+       u16 frame_ctl;
+       u16 duration_id;
+       u8 addr1[ETH_ALEN];
+       u8 addr2[ETH_ALEN];
+       u8 addr3[ETH_ALEN];
+       u16 seq_ctl;
+       u8 addr4[ETH_ALEN];
+
+       /* Data length */
+       u16 data_len;
 } __attribute__ ((packed));
 
 /********************************************************************/
 /* Function prototypes                                              */
 /********************************************************************/
 
-static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int __orinoco_program_rids(struct net_device *dev);
 static void __orinoco_set_multicast_list(struct net_device *dev);
 
@@ -628,6 +301,10 @@ static inline void set_port_type(struct orinoco_private *priv)
                        priv->createibss = 1;
                }
                break;
+       case IW_MODE_MONITOR:
+               priv->port_type = 3;
+               priv->createibss = 0;
+               break;
        default:
                printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
                       priv->ndev->name);
@@ -814,7 +491,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                return 1;
        }
 
-       if (! netif_carrier_ok(dev)) {
+       if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
                /* Oops, the firmware hasn't established a connection,
                    silently drop the packet (this seems to be the
                    safest approach). */
@@ -951,26 +628,55 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
        struct orinoco_private *priv = netdev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        u16 fid = hermes_read_regn(hw, TXCOMPLFID);
-       struct hermes_tx_descriptor desc;
+       struct hermes_tx_descriptor_802_11 hdr;
        int err = 0;
 
        if (fid == DUMMY_FID)
                return; /* Nothing's really happened */
 
-       err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0);
+       /* Read the frame header */
+       err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
+                              sizeof(struct hermes_tx_descriptor) +
+                              sizeof(struct ieee80211_hdr),
+                              fid, 0);
+
+       hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
+       stats->tx_errors++;
+
        if (err) {
                printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
                       "(FID=%04X error %d)\n",
                       dev->name, fid, err);
-       } else {
-               DEBUG(1, "%s: Tx error, status %d\n",
-                     dev->name, le16_to_cpu(desc.status));
+               return;
        }
        
-       stats->tx_errors++;
+       DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
+             err, fid);
+    
+       /* We produce a TXDROP event only for retry or lifetime
+        * exceeded, because that's the only status that really mean
+        * that this particular node went away.
+        * Other errors means that *we* screwed up. - Jean II */
+       hdr.status = le16_to_cpu(hdr.status);
+       if (hdr.status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
+               union iwreq_data        wrqu;
+
+               /* Copy 802.11 dest address.
+                * We use the 802.11 header because the frame may
+                * not be 802.3 or may be mangled...
+                * In Ad-Hoc mode, it will be the node address.
+                * In managed mode, it will be most likely the AP addr
+                * User space will figure out how to convert it to
+                * whatever it needs (IP address or else).
+                * - Jean II */
+               memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
+               wrqu.addr.sa_family = ARPHRD_ETHER;
+
+               /* Send event to user space */
+               wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
+       }
 
        netif_wake_queue(dev);
-       hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
 }
 
 static void orinoco_tx_timeout(struct net_device *dev)
@@ -1047,18 +753,127 @@ static void orinoco_stat_gather(struct net_device *dev,
        }
 }
 
+/*
+ * orinoco_rx_monitor - handle received monitor frames.
+ *
+ * Arguments:
+ *     dev             network device
+ *     rxfid           received FID
+ *     desc            rx descriptor of the frame
+ *
+ * Call context: interrupt
+ */
+static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
+                              struct hermes_rx_descriptor *desc)
+{
+       u32 hdrlen = 30;        /* return full header by default */
+       u32 datalen = 0;
+       u16 fc;
+       int err;
+       int len;
+       struct sk_buff *skb;
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &priv->stats;
+       hermes_t *hw = &priv->hw;
+
+       len = le16_to_cpu(desc->data_len);
+
+       /* Determine the size of the header and the data */
+       fc = le16_to_cpu(desc->frame_ctl);
+       switch (fc & IEEE80211_FCTL_FTYPE) {
+       case IEEE80211_FTYPE_DATA:
+               if ((fc & IEEE80211_FCTL_TODS)
+                   && (fc & IEEE80211_FCTL_FROMDS))
+                       hdrlen = 30;
+               else
+                       hdrlen = 24;
+               datalen = len;
+               break;
+       case IEEE80211_FTYPE_MGMT:
+               hdrlen = 24;
+               datalen = len;
+               break;
+       case IEEE80211_FTYPE_CTL:
+               switch (fc & IEEE80211_FCTL_STYPE) {
+               case IEEE80211_STYPE_PSPOLL:
+               case IEEE80211_STYPE_RTS:
+               case IEEE80211_STYPE_CFEND:
+               case IEEE80211_STYPE_CFENDACK:
+                       hdrlen = 16;
+                       break;
+               case IEEE80211_STYPE_CTS:
+               case IEEE80211_STYPE_ACK:
+                       hdrlen = 10;
+                       break;
+               }
+               break;
+       default:
+               /* Unknown frame type */
+               break;
+       }
+
+       /* sanity check the length */
+       if (datalen > IEEE80211_DATA_LEN + 12) {
+               printk(KERN_DEBUG "%s: oversized monitor frame, "
+                      "data length = %d\n", dev->name, datalen);
+               err = -EIO;
+               stats->rx_length_errors++;
+               goto update_stats;
+       }
+
+       skb = dev_alloc_skb(hdrlen + datalen);
+       if (!skb) {
+               printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
+                      dev->name);
+               err = -ENOMEM;
+               goto drop;
+       }
+
+       /* Copy the 802.11 header to the skb */
+       memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen);
+       skb->mac.raw = skb->data;
+
+       /* If any, copy the data from the card to the skb */
+       if (datalen > 0) {
+               err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
+                                      ALIGN(datalen, 2), rxfid,
+                                      HERMES_802_2_OFFSET);
+               if (err) {
+                       printk(KERN_ERR "%s: error %d reading monitor frame\n",
+                              dev->name, err);
+                       goto drop;
+               }
+       }
+
+       skb->dev = dev;
+       skb->ip_summed = CHECKSUM_NONE;
+       skb->pkt_type = PACKET_OTHERHOST;
+       skb->protocol = __constant_htons(ETH_P_802_2);
+       
+       dev->last_rx = jiffies;
+       stats->rx_packets++;
+       stats->rx_bytes += skb->len;
+
+       netif_rx(skb);
+       return;
+
+ drop:
+       dev_kfree_skb_irq(skb);
+ update_stats:
+       stats->rx_errors++;
+       stats->rx_dropped++;
+}
+
 static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        struct iw_statistics *wstats = &priv->wstats;
        struct sk_buff *skb = NULL;
-       u16 rxfid, status;
-       int length, data_len, data_off;
-       char *p;
+       u16 rxfid, status, fc;
+       int length;
        struct hermes_rx_descriptor desc;
-       struct header_struct hdr;
-       struct ethhdr *eh;
+       struct ethhdr *hdr;
        int err;
 
        rxfid = hermes_read_regn(hw, RXFID);
@@ -1068,53 +883,46 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
        if (err) {
                printk(KERN_ERR "%s: error %d reading Rx descriptor. "
                       "Frame dropped.\n", dev->name, err);
-               stats->rx_errors++;
-               goto drop;
+               goto update_stats;
        }
 
        status = le16_to_cpu(desc.status);
 
-       if (status & HERMES_RXSTAT_ERR) {
-               if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
-                       wstats->discard.code++;
-                       DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
-                              dev->name);
-               } else {
-                       stats->rx_crc_errors++;
-                       DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name);
-               }
-               stats->rx_errors++;
-               goto drop;
+       if (status & HERMES_RXSTAT_BADCRC) {
+               DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
+                     dev->name);
+               stats->rx_crc_errors++;
+               goto update_stats;
        }
 
-       /* For now we ignore the 802.11 header completely, assuming
-           that the card's firmware has handled anything vital */
+       /* Handle frames in monitor mode */
+       if (priv->iw_mode == IW_MODE_MONITOR) {
+               orinoco_rx_monitor(dev, rxfid, &desc);
+               return;
+       }
 
-       err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr),
-                              rxfid, HERMES_802_3_OFFSET);
-       if (err) {
-               printk(KERN_ERR "%s: error %d reading frame header. "
-                      "Frame dropped.\n", dev->name, err);
-               stats->rx_errors++;
-               goto drop;
+       if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
+               DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
+                     dev->name);
+               wstats->discard.code++;
+               goto update_stats;
        }
 
-       length = ntohs(hdr.len);
-       
+       length = le16_to_cpu(desc.data_len);
+       fc = le16_to_cpu(desc.frame_ctl);
+
        /* Sanity checks */
        if (length < 3) { /* No for even an 802.2 LLC header */
                /* At least on Symbol firmware with PCF we get quite a
                    lot of these legitimately - Poll frames with no
                    data. */
-               stats->rx_dropped++;
-               goto drop;
+               return;
        }
        if (length > IEEE802_11_DATA_LEN) {
                printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
                       dev->name, length);
                stats->rx_length_errors++;
-               stats->rx_errors++;
-               goto drop;
+               goto update_stats;
        }
 
        /* We need space for the packet data itself, plus an ethernet
@@ -1126,60 +934,53 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
        if (!skb) {
                printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
                       dev->name);
-               goto drop;
+               goto update_stats;
        }
 
-       skb_reserve(skb, 2); /* This way the IP header is aligned */
+       /* We'll prepend the header, so reserve space for it.  The worst
+          case is no decapsulation, when 802.3 header is prepended and
+          nothing is removed.  2 is for aligning the IP header.  */
+       skb_reserve(skb, ETH_HLEN + 2);
+
+       err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
+                              ALIGN(length, 2), rxfid,
+                              HERMES_802_2_OFFSET);
+       if (err) {
+               printk(KERN_ERR "%s: error %d reading frame. "
+                      "Frame dropped.\n", dev->name, err);
+               goto drop;
+       }
 
        /* Handle decapsulation
         * In most cases, the firmware tell us about SNAP frames.
         * For some reason, the SNAP frames sent by LinkSys APs
         * are not properly recognised by most firmwares.
         * So, check ourselves */
-       if (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
-           ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
-           is_ethersnap(&hdr)) {
+       if (length >= ENCAPS_OVERHEAD &&
+           (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
+            ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
+            is_ethersnap(skb->data))) {
                /* These indicate a SNAP within 802.2 LLC within
                   802.11 frame which we'll need to de-encapsulate to
                   the original EthernetII frame. */
-
-               if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */
-                       stats->rx_length_errors++;
-                       goto drop;
-               }
-
-               /* Remove SNAP header, reconstruct EthernetII frame */
-               data_len = length - ENCAPS_OVERHEAD;
-               data_off = HERMES_802_3_OFFSET + sizeof(hdr);
-
-               eh = (struct ethhdr *)skb_put(skb, ETH_HLEN);
-
-               memcpy(eh, &hdr, 2 * ETH_ALEN);
-               eh->h_proto = hdr.ethertype;
+               hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
        } else {
-               /* All other cases indicate a genuine 802.3 frame.  No
-                  decapsulation needed.  We just throw the whole
-                  thing in, and hope the protocol layer can deal with
-                  it as 802.3 */
-               data_len = length;
-               data_off = HERMES_802_3_OFFSET;
-               /* FIXME: we re-read from the card data we already read here */
-       }
-
-       p = skb_put(skb, data_len);
-       err = hermes_bap_pread(hw, IRQ_BAP, p, ALIGN(data_len, 2),
-                              rxfid, data_off);
-       if (err) {
-               printk(KERN_ERR "%s: error %d reading frame. "
-                      "Frame dropped.\n", dev->name, err);
-               stats->rx_errors++;
-               goto drop;
+               /* 802.3 frame - prepend 802.3 header as is */
+               hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+               hdr->h_proto = htons(length);
        }
+       memcpy(hdr->h_dest, desc.addr1, ETH_ALEN);
+       if (fc & IEEE80211_FCTL_FROMDS)
+               memcpy(hdr->h_source, desc.addr3, ETH_ALEN);
+       else
+               memcpy(hdr->h_source, desc.addr2, ETH_ALEN);
 
        dev->last_rx = jiffies;
        skb->dev = dev;
        skb->protocol = eth_type_trans(skb, dev);
        skb->ip_summed = CHECKSUM_NONE;
+       if (fc & IEEE80211_FCTL_TODS)
+               skb->pkt_type = PACKET_OTHERHOST;
        
        /* Process the wireless stats if needed */
        orinoco_stat_gather(dev, skb, &desc);
@@ -1192,11 +993,10 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
        return;
 
  drop: 
+       dev_kfree_skb_irq(skb);
+ update_stats:
+       stats->rx_errors++;
        stats->rx_dropped++;
-
-       if (skb)
-               dev_kfree_skb_irq(skb);
-       return;
 }
 
 /********************************************************************/
@@ -1240,6 +1040,99 @@ static void print_linkstatus(struct net_device *dev, u16 status)
               dev->name, s, status);
 }
 
+/* Search scan results for requested BSSID, join it if found */
+static void orinoco_join_ap(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct hermes *hw = &priv->hw;
+       int err;
+       unsigned long flags;
+       struct join_req {
+               u8 bssid[ETH_ALEN];
+               u16 channel;
+       } __attribute__ ((packed)) req;
+       const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
+       struct prism2_scan_apinfo *atom;
+       int offset = 4;
+       u8 *buf;
+       u16 len;
+
+       /* Allocate buffer for scan results */
+       buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
+       if (! buf)
+               return;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               goto out;
+
+       /* Sanity checks in case user changed something in the meantime */
+       if (! priv->bssid_fixed)
+               goto out;
+
+       if (strlen(priv->desired_essid) == 0)
+               goto out;
+
+       /* Read scan results from the firmware */
+       err = hermes_read_ltv(hw, USER_BAP,
+                             HERMES_RID_SCANRESULTSTABLE,
+                             MAX_SCAN_LEN, &len, buf);
+       if (err) {
+               printk(KERN_ERR "%s: Cannot read scan results\n",
+                      dev->name);
+               goto out;
+       }
+
+       len = HERMES_RECLEN_TO_BYTES(len);
+
+       /* Go through the scan results looking for the channel of the AP
+        * we were requested to join */
+       for (; offset + atom_len <= len; offset += atom_len) {
+               atom = (struct prism2_scan_apinfo *) (buf + offset);
+               if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0)
+                       goto found;
+       }
+
+       DEBUG(1, "%s: Requested AP not found in scan results\n",
+             dev->name);
+       goto out;
+
+ found:
+       memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
+       req.channel = atom->channel;    /* both are little-endian */
+       err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
+                                 &req);
+       if (err)
+               printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
+
+ out:
+       kfree(buf);
+       orinoco_unlock(priv, &flags);
+}
+
+/* Send new BSSID to userspace */
+static void orinoco_send_wevents(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct hermes *hw = &priv->hw;
+       union iwreq_data wrqu;
+       int err;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return;
+
+       err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,
+                             ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
+       if (err != 0)
+               return;
+
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+       /* Send event to user space */
+       wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+       orinoco_unlock(priv, &flags);
+}
+
 static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 {
        struct orinoco_private *priv = netdev_priv(dev);
@@ -1307,6 +1200,9 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                u16 newstatus;
                int connected;
 
+               if (priv->iw_mode == IW_MODE_MONITOR)
+                       break;
+
                if (len != sizeof(linkstatus)) {
                        printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
                               dev->name, len);
@@ -1319,6 +1215,15 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                        break;
                newstatus = le16_to_cpu(linkstatus.linkstatus);
 
+               /* Symbol firmware uses "out of range" to signal that
+                * the hostscan frame can be requested.  */
+               if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
+                   priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
+                   priv->has_hostscan && priv->scan_inprogress) {
+                       hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
+                       break;
+               }
+
                connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
                        || (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
                        || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
@@ -1328,12 +1233,89 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                else if (!ignore_disconnect)
                        netif_carrier_off(dev);
 
-               if (newstatus != priv->last_linkstatus)
+               if (newstatus != priv->last_linkstatus) {
+                       priv->last_linkstatus = newstatus;
                        print_linkstatus(dev, newstatus);
+                       /* The info frame contains only one word which is the
+                        * status (see hermes.h). The status is pretty boring
+                        * in itself, that's why we export the new BSSID...
+                        * Jean II */
+                       schedule_work(&priv->wevent_work);
+               }
+       }
+       break;
+       case HERMES_INQ_SCAN:
+               if (!priv->scan_inprogress && priv->bssid_fixed &&
+                   priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
+                       schedule_work(&priv->join_work);
+                       break;
+               }
+               /* fall through */
+       case HERMES_INQ_HOSTSCAN:
+       case HERMES_INQ_HOSTSCAN_SYMBOL: {
+               /* Result of a scanning. Contains information about
+                * cells in the vicinity - Jean II */
+               union iwreq_data        wrqu;
+               unsigned char *buf;
+
+               /* Sanity check */
+               if (len > 4096) {
+                       printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
+                              dev->name, len);
+                       break;
+               }
+
+               /* We are a strict producer. If the previous scan results
+                * have not been consumed, we just have to drop this
+                * frame. We can't remove the previous results ourselves,
+                * that would be *very* racy... Jean II */
+               if (priv->scan_result != NULL) {
+                       printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name);
+                       break;
+               }
+
+               /* Allocate buffer for results */
+               buf = kmalloc(len, GFP_ATOMIC);
+               if (buf == NULL)
+                       /* No memory, so can't printk()... */
+                       break;
 
-               priv->last_linkstatus = newstatus;
+               /* Read scan data */
+               err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
+                                      infofid, sizeof(info));
+               if (err)
+                       break;
+
+#ifdef ORINOCO_DEBUG
+               {
+                       int     i;
+                       printk(KERN_DEBUG "Scan result [%02X", buf[0]);
+                       for(i = 1; i < (len * 2); i++)
+                               printk(":%02X", buf[i]);
+                       printk("]\n");
+               }
+#endif /* ORINOCO_DEBUG */
+
+               /* Allow the clients to access the results */
+               priv->scan_len = len;
+               priv->scan_result = buf;
+
+               /* Send an empty event to user space.
+                * We don't send the received data on the event because
+                * it would require us to do complex transcoding, and
+                * we want to minimise the work done in the irq handler
+                * Use a request to extract the data - Jean II */
+               wrqu.data.length = 0;
+               wrqu.data.flags = 0;
+               wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
        }
        break;
+       case HERMES_INQ_SEC_STAT_AGERE:
+               /* Security status (Agere specific) */
+               /* Ignore this frame for now */
+               if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+                       break;
+               /* fall through */
        default:
                printk(KERN_DEBUG "%s: Unknown information frame received: "
                       "type 0x%04x, length %d\n", dev->name, type, len);
@@ -1470,6 +1452,36 @@ static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
        return err;
 }
 
+/* Set fixed AP address */
+static int __orinoco_hw_set_wap(struct orinoco_private *priv)
+{
+       int roaming_flag;
+       int err = 0;
+       hermes_t *hw = &priv->hw;
+
+       switch (priv->firmware_type) {
+       case FIRMWARE_TYPE_AGERE:
+               /* not supported */
+               break;
+       case FIRMWARE_TYPE_INTERSIL:
+               if (priv->bssid_fixed)
+                       roaming_flag = 2;
+               else
+                       roaming_flag = 1;
+
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFROAMINGMODE,
+                                          roaming_flag);
+               break;
+       case FIRMWARE_TYPE_SYMBOL:
+               err = HERMES_WRITE_RECORD(hw, USER_BAP,
+                                         HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
+                                         &priv->desired_bssid);
+               break;
+       }
+       return err;
+}
+
 /* Change the WEP keys and/or the current keys.  Can be called
  * either from __orinoco_hw_setup_wep() or directly from
  * orinoco_ioctl_setiwencode().  In the later case the association
@@ -1655,6 +1667,13 @@ static int __orinoco_program_rids(struct net_device *dev)
                }
        }
 
+       /* Set the desired BSSID */
+       err = __orinoco_hw_set_wap(priv);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting AP address\n",
+                      dev->name, err);
+               return err;
+       }
        /* Set the desired ESSID */
        idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
        memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
@@ -1793,7 +1812,21 @@ static int __orinoco_program_rids(struct net_device *dev)
                }
        }
 
-       /* Set promiscuity / multicast*/
+       if (priv->iw_mode == IW_MODE_MONITOR) {
+               /* Enable monitor mode */
+               dev->type = ARPHRD_IEEE80211;
+               err = hermes_docmd_wait(hw, HERMES_CMD_TEST | 
+                                           HERMES_TEST_MONITOR, 0, NULL);
+       } else {
+               /* Disable monitor mode */
+               dev->type = ARPHRD_ETHER;
+               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+                                           HERMES_TEST_STOP, 0, NULL);
+       }
+       if (err)
+               return err;
+
+       /* Set promiscuity / multicast*/
        priv->promiscuous = 0;
        priv->mc_count = 0;
        __orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */
@@ -1869,55 +1902,6 @@ __orinoco_set_multicast_list(struct net_device *dev)
                dev->flags &= ~IFF_PROMISC;
 }
 
-static int orinoco_reconfigure(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct hermes *hw = &priv->hw;
-       unsigned long flags;
-       int err = 0;
-
-       if (priv->broken_disableport) {
-               schedule_work(&priv->reset_work);
-               return 0;
-       }
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-               
-       err = hermes_disable_port(hw, 0);
-       if (err) {
-               printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n",
-                      dev->name);
-               priv->broken_disableport = 1;
-               goto out;
-       }
-
-       err = __orinoco_program_rids(dev);
-       if (err) {
-               printk(KERN_WARNING "%s: Unable to reconfigure card\n",
-                      dev->name);
-               goto out;
-       }
-
-       err = hermes_enable_port(hw, 0);
-       if (err) {
-               printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
-                      dev->name);
-               goto out;
-       }
-
- out:
-       if (err) {
-               printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
-               schedule_work(&priv->reset_work);
-               err = 0;
-       }
-
-       orinoco_unlock(priv, &flags);
-       return err;
-
-}
-
 /* This must be called from user context, without locks held - use
  * schedule_work() */
 static void orinoco_reset(struct net_device *dev)
@@ -1946,6 +1930,11 @@ static void orinoco_reset(struct net_device *dev)
 
        orinoco_unlock(priv, &flags);
 
+       /* Scanning support: Cleanup of driver struct */
+       kfree(priv->scan_result);
+       priv->scan_result = NULL;
+       priv->scan_inprogress = 0;
+
        if (priv->hard_reset) {
                err = (*priv->hard_reset)(priv);
                if (err) {
@@ -2184,6 +2173,8 @@ static int determine_firmware(struct net_device *dev)
                priv->has_mwo = (firmver >= 0x60000);
                priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
                priv->ibss_port = 1;
+               priv->has_hostscan = (firmver >= 0x8000a);
+               priv->broken_monitor = (firmver >= 0x80000);
 
                /* Tested with Agere firmware :
                 *      1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
@@ -2229,6 +2220,8 @@ static int determine_firmware(struct net_device *dev)
                priv->ibss_port = 4;
                priv->broken_disableport = (firmver == 0x25013) ||
                                           (firmver >= 0x30000 && firmver <= 0x31000);
+               priv->has_hostscan = (firmver >= 0x31001) ||
+                                    (firmver >= 0x29057 && firmver < 0x30000);
                /* Tested with Intel firmware : 0x20015 => Jean II */
                /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
                break;
@@ -2248,6 +2241,7 @@ static int determine_firmware(struct net_device *dev)
                priv->has_ibss = (firmver >= 0x000700); /* FIXME */
                priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
                priv->has_pm = (firmver >= 0x000700);
+               priv->has_hostscan = (firmver >= 0x010301);
 
                if (firmver >= 0x000800)
                        priv->ibss_port = 0;
@@ -2456,8 +2450,9 @@ struct net_device *alloc_orinocodev(int sizeof_card,
        dev->tx_timeout = orinoco_tx_timeout;
        dev->watchdog_timeo = HZ; /* 1 second timeout */
        dev->get_stats = orinoco_get_stats;
+       dev->ethtool_ops = &orinoco_ethtool_ops;
        dev->get_wireless_stats = orinoco_get_wireless_stats;
-       dev->do_ioctl = orinoco_ioctl;
+       dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def;
        dev->change_mtu = orinoco_change_mtu;
        dev->set_multicast_list = orinoco_set_multicast_list;
        /* we use the default eth_mac_addr for setting the MAC addr */
@@ -2473,6 +2468,8 @@ struct net_device *alloc_orinocodev(int sizeof_card,
                                   * before anything else touches the
                                   * hardware */
        INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
+       INIT_WORK(&priv->join_work, (void (*)(void *))orinoco_join_ap, dev);
+       INIT_WORK(&priv->wevent_work, (void (*)(void *))orinoco_send_wevents, dev);
 
        netif_carrier_off(dev);
        priv->last_linkstatus = 0xffff;
@@ -2483,6 +2480,9 @@ struct net_device *alloc_orinocodev(int sizeof_card,
 
 void free_orinocodev(struct net_device *dev)
 {
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       kfree(priv->scan_result);
        free_netdev(dev);
 }
 
@@ -2490,24 +2490,6 @@ void free_orinocodev(struct net_device *dev)
 /* Wireless extensions                                              */
 /********************************************************************/
 
-static int orinoco_hw_get_bssid(struct orinoco_private *priv,
-                               char buf[ETH_ALEN])
-{
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-                             ETH_ALEN, NULL, buf);
-
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
 static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
                                char buf[IW_ESSID_MAX_SIZE+1])
 {
@@ -2633,140 +2615,271 @@ static int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
        return 0;
 }
 
-static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq)
+static int orinoco_ioctl_getname(struct net_device *dev,
+                                struct iw_request_info *info,
+                                char *name,
+                                char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       int err = 0;
-       int mode;
-       struct iw_range range;
        int numrates;
-       int i, k;
+       int err;
+
+       err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
+
+       if (!err && (numrates > 2))
+               strcpy(name, "IEEE 802.11b");
+       else
+               strcpy(name, "IEEE 802.11-DS");
+
+       return 0;
+}
+
+static int orinoco_ioctl_setwap(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct sockaddr *ap_addr,
+                               char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = -EINPROGRESS;         /* Call commit handler */
        unsigned long flags;
+       static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
-       TRACE_ENTER(dev->name);
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       /* Enable automatic roaming - no sanity checks are needed */
+       if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 ||
+           memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) {
+               priv->bssid_fixed = 0;
+               memset(priv->desired_bssid, 0, ETH_ALEN);
+
+               /* "off" means keep existing connection */
+               if (ap_addr->sa_data[0] == 0) {
+                       __orinoco_hw_set_wap(priv);
+                       err = 0;
+               }
+               goto out;
+       }
+
+       if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
+               printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
+                      "support manual roaming\n",
+                      dev->name);
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (priv->iw_mode != IW_MODE_INFRA) {
+               printk(KERN_WARNING "%s: Manual roaming supported only in "
+                      "managed mode\n", dev->name);
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       /* Intersil firmware hangs without Desired ESSID */
+       if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
+           strlen(priv->desired_essid) == 0) {
+               printk(KERN_WARNING "%s: Desired ESSID must be set for "
+                      "manual roaming\n", dev->name);
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       /* Finally, enable manual roaming */
+       priv->bssid_fixed = 1;
+       memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
+
+ out:
+       orinoco_unlock(priv, &flags);
+       return err;
+}
+
+static int orinoco_ioctl_getwap(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct sockaddr *ap_addr,
+                               char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       ap_addr->sa_family = ARPHRD_ETHER;
+       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+                             ETH_ALEN, NULL, ap_addr->sa_data);
+
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
 
-       if (!access_ok(VERIFY_WRITE, rrq->pointer, sizeof(range)))
-               return -EFAULT;
+static int orinoco_ioctl_setmode(struct net_device *dev,
+                                struct iw_request_info *info,
+                                u32 *mode,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = -EINPROGRESS;         /* Call commit handler */
+       unsigned long flags;
 
-       rrq->length = sizeof(range);
+       if (priv->iw_mode == *mode)
+               return 0;
 
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
 
-       mode = priv->iw_mode;
+       switch (*mode) {
+       case IW_MODE_ADHOC:
+               if (!priv->has_ibss && !priv->has_port3)
+                       err = -EOPNOTSUPP;
+               break;
+
+       case IW_MODE_INFRA:
+               break;
+
+       case IW_MODE_MONITOR:
+               if (priv->broken_monitor && !force_monitor) {
+                       printk(KERN_WARNING "%s: Monitor mode support is "
+                              "buggy in this firmware, not enabling\n",
+                              dev->name);
+                       err = -EOPNOTSUPP;
+               }
+               break;
+
+       default:
+               err = -EOPNOTSUPP;
+               break;
+       }
+
+       if (err == -EINPROGRESS) {
+               priv->iw_mode = *mode;
+               set_port_type(priv);
+       }
+
        orinoco_unlock(priv, &flags);
 
-       memset(&range, 0, sizeof(range));
+       return err;
+}
 
-       /* Much of this shamelessly taken from wvlan_cs.c. No idea
-        * what it all means -dgibson */
-       range.we_version_compiled = WIRELESS_EXT;
-       range.we_version_source = 11;
+static int orinoco_ioctl_getmode(struct net_device *dev,
+                                struct iw_request_info *info,
+                                u32 *mode,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
 
-       range.min_nwid = range.max_nwid = 0; /* We don't use nwids */
+       *mode = priv->iw_mode;
+       return 0;
+}
+
+static int orinoco_ioctl_getiwrange(struct net_device *dev,
+                                   struct iw_request_info *info,
+                                   struct iw_point *rrq,
+                                   char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = 0;
+       struct iw_range *range = (struct iw_range *) extra;
+       int numrates;
+       int i, k;
+
+       TRACE_ENTER(dev->name);
+
+       rrq->length = sizeof(struct iw_range);
+       memset(range, 0, sizeof(struct iw_range));
+
+       range->we_version_compiled = WIRELESS_EXT;
+       range->we_version_source = 14;
 
        /* Set available channels/frequencies */
-       range.num_channels = NUM_CHANNELS;
+       range->num_channels = NUM_CHANNELS;
        k = 0;
        for (i = 0; i < NUM_CHANNELS; i++) {
                if (priv->channel_mask & (1 << i)) {
-                       range.freq[k].i = i + 1;
-                       range.freq[k].m = channel_frequency[i] * 100000;
-                       range.freq[k].e = 1;
+                       range->freq[k].i = i + 1;
+                       range->freq[k].m = channel_frequency[i] * 100000;
+                       range->freq[k].e = 1;
                        k++;
                }
                
                if (k >= IW_MAX_FREQUENCIES)
                        break;
        }
-       range.num_frequency = k;
+       range->num_frequency = k;
+       range->sensitivity = 3;
+
+       if (priv->has_wep) {
+               range->max_encoding_tokens = ORINOCO_MAX_KEYS;
+               range->encoding_size[0] = SMALL_KEY_SIZE;
+               range->num_encoding_sizes = 1;
 
-       range.sensitivity = 3;
+               if (priv->has_big_wep) {
+                       range->encoding_size[1] = LARGE_KEY_SIZE;
+                       range->num_encoding_sizes = 2;
+               }
+       }
 
-       if ((mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
+       if ((priv->iw_mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
                /* Quality stats meaningless in ad-hoc mode */
-               range.max_qual.qual = 0;
-               range.max_qual.level = 0;
-               range.max_qual.noise = 0;
-               range.avg_qual.qual = 0;
-               range.avg_qual.level = 0;
-               range.avg_qual.noise = 0;
        } else {
-               range.max_qual.qual = 0x8b - 0x2f;
-               range.max_qual.level = 0x2f - 0x95 - 1;
-               range.max_qual.noise = 0x2f - 0x95 - 1;
+               range->max_qual.qual = 0x8b - 0x2f;
+               range->max_qual.level = 0x2f - 0x95 - 1;
+               range->max_qual.noise = 0x2f - 0x95 - 1;
                /* Need to get better values */
-               range.avg_qual.qual = 0x24;
-               range.avg_qual.level = 0xC2;
-               range.avg_qual.noise = 0x9E;
+               range->avg_qual.qual = 0x24;
+               range->avg_qual.level = 0xC2;
+               range->avg_qual.noise = 0x9E;
        }
 
        err = orinoco_hw_get_bitratelist(priv, &numrates,
-                                        range.bitrate, IW_MAX_BITRATES);
+                                        range->bitrate, IW_MAX_BITRATES);
        if (err)
                return err;
-       range.num_bitrates = numrates;
-       
+       range->num_bitrates = numrates;
+
        /* Set an indication of the max TCP throughput in bit/s that we can
         * expect using this interface. May be use for QoS stuff...
         * Jean II */
-       if(numrates > 2)
-               range.throughput = 5 * 1000 * 1000;     /* ~5 Mb/s */
+       if (numrates > 2)
+               range->throughput = 5 * 1000 * 1000;    /* ~5 Mb/s */
        else
-               range.throughput = 1.5 * 1000 * 1000;   /* ~1.5 Mb/s */
-
-       range.min_rts = 0;
-       range.max_rts = 2347;
-       range.min_frag = 256;
-       range.max_frag = 2346;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-       if (priv->has_wep) {
-               range.max_encoding_tokens = ORINOCO_MAX_KEYS;
-
-               range.encoding_size[0] = SMALL_KEY_SIZE;
-               range.num_encoding_sizes = 1;
-
-               if (priv->has_big_wep) {
-                       range.encoding_size[1] = LARGE_KEY_SIZE;
-                       range.num_encoding_sizes = 2;
-               }
-       } else {
-               range.num_encoding_sizes = 0;
-               range.max_encoding_tokens = 0;
-       }
-       orinoco_unlock(priv, &flags);
-               
-       range.min_pmp = 0;
-       range.max_pmp = 65535000;
-       range.min_pmt = 0;
-       range.max_pmt = 65535 * 1000;   /* ??? */
-       range.pmp_flags = IW_POWER_PERIOD;
-       range.pmt_flags = IW_POWER_TIMEOUT;
-       range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
-
-       range.num_txpower = 1;
-       range.txpower[0] = 15; /* 15dBm */
-       range.txpower_capa = IW_TXPOW_DBM;
-
-       range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
-       range.retry_flags = IW_RETRY_LIMIT;
-       range.r_time_flags = IW_RETRY_LIFETIME;
-       range.min_retry = 0;
-       range.max_retry = 65535;        /* ??? */
-       range.min_r_time = 0;
-       range.max_r_time = 65535 * 1000;        /* ??? */
-
-       if (copy_to_user(rrq->pointer, &range, sizeof(range)))
-               return -EFAULT;
+               range->throughput = 1.5 * 1000 * 1000;  /* ~1.5 Mb/s */
+
+       range->min_rts = 0;
+       range->max_rts = 2347;
+       range->min_frag = 256;
+       range->max_frag = 2346;
+
+       range->min_pmp = 0;
+       range->max_pmp = 65535000;
+       range->min_pmt = 0;
+       range->max_pmt = 65535 * 1000;  /* ??? */
+       range->pmp_flags = IW_POWER_PERIOD;
+       range->pmt_flags = IW_POWER_TIMEOUT;
+       range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
+
+       range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+       range->retry_flags = IW_RETRY_LIMIT;
+       range->r_time_flags = IW_RETRY_LIFETIME;
+       range->min_retry = 0;
+       range->max_retry = 65535;       /* ??? */
+       range->min_r_time = 0;
+       range->max_r_time = 65535 * 1000;       /* ??? */
 
        TRACE_EXIT(dev->name);
 
        return 0;
 }
 
-static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setiwencode(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    struct iw_point *erq,
+                                    char *keybuf)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        int index = (erq->flags & IW_ENCODE_INDEX) - 1;
@@ -2774,8 +2887,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
        int enable = priv->wep_on;
        int restricted = priv->wep_restrict;
        u16 xlen = 0;
-       int err = 0;
-       char keybuf[ORINOCO_MAX_KEY_SIZE];
+       int err = -EINPROGRESS;         /* Call commit handler */
        unsigned long flags;
 
        if (! priv->has_wep)
@@ -2788,9 +2900,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
 
                if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep )
                        return -E2BIG;
-               
-               if (copy_from_user(keybuf, erq->pointer, erq->length))
-                       return -EFAULT;
        }
 
        if (orinoco_lock(priv, &flags) != 0)
@@ -2864,12 +2973,14 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
        return err;
 }
 
-static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getiwencode(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    struct iw_point *erq,
+                                    char *keybuf)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        int index = (erq->flags & IW_ENCODE_INDEX) - 1;
        u16 xlen = 0;
-       char keybuf[ORINOCO_MAX_KEY_SIZE];
        unsigned long flags;
 
        if (! priv->has_wep)
@@ -2898,51 +3009,47 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *er
        memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
 
        orinoco_unlock(priv, &flags);
-
-       if (erq->pointer) {
-               if (copy_to_user(erq->pointer, keybuf, xlen))
-                       return -EFAULT;
-       }
-
        return 0;
 }
 
-static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setessid(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_point *erq,
+                                 char *essidbuf)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       char essidbuf[IW_ESSID_MAX_SIZE+1];
        unsigned long flags;
 
        /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
         * anyway... - Jean II */
 
-       memset(&essidbuf, 0, sizeof(essidbuf));
-
-       if (erq->flags) {
-               /* iwconfig includes the NUL in the specified length */
-               if (erq->length > IW_ESSID_MAX_SIZE+1)
-                       return -E2BIG;
-               
-               if (copy_from_user(&essidbuf, erq->pointer, erq->length))
-                       return -EFAULT;
-
-               essidbuf[IW_ESSID_MAX_SIZE] = '\0';
-       }
+       /* Hum... Should not use Wireless Extension constant (may change),
+        * should use our own... - Jean II */
+       if (erq->length > IW_ESSID_MAX_SIZE)
+               return -E2BIG;
 
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
 
-       memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid));
+       /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
+       memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
+
+       /* If not ANY, get the new ESSID */
+       if (erq->flags) {
+               memcpy(priv->desired_essid, essidbuf, erq->length);
+       }
 
        orinoco_unlock(priv, &flags);
 
-       return 0;
+       return -EINPROGRESS;            /* Call commit handler */
 }
 
-static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getessid(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_point *erq,
+                                 char *essidbuf)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       char essidbuf[IW_ESSID_MAX_SIZE+1];
        int active;
        int err = 0;
        unsigned long flags;
@@ -2956,51 +3063,46 @@ static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
        } else {
                if (orinoco_lock(priv, &flags) != 0)
                        return -EBUSY;
-               memcpy(essidbuf, priv->desired_essid, sizeof(essidbuf));
+               memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE + 1);
                orinoco_unlock(priv, &flags);
        }
 
        erq->flags = 1;
        erq->length = strlen(essidbuf) + 1;
-       if (erq->pointer)
-               if (copy_to_user(erq->pointer, essidbuf, erq->length))
-                       return -EFAULT;
 
        TRACE_EXIT(dev->name);
        
        return 0;
 }
 
-static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_setnick(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *nrq,
+                                char *nickbuf)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       char nickbuf[IW_ESSID_MAX_SIZE+1];
        unsigned long flags;
 
        if (nrq->length > IW_ESSID_MAX_SIZE)
                return -E2BIG;
 
-       memset(nickbuf, 0, sizeof(nickbuf));
-
-       if (copy_from_user(nickbuf, nrq->pointer, nrq->length))
-               return -EFAULT;
-
-       nickbuf[nrq->length] = '\0';
-       
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
 
-       memcpy(priv->nick, nickbuf, sizeof(priv->nick));
+       memset(priv->nick, 0, sizeof(priv->nick));
+       memcpy(priv->nick, nickbuf, nrq->length);
 
        orinoco_unlock(priv, &flags);
 
-       return 0;
+       return -EINPROGRESS;            /* Call commit handler */
 }
 
-static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_getnick(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *nrq,
+                                char *nickbuf)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       char nickbuf[IW_ESSID_MAX_SIZE+1];
        unsigned long flags;
 
        if (orinoco_lock(priv, &flags) != 0)
@@ -3011,23 +3113,22 @@ static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
 
        nrq->length = strlen(nickbuf)+1;
 
-       if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf)))
-               return -EFAULT;
-
        return 0;
 }
 
-static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
+static int orinoco_ioctl_setfreq(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_freq *frq,
+                                char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        int chan = -1;
        unsigned long flags;
+       int err = -EINPROGRESS;         /* Call commit handler */
 
-       /* We can only use this in Ad-Hoc demo mode to set the operating
-        * frequency, or in IBSS mode to set the frequency where the IBSS
-        * will be created - Jean II */
-       if (priv->iw_mode != IW_MODE_ADHOC)
-               return -EOPNOTSUPP;
+       /* In infrastructure mode the AP sets the channel */
+       if (priv->iw_mode == IW_MODE_INFRA)
+               return -EBUSY;
 
        if ( (frq->e == 0) && (frq->m <= 1000) ) {
                /* Setting by channel number */
@@ -3051,13 +3152,44 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
 
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
+
        priv->channel = chan;
+       if (priv->iw_mode == IW_MODE_MONITOR) {
+               /* Fast channel change - no commit if successful */
+               hermes_t *hw = &priv->hw;
+               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+                                           HERMES_TEST_SET_CHANNEL,
+                                       chan, NULL);
+       }
        orinoco_unlock(priv, &flags);
 
+       return err;
+}
+
+static int orinoco_ioctl_getfreq(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_freq *frq,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int tmp;
+
+       /* Locking done in there */
+       tmp = orinoco_hw_get_freq(priv);
+       if (tmp < 0) {
+               return tmp;
+       }
+
+       frq->m = tmp;
+       frq->e = 1;
+
        return 0;
 }
 
-static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
+static int orinoco_ioctl_getsens(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *srq,
+                                char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        hermes_t *hw = &priv->hw;
@@ -3083,7 +3215,10 @@ static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
        return 0;
 }
 
-static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
+static int orinoco_ioctl_setsens(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *srq,
+                                char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        int val = srq->value;
@@ -3100,10 +3235,13 @@ static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
        priv->ap_density = val;
        orinoco_unlock(priv, &flags);
 
-       return 0;
+       return -EINPROGRESS;            /* Call commit handler */
 }
 
-static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_setrts(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_param *rrq,
+                               char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        int val = rrq->value;
@@ -3121,13 +3259,30 @@ static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
        priv->rts_thresh = val;
        orinoco_unlock(priv, &flags);
 
+       return -EINPROGRESS;            /* Call commit handler */
+}
+
+static int orinoco_ioctl_getrts(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_param *rrq,
+                               char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       rrq->value = priv->rts_thresh;
+       rrq->disabled = (rrq->value == 2347);
+       rrq->fixed = 1;
+
        return 0;
 }
 
-static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
+static int orinoco_ioctl_setfrag(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *frq,
+                                char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       int err = 0;
+       int err = -EINPROGRESS;         /* Call commit handler */
        unsigned long flags;
 
        if (orinoco_lock(priv, &flags) != 0)
@@ -3159,11 +3314,14 @@ static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
        return err;
 }
 
-static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
+static int orinoco_ioctl_getfrag(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *frq,
+                                char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        hermes_t *hw = &priv->hw;
-       int err = 0;
+       int err;
        u16 val;
        unsigned long flags;
 
@@ -3196,10 +3354,12 @@ static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
        return err;
 }
 
-static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_setrate(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *rrq,
+                                char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       int err = 0;
        int ratemode = -1;
        int bitrate; /* 100s of kilobits */
        int i;
@@ -3235,10 +3395,13 @@ static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
        priv->bitratemode = ratemode;
        orinoco_unlock(priv, &flags);
 
-       return err;
+       return -EINPROGRESS;
 }
 
-static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_getrate(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *rrq,
+                                char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        hermes_t *hw = &priv->hw;
@@ -3303,10 +3466,13 @@ static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
        return err;
 }
 
-static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
+static int orinoco_ioctl_setpower(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_param *prq,
+                                 char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       int err = 0;
+       int err = -EINPROGRESS;         /* Call commit handler */
        unsigned long flags;
 
        if (orinoco_lock(priv, &flags) != 0)
@@ -3355,7 +3521,10 @@ static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
        return err;
 }
 
-static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
+static int orinoco_ioctl_getpower(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_param *prq,
+                                 char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        hermes_t *hw = &priv->hw;
@@ -3403,7 +3572,10 @@ static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
        return err;
 }
 
-static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_getretry(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_param *rrq,
+                                 char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        hermes_t *hw = &priv->hw;
@@ -3454,10 +3626,38 @@ static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
        return err;
 }
 
-static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_reset(struct net_device *dev,
+                              struct iw_request_info *info,
+                              void *wrqu,
+                              char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       if (! capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
+               printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
+
+               /* Firmware reset */
+               orinoco_reset(dev);
+       } else {
+               printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
+
+               schedule_work(&priv->reset_work);
+       }
+
+       return 0;
+}
+
+static int orinoco_ioctl_setibssport(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    void *wrqu,
+                                    char *extra)
+
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       int val = *( (int *) wrq->u.name );
+       int val = *( (int *) extra );
        unsigned long flags;
 
        if (orinoco_lock(priv, &flags) != 0)
@@ -3469,28 +3669,28 @@ static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq)
        set_port_type(priv);
 
        orinoco_unlock(priv, &flags);
-       return 0;
+       return -EINPROGRESS;            /* Call commit handler */
 }
 
-static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_getibssport(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    void *wrqu,
+                                    char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       int *val = (int *)wrq->u.name;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
+       int *val = (int *) extra;
 
        *val = priv->ibss_port;
-       orinoco_unlock(priv, &flags);
-
        return 0;
 }
 
-static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_setport3(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 void *wrqu,
+                                 char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       int val = *( (int *) wrq->u.name );
+       int val = *( (int *) extra );
        int err = 0;
        unsigned long flags;
 
@@ -3519,51 +3719,131 @@ static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
                err = -EINVAL;
        }
 
-       if (! err)
+       if (! err) {
                /* Actually update the mode we are using */
                set_port_type(priv);
+               err = -EINPROGRESS;
+       }
 
        orinoco_unlock(priv, &flags);
 
        return err;
 }
 
-static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_getport3(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 void *wrqu,
+                                 char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int *val = (int *) extra;
+
+       *val = priv->prefer_port3;
+       return 0;
+}
+
+static int orinoco_ioctl_setpreamble(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    void *wrqu,
+                                    char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       int *val = (int *)wrq->u.name;
        unsigned long flags;
+       int val;
+
+       if (! priv->has_preamble)
+               return -EOPNOTSUPP;
+
+       /* 802.11b has recently defined some short preamble.
+        * Basically, the Phy header has been reduced in size.
+        * This increase performance, especially at high rates
+        * (the preamble is transmitted at 1Mb/s), unfortunately
+        * this give compatibility troubles... - Jean II */
+       val = *( (int *) extra );
 
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
 
-       *val = priv->prefer_port3;
+       if (val)
+               priv->preamble = 1;
+       else
+               priv->preamble = 0;
+
        orinoco_unlock(priv, &flags);
+
+       return -EINPROGRESS;            /* Call commit handler */
+}
+
+static int orinoco_ioctl_getpreamble(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    void *wrqu,
+                                    char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int *val = (int *) extra;
+
+       if (! priv->has_preamble)
+               return -EOPNOTSUPP;
+
+       *val = priv->preamble;
        return 0;
 }
 
+/* ioctl interface to hermes_read_ltv()
+ * To use with iwpriv, pass the RID as the token argument, e.g.
+ * iwpriv get_rid [0xfc00]
+ * At least Wireless Tools 25 is required to use iwpriv.
+ * For Wireless Tools 25 and 26 append "dummy" are the end. */
+static int orinoco_ioctl_getrid(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_point *data,
+                               char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       int rid = data->flags;
+       u16 length;
+       int err;
+       unsigned long flags;
+
+       /* It's a "get" function, but we don't want users to access the
+        * WEP key and other raw firmware data */
+       if (! capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (rid < 0xfc00 || rid > 0xffff)
+               return -EINVAL;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
+                             extra);
+       if (err)
+               goto out;
+
+       data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
+                            MAX_RID_LEN);
+
+ out:
+       orinoco_unlock(priv, &flags);
+       return err;
+}
+
 /* Spy is used for link quality/strength measurements in Ad-Hoc mode
  * Jean II */
-static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
+static int orinoco_ioctl_setspy(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_point *srq,
+                               char *extra)
+
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       struct sockaddr address[IW_MAX_SPY];
+       struct sockaddr *address = (struct sockaddr *) extra;
        int number = srq->length;
        int i;
-       int err = 0;
        unsigned long flags;
 
-       /* Check the number of addresses */
-       if (number > IW_MAX_SPY)
-               return -E2BIG;
-
-       /* Get the data in the driver */
-       if (srq->pointer) {
-               if (copy_from_user(address, srq->pointer,
-                                  sizeof(struct sockaddr) * number))
-                       return -EFAULT;
-       }
-
        /* Make sure nobody mess with the structure while we do */
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
@@ -3587,14 +3867,17 @@ static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
        /* Now, let the others play */
        orinoco_unlock(priv, &flags);
 
-       return err;
+       /* Do NOT call commit handler */
+       return 0;
 }
 
-static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
+static int orinoco_ioctl_getspy(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_point *srq,
+                               char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       struct sockaddr address[IW_MAX_SPY];
-       struct iw_quality spy_stat[IW_MAX_SPY];
+       struct sockaddr *address = (struct sockaddr *) extra;
        int number;
        int i;
        unsigned long flags;
@@ -3603,7 +3886,12 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
                return -EBUSY;
 
        number = priv->spy_number;
-       if ((number > 0) && (srq->pointer)) {
+       /* Create address struct */
+       for (i = 0; i < number; i++) {
+               memcpy(address[i].sa_data, priv->spy_address[i], ETH_ALEN);
+               address[i].sa_family = AF_UNIX;
+       }
+       if (number > 0) {
                /* Create address struct */
                for (i = 0; i < number; i++) {
                        memcpy(address[i].sa_data, priv->spy_address[i],
@@ -3614,344 +3902,503 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
                /* In theory, we should disable irqs while copying the stats
                 * because the rx path might update it in the middle...
                 * Bah, who care ? - Jean II */
-               memcpy(&spy_stat, priv->spy_stat,
-                      sizeof(struct iw_quality) * IW_MAX_SPY);
-               for (i=0; i < number; i++)
-                       priv->spy_stat[i].updated = 0;
+               memcpy(extra  + (sizeof(struct sockaddr) * number),
+                      priv->spy_stat, sizeof(struct iw_quality) * number);
        }
+       /* Reset updated flags. */
+       for (i = 0; i < number; i++)
+               priv->spy_stat[i].updated = 0;
 
        orinoco_unlock(priv, &flags);
 
-       /* Push stuff to user space */
        srq->length = number;
-       if(copy_to_user(srq->pointer, address,
-                        sizeof(struct sockaddr) * number))
-               return -EFAULT;
-       if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number),
-                       &spy_stat, sizeof(struct iw_quality) * number))
-               return -EFAULT;
 
        return 0;
 }
 
-static int
-orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+/* Trigger a scan (look for other cells in the vicinity */
+static int orinoco_ioctl_setscan(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *srq,
+                                char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       struct iwreq *wrq = (struct iwreq *)rq;
+       hermes_t *hw = &priv->hw;
        int err = 0;
-       int tmp;
-       int changed = 0;
        unsigned long flags;
 
-       TRACE_ENTER(dev->name);
+       /* Note : you may have realised that, as this is a SET operation,
+        * this is priviledged and therefore a normal user can't
+        * perform scanning.
+        * This is not an error, while the device perform scanning,
+        * traffic doesn't flow, so it's a perfect DoS...
+        * Jean II */
 
-       /* In theory, we could allow most of the the SET stuff to be
-        * done. In practice, the lapse of time at startup when the
-        * card is not ready is very short, so why bother...  Note
-        * that netif_device_present is different from up/down
-        * (ifconfig), when the device is not yet up, it is usually
-        * already ready...  Jean II */
-       if (! netif_device_present(dev))
-               return -ENODEV;
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
 
-       switch (cmd) {
-       case SIOCGIWNAME:
-               strcpy(wrq->u.name, "IEEE 802.11-DS");
-               break;
-               
-       case SIOCGIWAP:
-               wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
-               err = orinoco_hw_get_bssid(priv, wrq->u.ap_addr.sa_data);
-               break;
+       /* Scanning with port 0 disabled would fail */
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
+               goto out;
+       }
 
-       case SIOCGIWRANGE:
-               err = orinoco_ioctl_getiwrange(dev, &wrq->u.data);
-               break;
+       /* In monitor mode, the scan results are always empty.
+        * Probe responses are passed to the driver as received
+        * frames and could be processed in software. */
+       if (priv->iw_mode == IW_MODE_MONITOR) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
 
-       case SIOCSIWMODE:
-               if (orinoco_lock(priv, &flags) != 0)
-                       return -EBUSY;
-               switch (wrq->u.mode) {
-               case IW_MODE_ADHOC:
-                       if (! (priv->has_ibss || priv->has_port3) )
-                               err = -EINVAL;
-                       else {
-                               priv->iw_mode = IW_MODE_ADHOC;
-                               changed = 1;
-                       }
-                       break;
+       /* Note : because we don't lock out the irq handler, the way
+        * we access scan variables in priv is critical.
+        *      o scan_inprogress : not touched by irq handler
+        *      o scan_mode : not touched by irq handler
+        *      o scan_result : irq is strict producer, non-irq is strict
+        *              consumer.
+        *      o scan_len : synchronised with scan_result
+        * Before modifying anything on those variables, please think hard !
+        * Jean II */
 
-               case IW_MODE_INFRA:
-                       priv->iw_mode = IW_MODE_INFRA;
-                       changed = 1;
-                       break;
+       /* If there is still some left-over scan results, get rid of it */
+       if (priv->scan_result != NULL) {
+               /* What's likely is that a client did crash or was killed
+                * between triggering the scan request and reading the
+                * results, so we need to reset everything.
+                * Some clients that are too slow may suffer from that...
+                * Jean II */
+               kfree(priv->scan_result);
+               priv->scan_result = NULL;
+       }
 
-               default:
-                       err = -EINVAL;
-                       break;
-               }
-               set_port_type(priv);
-               orinoco_unlock(priv, &flags);
-               break;
+       /* Save flags */
+       priv->scan_mode = srq->flags;
 
-       case SIOCGIWMODE:
-               if (orinoco_lock(priv, &flags) != 0)
-                       return -EBUSY;
-               wrq->u.mode = priv->iw_mode;
-               orinoco_unlock(priv, &flags);
-               break;
+       /* Always trigger scanning, even if it's in progress.
+        * This way, if the info frame get lost, we will recover somewhat
+        * gracefully  - Jean II */
 
-       case SIOCSIWENCODE:
-               err = orinoco_ioctl_setiwencode(dev, &wrq->u.encoding);
-               if (! err)
-                       changed = 1;
+       if (priv->has_hostscan) {
+               switch (priv->firmware_type) {
+               case FIRMWARE_TYPE_SYMBOL:
+                       err = hermes_write_wordrec(hw, USER_BAP,
+                                                  HERMES_RID_CNFHOSTSCAN_SYMBOL,
+                                                  HERMES_HOSTSCAN_SYMBOL_ONCE |
+                                                  HERMES_HOSTSCAN_SYMBOL_BCAST);
+                       break;
+               case FIRMWARE_TYPE_INTERSIL: {
+                       u16 req[3];
+
+                       req[0] = cpu_to_le16(0x3fff);   /* All channels */
+                       req[1] = cpu_to_le16(0x0001);   /* rate 1 Mbps */
+                       req[2] = 0;                     /* Any ESSID */
+                       err = HERMES_WRITE_RECORD(hw, USER_BAP,
+                                                 HERMES_RID_CNFHOSTSCAN, &req);
+               }
                break;
+               case FIRMWARE_TYPE_AGERE:
+                       err = hermes_write_wordrec(hw, USER_BAP,
+                                                  HERMES_RID_CNFSCANSSID_AGERE,
+                                                  0);  /* Any ESSID */
+                       if (err)
+                               break;
 
-       case SIOCGIWENCODE:
-               if (! capable(CAP_NET_ADMIN)) {
-                       err = -EPERM;
+                       err = hermes_inquire(hw, HERMES_INQ_SCAN);
                        break;
                }
+       } else
+               err = hermes_inquire(hw, HERMES_INQ_SCAN);
 
-               err = orinoco_ioctl_getiwencode(dev, &wrq->u.encoding);
-               break;
-
-       case SIOCSIWESSID:
-               err = orinoco_ioctl_setessid(dev, &wrq->u.essid);
-               if (! err)
-                       changed = 1;
-               break;
+       /* One more client */
+       if (! err)
+               priv->scan_inprogress = 1;
 
-       case SIOCGIWESSID:
-               err = orinoco_ioctl_getessid(dev, &wrq->u.essid);
-               break;
+ out:
+       orinoco_unlock(priv, &flags);
+       return err;
+}
 
-       case SIOCSIWNICKN:
-               err = orinoco_ioctl_setnick(dev, &wrq->u.data);
-               if (! err)
-                       changed = 1;
-               break;
+/* Translate scan data returned from the card to a card independant
+ * format that the Wireless Tools will understand - Jean II */
+static inline int orinoco_translate_scan(struct net_device *dev,
+                                        char *buffer,
+                                        char *scan,
+                                        int scan_len)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int                     offset;         /* In the scan data */
+       union hermes_scan_info *atom;
+       int                     atom_len;
+       u16                     capabilities;
+       u16                     channel;
+       struct iw_event         iwe;            /* Temporary buffer */
+       char *                  current_ev = buffer;
+       char *                  end_buf = buffer + IW_SCAN_MAX_DATA;
 
-       case SIOCGIWNICKN:
-               err = orinoco_ioctl_getnick(dev, &wrq->u.data);
+       switch (priv->firmware_type) {
+       case FIRMWARE_TYPE_AGERE:
+               atom_len = sizeof(struct agere_scan_apinfo);
+               offset = 0;
                break;
-
-       case SIOCGIWFREQ:
-               tmp = orinoco_hw_get_freq(priv);
-               if (tmp < 0) {
-                       err = tmp;
-               } else {
-                       wrq->u.freq.m = tmp;
-                       wrq->u.freq.e = 1;
-               }
+       case FIRMWARE_TYPE_SYMBOL:
+               /* Lack of documentation necessitates this hack.
+                * Different firmwares have 68 or 76 byte long atoms.
+                * We try modulo first.  If the length divides by both,
+                * we check what would be the channel in the second
+                * frame for a 68-byte atom.  76-byte atoms have 0 there.
+                * Valid channel cannot be 0.  */
+               if (scan_len % 76)
+                       atom_len = 68;
+               else if (scan_len % 68)
+                       atom_len = 76;
+               else if (scan_len >= 1292 && scan[68] == 0)
+                       atom_len = 76;
+               else
+                       atom_len = 68;
+               offset = 0;
                break;
-
-       case SIOCSIWFREQ:
-               err = orinoco_ioctl_setfreq(dev, &wrq->u.freq);
-               if (! err)
-                       changed = 1;
+       case FIRMWARE_TYPE_INTERSIL:
+               offset = 4;
+               if (priv->has_hostscan)
+                       atom_len = scan[0] + (scan[1] << 8);
+               else
+                       atom_len = offsetof(struct prism2_scan_apinfo, atim);
                break;
+       default:
+               return 0;
+       }
 
-       case SIOCGIWSENS:
-               err = orinoco_ioctl_getsens(dev, &wrq->u.sens);
-               break;
+       /* Check that we got an whole number of atoms */
+       if ((scan_len - offset) % atom_len) {
+               printk(KERN_ERR "%s: Unexpected scan data length %d, "
+                      "atom_len %d, offset %d\n", dev->name, scan_len,
+                      atom_len, offset);
+               return 0;
+       }
 
-       case SIOCSIWSENS:
-               err = orinoco_ioctl_setsens(dev, &wrq->u.sens);
-               if (! err)
-                       changed = 1;
-               break;
+       /* Read the entries one by one */
+       for (; offset + atom_len <= scan_len; offset += atom_len) {
+               /* Get next atom */
+               atom = (union hermes_scan_info *) (scan + offset);
+
+               /* First entry *MUST* be the AP MAC address */
+               iwe.cmd = SIOCGIWAP;
+               iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+               memcpy(iwe.u.ap_addr.sa_data, atom->a.bssid, ETH_ALEN);
+               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+               /* Other entries will be displayed in the order we give them */
+
+               /* Add the ESSID */
+               iwe.u.data.length = le16_to_cpu(atom->a.essid_len);
+               if (iwe.u.data.length > 32)
+                       iwe.u.data.length = 32;
+               iwe.cmd = SIOCGIWESSID;
+               iwe.u.data.flags = 1;
+               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
+
+               /* Add mode */
+               iwe.cmd = SIOCGIWMODE;
+               capabilities = le16_to_cpu(atom->a.capabilities);
+               if (capabilities & 0x3) {
+                       if (capabilities & 0x1)
+                               iwe.u.mode = IW_MODE_MASTER;
+                       else
+                               iwe.u.mode = IW_MODE_ADHOC;
+                       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
+               }
 
-       case SIOCGIWRTS:
-               wrq->u.rts.value = priv->rts_thresh;
-               wrq->u.rts.disabled = (wrq->u.rts.value == 2347);
-               wrq->u.rts.fixed = 1;
-               break;
+               channel = atom->s.channel;
+               if ( (channel >= 1) && (channel <= NUM_CHANNELS) ) {
+                       /* Add frequency */
+                       iwe.cmd = SIOCGIWFREQ;
+                       iwe.u.freq.m = channel_frequency[channel-1] * 100000;
+                       iwe.u.freq.e = 1;
+                       current_ev = iwe_stream_add_event(current_ev, end_buf,
+                                                         &iwe, IW_EV_FREQ_LEN);
+               }
 
-       case SIOCSIWRTS:
-               err = orinoco_ioctl_setrts(dev, &wrq->u.rts);
-               if (! err)
-                       changed = 1;
-               break;
+               /* Add quality statistics */
+               iwe.cmd = IWEVQUAL;
+               iwe.u.qual.updated = 0x10;      /* no link quality */
+               iwe.u.qual.level = (__u8) le16_to_cpu(atom->a.level) - 0x95;
+               iwe.u.qual.noise = (__u8) le16_to_cpu(atom->a.noise) - 0x95;
+               /* Wireless tools prior to 27.pre22 will show link quality
+                * anyway, so we provide a reasonable value. */
+               if (iwe.u.qual.level > iwe.u.qual.noise)
+                       iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
+               else
+                       iwe.u.qual.qual = 0;
+               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
 
-       case SIOCSIWFRAG:
-               err = orinoco_ioctl_setfrag(dev, &wrq->u.frag);
-               if (! err)
-                       changed = 1;
-               break;
+               /* Add encryption capability */
+               iwe.cmd = SIOCGIWENCODE;
+               if (capabilities & 0x10)
+                       iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+               else
+                       iwe.u.data.flags = IW_ENCODE_DISABLED;
+               iwe.u.data.length = 0;
+               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
+
+               /* Bit rate is not available in Lucent/Agere firmwares */
+               if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
+                       char *  current_val = current_ev + IW_EV_LCP_LEN;
+                       int     i;
+                       int     step;
+
+                       if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
+                               step = 2;
+                       else
+                               step = 1;
+
+                       iwe.cmd = SIOCGIWRATE;
+                       /* Those two flags are ignored... */
+                       iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+                       /* Max 10 values */
+                       for (i = 0; i < 10; i += step) {
+                               /* NULL terminated */
+                               if (atom->p.rates[i] == 0x0)
+                                       break;
+                               /* Bit rate given in 500 kb/s units (+ 0x80) */
+                               iwe.u.bitrate.value = ((atom->p.rates[i] & 0x7f) * 500000);
+                               current_val = iwe_stream_add_value(current_ev, current_val,
+                                                                  end_buf, &iwe,
+                                                                  IW_EV_PARAM_LEN);
+                       }
+                       /* Check if we added any event */
+                       if ((current_val - current_ev) > IW_EV_LCP_LEN)
+                               current_ev = current_val;
+               }
 
-       case SIOCGIWFRAG:
-               err = orinoco_ioctl_getfrag(dev, &wrq->u.frag);
-               break;
+               /* The other data in the scan result are not really
+                * interesting, so for now drop it - Jean II */
+       }
+       return current_ev - buffer;
+}
 
-       case SIOCSIWRATE:
-               err = orinoco_ioctl_setrate(dev, &wrq->u.bitrate);
-               if (! err)
-                       changed = 1;
-               break;
+/* Return results of a scan */
+static int orinoco_ioctl_getscan(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *srq,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = 0;
+       unsigned long flags;
 
-       case SIOCGIWRATE:
-               err = orinoco_ioctl_getrate(dev, &wrq->u.bitrate);
-               break;
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
 
-       case SIOCSIWPOWER:
-               err = orinoco_ioctl_setpower(dev, &wrq->u.power);
-               if (! err)
-                       changed = 1;
-               break;
+       /* If no results yet, ask to try again later */
+       if (priv->scan_result == NULL) {
+               if (priv->scan_inprogress)
+                       /* Important note : we don't want to block the caller
+                        * until results are ready for various reasons.
+                        * First, managing wait queues is complex and racy.
+                        * Second, we grab some rtnetlink lock before comming
+                        * here (in dev_ioctl()).
+                        * Third, we generate an Wireless Event, so the
+                        * caller can wait itself on that - Jean II */
+                       err = -EAGAIN;
+               else
+                       /* Client error, no scan results...
+                        * The caller need to restart the scan. */
+                       err = -ENODATA;
+       } else {
+               /* We have some results to push back to user space */
+
+               /* Translate to WE format */
+               srq->length = orinoco_translate_scan(dev, extra,
+                                                    priv->scan_result,
+                                                    priv->scan_len);
+
+               /* Return flags */
+               srq->flags = (__u16) priv->scan_mode;
+
+               /* Results are here, so scan no longer in progress */
+               priv->scan_inprogress = 0;
+
+               /* In any case, Scan results will be cleaned up in the
+                * reset function and when exiting the driver.
+                * The person triggering the scanning may never come to
+                * pick the results, so we need to do it in those places.
+                * Jean II */
+
+#ifdef SCAN_SINGLE_READ
+               /* If you enable this option, only one client (the first
+                * one) will be able to read the result (and only one
+                * time). If there is multiple concurent clients that
+                * want to read scan results, this behavior is not
+                * advisable - Jean II */
+               kfree(priv->scan_result);
+               priv->scan_result = NULL;
+#endif /* SCAN_SINGLE_READ */
+               /* Here, if too much time has elapsed since last scan,
+                * we may want to clean up scan results... - Jean II */
+       }
+         
+       orinoco_unlock(priv, &flags);
+       return err;
+}
 
-       case SIOCGIWPOWER:
-               err = orinoco_ioctl_getpower(dev, &wrq->u.power);
-               break;
+/* Commit handler, called after set operations */
+static int orinoco_ioctl_commit(struct net_device *dev,
+                               struct iw_request_info *info,
+                               void *wrqu,
+                               char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct hermes *hw = &priv->hw;
+       unsigned long flags;
+       int err = 0;
 
-       case SIOCGIWTXPOW:
-               /* The card only supports one tx power, so this is easy */
-               wrq->u.txpower.value = 15; /* dBm */
-               wrq->u.txpower.fixed = 1;
-               wrq->u.txpower.disabled = 0;
-               wrq->u.txpower.flags = IW_TXPOW_DBM;
-               break;
+       if (!priv->open)
+               return 0;
 
-       case SIOCSIWRETRY:
-               err = -EOPNOTSUPP;
-               break;
+       if (priv->broken_disableport) {
+               orinoco_reset(dev);
+               return 0;
+       }
 
-       case SIOCGIWRETRY:
-               err = orinoco_ioctl_getretry(dev, &wrq->u.retry);
-               break;
+       if (orinoco_lock(priv, &flags) != 0)
+               return err;
 
-       case SIOCSIWSPY:
-               err = orinoco_ioctl_setspy(dev, &wrq->u.data);
-               break;
+       err = hermes_disable_port(hw, 0);
+       if (err) {
+               printk(KERN_WARNING "%s: Unable to disable port "
+                      "while reconfiguring card\n", dev->name);
+               priv->broken_disableport = 1;
+               goto out;
+       }
 
-       case SIOCGIWSPY:
-               err = orinoco_ioctl_getspy(dev, &wrq->u.data);
-               break;
+       err = __orinoco_program_rids(dev);
+       if (err) {
+               printk(KERN_WARNING "%s: Unable to reconfigure card\n",
+                      dev->name);
+               goto out;
+       }
 
-       case SIOCGIWPRIV:
-               if (wrq->u.data.pointer) {
-                       struct iw_priv_args privtab[] = {
-                               { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
-                               { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
-                               { SIOCIWFIRSTPRIV + 0x2,
-                                 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-                                 0, "set_port3" },
-                               { SIOCIWFIRSTPRIV + 0x3, 0,
-                                 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-                                 "get_port3" },
-                               { SIOCIWFIRSTPRIV + 0x4,
-                                 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-                                 0, "set_preamble" },
-                               { SIOCIWFIRSTPRIV + 0x5, 0,
-                                 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-                                 "get_preamble" },
-                               { SIOCIWFIRSTPRIV + 0x6,
-                                 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-                                 0, "set_ibssport" },
-                               { SIOCIWFIRSTPRIV + 0x7, 0,
-                                 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-                                 "get_ibssport" },
-                       };
-
-                       wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]);
-                       if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab)))
-                               err = -EFAULT;
-               }
-               break;
-              
-       case SIOCIWFIRSTPRIV + 0x0: /* force_reset */
-       case SIOCIWFIRSTPRIV + 0x1: /* card_reset */
-               if (! capable(CAP_NET_ADMIN)) {
-                       err = -EPERM;
-                       break;
-               }
-               
-               printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
+       err = hermes_enable_port(hw, 0);
+       if (err) {
+               printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
+                      dev->name);
+               goto out;
+       }
 
+ out:
+       if (err) {
+               printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
                schedule_work(&priv->reset_work);
-               break;
-
-       case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */
-               if (! capable(CAP_NET_ADMIN)) {
-                       err = -EPERM;
-                       break;
-               }
-
-               err = orinoco_ioctl_setport3(dev, wrq);
-               if (! err)
-                       changed = 1;
-               break;
+               err = 0;
+       }
 
-       case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */
-               err = orinoco_ioctl_getport3(dev, wrq);
-               break;
+       orinoco_unlock(priv, &flags);
+       return err;
+}
 
-       case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */
-               if (! capable(CAP_NET_ADMIN)) {
-                       err = -EPERM;
-                       break;
-               }
+static const struct iw_priv_args orinoco_privtab[] = {
+       { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
+       { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
+       { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         0, "set_port3" },
+       { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         "get_port3" },
+       { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         0, "set_preamble" },
+       { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         "get_preamble" },
+       { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         0, "set_ibssport" },
+       { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         "get_ibssport" },
+       { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
+         "get_rid" },
+};
 
-               /* 802.11b has recently defined some short preamble.
-                * Basically, the Phy header has been reduced in size.
-                * This increase performance, especially at high rates
-                * (the preamble is transmitted at 1Mb/s), unfortunately
-                * this give compatibility troubles... - Jean II */
-               if(priv->has_preamble) {
-                       int val = *( (int *) wrq->u.name );
-
-                       if (orinoco_lock(priv, &flags) != 0)
-                               return -EBUSY;
-                       if (val)
-                               priv->preamble = 1;
-                       else
-                               priv->preamble = 0;
-                       orinoco_unlock(priv, &flags);
-                       changed = 1;
-               } else
-                       err = -EOPNOTSUPP;
-               break;
 
-       case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */
-               if(priv->has_preamble) {
-                       int *val = (int *)wrq->u.name;
+/*
+ * Structures to export the Wireless Handlers
+ */
 
-                       if (orinoco_lock(priv, &flags) != 0)
-                               return -EBUSY;
-                       *val = priv->preamble;
-                       orinoco_unlock(priv, &flags);
-               } else
-                       err = -EOPNOTSUPP;
-               break;
-       case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */
-               if (! capable(CAP_NET_ADMIN)) {
-                       err = -EPERM;
-                       break;
-               }
+static const iw_handler        orinoco_handler[] = {
+       [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) orinoco_ioctl_commit,
+       [SIOCGIWNAME  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getname,
+       [SIOCSIWFREQ  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfreq,
+       [SIOCGIWFREQ  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfreq,
+       [SIOCSIWMODE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setmode,
+       [SIOCGIWMODE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getmode,
+       [SIOCSIWSENS  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setsens,
+       [SIOCGIWSENS  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getsens,
+       [SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwrange,
+       [SIOCSIWSPY   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setspy,
+       [SIOCGIWSPY   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy,
+       [SIOCSIWAP    -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setwap,
+       [SIOCGIWAP    -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap,
+       [SIOCSIWSCAN  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setscan,
+       [SIOCGIWSCAN  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getscan,
+       [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid,
+       [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid,
+       [SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick,
+       [SIOCGIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getnick,
+       [SIOCSIWRATE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrate,
+       [SIOCGIWRATE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrate,
+       [SIOCSIWRTS   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrts,
+       [SIOCGIWRTS   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrts,
+       [SIOCSIWFRAG  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfrag,
+       [SIOCGIWFRAG  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfrag,
+       [SIOCGIWRETRY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getretry,
+       [SIOCSIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_setiwencode,
+       [SIOCGIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwencode,
+       [SIOCSIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setpower,
+       [SIOCGIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getpower,
+};
 
-               err = orinoco_ioctl_setibssport(dev, wrq);
-               if (! err)
-                       changed = 1;
-               break;
 
-       case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */
-               err = orinoco_ioctl_getibssport(dev, wrq);
-               break;
+/*
+  Added typecasting since we no longer use iwreq_data -- Moustafa
+ */
+static const iw_handler        orinoco_private_handler[] = {
+       [0] (iw_handler) orinoco_ioctl_reset,
+       [1] (iw_handler) orinoco_ioctl_reset,
+       [2] (iw_handler) orinoco_ioctl_setport3,
+       [3] (iw_handler) orinoco_ioctl_getport3,
+       [4] (iw_handler) orinoco_ioctl_setpreamble,
+       [5] (iw_handler) orinoco_ioctl_getpreamble,
+       [6] (iw_handler) orinoco_ioctl_setibssport,
+       [7] (iw_handler) orinoco_ioctl_getibssport,
+       [9] (iw_handler) orinoco_ioctl_getrid,
+};
 
-       default:
-               err = -EOPNOTSUPP;
-       }
-       
-       if (! err && changed && netif_running(dev)) {
-               err = orinoco_reconfigure(dev);
-       }               
+static const struct iw_handler_def orinoco_handler_def = {
+       .num_standard = ARRAY_SIZE(orinoco_handler),
+       .num_private = ARRAY_SIZE(orinoco_private_handler),
+       .num_private_args = ARRAY_SIZE(orinoco_privtab),
+       .standard = orinoco_handler,
+       .private = orinoco_private_handler,
+       .private_args = orinoco_privtab,
+};
 
-       TRACE_EXIT(dev->name);
+static void orinoco_get_drvinfo(struct net_device *dev,
+                               struct ethtool_drvinfo *info)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
 
-       return err;
+       strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
+       strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
+       strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
+       if (dev->class_dev.dev)
+               strncpy(info->bus_info, dev->class_dev.dev->bus_id,
+                       sizeof(info->bus_info) - 1);
+       else
+               snprintf(info->bus_info, sizeof(info->bus_info) - 1,
+                        "PCMCIA %p", priv->hw.iobase);
 }
 
+static struct ethtool_ops orinoco_ethtool_ops = {
+       .get_drvinfo = orinoco_get_drvinfo,
+       .get_link = ethtool_op_get_link,
+};
 
 /********************************************************************/
 /* Debugging                                                        */
index f749b50d10883359c0a9f73596eaab8644c42ae3..2f213a7103fe70cee7ca41ca66f0994928471f85 100644 (file)
@@ -7,7 +7,7 @@
 #ifndef _ORINOCO_H
 #define _ORINOCO_H
 
-#define DRIVER_VERSION "0.14alpha2"
+#define DRIVER_VERSION "0.15rc2"
 
 #include <linux/types.h>
 #include <linux/spinlock.h>
@@ -22,6 +22,8 @@
 
 #define WIRELESS_SPY           // enable iwspy support
 
+#define MAX_SCAN_LEN           4096
+
 #define ORINOCO_MAX_KEY_SIZE   14
 #define ORINOCO_MAX_KEYS       4
 
@@ -30,6 +32,20 @@ struct orinoco_key {
        char data[ORINOCO_MAX_KEY_SIZE];
 } __attribute__ ((packed));
 
+struct header_struct {
+       /* 802.3 */
+       u8 dest[ETH_ALEN];
+       u8 src[ETH_ALEN];
+       u16 len;
+       /* 802.2 */
+       u8 dsap;
+       u8 ssap;
+       u8 ctrl;
+       /* SNAP */
+       u8 oui[3];
+       u16 ethertype;
+} __attribute__ ((packed));
+
 typedef enum {
        FIRMWARE_TYPE_AGERE,
        FIRMWARE_TYPE_INTERSIL,
@@ -48,6 +64,8 @@ struct orinoco_private {
        /* driver state */
        int open;
        u16 last_linkstatus;
+       struct work_struct join_work;
+       struct work_struct wevent_work;
 
        /* Net device stuff */
        struct net_device *ndev;
@@ -74,7 +92,9 @@ struct orinoco_private {
        unsigned int has_pm:1;
        unsigned int has_preamble:1;
        unsigned int has_sensitivity:1;
+       unsigned int has_hostscan:1;
        unsigned int broken_disableport:1;
+       unsigned int broken_monitor:1;
 
        /* Configuration paramaters */
        u32 iw_mode;
@@ -84,6 +104,8 @@ struct orinoco_private {
        int bitratemode;
        char nick[IW_ESSID_MAX_SIZE+1];
        char desired_essid[IW_ESSID_MAX_SIZE+1];
+       char desired_bssid[ETH_ALEN];
+       int bssid_fixed;
        u16 frag_thresh, mwo_robust;
        u16 channel;
        u16 ap_density, rts_thresh;
@@ -98,6 +120,12 @@ struct orinoco_private {
        /* Configuration dependent variables */
        int port_type, createibss;
        int promiscuous, mc_count;
+
+       /* Scanning support */
+       int     scan_inprogress;        /* Scan pending... */
+       u32     scan_mode;              /* Type of scan done */
+       char *  scan_result;            /* Result of previous scan */
+       int     scan_len;               /* Lenght of result */
 };
 
 #ifdef ORINOCO_DEBUG
index 74a8227256aa3ab0dd1e9bb8dc912774a2ee90c9..597c4586d04931e212eb06cb550928a94a6393ae 100644 (file)
@@ -608,6 +608,56 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
        " (David Gibson <hermes@gibson.dropbear.id.au>, "
        "Pavel Roskin <proski@gnu.org>, et al)";
 
+static struct pcmcia_device_id orinoco_cs_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
+       PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001),
+       PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a),
+       PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305),
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613),
+       PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673),
+       PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001),
+       PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300),
+       PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021),
+       PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
+       PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3),
+       PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0),
+       PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5),
+       PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169),
+       PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3),
+       PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9),
+       PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac),
+       PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab),
+       PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3),
+       PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c),
+       PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18),
+       PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3),
+       PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01),
+       PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a),
+       PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1),
+       PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264),
+       PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9),
+       PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26),
+       PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b),
+       PCMCIA_DEVICE_PROD_ID1("Symbol Technologies", 0x3f02b4d6),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids);
+
 static struct pcmcia_driver orinoco_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -615,6 +665,7 @@ static struct pcmcia_driver orinoco_driver = {
        },
        .attach         = orinoco_cs_attach,
        .detach         = orinoco_cs_detach,
+       .id_table       = orinoco_cs_ids,
 };
 
 static int __init
index 4481ec18c5a0885204e20c8656fe959b71afae6a..adc7499136dc1281ba87fd4f4d398263866b073a 100644 (file)
@@ -112,10 +112,10 @@ isl38xx_handle_wakeup(isl38xx_control_block *control_block,
 void
 isl38xx_trigger_device(int asleep, void __iomem *device_base)
 {
-       struct timeval current_time;
        u32 reg, counter = 0;
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
+       struct timeval current_time;
        DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
 #endif
 
@@ -126,11 +126,11 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
                do_gettimeofday(&current_time);
                DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n",
                      current_time.tv_sec, (long)current_time.tv_usec);
-#endif
 
                DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
                      current_time.tv_sec, (long)current_time.tv_usec,
                      readl(device_base + ISL38XX_CTRL_STAT_REG));
+#endif
                udelay(ISL38XX_WRITEIO_DELAY);
 
                reg = readl(device_base + ISL38XX_INT_IDENT_REG);
@@ -148,10 +148,12 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
                                counter++;
                        }
 
+#if VERBOSE > SHOW_ERROR_MESSAGES
                        DEBUG(SHOW_TRACING,
                              "%08li.%08li Device register read %08x\n",
                              current_time.tv_sec, (long)current_time.tv_usec,
                              readl(device_base + ISL38XX_CTRL_STAT_REG));
+#endif
                        udelay(ISL38XX_WRITEIO_DELAY);
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
index 6e5bda56b8f8774b6dbd549f9599fd20654e19b2..31652af52eac240dd093d62a3e2be025a4f39453 100644 (file)
@@ -2904,6 +2904,12 @@ static int write_int(struct file *file, const char __user *buffer, unsigned long
 }
 #endif
 
+static struct pcmcia_device_id ray_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x01a6, 0x0000),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, ray_ids);
+
 static struct pcmcia_driver ray_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -2911,6 +2917,7 @@ static struct pcmcia_driver ray_driver = {
        },
        .attach         = ray_attach,
        .detach         = ray_detach,
+       .id_table       = ray_ids,
 };
 
 static int __init init_ray_cs(void)
index ec8329788e4966b3d1c9647f6efd1f1a02ec4620..89532fd929415bd5226b6ffdb2770ff606887f30 100644 (file)
@@ -4889,6 +4889,15 @@ wavelan_event(event_t            event,          /* The event received */
   return 0;
 }
 
+static struct pcmcia_device_id wavelan_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("AT&T","WaveLAN/PCMCIA", 0xe7c5affd, 0x1bc50975),
+       PCMCIA_DEVICE_PROD_ID12("Digital", "RoamAbout/DS", 0x9999ab35, 0x00d05e06),
+       PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/PCMCIA", 0x23eb9949, 0x1bc50975),
+       PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/PCMCIA", 0x24358cd4, 0x1bc50975),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, wavelan_ids);
+
 static struct pcmcia_driver wavelan_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -4896,6 +4905,7 @@ static struct pcmcia_driver wavelan_driver = {
        },
        .attach         = wavelan_attach,
        .detach         = wavelan_detach,
+       .id_table       = wavelan_ids,
 };
 
 static int __init
index 1433e5aaf1b408883a7b389b19550527ac4418a2..e3a900482d920521db9356fb1251e57d59db0c83 100644 (file)
@@ -2239,6 +2239,12 @@ static int wl3501_event(event_t event, int pri, event_callback_args_t *args)
        return 0;
 }
 
+static struct pcmcia_device_id wl3501_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, wl3501_ids);
+
 static struct pcmcia_driver wl3501_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -2246,6 +2252,7 @@ static struct pcmcia_driver wl3501_driver = {
        },
        .attach         = wl3501_attach,
        .detach         = wl3501_detach,
+       .id_table       = wl3501_ids,
 };
 
 static int __init wl3501_init_module(void)
index 9da925430109c1c698f6c8a93f02434a7441de1e..1c2506535f7e666c6970c0d901d4621d6d3c3bf7 100644 (file)
@@ -786,7 +786,7 @@ static void yellowfin_init_ring(struct net_device *dev)
                skb->dev = dev;         /* Mark as being used by this device. */
                skb_reserve(skb, 2);    /* 16 byte align the IP header. */
                yp->rx_ring[i].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
-                       skb->tail, yp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+                       skb->data, yp->rx_buf_sz, PCI_DMA_FROMDEVICE));
        }
        yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP);
        yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
@@ -1111,7 +1111,7 @@ static int yellowfin_rx(struct net_device *dev)
                pci_dma_sync_single_for_cpu(yp->pci_dev, desc->addr,
                        yp->rx_buf_sz, PCI_DMA_FROMDEVICE);
                desc_status = le32_to_cpu(desc->result_status) >> 16;
-               buf_addr = rx_skb->tail;
+               buf_addr = rx_skb->data;
                data_size = (le32_to_cpu(desc->dbdma_cmd) - 
                        le32_to_cpu(desc->result_status)) & 0xffff;
                frame_status = le16_to_cpu(get_unaligned((s16*)&(buf_addr[data_size - 2])));
@@ -1185,7 +1185,7 @@ static int yellowfin_rx(struct net_device *dev)
                                        break;
                                skb->dev = dev;
                                skb_reserve(skb, 2);    /* 16 byte align the IP header */
-                               eth_copy_and_sum(skb, rx_skb->tail, pkt_len, 0);
+                               eth_copy_and_sum(skb, rx_skb->data, pkt_len, 0);
                                skb_put(skb, pkt_len);
                                pci_dma_sync_single_for_device(yp->pci_dev, desc->addr,
                                                                                           yp->rx_buf_sz,
@@ -1211,7 +1211,7 @@ static int yellowfin_rx(struct net_device *dev)
                        skb->dev = dev; /* Mark as being used by this device. */
                        skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
                        yp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
-                               skb->tail, yp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+                               skb->data, yp->rx_buf_sz, PCI_DMA_FROMDEVICE));
                }
                yp->rx_ring[entry].dbdma_cmd = cpu_to_le32(CMD_STOP);
                yp->rx_ring[entry].result_status = 0;   /* Clear complete bit. */
index 745a14183634feb56d83e51685b10d549eb4e846..531b0731314162e4afea759d8e52ada9bb11a1f8 100644 (file)
@@ -206,7 +206,7 @@ static inline unsigned long fast_get_dcookie(struct dentry * dentry,
  */
 static unsigned long get_exec_dcookie(struct mm_struct * mm)
 {
-       unsigned long cookie = 0;
+       unsigned long cookie = NO_COOKIE;
        struct vm_area_struct * vma;
  
        if (!mm)
@@ -234,35 +234,42 @@ out:
  */
 static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, off_t * offset)
 {
-       unsigned long cookie = 0;
+       unsigned long cookie = NO_COOKIE;
        struct vm_area_struct * vma;
 
        for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
  
-               if (!vma->vm_file)
-                       continue;
-
                if (addr < vma->vm_start || addr >= vma->vm_end)
                        continue;
 
-               cookie = fast_get_dcookie(vma->vm_file->f_dentry,
-                       vma->vm_file->f_vfsmnt);
-               *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start; 
+               if (vma->vm_file) {
+                       cookie = fast_get_dcookie(vma->vm_file->f_dentry,
+                               vma->vm_file->f_vfsmnt);
+                       *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr -
+                               vma->vm_start;
+               } else {
+                       /* must be an anonymous map */
+                       *offset = addr;
+               }
+
                break;
        }
 
+       if (!vma)
+               cookie = INVALID_COOKIE;
+
        return cookie;
 }
 
 
-static unsigned long last_cookie = ~0UL;
+static unsigned long last_cookie = INVALID_COOKIE;
  
 static void add_cpu_switch(int i)
 {
        add_event_entry(ESCAPE_CODE);
        add_event_entry(CPU_SWITCH_CODE);
        add_event_entry(i);
-       last_cookie = ~0UL;
+       last_cookie = INVALID_COOKIE;
 }
 
 static void add_kernel_ctx_switch(unsigned int in_kernel)
@@ -317,7 +324,7 @@ static int add_us_sample(struct mm_struct * mm, struct op_sample * s)
  
        cookie = lookup_dcookie(mm, s->eip, &offset);
  
-       if (!cookie) {
+       if (cookie == INVALID_COOKIE) {
                atomic_inc(&oprofile_stats.sample_lost_no_mapping);
                return 0;
        }
index 442aaad391e08ac7963693111cd5b1bbf20fce8d..0180236305992d390715e640b3805ec21bcd94a5 100644 (file)
@@ -35,6 +35,9 @@ void wake_up_buffer_waiter(void);
 #define TRACE_BEGIN_CODE               8
 #define TRACE_END_CODE                 9
  
+#define INVALID_COOKIE ~0UL
+#define NO_COOKIE 0UL
+
 /* add data to the event buffer */
 void add_event_entry(unsigned long data);
  
index b0d2a73d1d473407ff7b7c25ec7b12f7c8ba55ff..2f2dbef2c3b7bf46df13309aa74e3446c32ab695 100644 (file)
@@ -993,6 +993,7 @@ dino_driver_callback(struct parisc_device *dev)
        bus = pci_scan_bus_parented(&dev->dev, dino_current_bus,
                                    &dino_cfg_ops, NULL);
        if(bus) {
+               pci_bus_add_devices(bus);
                /* This code *depends* on scanning being single threaded
                 * if it isn't, this global bus number count will fail
                 */
index dc838804c0dda41363e0529fffeaf9b0955e210b..7fdd80b7eb479b801cfccdb511ae7730f588abaf 100644 (file)
@@ -1570,6 +1570,8 @@ lba_driver_probe(struct parisc_device *dev)
        lba_bus = lba_dev->hba.hba_bus =
                pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start,
                                cfg_ops, NULL);
+       if (lba_bus)
+               pci_bus_add_devices(lba_bus);
 
        /* This is in lieu of calling pci_assign_unassigned_resources() */
        if (is_pdc_pat()) {
index a3fa8185af2afb70f01d490f54d9169ec75f7243..ff45662c4f7cb412f430e844de86094328413d14 100644 (file)
@@ -373,6 +373,13 @@ int parport_event(event_t event, int priority,
     return 0;
 } /* parport_event */
 
+static struct pcmcia_device_id parport_ids[] = {
+       PCMCIA_DEVICE_FUNC_ID(3),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, parport_ids);
+
 static struct pcmcia_driver parport_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -380,6 +387,8 @@ static struct pcmcia_driver parport_cs_driver = {
        },
        .attach         = parport_attach,
        .detach         = parport_detach,
+       .id_table       = parport_ids,
+
 };
 
 static int __init init_parport_cs(void)
index dbd33605cc107c058e028ab447ca39eb1c814001..fedae89d8f7d5678b7b7126a084b8a49a9939858 100644 (file)
@@ -121,10 +121,13 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus)
                 * If there is an unattached subordinate bus, attach
                 * it and then scan for unattached PCI devices.
                 */
-               if (dev->subordinate && list_empty(&dev->subordinate->node)) {
-                       spin_lock(&pci_bus_lock);
-                       list_add_tail(&dev->subordinate->node, &dev->bus->children);
-                       spin_unlock(&pci_bus_lock);
+               if (dev->subordinate) {
+                      if (list_empty(&dev->subordinate->node)) {
+                              spin_lock(&pci_bus_lock);
+                              list_add_tail(&dev->subordinate->node,
+                                              &dev->bus->children);
+                              spin_unlock(&pci_bus_lock);
+                      }
                        pci_bus_add_devices(dev->subordinate);
 
                        sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge");
index 93c120ddbd395f5ddeddcc3cc5d52bd31a47dcc4..3e632ff8c717116d0dca075a6ec969e2b1acf31f 100644 (file)
@@ -36,9 +36,7 @@ ibmphp-objs           :=      ibmphp_core.o   \
                                ibmphp_hpc.o
 
 acpiphp-objs           :=      acpiphp_core.o  \
-                               acpiphp_glue.o  \
-                               acpiphp_pci.o   \
-                               acpiphp_res.o
+                               acpiphp_glue.o
 
 rpaphp-objs            :=      rpaphp_core.o   \
                                rpaphp_pci.o    \
index d9499874c8a90e84cfa5df3f33732c0b03c5604d..293603e1b7c3b10f64f281087f26a51d32da47a1 100644 (file)
@@ -7,6 +7,8 @@
  * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
  * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
  * Copyright (C) 2002,2003 NEC Corporation
+ * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com)
+ * Copyright (C) 2003-2005 Hewlett Packard
  *
  * All rights reserved.
  *
@@ -52,7 +54,6 @@
 
 struct acpiphp_bridge;
 struct acpiphp_slot;
-struct pci_resource;
 
 /*
  * struct slot - slot information for each *physical* slot
@@ -65,15 +66,6 @@ struct slot {
        struct acpiphp_slot     *acpi_slot;
 };
 
-/*
- * struct pci_resource - describes pci resource (mem, pfmem, io, bus)
- */
-struct pci_resource {
-       struct pci_resource * next;
-       u64 base;
-       u32 length;
-};
-
 /**
  * struct hpp_param - ACPI 2.0 _HPP Hot Plug Parameters
  * @cache_line_size in DWORD
@@ -101,10 +93,6 @@ struct acpiphp_bridge {
        int type;
        int nr_slots;
 
-       u8 seg;
-       u8 bus;
-       u8 sub;
-
        u32 flags;
 
        /* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */
@@ -117,12 +105,6 @@ struct acpiphp_bridge {
        struct hpp_param hpp;
 
        spinlock_t res_lock;
-
-       /* available resources on this bus */
-       struct pci_resource *mem_head;
-       struct pci_resource *p_mem_head;
-       struct pci_resource *io_head;
-       struct pci_resource *bus_head;
 };
 
 
@@ -163,12 +145,6 @@ struct acpiphp_func {
 
        u8              function;       /* pci function# */
        u32             flags;          /* see below */
-
-       /* resources used for this function */
-       struct pci_resource *mem_head;
-       struct pci_resource *p_mem_head;
-       struct pci_resource *io_head;
-       struct pci_resource *bus_head;
 };
 
 /**
@@ -243,25 +219,6 @@ extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot);
 extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
 extern u32 acpiphp_get_address (struct acpiphp_slot *slot);
 
-/* acpiphp_pci.c */
-extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn);
-extern int acpiphp_configure_slot (struct acpiphp_slot *slot);
-extern int acpiphp_configure_function (struct acpiphp_func *func);
-extern void acpiphp_unconfigure_function (struct acpiphp_func *func);
-extern int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge);
-extern int acpiphp_init_func_resource (struct acpiphp_func *func);
-
-/* acpiphp_res.c */
-extern struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size);
-extern struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size);
-extern struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size);
-extern int acpiphp_resource_sort_and_combine (struct pci_resource **head);
-extern struct pci_resource *acpiphp_make_resource (u64 base, u32 length);
-extern void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to);
-extern void acpiphp_free_resource (struct pci_resource **res);
-extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */
-extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */
-
 /* variables */
 extern int acpiphp_debug;
 
index 4539e61a3dc1f07cfb2797b08a0d00c68cfb7ad0..60c4c38047a3a63f4b308d269ddbb520c171a9e2 100644 (file)
@@ -7,6 +7,8 @@
  * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
  * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
  * Copyright (C) 2002,2003 NEC Corporation
+ * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com)
+ * Copyright (C) 2003-2005 Hewlett Packard
  *
  * All rights reserved.
  *
@@ -53,8 +55,8 @@ int acpiphp_debug;
 static int num_slots;
 static struct acpiphp_attention_info *attention_info;
 
-#define DRIVER_VERSION "0.4"
-#define DRIVER_AUTHOR  "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>"
+#define DRIVER_VERSION "0.5"
+#define DRIVER_AUTHOR  "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>, Matthew Wilcox <willy@hp.com>"
 #define DRIVER_DESC    "ACPI Hot Plug PCI Controller Driver"
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
@@ -281,8 +283,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
 /**
  * get_address - get pci address of a slot
  * @hotplug_slot: slot to get status
- * @busdev: pointer to struct pci_busdev (seg, bus, dev)
- *
+ * @value: pointer to struct pci_busdev (seg, bus, dev)
  */
 static int get_address(struct hotplug_slot *hotplug_slot, u32 *value)
 {
index e7f41294f81130bf65f90b6448f1bd4121df04dc..424e7de181aed457457374830ea059c3be1833fa 100644 (file)
@@ -4,6 +4,10 @@
  * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
  * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
  * Copyright (C) 2002,2003 NEC Corporation
+ * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com)
+ * Copyright (C) 2003-2005 Hewlett Packard
+ * Copyright (C) 2005 Rajesh Shah (rajesh.shah@intel.com)
+ * Copyright (C) 2005 Intel Corporation
  *
  * All rights reserved.
  *
  *
  */
 
+/*
+ * Lifetime rules for pci_dev:
+ *  - The one in acpiphp_func has its refcount elevated by pci_get_slot()
+ *    when the driver is loaded or when an insertion event occurs.  It loses
+ *    a refcount when its ejected or the driver unloads.
+ *  - The one in acpiphp_bridge has its refcount elevated by pci_get_slot()
+ *    when the bridge is scanned and it loses a refcount when the bridge
+ *    is removed.
+ */
+
 #include <linux/init.h>
 #include <linux/module.h>
 
@@ -178,21 +192,18 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
 
                bridge->nr_slots++;
 
-               dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n",
-                   slot->bridge->bus, slot->device, slot->sun);
+               dbg("found ACPI PCI Hotplug slot %d at PCI %04x:%02x:%02x\n",
+                               slot->sun, pci_domain_nr(bridge->pci_bus),
+                               bridge->pci_bus->number, slot->device);
        }
 
        newfunc->slot = slot;
        list_add_tail(&newfunc->sibling, &slot->funcs);
 
        /* associate corresponding pci_dev */
-       newfunc->pci_dev = pci_find_slot(bridge->bus,
+       newfunc->pci_dev = pci_get_slot(bridge->pci_bus,
                                         PCI_DEVFN(device, function));
        if (newfunc->pci_dev) {
-               if (acpiphp_init_func_resource(newfunc) < 0) {
-                       kfree(newfunc);
-                       return AE_ERROR;
-               }
                slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
        }
 
@@ -227,62 +238,6 @@ static int detect_ejectable_slots(acpi_handle *bridge_handle)
 }
 
 
-/* decode ACPI _CRS data and convert into our internal resource list
- * TBD: _TRA, etc.
- */
-static acpi_status
-decode_acpi_resource(struct acpi_resource *resource, void *context)
-{
-       struct acpiphp_bridge *bridge = (struct acpiphp_bridge *) context;
-       struct acpi_resource_address64 address;
-       struct pci_resource *res;
-
-       if (resource->id != ACPI_RSTYPE_ADDRESS16 &&
-           resource->id != ACPI_RSTYPE_ADDRESS32 &&
-           resource->id != ACPI_RSTYPE_ADDRESS64)
-               return AE_OK;
-
-       acpi_resource_to_address64(resource, &address);
-
-       if (address.producer_consumer == ACPI_PRODUCER && address.address_length > 0) {
-               dbg("resource type: %d: 0x%llx - 0x%llx\n", address.resource_type,
-                   (unsigned long long)address.min_address_range,
-                   (unsigned long long)address.max_address_range);
-               res = acpiphp_make_resource(address.min_address_range,
-                                   address.address_length);
-               if (!res) {
-                       err("out of memory\n");
-                       return AE_OK;
-               }
-
-               switch (address.resource_type) {
-               case ACPI_MEMORY_RANGE:
-                       if (address.attribute.memory.cache_attribute == ACPI_PREFETCHABLE_MEMORY) {
-                               res->next = bridge->p_mem_head;
-                               bridge->p_mem_head = res;
-                       } else {
-                               res->next = bridge->mem_head;
-                               bridge->mem_head = res;
-                       }
-                       break;
-               case ACPI_IO_RANGE:
-                       res->next = bridge->io_head;
-                       bridge->io_head = res;
-                       break;
-               case ACPI_BUS_NUMBER_RANGE:
-                       res->next = bridge->bus_head;
-                       bridge->bus_head = res;
-                       break;
-               default:
-                       /* invalid type */
-                       kfree(res);
-                       break;
-               }
-       }
-
-       return AE_OK;
-}
-
 /* decode ACPI 2.0 _HPP hot plug parameters */
 static void decode_hpp(struct acpiphp_bridge *bridge)
 {
@@ -346,34 +301,29 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
        /* decode ACPI 2.0 _HPP (hot plug parameters) */
        decode_hpp(bridge);
 
-       /* subtract all resources already allocated */
-       acpiphp_detect_pci_resource(bridge);
-
        /* register all slot objects under this bridge */
        status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
                                     register_slot, bridge, NULL);
 
        /* install notify handler */
-       status = acpi_install_notify_handler(bridge->handle,
+       if (bridge->type != BRIDGE_TYPE_HOST) {
+               status = acpi_install_notify_handler(bridge->handle,
                                             ACPI_SYSTEM_NOTIFY,
                                             handle_hotplug_event_bridge,
                                             bridge);
 
-       if (ACPI_FAILURE(status)) {
-               err("failed to register interrupt notify handler\n");
+               if (ACPI_FAILURE(status)) {
+                       err("failed to register interrupt notify handler\n");
+               }
        }
 
        list_add(&bridge->list, &bridge_list);
-
-       dbg("Bridge resource:\n");
-       acpiphp_dump_resource(bridge);
 }
 
 
 /* allocate and initialize host bridge data structure */
-static void add_host_bridge(acpi_handle *handle, int seg, int bus)
+static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus)
 {
-       acpi_status status;
        struct acpiphp_bridge *bridge;
 
        bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
@@ -384,52 +334,19 @@ static void add_host_bridge(acpi_handle *handle, int seg, int bus)
 
        bridge->type = BRIDGE_TYPE_HOST;
        bridge->handle = handle;
-       bridge->seg = seg;
-       bridge->bus = bus;
 
-       bridge->pci_bus = pci_find_bus(seg, bus);
+       bridge->pci_bus = pci_bus;
 
        spin_lock_init(&bridge->res_lock);
 
-       /* to be overridden when we decode _CRS */
-       bridge->sub = bridge->bus;
-
-       /* decode resources */
-
-       status = acpi_walk_resources(handle, METHOD_NAME__CRS,
-               decode_acpi_resource, bridge);
-
-       if (ACPI_FAILURE(status)) {
-               err("failed to decode bridge resources\n");
-               kfree(bridge);
-               return;
-       }
-
-       acpiphp_resource_sort_and_combine(&bridge->io_head);
-       acpiphp_resource_sort_and_combine(&bridge->mem_head);
-       acpiphp_resource_sort_and_combine(&bridge->p_mem_head);
-       acpiphp_resource_sort_and_combine(&bridge->bus_head);
-
-       dbg("ACPI _CRS resource:\n");
-       acpiphp_dump_resource(bridge);
-
-       if (bridge->bus_head) {
-               bridge->bus = bridge->bus_head->base;
-               bridge->sub = bridge->bus_head->base + bridge->bus_head->length - 1;
-       }
-
        init_bridge_misc(bridge);
 }
 
 
 /* allocate and initialize PCI-to-PCI bridge data structure */
-static void add_p2p_bridge(acpi_handle *handle, int seg, int bus, int dev, int fn)
+static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev)
 {
        struct acpiphp_bridge *bridge;
-       u8 tmp8;
-       u16 tmp16;
-       u64 base64, limit64;
-       u32 base, limit, base32u, limit32u;
 
        bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
        if (bridge == NULL) {
@@ -441,133 +358,22 @@ static void add_p2p_bridge(acpi_handle *handle, int seg, int bus, int dev, int f
 
        bridge->type = BRIDGE_TYPE_P2P;
        bridge->handle = handle;
-       bridge->seg = seg;
-
-       bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn));
-       if (!bridge->pci_dev) {
-               err("Can't get pci_dev\n");
-               kfree(bridge);
-               return;
-       }
 
-       bridge->pci_bus = bridge->pci_dev->subordinate;
+       bridge->pci_dev = pci_dev_get(pci_dev);
+       bridge->pci_bus = pci_dev->subordinate;
        if (!bridge->pci_bus) {
                err("This is not a PCI-to-PCI bridge!\n");
-               kfree(bridge);
-               return;
+               goto err;
        }
 
        spin_lock_init(&bridge->res_lock);
 
-       bridge->bus = bridge->pci_bus->number;
-       bridge->sub = bridge->pci_bus->subordinate;
-
-       /*
-        * decode resources under this P2P bridge
-        */
-
-       /* I/O resources */
-       pci_read_config_byte(bridge->pci_dev, PCI_IO_BASE, &tmp8);
-       base = tmp8;
-       pci_read_config_byte(bridge->pci_dev, PCI_IO_LIMIT, &tmp8);
-       limit = tmp8;
-
-       switch (base & PCI_IO_RANGE_TYPE_MASK) {
-       case PCI_IO_RANGE_TYPE_16:
-               base = (base << 8) & 0xf000;
-               limit = ((limit << 8) & 0xf000) + 0xfff;
-               bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
-               if (!bridge->io_head) {
-                       err("out of memory\n");
-                       kfree(bridge);
-                       return;
-               }
-               dbg("16bit I/O range: %04x-%04x\n",
-                   (u32)bridge->io_head->base,
-                   (u32)(bridge->io_head->base + bridge->io_head->length - 1));
-               break;
-       case PCI_IO_RANGE_TYPE_32:
-               pci_read_config_word(bridge->pci_dev, PCI_IO_BASE_UPPER16, &tmp16);
-               base = ((u32)tmp16 << 16) | ((base << 8) & 0xf000);
-               pci_read_config_word(bridge->pci_dev, PCI_IO_LIMIT_UPPER16, &tmp16);
-               limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff;
-               bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
-               if (!bridge->io_head) {
-                       err("out of memory\n");
-                       kfree(bridge);
-                       return;
-               }
-               dbg("32bit I/O range: %08x-%08x\n",
-                   (u32)bridge->io_head->base,
-                   (u32)(bridge->io_head->base + bridge->io_head->length - 1));
-               break;
-       case 0x0f:
-               dbg("I/O space unsupported\n");
-               break;
-       default:
-               warn("Unknown I/O range type\n");
-       }
-
-       /* Memory resources (mandatory for P2P bridge) */
-       pci_read_config_word(bridge->pci_dev, PCI_MEMORY_BASE, &tmp16);
-       base = (tmp16 & 0xfff0) << 16;
-       pci_read_config_word(bridge->pci_dev, PCI_MEMORY_LIMIT, &tmp16);
-       limit = ((tmp16 & 0xfff0) << 16) | 0xfffff;
-       bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
-       if (!bridge->mem_head) {
-               err("out of memory\n");
-               kfree(bridge);
-               return;
-       }
-       dbg("32bit Memory range: %08x-%08x\n",
-           (u32)bridge->mem_head->base,
-           (u32)(bridge->mem_head->base + bridge->mem_head->length-1));
-
-       /* Prefetchable Memory resources (optional) */
-       pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_BASE, &tmp16);
-       base = tmp16;
-       pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_LIMIT, &tmp16);
-       limit = tmp16;
-
-       switch (base & PCI_MEMORY_RANGE_TYPE_MASK) {
-       case PCI_PREF_RANGE_TYPE_32:
-               base = (base & 0xfff0) << 16;
-               limit = ((limit & 0xfff0) << 16) | 0xfffff;
-               bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
-               if (!bridge->p_mem_head) {
-                       err("out of memory\n");
-                       kfree(bridge);
-                       return;
-               }
-               dbg("32bit Prefetchable memory range: %08x-%08x\n",
-                   (u32)bridge->p_mem_head->base,
-                   (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1));
-               break;
-       case PCI_PREF_RANGE_TYPE_64:
-               pci_read_config_dword(bridge->pci_dev, PCI_PREF_BASE_UPPER32, &base32u);
-               pci_read_config_dword(bridge->pci_dev, PCI_PREF_LIMIT_UPPER32, &limit32u);
-               base64 = ((u64)base32u << 32) | ((base & 0xfff0) << 16);
-               limit64 = (((u64)limit32u << 32) | ((limit & 0xfff0) << 16)) + 0xfffff;
-
-               bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1);
-               if (!bridge->p_mem_head) {
-                       err("out of memory\n");
-                       kfree(bridge);
-                       return;
-               }
-               dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n",
-                   (u32)(bridge->p_mem_head->base >> 32),
-                   (u32)(bridge->p_mem_head->base & 0xffffffff),
-                   (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32),
-                   (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) & 0xffffffff));
-               break;
-       case 0x0f:
-               break;
-       default:
-               warn("Unknown prefetchale memory type\n");
-       }
-
        init_bridge_misc(bridge);
+       return;
+ err:
+       pci_dev_put(pci_dev);
+       kfree(bridge);
+       return;
 }
 
 
@@ -577,14 +383,10 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        acpi_status status;
        acpi_handle dummy_handle;
-       unsigned long *segbus = context;
        unsigned long tmp;
-       int seg, bus, device, function;
+       int device, function;
        struct pci_dev *dev;
-
-       /* get PCI address */
-       seg = (*segbus >> 8) & 0xff;
-       bus = *segbus & 0xff;
+       struct pci_bus *pci_bus = context;
 
        status = acpi_get_handle(handle, "_ADR", &dummy_handle);
        if (ACPI_FAILURE(status))
@@ -599,20 +401,19 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
        device = (tmp >> 16) & 0xffff;
        function = tmp & 0xffff;
 
-       dev = pci_find_slot(bus, PCI_DEVFN(device, function));
+       dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function));
 
-       if (!dev)
-               return AE_OK;
-
-       if (!dev->subordinate)
-               return AE_OK;
+       if (!dev || !dev->subordinate)
+               goto out;
 
        /* check if this bridge has ejectable slots */
        if (detect_ejectable_slots(handle) > 0) {
                dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
-               add_p2p_bridge(handle, seg, bus, device, function);
+               add_p2p_bridge(handle, dev);
        }
 
+ out:
+       pci_dev_put(dev);
        return AE_OK;
 }
 
@@ -624,6 +425,7 @@ static int add_bridge(acpi_handle handle)
        unsigned long tmp;
        int seg, bus;
        acpi_handle dummy_handle;
+       struct pci_bus *pci_bus;
 
        /* if the bridge doesn't have _STA, we assume it is always there */
        status = acpi_get_handle(handle, "_STA", &dummy_handle);
@@ -653,18 +455,22 @@ static int add_bridge(acpi_handle handle)
                bus = 0;
        }
 
+       pci_bus = pci_find_bus(seg, bus);
+       if (!pci_bus) {
+               err("Can't find bus %04x:%02x\n", seg, bus);
+               return 0;
+       }
+
        /* check if this bridge has ejectable slots */
        if (detect_ejectable_slots(handle) > 0) {
                dbg("found PCI host-bus bridge with hot-pluggable slots\n");
-               add_host_bridge(handle, seg, bus);
+               add_host_bridge(handle, pci_bus);
                return 0;
        }
 
-       tmp = seg << 8 | bus;
-
        /* search P2P bridges under this host bridge */
        status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    find_p2p_bridge, &tmp, NULL);
+                                    find_p2p_bridge, pci_bus, NULL);
 
        if (ACPI_FAILURE(status))
                warn("find_p2p_bridge faied (error code = 0x%x)\n",status);
@@ -672,12 +478,205 @@ static int add_bridge(acpi_handle handle)
        return 0;
 }
 
+static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
+{
+       struct list_head *head;
+       list_for_each(head, &bridge_list) {
+               struct acpiphp_bridge *bridge = list_entry(head,
+                                               struct acpiphp_bridge, list);
+               if (bridge->handle == handle)
+                       return bridge;
+       }
+
+       return NULL;
+}
+
+static void cleanup_bridge(struct acpiphp_bridge *bridge)
+{
+       struct list_head *list, *tmp;
+       struct acpiphp_slot *slot;
+       acpi_status status;
+       acpi_handle handle = bridge->handle;
+
+       status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+                                           handle_hotplug_event_bridge);
+       if (ACPI_FAILURE(status))
+               err("failed to remove notify handler\n");
+
+       slot = bridge->slots;
+       while (slot) {
+               struct acpiphp_slot *next = slot->next;
+               list_for_each_safe (list, tmp, &slot->funcs) {
+                       struct acpiphp_func *func;
+                       func = list_entry(list, struct acpiphp_func, sibling);
+                       status = acpi_remove_notify_handler(func->handle,
+                                               ACPI_SYSTEM_NOTIFY,
+                                               handle_hotplug_event_func);
+                       if (ACPI_FAILURE(status))
+                               err("failed to remove notify handler\n");
+                       pci_dev_put(func->pci_dev);
+                       list_del(list);
+                       kfree(func);
+               }
+               kfree(slot);
+               slot = next;
+       }
+
+       pci_dev_put(bridge->pci_dev);
+       list_del(&bridge->list);
+       kfree(bridge);
+}
+
+static acpi_status
+cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+       struct acpiphp_bridge *bridge;
+
+       if (!(bridge = acpiphp_handle_to_bridge(handle)))
+               return AE_OK;
+       cleanup_bridge(bridge);
+       return AE_OK;
+}
 
 static void remove_bridge(acpi_handle handle)
 {
-       /* No-op for now .. */
+       struct acpiphp_bridge *bridge;
+
+       bridge = acpiphp_handle_to_bridge(handle);
+       if (bridge) {
+               cleanup_bridge(bridge);
+       } else {
+               /* clean-up p2p bridges under this host bridge */
+               acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+                               (u32)1, cleanup_p2p_bridge, NULL, NULL);
+       }
+}
+
+static struct pci_dev * get_apic_pci_info(acpi_handle handle)
+{
+       struct acpi_pci_id id;
+       struct pci_bus *bus;
+       struct pci_dev *dev;
+
+       if (ACPI_FAILURE(acpi_get_pci_id(handle, &id)))
+               return NULL;
+
+       bus = pci_find_bus(id.segment, id.bus);
+       if (!bus)
+               return NULL;
+
+       dev = pci_get_slot(bus, PCI_DEVFN(id.device, id.function));
+       if (!dev)
+               return NULL;
+
+       if ((dev->class != PCI_CLASS_SYSTEM_PIC_IOAPIC) &&
+           (dev->class != PCI_CLASS_SYSTEM_PIC_IOXAPIC))
+       {
+               pci_dev_put(dev);
+               return NULL;
+       }
+
+       return dev;
+}
+
+static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
+{
+       acpi_status status;
+       int result = -1;
+       unsigned long gsb;
+       struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+       union acpi_object *obj;
+       void *table;
+
+       status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
+       if (ACPI_SUCCESS(status)) {
+               *gsi_base = (u32)gsb;
+               return 0;
+       }
+
+       status = acpi_evaluate_object(handle, "_MAT", NULL, &buffer);
+       if (ACPI_FAILURE(status) || !buffer.length || !buffer.pointer)
+               return -1;
+
+       obj = buffer.pointer;
+       if (obj->type != ACPI_TYPE_BUFFER)
+               goto out;
+
+       table = obj->buffer.pointer;
+       switch (((acpi_table_entry_header *)table)->type) {
+       case ACPI_MADT_IOSAPIC:
+               *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base;
+               result = 0;
+               break;
+       case ACPI_MADT_IOAPIC:
+               *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base;
+               result = 0;
+               break;
+       default:
+               break;
+       }
+ out:
+       acpi_os_free(buffer.pointer);
+       return result;
+}
+
+static acpi_status
+ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+       acpi_status status;
+       unsigned long sta;
+       acpi_handle tmp;
+       struct pci_dev *pdev;
+       u32 gsi_base;
+       u64 phys_addr;
+
+       /* Evaluate _STA if present */
+       status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+       if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL)
+               return AE_CTRL_DEPTH;
+
+       /* Scan only PCI bus scope */
+       status = acpi_get_handle(handle, "_HID", &tmp);
+       if (ACPI_SUCCESS(status))
+               return AE_CTRL_DEPTH;
+
+       if (get_gsi_base(handle, &gsi_base))
+               return AE_OK;
+
+       pdev = get_apic_pci_info(handle);
+       if (!pdev)
+               return AE_OK;
+
+       if (pci_enable_device(pdev)) {
+               pci_dev_put(pdev);
+               return AE_OK;
+       }
+
+       pci_set_master(pdev);
+
+       if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) {
+               pci_disable_device(pdev);
+               pci_dev_put(pdev);
+               return AE_OK;
+       }
+
+       phys_addr = pci_resource_start(pdev, 0);
+       if (acpi_register_ioapic(handle, phys_addr, gsi_base)) {
+               pci_release_region(pdev, 0);
+               pci_disable_device(pdev);
+               pci_dev_put(pdev);
+               return AE_OK;
+       }
+
+       return AE_OK;
 }
 
+static int acpiphp_configure_ioapics(acpi_handle handle)
+{
+       acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+                           ACPI_UINT32_MAX, ioapic_add, NULL, NULL);
+       return 0;
+}
 
 static int power_on_slot(struct acpiphp_slot *slot)
 {
@@ -719,8 +718,6 @@ static int power_off_slot(struct acpiphp_slot *slot)
        acpi_status status;
        struct acpiphp_func *func;
        struct list_head *l;
-       struct acpi_object_list arg_list;
-       union acpi_object arg;
 
        int retval = 0;
 
@@ -731,7 +728,7 @@ static int power_off_slot(struct acpiphp_slot *slot)
        list_for_each (l, &slot->funcs) {
                func = list_entry(l, struct acpiphp_func, sibling);
 
-               if (func->pci_dev && (func->flags & FUNC_HAS_PS3)) {
+               if (func->flags & FUNC_HAS_PS3) {
                        status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
                        if (ACPI_FAILURE(status)) {
                                warn("%s: _PS3 failed\n", __FUNCTION__);
@@ -742,27 +739,6 @@ static int power_off_slot(struct acpiphp_slot *slot)
                }
        }
 
-       list_for_each (l, &slot->funcs) {
-               func = list_entry(l, struct acpiphp_func, sibling);
-
-               /* We don't want to call _EJ0 on non-existing functions. */
-               if (func->pci_dev && (func->flags & FUNC_HAS_EJ0)) {
-                       /* _EJ0 method take one argument */
-                       arg_list.count = 1;
-                       arg_list.pointer = &arg;
-                       arg.type = ACPI_TYPE_INTEGER;
-                       arg.integer.value = 1;
-
-                       status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
-                       if (ACPI_FAILURE(status)) {
-                               warn("%s: _EJ0 failed\n", __FUNCTION__);
-                               retval = -1;
-                               goto err_exit;
-                       } else
-                               break;
-               }
-       }
-
        /* TBD: evaluate _STA to check if the slot is disabled */
 
        slot->flags &= (~SLOT_POWEREDON);
@@ -782,70 +758,56 @@ static int power_off_slot(struct acpiphp_slot *slot)
  */
 static int enable_device(struct acpiphp_slot *slot)
 {
-       u8 bus;
        struct pci_dev *dev;
-       struct pci_bus *child;
+       struct pci_bus *bus = slot->bridge->pci_bus;
        struct list_head *l;
        struct acpiphp_func *func;
        int retval = 0;
-       int num;
+       int num, max, pass;
 
        if (slot->flags & SLOT_ENABLED)
                goto err_exit;
 
        /* sanity check: dev should be NULL when hot-plugged in */
-       dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
+       dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
        if (dev) {
                /* This case shouldn't happen */
                err("pci_dev structure already exists.\n");
+               pci_dev_put(dev);
                retval = -1;
                goto err_exit;
        }
 
-       /* allocate resources to device */
-       retval = acpiphp_configure_slot(slot);
-       if (retval)
-               goto err_exit;
-
-       /* returned `dev' is the *first function* only! */
-       num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0));
-       if (num)
-               pci_bus_add_devices(slot->bridge->pci_bus);
-       dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
-
-       if (!dev) {
+       num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
+       if (num == 0) {
                err("No new device found\n");
                retval = -1;
                goto err_exit;
        }
 
-       if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
-               pci_read_config_byte(dev, PCI_SECONDARY_BUS, &bus);
-               child = (struct pci_bus*) pci_add_new_bus(dev->bus, dev, bus);
-               pci_do_scan_bus(child);
+       max = bus->secondary;
+       for (pass = 0; pass < 2; pass++) {
+               list_for_each_entry(dev, &bus->devices, bus_list) {
+                       if (PCI_SLOT(dev->devfn) != slot->device)
+                               continue;
+                       if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+                           dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+                               max = pci_scan_bridge(bus, dev, max, pass);
+               }
        }
 
+       pci_bus_assign_resources(bus);
+       pci_bus_add_devices(bus);
+
        /* associate pci_dev to our representation */
        list_for_each (l, &slot->funcs) {
                func = list_entry(l, struct acpiphp_func, sibling);
-
-               func->pci_dev = pci_find_slot(slot->bridge->bus,
-                                             PCI_DEVFN(slot->device,
+               func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
                                                        func->function));
-               if (!func->pci_dev)
-                       continue;
-
-               /* configure device */
-               retval = acpiphp_configure_function(func);
-               if (retval)
-                       goto err_exit;
        }
 
        slot->flags |= SLOT_ENABLED;
 
-       dbg("Available resources:\n");
-       acpiphp_dump_resource(slot->bridge);
-
  err_exit:
        return retval;
 }
@@ -866,9 +828,12 @@ static int disable_device(struct acpiphp_slot *slot)
 
        list_for_each (l, &slot->funcs) {
                func = list_entry(l, struct acpiphp_func, sibling);
+               if (!func->pci_dev)
+                       continue;
 
-               if (func->pci_dev)
-                       acpiphp_unconfigure_function(func);
+               pci_remove_bus_device(func->pci_dev);
+               pci_dev_put(func->pci_dev);
+               func->pci_dev = NULL;
        }
 
        slot->flags &= (~SLOT_ENABLED);
@@ -919,6 +884,39 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot)
        return (unsigned int)sta;
 }
 
+/**
+ * acpiphp_eject_slot - physically eject the slot
+ */
+static int acpiphp_eject_slot(struct acpiphp_slot *slot)
+{
+       acpi_status status;
+       struct acpiphp_func *func;
+       struct list_head *l;
+       struct acpi_object_list arg_list;
+       union acpi_object arg;
+
+       list_for_each (l, &slot->funcs) {
+               func = list_entry(l, struct acpiphp_func, sibling);
+
+               /* We don't want to call _EJ0 on non-existing functions. */
+               if ((func->flags & FUNC_HAS_EJ0)) {
+                       /* _EJ0 method take one argument */
+                       arg_list.count = 1;
+                       arg_list.pointer = &arg;
+                       arg.type = ACPI_TYPE_INTEGER;
+                       arg.integer.value = 1;
+
+                       status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
+                       if (ACPI_FAILURE(status)) {
+                               warn("%s: _EJ0 failed\n", __FUNCTION__);
+                               return -1;
+                       } else
+                               break;
+               }
+       }
+       return 0;
+}
+
 /**
  * acpiphp_check_bridge - re-enumerate devices
  *
@@ -942,6 +940,8 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
                        if (retval) {
                                err("Error occurred in disabling\n");
                                goto err_exit;
+                       } else {
+                               acpiphp_eject_slot(slot);
                        }
                        disabled++;
                } else {
@@ -962,6 +962,144 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
        return retval;
 }
 
+static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge)
+{
+       u16 pci_cmd, pci_bctl;
+       struct pci_dev *cdev;
+
+       /* Program hpp values for this device */
+       if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL ||
+                       (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
+                       (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
+               return;
+       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+                       bridge->hpp.cache_line_size);
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER,
+                       bridge->hpp.latency_timer);
+       pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
+       if (bridge->hpp.enable_SERR)
+               pci_cmd |= PCI_COMMAND_SERR;
+       else
+               pci_cmd &= ~PCI_COMMAND_SERR;
+       if (bridge->hpp.enable_PERR)
+               pci_cmd |= PCI_COMMAND_PARITY;
+       else
+               pci_cmd &= ~PCI_COMMAND_PARITY;
+       pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
+
+       /* Program bridge control value and child devices */
+       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+               pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER,
+                               bridge->hpp.latency_timer);
+               pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl);
+               if (bridge->hpp.enable_SERR)
+                       pci_bctl |= PCI_BRIDGE_CTL_SERR;
+               else
+                       pci_bctl &= ~PCI_BRIDGE_CTL_SERR;
+               if (bridge->hpp.enable_PERR)
+                       pci_bctl |= PCI_BRIDGE_CTL_PARITY;
+               else
+                       pci_bctl &= ~PCI_BRIDGE_CTL_PARITY;
+               pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl);
+               if (dev->subordinate) {
+                       list_for_each_entry(cdev, &dev->subordinate->devices,
+                                       bus_list)
+                               program_hpp(cdev, bridge);
+               }
+       }
+}
+
+static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus)
+{
+       struct acpiphp_bridge bridge;
+       struct pci_dev *dev;
+
+       memset(&bridge, 0, sizeof(bridge));
+       bridge.handle = handle;
+       decode_hpp(&bridge);
+       list_for_each_entry(dev, &bus->devices, bus_list)
+               program_hpp(dev, &bridge);
+
+}
+
+/*
+ * Remove devices for which we could not assign resources, call
+ * arch specific code to fix-up the bus
+ */
+static void acpiphp_sanitize_bus(struct pci_bus *bus)
+{
+       struct pci_dev *dev;
+       int i;
+       unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM;
+
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               for (i=0; i<PCI_BRIDGE_RESOURCES; i++) {
+                       struct resource *res = &dev->resource[i];
+                       if ((res->flags & type_mask) && !res->start &&
+                                       res->end) {
+                               /* Could not assign a required resources
+                                * for this device, remove it */
+                               pci_remove_bus_device(dev);
+                               break;
+                       }
+               }
+       }
+}
+
+/* Program resources in newly inserted bridge */
+static int acpiphp_configure_bridge (acpi_handle handle)
+{
+       struct acpi_pci_id pci_id;
+       struct pci_bus *bus;
+
+       if (ACPI_FAILURE(acpi_get_pci_id(handle, &pci_id))) {
+               err("cannot get PCI domain and bus number for bridge\n");
+               return -EINVAL;
+       }
+       bus = pci_find_bus(pci_id.segment, pci_id.bus);
+       if (!bus) {
+               err("cannot find bus %d:%d\n",
+                               pci_id.segment, pci_id.bus);
+               return -EINVAL;
+       }
+
+       pci_bus_size_bridges(bus);
+       pci_bus_assign_resources(bus);
+       acpiphp_sanitize_bus(bus);
+       acpiphp_set_hpp_values(handle, bus);
+       pci_enable_bridges(bus);
+       acpiphp_configure_ioapics(handle);
+       return 0;
+}
+
+static void handle_bridge_insertion(acpi_handle handle, u32 type)
+{
+       struct acpi_device *device, *pdevice;
+       acpi_handle phandle;
+
+       if ((type != ACPI_NOTIFY_BUS_CHECK) &&
+                       (type != ACPI_NOTIFY_DEVICE_CHECK)) {
+               err("unexpected notification type %d\n", type);
+               return;
+       }
+
+       acpi_get_parent(handle, &phandle);
+       if (acpi_bus_get_device(phandle, &pdevice)) {
+               dbg("no parent device, assuming NULL\n");
+               pdevice = NULL;
+       }
+       if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) {
+               err("cannot add bridge to acpi list\n");
+               return;
+       }
+       if (!acpiphp_configure_bridge(handle) &&
+               !acpi_bus_start(device))
+               add_bridge(handle);
+       else
+               err("cannot configure and start bridge\n");
+
+}
+
 /*
  * ACPI event handlers
  */
@@ -982,8 +1120,19 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
        char objname[64];
        struct acpi_buffer buffer = { .length = sizeof(objname),
                                      .pointer = objname };
+       struct acpi_device *device;
 
-       bridge = (struct acpiphp_bridge *)context;
+       if (acpi_bus_get_device(handle, &device)) {
+               /* This bridge must have just been physically inserted */
+               handle_bridge_insertion(handle, type);
+               return;
+       }
+
+       bridge = acpiphp_handle_to_bridge(handle);
+       if (!bridge) {
+               err("cannot get bridge info\n");
+               return;
+       }
 
        acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
@@ -1031,7 +1180,6 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
        }
 }
 
-
 /**
  * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
  *
@@ -1074,7 +1222,8 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex
        case ACPI_NOTIFY_EJECT_REQUEST:
                /* request device eject */
                dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
-               acpiphp_disable_slot(func->slot);
+               if (!(acpiphp_disable_slot(func->slot)))
+                       acpiphp_eject_slot(func->slot);
                break;
 
        default:
@@ -1083,6 +1232,47 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex
        }
 }
 
+static int is_root_bridge(acpi_handle handle)
+{
+       acpi_status status;
+       struct acpi_device_info *info;
+       struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+       int i;
+
+       status = acpi_get_object_info(handle, &buffer);
+       if (ACPI_SUCCESS(status)) {
+               info = buffer.pointer;
+               if ((info->valid & ACPI_VALID_HID) &&
+                       !strcmp(PCI_ROOT_HID_STRING,
+                                       info->hardware_id.value)) {
+                       acpi_os_free(buffer.pointer);
+                       return 1;
+               }
+               if (info->valid & ACPI_VALID_CID) {
+                       for (i=0; i < info->compatibility_id.count; i++) {
+                               if (!strcmp(PCI_ROOT_HID_STRING,
+                                       info->compatibility_id.id[i].value)) {
+                                       acpi_os_free(buffer.pointer);
+                                       return 1;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+static acpi_status
+find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+       int *count = (int *)context;
+
+       if (is_root_bridge(handle)) {
+               acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+                               handle_hotplug_event_bridge, NULL);
+                       (*count)++;
+       }
+       return AE_OK ;
+}
 
 static struct acpi_pci_driver acpi_pci_hp_driver = {
        .add =          add_bridge,
@@ -1095,15 +1285,15 @@ static struct acpi_pci_driver acpi_pci_hp_driver = {
  */
 int __init acpiphp_glue_init(void)
 {
-       int num;
-
-       if (list_empty(&pci_root_buses))
-               return -1;
+       int num = 0;
 
-       num = acpi_pci_register_driver(&acpi_pci_hp_driver);
+       acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+                       ACPI_UINT32_MAX, find_root_bridges, &num, NULL);
 
        if (num <= 0)
                return -1;
+       else
+               acpi_pci_register_driver(&acpi_pci_hp_driver);
 
        return 0;
 }
@@ -1116,46 +1306,6 @@ int __init acpiphp_glue_init(void)
  */
 void __exit acpiphp_glue_exit(void)
 {
-       struct list_head *l1, *l2, *n1, *n2;
-       struct acpiphp_bridge *bridge;
-       struct acpiphp_slot *slot, *next;
-       struct acpiphp_func *func;
-       acpi_status status;
-
-       list_for_each_safe (l1, n1, &bridge_list) {
-               bridge = (struct acpiphp_bridge *)l1;
-               slot = bridge->slots;
-               while (slot) {
-                       next = slot->next;
-                       list_for_each_safe (l2, n2, &slot->funcs) {
-                               func = list_entry(l2, struct acpiphp_func, sibling);
-                               acpiphp_free_resource(&func->io_head);
-                               acpiphp_free_resource(&func->mem_head);
-                               acpiphp_free_resource(&func->p_mem_head);
-                               acpiphp_free_resource(&func->bus_head);
-                               status = acpi_remove_notify_handler(func->handle,
-                                                                   ACPI_SYSTEM_NOTIFY,
-                                                                   handle_hotplug_event_func);
-                               if (ACPI_FAILURE(status))
-                                       err("failed to remove notify handler\n");
-                               kfree(func);
-                       }
-                       kfree(slot);
-                       slot = next;
-               }
-               status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
-                                                   handle_hotplug_event_bridge);
-               if (ACPI_FAILURE(status))
-                       err("failed to remove notify handler\n");
-
-               acpiphp_free_resource(&bridge->io_head);
-               acpiphp_free_resource(&bridge->mem_head);
-               acpiphp_free_resource(&bridge->p_mem_head);
-               acpiphp_free_resource(&bridge->bus_head);
-
-               kfree(bridge);
-       }
-
        acpi_pci_unregister_driver(&acpi_pci_hp_driver);
 }
 
@@ -1173,11 +1323,14 @@ int __init acpiphp_get_num_slots(void)
 
        list_for_each (node, &bridge_list) {
                bridge = (struct acpiphp_bridge *)node;
-               dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots);
+               dbg("Bus %04x:%02x has %d slot%s\n",
+                               pci_domain_nr(bridge->pci_bus),
+                               bridge->pci_bus->number, bridge->nr_slots,
+                               bridge->nr_slots == 1 ? "" : "s");
                num_slots += bridge->nr_slots;
        }
 
-       dbg("Total %dslots\n", num_slots);
+       dbg("Total %d slots\n", num_slots);
        return num_slots;
 }
 
@@ -1254,7 +1407,6 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot)
        return retval;
 }
 
-
 /**
  * acpiphp_disable_slot - power off slot
  */
@@ -1274,13 +1426,6 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot)
        if (retval)
                goto err_exit;
 
-       acpiphp_resource_sort_and_combine(&slot->bridge->io_head);
-       acpiphp_resource_sort_and_combine(&slot->bridge->mem_head);
-       acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head);
-       acpiphp_resource_sort_and_combine(&slot->bridge->bus_head);
-       dbg("Available resources:\n");
-       acpiphp_dump_resource(slot->bridge);
-
  err_exit:
        up(&slot->crit_sect);
        return retval;
@@ -1293,11 +1438,7 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot)
  */
 u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
 {
-       unsigned int sta;
-
-       sta = get_slot_status(slot);
-
-       return (sta & ACPI_STA_ENABLED) ? 1 : 0;
+       return (slot->flags & SLOT_POWEREDON);
 }
 
 
@@ -1335,9 +1476,10 @@ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)
 u32 acpiphp_get_address(struct acpiphp_slot *slot)
 {
        u32 address;
+       struct pci_bus *pci_bus = slot->bridge->pci_bus;
 
-       address = ((slot->bridge->seg) << 16) |
-                 ((slot->bridge->bus) << 8) |
+       address = (pci_domain_nr(pci_bus) << 16) |
+                 (pci_bus->number << 8) |
                  slot->device;
 
        return address;
diff --git a/drivers/pci/hotplug/acpiphp_pci.c b/drivers/pci/hotplug/acpiphp_pci.c
deleted file mode 100644 (file)
index 54d97c9..0000000
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * ACPI PCI HotPlug PCI configuration space management
- *
- * Copyright (C) 1995,2001 Compaq Computer Corporation
- * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2001,2002 IBM Corp.
- * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
- * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (C) 2002 NEC Corporation
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT.  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.
- *
- * Send feedback to <t-kochi@bq.jp.nec.com>
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/acpi.h>
-#include "../pci.h"
-#include "pci_hotplug.h"
-#include "acpiphp.h"
-
-#define MY_NAME "acpiphp_pci"
-
-
-/* allocate mem/pmem/io resource to a new function */
-static int init_config_space (struct acpiphp_func *func)
-{
-       u32 bar, len;
-       u32 address[] = {
-               PCI_BASE_ADDRESS_0,
-               PCI_BASE_ADDRESS_1,
-               PCI_BASE_ADDRESS_2,
-               PCI_BASE_ADDRESS_3,
-               PCI_BASE_ADDRESS_4,
-               PCI_BASE_ADDRESS_5,
-               0
-       };
-       int count;
-       struct acpiphp_bridge *bridge;
-       struct pci_resource *res;
-       struct pci_bus *pbus;
-       int bus, device, function;
-       unsigned int devfn;
-       u16 tmp;
-
-       bridge = func->slot->bridge;
-       pbus = bridge->pci_bus;
-       bus = bridge->bus;
-       device = func->slot->device;
-       function = func->function;
-       devfn = PCI_DEVFN(device, function);
-
-       for (count = 0; address[count]; count++) {      /* for 6 BARs */
-               pci_bus_write_config_dword(pbus, devfn,
-                                          address[count], 0xFFFFFFFF);
-               pci_bus_read_config_dword(pbus, devfn, address[count], &bar);
-
-               if (!bar)       /* This BAR is not implemented */
-                       continue;
-
-               dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar);
-
-               if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
-                       /* This is IO */
-
-                       len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
-                       len = len & ~(len - 1);
-
-                       dbg("len in IO %x, BAR %d\n", len, count);
-
-                       spin_lock(&bridge->res_lock);
-                       res = acpiphp_get_io_resource(&bridge->io_head, len);
-                       spin_unlock(&bridge->res_lock);
-
-                       if (!res) {
-                               err("cannot allocate requested io for %02x:%02x.%d len %x\n",
-                                   bus, device, function, len);
-                               return -1;
-                       }
-                       pci_bus_write_config_dword(pbus, devfn,
-                                                  address[count],
-                                                  (u32)res->base);
-                       res->next = func->io_head;
-                       func->io_head = res;
-
-               } else {
-                       /* This is Memory */
-                       if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) {
-                               /* pfmem */
-
-                               len = bar & 0xFFFFFFF0;
-                               len = ~len + 1;
-
-                               dbg("len in PFMEM %x, BAR %d\n", len, count);
-
-                               spin_lock(&bridge->res_lock);
-                               res = acpiphp_get_resource(&bridge->p_mem_head, len);
-                               spin_unlock(&bridge->res_lock);
-
-                               if (!res) {
-                                       err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
-                                           bus, device, function, len);
-                                       return -1;
-                               }
-
-                               pci_bus_write_config_dword(pbus, devfn,
-                                                          address[count],
-                                                          (u32)res->base);
-
-                               if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {       /* takes up another dword */
-                                       dbg("inside the pfmem 64 case, count %d\n", count);
-                                       count += 1;
-                                       pci_bus_write_config_dword(pbus, devfn,
-                                                                  address[count],
-                                                                  (u32)(res->base >> 32));
-                               }
-
-                               res->next = func->p_mem_head;
-                               func->p_mem_head = res;
-
-                       } else {
-                               /* regular memory */
-
-                               len = bar & 0xFFFFFFF0;
-                               len = ~len + 1;
-
-                               dbg("len in MEM %x, BAR %d\n", len, count);
-
-                               spin_lock(&bridge->res_lock);
-                               res = acpiphp_get_resource(&bridge->mem_head, len);
-                               spin_unlock(&bridge->res_lock);
-
-                               if (!res) {
-                                       err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
-                                           bus, device, function, len);
-                                       return -1;
-                               }
-
-                               pci_bus_write_config_dword(pbus, devfn,
-                                                          address[count],
-                                                          (u32)res->base);
-
-                               if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
-                                       /* takes up another dword */
-                                       dbg("inside mem 64 case, reg. mem, count %d\n", count);
-                                       count += 1;
-                                       pci_bus_write_config_dword(pbus, devfn,
-                                                                  address[count],
-                                                                  (u32)(res->base >> 32));
-                               }
-
-                               res->next = func->mem_head;
-                               func->mem_head = res;
-
-                       }
-               }
-       }
-
-       /* disable expansion rom */
-       pci_bus_write_config_dword(pbus, devfn, PCI_ROM_ADDRESS, 0x00000000);
-
-       /* set PCI parameters from _HPP */
-       pci_bus_write_config_byte(pbus, devfn, PCI_CACHE_LINE_SIZE,
-                                 bridge->hpp.cache_line_size);
-       pci_bus_write_config_byte(pbus, devfn, PCI_LATENCY_TIMER,
-                                 bridge->hpp.latency_timer);
-
-       pci_bus_read_config_word(pbus, devfn, PCI_COMMAND, &tmp);
-       if (bridge->hpp.enable_SERR)
-               tmp |= PCI_COMMAND_SERR;
-       if (bridge->hpp.enable_PERR)
-               tmp |= PCI_COMMAND_PARITY;
-       pci_bus_write_config_word(pbus, devfn, PCI_COMMAND, tmp);
-
-       return 0;
-}
-
-/* detect_used_resource - subtract resource under dev from bridge */
-static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev)
-{
-       int count;
-
-       dbg("Device %s\n", pci_name(dev));
-
-       for (count = 0; count < DEVICE_COUNT_RESOURCE; count++) {
-               struct pci_resource *res;
-               struct pci_resource **head;
-               unsigned long base = dev->resource[count].start;
-               unsigned long len = dev->resource[count].end - base + 1;
-               unsigned long flags = dev->resource[count].flags;
-
-               if (!flags)
-                       continue;
-
-               dbg("BAR[%d] 0x%lx - 0x%lx (0x%lx)\n", count, base,
-                               base + len - 1, flags);
-
-               if (flags & IORESOURCE_IO) {
-                       head = &bridge->io_head;
-               } else if (flags & IORESOURCE_PREFETCH) {
-                       head = &bridge->p_mem_head;
-               } else {
-                       head = &bridge->mem_head;
-               }
-
-               spin_lock(&bridge->res_lock);
-               res = acpiphp_get_resource_with_base(head, base, len);
-               spin_unlock(&bridge->res_lock);
-               if (res)
-                       kfree(res);
-       }
-
-       return 0;
-}
-
-
-/**
- * acpiphp_detect_pci_resource - detect resources under bridge
- * @bridge: detect all resources already used under this bridge
- *
- * collect all resources already allocated for all devices under a bridge.
- */
-int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge)
-{
-       struct list_head *l;
-       struct pci_dev *dev;
-
-       list_for_each (l, &bridge->pci_bus->devices) {
-               dev = pci_dev_b(l);
-               detect_used_resource(bridge, dev);
-       }
-
-       return 0;
-}
-
-
-/**
- * acpiphp_init_slot_resource - gather resource usage information of a slot
- * @slot: ACPI slot object to be checked, should have valid pci_dev member
- *
- * TBD: PCI-to-PCI bridge case
- *      use pci_dev->resource[]
- */
-int acpiphp_init_func_resource (struct acpiphp_func *func)
-{
-       u64 base;
-       u32 bar, len;
-       u32 address[] = {
-               PCI_BASE_ADDRESS_0,
-               PCI_BASE_ADDRESS_1,
-               PCI_BASE_ADDRESS_2,
-               PCI_BASE_ADDRESS_3,
-               PCI_BASE_ADDRESS_4,
-               PCI_BASE_ADDRESS_5,
-               0
-       };
-       int count;
-       struct pci_resource *res;
-       struct pci_dev *dev;
-
-       dev = func->pci_dev;
-       dbg("Hot-pluggable device %s\n", pci_name(dev));
-
-       for (count = 0; address[count]; count++) {      /* for 6 BARs */
-               pci_read_config_dword(dev, address[count], &bar);
-
-               if (!bar)       /* This BAR is not implemented */
-                       continue;
-
-               pci_write_config_dword(dev, address[count], 0xFFFFFFFF);
-               pci_read_config_dword(dev, address[count], &len);
-
-               if (len & PCI_BASE_ADDRESS_SPACE_IO) {
-                       /* This is IO */
-                       base = bar & 0xFFFFFFFC;
-                       len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
-                       len = len & ~(len - 1);
-
-                       dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
-
-                       res = acpiphp_make_resource(base, len);
-                       if (!res)
-                               goto no_memory;
-
-                       res->next = func->io_head;
-                       func->io_head = res;
-
-               } else {
-                       /* This is Memory */
-                       base = bar & 0xFFFFFFF0;
-                       if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) {
-                               /* pfmem */
-
-                               len &= 0xFFFFFFF0;
-                               len = ~len + 1;
-
-                               if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {       /* takes up another dword */
-                                       dbg("prefetch mem 64\n");
-                                       count += 1;
-                               }
-                               dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
-                               res = acpiphp_make_resource(base, len);
-                               if (!res)
-                                       goto no_memory;
-
-                               res->next = func->p_mem_head;
-                               func->p_mem_head = res;
-
-                       } else {
-                               /* regular memory */
-
-                               len &= 0xFFFFFFF0;
-                               len = ~len + 1;
-
-                               if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
-                                       /* takes up another dword */
-                                       dbg("mem 64\n");
-                                       count += 1;
-                               }
-                               dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
-                               res = acpiphp_make_resource(base, len);
-                               if (!res)
-                                       goto no_memory;
-
-                               res->next = func->mem_head;
-                               func->mem_head = res;
-
-                       }
-               }
-
-               pci_write_config_dword(dev, address[count], bar);
-       }
-#if 1
-       acpiphp_dump_func_resource(func);
-#endif
-
-       return 0;
-
- no_memory:
-       err("out of memory\n");
-       acpiphp_free_resource(&func->io_head);
-       acpiphp_free_resource(&func->mem_head);
-       acpiphp_free_resource(&func->p_mem_head);
-
-       return -1;
-}
-
-
-/**
- * acpiphp_configure_slot - allocate PCI resources
- * @slot: slot to be configured
- *
- * initializes a PCI functions on a device inserted
- * into the slot
- *
- */
-int acpiphp_configure_slot (struct acpiphp_slot *slot)
-{
-       struct acpiphp_func *func;
-       struct list_head *l;
-       u8 hdr;
-       u32 dvid;
-       int retval = 0;
-       int is_multi = 0;
-
-       pci_bus_read_config_byte(slot->bridge->pci_bus,
-                                PCI_DEVFN(slot->device, 0),
-                                PCI_HEADER_TYPE, &hdr);
-
-       if (hdr & 0x80)
-               is_multi = 1;
-
-       list_for_each (l, &slot->funcs) {
-               func = list_entry(l, struct acpiphp_func, sibling);
-               if (is_multi || func->function == 0) {
-                       pci_bus_read_config_dword(slot->bridge->pci_bus,
-                                                 PCI_DEVFN(slot->device,
-                                                           func->function),
-                                                 PCI_VENDOR_ID, &dvid);
-                       if (dvid != 0xffffffff) {
-                               retval = init_config_space(func);
-                               if (retval)
-                                       break;
-                       }
-               }
-       }
-
-       return retval;
-}
-
-/**
- * acpiphp_configure_function - configure PCI function
- * @func: function to be configured
- *
- * initializes a PCI functions on a device inserted
- * into the slot
- *
- */
-int acpiphp_configure_function (struct acpiphp_func *func)
-{
-       /* all handled by the pci core now */
-       return 0;
-}
-
-/**
- * acpiphp_unconfigure_function - unconfigure PCI function
- * @func: function to be unconfigured
- *
- */
-void acpiphp_unconfigure_function (struct acpiphp_func *func)
-{
-       struct acpiphp_bridge *bridge;
-
-       /* if pci_dev is NULL, ignore it */
-       if (!func->pci_dev)
-               return;
-
-       pci_remove_bus_device(func->pci_dev);
-
-       /* free all resources */
-       bridge = func->slot->bridge;
-
-       spin_lock(&bridge->res_lock);
-       acpiphp_move_resource(&func->io_head, &bridge->io_head);
-       acpiphp_move_resource(&func->mem_head, &bridge->mem_head);
-       acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head);
-       acpiphp_move_resource(&func->bus_head, &bridge->bus_head);
-       spin_unlock(&bridge->res_lock);
-}
diff --git a/drivers/pci/hotplug/acpiphp_res.c b/drivers/pci/hotplug/acpiphp_res.c
deleted file mode 100644 (file)
index f54b1fa..0000000
+++ /dev/null
@@ -1,700 +0,0 @@
-/*
- * ACPI PCI HotPlug Utility functions
- *
- * Copyright (C) 1995,2001 Compaq Computer Corporation
- * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2001 IBM Corp.
- * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
- * Copyright (C) 2002 NEC Corporation
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT.  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.
- *
- * Send feedback to <gregkh@us.ibm.com>, <t-kochi@bq.jp.nec.com>
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/sysctl.h>
-#include <linux/pci.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-
-#include <linux/ioctl.h>
-#include <linux/fcntl.h>
-
-#include <linux/list.h>
-
-#include "pci_hotplug.h"
-#include "acpiphp.h"
-
-#define MY_NAME "acpiphp_res"
-
-
-/*
- * sort_by_size - sort nodes by their length, smallest first
- */
-static int sort_by_size(struct pci_resource **head)
-{
-       struct pci_resource *current_res;
-       struct pci_resource *next_res;
-       int out_of_order = 1;
-
-       if (!(*head))
-               return 1;
-
-       if (!((*head)->next))
-               return 0;
-
-       while (out_of_order) {
-               out_of_order = 0;
-
-               /* Special case for swapping list head */
-               if (((*head)->next) &&
-                   ((*head)->length > (*head)->next->length)) {
-                       out_of_order++;
-                       current_res = *head;
-                       *head = (*head)->next;
-                       current_res->next = (*head)->next;
-                       (*head)->next = current_res;
-               }
-
-               current_res = *head;
-
-               while (current_res->next && current_res->next->next) {
-                       if (current_res->next->length > current_res->next->next->length) {
-                               out_of_order++;
-                               next_res = current_res->next;
-                               current_res->next = current_res->next->next;
-                               current_res = current_res->next;
-                               next_res->next = current_res->next;
-                               current_res->next = next_res;
-                       } else
-                               current_res = current_res->next;
-               }
-       }  /* End of out_of_order loop */
-
-       return 0;
-}
-
-#if 0
-/*
- * sort_by_max_size - sort nodes by their length, largest first
- */
-static int sort_by_max_size(struct pci_resource **head)
-{
-       struct pci_resource *current_res;
-       struct pci_resource *next_res;
-       int out_of_order = 1;
-
-       if (!(*head))
-               return 1;
-
-       if (!((*head)->next))
-               return 0;
-
-       while (out_of_order) {
-               out_of_order = 0;
-
-               /* Special case for swapping list head */
-               if (((*head)->next) &&
-                   ((*head)->length < (*head)->next->length)) {
-                       out_of_order++;
-                       current_res = *head;
-                       *head = (*head)->next;
-                       current_res->next = (*head)->next;
-                       (*head)->next = current_res;
-               }
-
-               current_res = *head;
-
-               while (current_res->next && current_res->next->next) {
-                       if (current_res->next->length < current_res->next->next->length) {
-                               out_of_order++;
-                               next_res = current_res->next;
-                               current_res->next = current_res->next->next;
-                               current_res = current_res->next;
-                               next_res->next = current_res->next;
-                               current_res->next = next_res;
-                       } else
-                               current_res = current_res->next;
-               }
-       }  /* End of out_of_order loop */
-
-       return 0;
-}
-#endif
-
-/**
- * get_io_resource - get resource for I/O ports
- *
- * this function sorts the resource list by size and then
- * returns the first node of "size" length that is not in the
- * ISA aliasing window.  If it finds a node larger than "size"
- * it will split it up.
- *
- * size must be a power of two.
- *
- * difference from get_resource is handling of ISA aliasing space.
- *
- */
-struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size)
-{
-       struct pci_resource *prevnode;
-       struct pci_resource *node;
-       struct pci_resource *split_node;
-       u64 temp_qword;
-
-       if (!(*head))
-               return NULL;
-
-       if (acpiphp_resource_sort_and_combine(head))
-               return NULL;
-
-       if (sort_by_size(head))
-               return NULL;
-
-       for (node = *head; node; node = node->next) {
-               if (node->length < size)
-                       continue;
-
-               if (node->base & (size - 1)) {
-                       /* this one isn't base aligned properly
-                          so we'll make a new entry and split it up */
-                       temp_qword = (node->base | (size-1)) + 1;
-
-                       /* Short circuit if adjusted size is too small */
-                       if ((node->length - (temp_qword - node->base)) < size)
-                               continue;
-
-                       split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
-
-                       if (!split_node)
-                               return NULL;
-
-                       node->base = temp_qword;
-                       node->length -= split_node->length;
-
-                       /* Put it in the list */
-                       split_node->next = node->next;
-                       node->next = split_node;
-               } /* End of non-aligned base */
-
-               /* Don't need to check if too small since we already did */
-               if (node->length > size) {
-                       /* this one is longer than we need
-                          so we'll make a new entry and split it up */
-                       split_node = acpiphp_make_resource(node->base + size, node->length - size);
-
-                       if (!split_node)
-                               return NULL;
-
-                       node->length = size;
-
-                       /* Put it in the list */
-                       split_node->next = node->next;
-                       node->next = split_node;
-               }  /* End of too big on top end */
-
-               /* For IO make sure it's not in the ISA aliasing space */
-               if ((node->base & 0x300L) && !(node->base & 0xfffff000))
-                       continue;
-
-               /* If we got here, then it is the right size
-                  Now take it out of the list */
-               if (*head == node) {
-                       *head = node->next;
-               } else {
-                       prevnode = *head;
-                       while (prevnode->next != node)
-                               prevnode = prevnode->next;
-
-                       prevnode->next = node->next;
-               }
-               node->next = NULL;
-               /* Stop looping */
-               break;
-       }
-
-       return node;
-}
-
-
-#if 0
-/**
- * get_max_resource - get the largest resource
- *
- * Gets the largest node that is at least "size" big from the
- * list pointed to by head.  It aligns the node on top and bottom
- * to "size" alignment before returning it.
- */
-static struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size)
-{
-       struct pci_resource *max;
-       struct pci_resource *temp;
-       struct pci_resource *split_node;
-       u64 temp_qword;
-
-       if (!(*head))
-               return NULL;
-
-       if (acpiphp_resource_sort_and_combine(head))
-               return NULL;
-
-       if (sort_by_max_size(head))
-               return NULL;
-
-       for (max = *head;max; max = max->next) {
-
-               /* If not big enough we could probably just bail,
-                  instead we'll continue to the next. */
-               if (max->length < size)
-                       continue;
-
-               if (max->base & (size - 1)) {
-                       /* this one isn't base aligned properly
-                          so we'll make a new entry and split it up */
-                       temp_qword = (max->base | (size-1)) + 1;
-
-                       /* Short circuit if adjusted size is too small */
-                       if ((max->length - (temp_qword - max->base)) < size)
-                               continue;
-
-                       split_node = acpiphp_make_resource(max->base, temp_qword - max->base);
-
-                       if (!split_node)
-                               return NULL;
-
-                       max->base = temp_qword;
-                       max->length -= split_node->length;
-
-                       /* Put it next in the list */
-                       split_node->next = max->next;
-                       max->next = split_node;
-               }
-
-               if ((max->base + max->length) & (size - 1)) {
-                       /* this one isn't end aligned properly at the top
-                          so we'll make a new entry and split it up */
-                       temp_qword = ((max->base + max->length) & ~(size - 1));
-
-                       split_node = acpiphp_make_resource(temp_qword,
-                                                          max->length + max->base - temp_qword);
-
-                       if (!split_node)
-                               return NULL;
-
-                       max->length -= split_node->length;
-
-                       /* Put it in the list */
-                       split_node->next = max->next;
-                       max->next = split_node;
-               }
-
-               /* Make sure it didn't shrink too much when we aligned it */
-               if (max->length < size)
-                       continue;
-
-               /* Now take it out of the list */
-               temp = (struct pci_resource*) *head;
-               if (temp == max) {
-                       *head = max->next;
-               } else {
-                       while (temp && temp->next != max) {
-                               temp = temp->next;
-                       }
-
-                       temp->next = max->next;
-               }
-
-               max->next = NULL;
-               return max;
-       }
-
-       /* If we get here, we couldn't find one */
-       return NULL;
-}
-#endif
-
-/**
- * get_resource - get resource (mem, pfmem)
- *
- * this function sorts the resource list by size and then
- * returns the first node of "size" length.  If it finds a node
- * larger than "size" it will split it up.
- *
- * size must be a power of two.
- *
- */
-struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size)
-{
-       struct pci_resource *prevnode;
-       struct pci_resource *node;
-       struct pci_resource *split_node;
-       u64 temp_qword;
-
-       if (!(*head))
-               return NULL;
-
-       if (acpiphp_resource_sort_and_combine(head))
-               return NULL;
-
-       if (sort_by_size(head))
-               return NULL;
-
-       for (node = *head; node; node = node->next) {
-               dbg("%s: req_size =%x node=%p, base=%x, length=%x\n",
-                   __FUNCTION__, size, node, (u32)node->base, node->length);
-               if (node->length < size)
-                       continue;
-
-               if (node->base & (size - 1)) {
-                       dbg("%s: not aligned\n", __FUNCTION__);
-                       /* this one isn't base aligned properly
-                          so we'll make a new entry and split it up */
-                       temp_qword = (node->base | (size-1)) + 1;
-
-                       /* Short circuit if adjusted size is too small */
-                       if ((node->length - (temp_qword - node->base)) < size)
-                               continue;
-
-                       split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
-
-                       if (!split_node)
-                               return NULL;
-
-                       node->base = temp_qword;
-                       node->length -= split_node->length;
-
-                       /* Put it in the list */
-                       split_node->next = node->next;
-                       node->next = split_node;
-               } /* End of non-aligned base */
-
-               /* Don't need to check if too small since we already did */
-               if (node->length > size) {
-                       dbg("%s: too big\n", __FUNCTION__);
-                       /* this one is longer than we need
-                          so we'll make a new entry and split it up */
-                       split_node = acpiphp_make_resource(node->base + size, node->length - size);
-
-                       if (!split_node)
-                               return NULL;
-
-                       node->length = size;
-
-                       /* Put it in the list */
-                       split_node->next = node->next;
-                       node->next = split_node;
-               }  /* End of too big on top end */
-
-               dbg("%s: got one!!!\n", __FUNCTION__);
-               /* If we got here, then it is the right size
-                  Now take it out of the list */
-               if (*head == node) {
-                       *head = node->next;
-               } else {
-                       prevnode = *head;
-                       while (prevnode->next != node)
-                               prevnode = prevnode->next;
-
-                       prevnode->next = node->next;
-               }
-               node->next = NULL;
-               /* Stop looping */
-               break;
-       }
-       return node;
-}
-
-/**
- * get_resource_with_base - get resource with specific base address
- *
- * this function
- * returns the first node of "size" length located at specified base address.
- * If it finds a node larger than "size" it will split it up.
- *
- * size must be a power of two.
- *
- */
-struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size)
-{
-       struct pci_resource *prevnode;
-       struct pci_resource *node;
-       struct pci_resource *split_node;
-       u64 temp_qword;
-
-       if (!(*head))
-               return NULL;
-
-       if (acpiphp_resource_sort_and_combine(head))
-               return NULL;
-
-       for (node = *head; node; node = node->next) {
-               dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
-                   (u32)base, size, node, (u32)node->base, node->length);
-               if (node->base > base)
-                       continue;
-
-               if ((node->base + node->length) < (base + size))
-                       continue;
-
-               if (node->base < base) {
-                       dbg(": split 1\n");
-                       /* this one isn't base aligned properly
-                          so we'll make a new entry and split it up */
-                       temp_qword = base;
-
-                       /* Short circuit if adjusted size is too small */
-                       if ((node->length - (temp_qword - node->base)) < size)
-                               continue;
-
-                       split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
-
-                       if (!split_node)
-                               return NULL;
-
-                       node->base = temp_qword;
-                       node->length -= split_node->length;
-
-                       /* Put it in the list */
-                       split_node->next = node->next;
-                       node->next = split_node;
-               }
-
-               dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
-                   (u32)base, size, node, (u32)node->base, node->length);
-
-               /* Don't need to check if too small since we already did */
-               if (node->length > size) {
-                       dbg(": split 2\n");
-                       /* this one is longer than we need
-                          so we'll make a new entry and split it up */
-                       split_node = acpiphp_make_resource(node->base + size, node->length - size);
-
-                       if (!split_node)
-                               return NULL;
-
-                       node->length = size;
-
-                       /* Put it in the list */
-                       split_node->next = node->next;
-                       node->next = split_node;
-               }  /* End of too big on top end */
-
-               dbg(": got one!!!\n");
-               /* If we got here, then it is the right size
-                  Now take it out of the list */
-               if (*head == node) {
-                       *head = node->next;
-               } else {
-                       prevnode = *head;
-                       while (prevnode->next != node)
-                               prevnode = prevnode->next;
-
-                       prevnode->next = node->next;
-               }
-               node->next = NULL;
-               /* Stop looping */
-               break;
-       }
-       return node;
-}
-
-
-/**
- * acpiphp_resource_sort_and_combine
- *
- * Sorts all of the nodes in the list in ascending order by
- * their base addresses.  Also does garbage collection by
- * combining adjacent nodes.
- *
- * returns 0 if success
- */
-int acpiphp_resource_sort_and_combine (struct pci_resource **head)
-{
-       struct pci_resource *node1;
-       struct pci_resource *node2;
-       int out_of_order = 1;
-
-       if (!(*head))
-               return 1;
-
-       dbg("*head->next = %p\n",(*head)->next);
-
-       if (!(*head)->next)
-               return 0;       /* only one item on the list, already sorted! */
-
-       dbg("*head->base = 0x%x\n",(u32)(*head)->base);
-       dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base);
-       while (out_of_order) {
-               out_of_order = 0;
-
-               /* Special case for swapping list head */
-               if (((*head)->next) &&
-                   ((*head)->base > (*head)->next->base)) {
-                       node1 = *head;
-                       (*head) = (*head)->next;
-                       node1->next = (*head)->next;
-                       (*head)->next = node1;
-                       out_of_order++;
-               }
-
-               node1 = (*head);
-
-               while (node1->next && node1->next->next) {
-                       if (node1->next->base > node1->next->next->base) {
-                               out_of_order++;
-                               node2 = node1->next;
-                               node1->next = node1->next->next;
-                               node1 = node1->next;
-                               node2->next = node1->next;
-                               node1->next = node2;
-                       } else
-                               node1 = node1->next;
-               }
-       }  /* End of out_of_order loop */
-
-       node1 = *head;
-
-       while (node1 && node1->next) {
-               if ((node1->base + node1->length) == node1->next->base) {
-                       /* Combine */
-                       dbg("8..\n");
-                       node1->length += node1->next->length;
-                       node2 = node1->next;
-                       node1->next = node1->next->next;
-                       kfree(node2);
-               } else
-                       node1 = node1->next;
-       }
-
-       return 0;
-}
-
-
-/**
- * acpiphp_make_resource - make resource structure
- * @base: base address of a resource
- * @length: length of a resource
- */
-struct pci_resource *acpiphp_make_resource (u64 base, u32 length)
-{
-       struct pci_resource *res;
-
-       res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-       if (res) {
-               memset(res, 0, sizeof(struct pci_resource));
-               res->base = base;
-               res->length = length;
-       }
-
-       return res;
-}
-
-
-/**
- * acpiphp_move_resource - move linked resources from one to another
- * @from: head of linked resource list
- * @to: head of linked resource list
- */
-void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to)
-{
-       struct pci_resource *tmp;
-
-       while (*from) {
-               tmp = (*from)->next;
-               (*from)->next = *to;
-               *to = *from;
-               *from = tmp;
-       }
-
-       /* *from = NULL is guaranteed */
-}
-
-
-/**
- * acpiphp_free_resource - free all linked resources
- * @res: head of linked resource list
- */
-void acpiphp_free_resource (struct pci_resource **res)
-{
-       struct pci_resource *tmp;
-
-       while (*res) {
-               tmp = (*res)->next;
-               kfree(*res);
-               *res = tmp;
-       }
-
-       /* *res = NULL is guaranteed */
-}
-
-
-/* debug support functions;  will go away sometime :) */
-static void dump_resource(struct pci_resource *head)
-{
-       struct pci_resource *p;
-       int cnt;
-
-       p = head;
-       cnt = 0;
-
-       while (p) {
-               dbg("[%02d] %08x - %08x\n",
-                   cnt++, (u32)p->base, (u32)p->base + p->length - 1);
-               p = p->next;
-       }
-}
-
-void acpiphp_dump_resource(struct acpiphp_bridge *bridge)
-{
-       dbg("I/O resource:\n");
-       dump_resource(bridge->io_head);
-       dbg("MEM resource:\n");
-       dump_resource(bridge->mem_head);
-       dbg("PMEM resource:\n");
-       dump_resource(bridge->p_mem_head);
-       dbg("BUS resource:\n");
-       dump_resource(bridge->bus_head);
-}
-
-void acpiphp_dump_func_resource(struct acpiphp_func *func)
-{
-       dbg("I/O resource:\n");
-       dump_resource(func->io_head);
-       dbg("MEM resource:\n");
-       dump_resource(func->mem_head);
-       dbg("PMEM resource:\n");
-       dump_resource(func->p_mem_head);
-       dbg("BUS resource:\n");
-       dump_resource(func->bus_head);
-}
index afbccfa5217d7226b934cbcc4ca63ca793fde5be..8c6d3987d461361973a460efbd1cd982548b3051 100644 (file)
@@ -60,6 +60,7 @@ static void __iomem *smbios_start;
 static void __iomem *cpqhp_rom_start;
 static int power_mode;
 static int debug;
+static int initialized;
 
 #define DRIVER_VERSION "0.9.8"
 #define DRIVER_AUTHOR  "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>"
@@ -1271,7 +1272,6 @@ static int one_time_init(void)
 {
        int loop;
        int retval = 0;
-       static int initialized = 0;
 
        if (initialized)
                return 0;
@@ -1441,7 +1441,8 @@ static void __exit unload_cpqphpd(void)
        }
 
        // Stop the notification mechanism
-       cpqhp_event_stop_thread();
+       if (initialized)
+               cpqhp_event_stop_thread();
 
        //unmap the rom address
        if (cpqhp_rom_start)
index 30206ac43c443c68eb6d89c8fc3146a6f0f307d7..b5ab9aa6ff7c8703f842901e02497bc05dd3100d 100644 (file)
@@ -28,10 +28,10 @@ static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
 static kmem_cache_t* msi_cachep;
 
 static int pci_msi_enable = 1;
-static int last_alloc_vector = 0;
-static int nr_released_vectors = 0;
+static int last_alloc_vector;
+static int nr_released_vectors;
 static int nr_reserved_vectors = NR_HP_RESERVED_VECTORS;
-static int nr_msix_devices = 0;
+static int nr_msix_devices;
 
 #ifndef CONFIG_X86_IO_APIC
 int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
@@ -170,44 +170,30 @@ static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector)
        return 0;       /* never anything pending */
 }
 
-static void release_msi(unsigned int vector);
-static void shutdown_msi_irq(unsigned int vector)
-{
-       release_msi(vector);
-}
-
-#define shutdown_msi_irq_wo_maskbit    shutdown_msi_irq
-static void enable_msi_irq_wo_maskbit(unsigned int vector) {}
-static void disable_msi_irq_wo_maskbit(unsigned int vector) {}
-static void ack_msi_irq_wo_maskbit(unsigned int vector) {}
-static void end_msi_irq_wo_maskbit(unsigned int vector)
+static unsigned int startup_msi_irq_w_maskbit(unsigned int vector)
 {
-       move_msi(vector);
-       ack_APIC_irq();
+       startup_msi_irq_wo_maskbit(vector);
+       unmask_MSI_irq(vector);
+       return 0;       /* never anything pending */
 }
 
-static unsigned int startup_msi_irq_w_maskbit(unsigned int vector)
+static void shutdown_msi_irq(unsigned int vector)
 {
        struct msi_desc *entry;
        unsigned long flags;
 
        spin_lock_irqsave(&msi_lock, flags);
        entry = msi_desc[vector];
-       if (!entry || !entry->dev) {
-               spin_unlock_irqrestore(&msi_lock, flags);
-               return 0;
-       }
-       entry->msi_attrib.state = 1;    /* Mark it active */
+       if (entry && entry->dev)
+               entry->msi_attrib.state = 0;    /* Mark it not active */
        spin_unlock_irqrestore(&msi_lock, flags);
-
-       unmask_MSI_irq(vector);
-       return 0;       /* never anything pending */
 }
 
-#define shutdown_msi_irq_w_maskbit     shutdown_msi_irq
-#define enable_msi_irq_w_maskbit       unmask_MSI_irq
-#define disable_msi_irq_w_maskbit      mask_MSI_irq
-#define ack_msi_irq_w_maskbit          mask_MSI_irq
+static void end_msi_irq_wo_maskbit(unsigned int vector)
+{
+       move_msi(vector);
+       ack_APIC_irq();
+}
 
 static void end_msi_irq_w_maskbit(unsigned int vector)
 {
@@ -216,6 +202,10 @@ static void end_msi_irq_w_maskbit(unsigned int vector)
        ack_APIC_irq();
 }
 
+static void do_nothing(unsigned int vector)
+{
+}
+
 /*
  * Interrupt Type for MSI-X PCI/PCI-X/PCI-Express Devices,
  * which implement the MSI-X Capability Structure.
@@ -223,10 +213,10 @@ static void end_msi_irq_w_maskbit(unsigned int vector)
 static struct hw_interrupt_type msix_irq_type = {
        .typename       = "PCI-MSI-X",
        .startup        = startup_msi_irq_w_maskbit,
-       .shutdown       = shutdown_msi_irq_w_maskbit,
-       .enable         = enable_msi_irq_w_maskbit,
-       .disable        = disable_msi_irq_w_maskbit,
-       .ack            = ack_msi_irq_w_maskbit,
+       .shutdown       = shutdown_msi_irq,
+       .enable         = unmask_MSI_irq,
+       .disable        = mask_MSI_irq,
+       .ack            = mask_MSI_irq,
        .end            = end_msi_irq_w_maskbit,
        .set_affinity   = set_msi_irq_affinity
 };
@@ -239,10 +229,10 @@ static struct hw_interrupt_type msix_irq_type = {
 static struct hw_interrupt_type msi_irq_w_maskbit_type = {
        .typename       = "PCI-MSI",
        .startup        = startup_msi_irq_w_maskbit,
-       .shutdown       = shutdown_msi_irq_w_maskbit,
-       .enable         = enable_msi_irq_w_maskbit,
-       .disable        = disable_msi_irq_w_maskbit,
-       .ack            = ack_msi_irq_w_maskbit,
+       .shutdown       = shutdown_msi_irq,
+       .enable         = unmask_MSI_irq,
+       .disable        = mask_MSI_irq,
+       .ack            = mask_MSI_irq,
        .end            = end_msi_irq_w_maskbit,
        .set_affinity   = set_msi_irq_affinity
 };
@@ -255,10 +245,10 @@ static struct hw_interrupt_type msi_irq_w_maskbit_type = {
 static struct hw_interrupt_type msi_irq_wo_maskbit_type = {
        .typename       = "PCI-MSI",
        .startup        = startup_msi_irq_wo_maskbit,
-       .shutdown       = shutdown_msi_irq_wo_maskbit,
-       .enable         = enable_msi_irq_wo_maskbit,
-       .disable        = disable_msi_irq_wo_maskbit,
-       .ack            = ack_msi_irq_wo_maskbit,
+       .shutdown       = shutdown_msi_irq,
+       .enable         = do_nothing,
+       .disable        = do_nothing,
+       .ack            = do_nothing,
        .end            = end_msi_irq_wo_maskbit,
        .set_affinity   = set_msi_irq_affinity
 };
@@ -407,7 +397,7 @@ static struct msi_desc* alloc_msi_entry(void)
 {
        struct msi_desc *entry;
 
-       entry = (struct msi_desc*) kmem_cache_alloc(msi_cachep, SLAB_KERNEL);
+       entry = kmem_cache_alloc(msi_cachep, SLAB_KERNEL);
        if (!entry)
                return NULL;
 
@@ -796,18 +786,6 @@ void pci_disable_msi(struct pci_dev* dev)
        }
 }
 
-static void release_msi(unsigned int vector)
-{
-       struct msi_desc *entry;
-       unsigned long flags;
-
-       spin_lock_irqsave(&msi_lock, flags);
-       entry = msi_desc[vector];
-       if (entry && entry->dev)
-               entry->msi_attrib.state = 0;    /* Mark it not active */
-       spin_unlock_irqrestore(&msi_lock, flags);
-}
-
 static int msi_free_vector(struct pci_dev* dev, int vector, int reassign)
 {
        struct msi_desc *entry;
@@ -924,7 +902,7 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec)
 /**
  * pci_enable_msix - configure device's MSI-X capability structure
  * @dev: pointer to the pci_dev data structure of MSI-X device function
- * @data: pointer to an array of MSI-X entries
+ * @entries: pointer to an array of MSI-X entries
  * @nvec: number of MSI-X vectors requested for allocation by device driver
  *
  * Setup the MSI-X capability structure of device function with the number
index bef21ae3cbd05878487e9cb03da5706c7804ef5c..390f1851c0f11b4d88206f13f720bd0b8c1b5ffa 100644 (file)
@@ -41,11 +41,11 @@ static inline void move_msi(int vector) {}
 #define PCI_MSIX_FLAGS_BIRMASK         (7 << 0)
 #define PCI_MSIX_FLAGS_BITMASK         (1 << 0)
 
-#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET       0
-#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET       4
-#define PCI_MSIX_ENTRY_DATA_OFFSET             8
-#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET      12
 #define PCI_MSIX_ENTRY_SIZE                    16
+#define  PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET      0
+#define  PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET      4
+#define  PCI_MSIX_ENTRY_DATA_OFFSET            8
+#define  PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET     12
 
 #define msi_control_reg(base)          (base + PCI_MSI_FLAGS)
 #define msi_lower_address_reg(base)    (base + PCI_MSI_ADDRESS_LO)
@@ -64,7 +64,6 @@ static inline void move_msi(int vector) {}
 #define msi_enable(control, num) multi_msi_enable(control, num); \
        control |= PCI_MSI_FLAGS_ENABLE
 
-#define msix_control_reg               msi_control_reg
 #define msix_table_offset_reg(base)    (base + 0x04)
 #define msix_pba_offset_reg(base)      (base + 0x08)
 #define msix_enable(control)           control |= PCI_MSIX_FLAGS_ENABLE
index a15f94072a6f554a4e43b70db5c24d7e1b64240a..cc9d65388e623ffb3436904c16e13cda81204216 100644 (file)
@@ -60,15 +60,18 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf)
        char * str = buf;
        int i;
        int max = 7;
+       u64 start, end;
 
        if (pci_dev->subordinate)
                max = DEVICE_COUNT_RESOURCE;
 
        for (i = 0; i < max; i++) {
-               str += sprintf(str,"0x%016lx 0x%016lx 0x%016lx\n",
-                              pci_resource_start(pci_dev,i),
-                              pci_resource_end(pci_dev,i),
-                              pci_resource_flags(pci_dev,i));
+               struct resource *res =  &pci_dev->resource[i];
+               pci_resource_to_user(pci_dev, i, res, &start, &end);
+               str += sprintf(str,"0x%016llx 0x%016llx 0x%016llx\n",
+                              (unsigned long long)start,
+                              (unsigned long long)end,
+                              (unsigned long long)res->flags);
        }
        return (str - buf);
 }
@@ -313,8 +316,21 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
                                                       struct device, kobj));
        struct resource *res = (struct resource *)attr->private;
        enum pci_mmap_state mmap_type;
+       u64 start, end;
+       int i;
 
-       vma->vm_pgoff += res->start >> PAGE_SHIFT;
+       for (i = 0; i < PCI_ROM_RESOURCE; i++)
+               if (res == &pdev->resource[i])
+                       break;
+       if (i >= PCI_ROM_RESOURCE)
+               return -ENODEV;
+
+       /* pci_mmap_page_range() expects the same kind of entry as coming
+        * from /proc/bus/pci/ which is a "user visible" value. If this is
+        * different from the resource itself, arch will do necessary fixup.
+        */
+       pci_resource_to_user(pdev, i, res, &start, &end);
+       vma->vm_pgoff += start >> PAGE_SHIFT;
        mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
 
        return pci_mmap_page_range(pdev, vma, mmap_type, 0);
index fd48b201eb53ac18e443519c17046ba7b68bb94c..6a0a82f0508bf2d81112cd5f2236acad46a635b6 100644 (file)
@@ -374,8 +374,11 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de
        struct pci_bus *child;
 
        child = pci_alloc_child_bus(parent, dev, busnr);
-       if (child)
+       if (child) {
+               spin_lock(&pci_bus_lock);
                list_add_tail(&child->node, &parent->children);
+               spin_unlock(&pci_bus_lock);
+       }
        return child;
 }
 
@@ -411,7 +414,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
 {
        struct pci_bus *child;
        int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
-       u32 buses;
+       u32 buses, i;
        u16 bctl;
 
        pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
@@ -447,7 +450,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
                        return max;
                }
 
-               child = pci_alloc_child_bus(bus, dev, busnr);
+               child = pci_add_new_bus(bus, dev, busnr);
                if (!child)
                        return max;
                child->primary = buses & 0xFF;
@@ -470,7 +473,11 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
                /* Clear errors */
                pci_write_config_word(dev, PCI_STATUS, 0xffff);
 
-               child = pci_alloc_child_bus(bus, dev, ++max);
+               /* Prevent assigning a bus number that already exists.
+                * This can happen when a bridge is hot-plugged */
+               if (pci_find_bus(pci_domain_nr(bus), max+1))
+                       return max;
+               child = pci_add_new_bus(bus, dev, ++max);
                buses = (buses & 0xff000000)
                      | ((unsigned int)(child->primary)     <<  0)
                      | ((unsigned int)(child->secondary)   <<  8)
@@ -501,7 +508,11 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
                         * as cards with a PCI-to-PCI bridge can be
                         * inserted later.
                         */
-                       max += CARDBUS_RESERVE_BUSNR;
+                       for (i=0; i<CARDBUS_RESERVE_BUSNR; i++)
+                               if (pci_find_bus(pci_domain_nr(bus),
+                                                       max+i+1))
+                                       break;
+                       max += i;
                }
                /*
                 * Set the subordinate bus number to its real value.
@@ -757,7 +768,9 @@ pci_scan_single_device(struct pci_bus *bus, int devfn)
         * and the bus list for fixup functions, etc.
         */
        INIT_LIST_HEAD(&dev->global_list);
+       spin_lock(&pci_bus_lock);
        list_add_tail(&dev->bus_list, &bus->devices);
+       spin_unlock(&pci_bus_lock);
 
        return dev;
 }
@@ -878,7 +891,9 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus,
                pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus);
                goto err_out;
        }
+       spin_lock(&pci_bus_lock);
        list_add_tail(&b->node, &pci_root_buses);
+       spin_unlock(&pci_bus_lock);
 
        memset(dev, 0, sizeof(*dev));
        dev->parent = parent;
@@ -911,8 +926,6 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus,
 
        b->subordinate = pci_scan_child_bus(b);
 
-       pci_bus_add_devices(b);
-
        return b;
 
 sys_create_link_err:
@@ -922,7 +935,9 @@ class_dev_create_file_err:
 class_dev_reg_err:
        device_unregister(dev);
 dev_reg_err:
+       spin_lock(&pci_bus_lock);
        list_del(&b->node);
+       spin_unlock(&pci_bus_lock);
 err_out:
        kfree(dev);
        kfree(b);
index e68bbfb1e7c318d0c34c11e3c76774ae17f3c60a..7988fc8df3fd24327d60c2cc24ed1e7b6fc5b3e3 100644 (file)
@@ -355,14 +355,20 @@ static int show_device(struct seq_file *m, void *v)
                        dev->device,
                        dev->irq);
        /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */
-       for(i=0; i<7; i++)
+       for (i=0; i<7; i++) {
+               u64 start, end;
+               pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
                seq_printf(m, LONG_FORMAT,
-                       dev->resource[i].start |
+                       ((unsigned long)start) |
                        (dev->resource[i].flags & PCI_REGION_FLAG_MASK));
-       for(i=0; i<7; i++)
+       }
+       for (i=0; i<7; i++) {
+               u64 start, end;
+               pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
                seq_printf(m, LONG_FORMAT,
                        dev->resource[i].start < dev->resource[i].end ?
-                       dev->resource[i].end - dev->resource[i].start + 1 : 0);
+                       (unsigned long)(end - start) + 1 : 0);
+       }
        seq_putc(m, '\t');
        if (drv)
                seq_printf(m, "%s", drv->name);
index 96f077f9a6594057105f1901f9aea4620f6a1e15..27a294b6965d41e964a8630ad15a3571a0f6430e 100644 (file)
@@ -18,17 +18,21 @@ static void pci_free_resources(struct pci_dev *dev)
 
 static void pci_destroy_dev(struct pci_dev *dev)
 {
-       pci_proc_detach_device(dev);
-       pci_remove_sysfs_dev_files(dev);
-       device_unregister(&dev->dev);
+       if (!list_empty(&dev->global_list)) {
+               pci_proc_detach_device(dev);
+               pci_remove_sysfs_dev_files(dev);
+               device_unregister(&dev->dev);
+               spin_lock(&pci_bus_lock);
+               list_del(&dev->global_list);
+               dev->global_list.next = dev->global_list.prev = NULL;
+               spin_unlock(&pci_bus_lock);
+       }
 
        /* Remove the device from the device lists, and prevent any further
         * list accesses from this device */
        spin_lock(&pci_bus_lock);
        list_del(&dev->bus_list);
-       list_del(&dev->global_list);
        dev->bus_list.next = dev->bus_list.prev = NULL;
-       dev->global_list.next = dev->global_list.prev = NULL;
        spin_unlock(&pci_bus_lock);
 
        pci_free_resources(dev);
index 1ba84be0b4c0fa041efcb9fc086302eaec887079..6b628de948af522fd3f00fdb7b4725a2c6cf275d 100644 (file)
@@ -72,7 +72,10 @@ pbus_assign_resources_sorted(struct pci_bus *bus)
        for (list = head.next; list;) {
                res = list->res;
                idx = res - &list->dev->resource[0];
-               pci_assign_resource(list->dev, idx);
+               if (pci_assign_resource(list->dev, idx)) {
+                       res->start = 0;
+                       res->flags = 0;
+               }
                tmp = list;
                list = list->next;
                kfree(tmp);
index 14e4124e15231f777cc9602db8a9f9289b50adba..52ea34594363e746b5f373fa8542fc460c5ef399 100644 (file)
@@ -14,8 +14,8 @@ config PCCARD
          Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
          computer.  These are credit-card size devices such as network cards,
          modems or hard drives often used with laptops computers.  There are
-         actually two varieties of these cards: the older 16 bit PCMCIA cards
-         and the newer 32 bit CardBus cards.
+         actually two varieties of these cards: 16 bit PCMCIA and 32 bit
+         CardBus cards.
 
          To compile this driver as modules, choose M here: the
          module will be called pcmcia_core.
@@ -42,22 +42,51 @@ config PCMCIA_DEBUG
 
 config PCMCIA
        tristate "16-bit PCMCIA support"
+       select CRC32
        default y
        ---help---
           This option enables support for 16-bit PCMCIA cards. Most older
           PC-cards are such 16-bit PCMCIA cards, so unless you know you're
           only using 32-bit CardBus cards, say Y or M here.
 
-          To use 16-bit PCMCIA cards, you will need supporting software from 
-          David Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-          for location).  Please also read the PCMCIA-HOWTO, available from
-          <http://www.tldp.org/docs.html#howto>.
+          To use 16-bit PCMCIA cards, you will need supporting software in
+          most cases. (see the file <file:Documentation/Changes> for
+          location and details).
 
           To compile this driver as modules, choose M here: the
           module will be called pcmcia.
 
           If unsure, say Y.
 
+config PCMCIA_LOAD_CIS
+       bool "Load CIS updates from userspace (EXPERIMENTAL)"
+       depends on PCMCIA && EXPERIMENTAL
+       select FW_LOADER
+       default y
+       help
+         Some PCMCIA cards require an updated Card Information Structure (CIS)
+         to be loaded from userspace to work correctly. If you say Y here,
+         and your userspace is arranged correctly, this will be loaded
+         automatically using the in-kernel firmware loader and the hotplug
+         subsystem, instead of relying on cardmgr from pcmcia-cs to do so.
+
+         If unsure, say Y.
+
+config PCMCIA_IOCTL
+       bool
+       depends on PCMCIA
+       default y
+       help
+         If you say Y here, the deprecated ioctl interface to the PCMCIA
+         subsystem will be built. It is needed by cardmgr and cardctl
+         (pcmcia-cs) to function properly.
+
+         If you do not use the new pcmciautils package, and have a
+         yenta, Cirrus PD6729, i82092, i82365 or tcic compatible bridge,
+         you need to say Y here to be able to use 16-bit PCMCIA cards.
+
+         If unsure, say Y.
+
 config CARDBUS
        bool "32-bit CardBus support"   
        depends on PCI
@@ -77,8 +106,6 @@ comment "PC-card bridges"
 
 config YENTA
        tristate "CardBus yenta-compatible bridge support"
-       depends on PCI
-#fixme: remove dependendcy on CARDBUS
        depends on CARDBUS
        select PCCARD_NONSTATIC
        ---help---
index 50c29361bc5f6517649277ab3896e49abd065af7..ef694c74dfb7ee683938c03df73bc0cbfcae1f86 100644 (file)
@@ -10,7 +10,8 @@ pcmcia_core-y                                 += cs.o cistpl.o rsrc_mgr.o socket_sysfs.o
 pcmcia_core-$(CONFIG_CARDBUS)                  += cardbus.o
 obj-$(CONFIG_PCCARD)                           += pcmcia_core.o
 
-pcmcia-y                                       += ds.o pcmcia_compat.o
+pcmcia-y                                       += ds.o pcmcia_compat.o pcmcia_resource.o
+pcmcia-$(CONFIG_PCMCIA_IOCTL)                  += pcmcia_ioctl.o
 obj-$(CONFIG_PCMCIA)                           += pcmcia.o
 
 obj-$(CONFIG_PCCARD_NONSTATIC)                 += rsrc_nonstatic.o
index e29a6ddf2fd7e18af9b2c58cfeca312d1b67cec3..dd7651ff5b4386f18a6a28844716dfe11d7e5fbf 100644 (file)
@@ -89,8 +89,10 @@ static void __iomem *
 set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags)
 {
     pccard_mem_map *mem = &s->cis_mem;
+    int ret;
+
     if (!(s->features & SS_CAP_STATIC_MAP) && mem->res == NULL) {
-       mem->res = find_mem_region(0, s->map_size, s->map_size, 0, s);
+       mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s);
        if (mem->res == NULL) {
            printk(KERN_NOTICE "cs: unable to map card memory!\n");
            return NULL;
@@ -99,7 +101,12 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
     }
     mem->card_start = card_offset;
     mem->flags = flags;
-    s->ops->set_mem_map(s, mem);
+    ret = s->ops->set_mem_map(s, mem);
+    if (ret) {
+       iounmap(s->cis_virt);
+       return NULL;
+    }
+
     if (s->features & SS_CAP_STATIC_MAP) {
        if (s->cis_virt)
            iounmap(s->cis_virt);
@@ -119,13 +126,13 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
 #define IS_ATTR                1
 #define IS_INDIRECT    8
 
-int read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
+int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
                 u_int len, void *ptr)
 {
     void __iomem *sys, *end;
     unsigned char *buf = ptr;
     
-    cs_dbg(s, 3, "read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+    cs_dbg(s, 3, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
 
     if (attr & IS_INDIRECT) {
        /* Indirect accesses use a bunch of special registers at fixed
@@ -182,14 +189,16 @@ int read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
          *(u_char *)(ptr+2), *(u_char *)(ptr+3));
     return 0;
 }
+EXPORT_SYMBOL(pcmcia_read_cis_mem);
+
 
-void write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
+void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
                   u_int len, void *ptr)
 {
     void __iomem *sys, *end;
     unsigned char *buf = ptr;
     
-    cs_dbg(s, 3, "write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+    cs_dbg(s, 3, "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
 
     if (attr & IS_INDIRECT) {
        /* Indirect accesses use a bunch of special registers at fixed
@@ -239,6 +248,8 @@ void write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
        }
     }
 }
+EXPORT_SYMBOL(pcmcia_write_cis_mem);
+
 
 /*======================================================================
 
@@ -274,7 +285,7 @@ static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
        ret = read_cb_mem(s, attr, addr, len, ptr);
     else
 #endif
-       ret = read_cis_mem(s, attr, addr, len, ptr);
+       ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr);
 
        if (ret == 0) {
                /* Copy data into the cache */
@@ -348,7 +359,7 @@ int verify_cis_cache(struct pcmcia_socket *s)
                        read_cb_mem(s, cis->attr, cis->addr, len, buf);
                else
 #endif
-                       read_cis_mem(s, cis->attr, cis->addr, len, buf);
+                       pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf);
 
                if (memcmp(buf, cis->cache, len) != 0) {
                        kfree(buf);
@@ -381,6 +392,7 @@ int pcmcia_replace_cis(struct pcmcia_socket *s, cisdump_t *cis)
     memcpy(s->fake_cis, cis->Data, cis->Length);
     return CS_SUCCESS;
 }
+EXPORT_SYMBOL(pcmcia_replace_cis);
 
 /*======================================================================
 
index d136b3c8fac99299c9d1b2cf4d7f00dce8d39d16..e82859d3227a61e661d159acaf8b3d1c51a7f9fa 100644 (file)
 #include <pcmcia/ds.h>
 #include "cs_internal.h"
 
-#ifdef CONFIG_PCI
-#define PCI_OPT " [pci]"
-#else
-#define PCI_OPT ""
-#endif
-#ifdef CONFIG_CARDBUS
-#define CB_OPT " [cardbus]"
-#else
-#define CB_OPT ""
-#endif
-#ifdef CONFIG_PM
-#define PM_OPT " [pm]"
-#else
-#define PM_OPT ""
-#endif
-#if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && !defined(CONFIG_PM)
-#define OPTIONS " none"
-#else
-#define OPTIONS PCI_OPT CB_OPT PM_OPT
-#endif
-
-static const char *release = "Linux Kernel Card Services";
-static const char *options = "options: " OPTIONS;
-
-/*====================================================================*/
 
 /* Module parameters */
 
 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("Linux Kernel Card Services\noptions:" OPTIONS);
+MODULE_DESCRIPTION("Linux Kernel Card Services");
 MODULE_LICENSE("GPL");
 
 #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
@@ -89,9 +64,6 @@ INT_MODULE_PARM(unreset_limit,        30);            /* unreset_check's */
 /* Access speed for attribute memory windows */
 INT_MODULE_PARM(cis_speed,     300);           /* ns */
 
-/* Access speed for IO windows */
-INT_MODULE_PARM(io_speed,      0);             /* ns */
-
 #ifdef DEBUG
 static int pc_debug;
 
@@ -103,34 +75,26 @@ int cs_debug_level(int level)
 }
 #endif
 
-/*====================================================================*/
 
 socket_state_t dead_socket = {
        .csc_mask       = SS_DETECT,
 };
+EXPORT_SYMBOL(dead_socket);
 
 
 /* List of all sockets, protected by a rwsem */
 LIST_HEAD(pcmcia_socket_list);
-DECLARE_RWSEM(pcmcia_socket_list_rwsem);
 EXPORT_SYMBOL(pcmcia_socket_list);
-EXPORT_SYMBOL(pcmcia_socket_list_rwsem);
-
 
-#ifdef CONFIG_PCMCIA_PROBE
-/* mask ofIRQs already reserved by other cards, we should avoid using them */
-static u8 pcmcia_used_irq[NR_IRQS];
-#endif
+DECLARE_RWSEM(pcmcia_socket_list_rwsem);
+EXPORT_SYMBOL(pcmcia_socket_list_rwsem);
 
-/*====================================================================
-
-    Low-level PC Card interface drivers need to register with Card
-    Services using these calls.
-    
-======================================================================*/
 
 /**
- * socket drivers are expected to use the following callbacks in their 
+ * Low-level PCMCIA socket drivers need to register with the PCCard
+ * core using pcmcia_register_socket.
+ *
+ * socket drivers are expected to use the following callbacks in their
  * .drv struct:
  *  - pcmcia_socket_dev_suspend
  *  - pcmcia_socket_dev_resume
@@ -230,8 +194,8 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
        }
 
        /* try to obtain a socket number [yes, it gets ugly if we
-        * register more than 2^sizeof(unsigned int) pcmcia 
-        * sockets... but the socket number is deprecated 
+        * register more than 2^sizeof(unsigned int) pcmcia
+        * sockets... but the socket number is deprecated
         * anyways, so I don't care] */
        down_write(&pcmcia_socket_list_rwsem);
        if (list_empty(&pcmcia_socket_list))
@@ -340,54 +304,49 @@ struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr)
 EXPORT_SYMBOL(pcmcia_get_socket_by_nr);
 
 
-/*======================================================================
-
-    socket_setup() and shutdown_socket() are called by the main event
-    handler when card insertion and removal events are received.
-    socket_setup() turns on socket power and resets the socket, in two stages.
-    shutdown_socket() unconfigures a socket and turns off socket power.
-
-======================================================================*/
-
+/**
+ * socket_setup() and shutdown_socket() are called by the main event
+ * handler when card insertion and removal events are received.
+ * socket_setup() turns on socket power and resets the socket, in two stages.
+ * shutdown_socket() unconfigures a socket and turns off socket power.
+ */
 static void shutdown_socket(struct pcmcia_socket *s)
 {
-    cs_dbg(s, 1, "shutdown_socket\n");
-
-    /* Blank out the socket state */
-    s->socket = dead_socket;
-    s->ops->init(s);
-    s->ops->set_socket(s, &s->socket);
-    s->irq.AssignedIRQ = s->irq.Config = 0;
-    s->lock_count = 0;
-    destroy_cis_cache(s);
+       cs_dbg(s, 1, "shutdown_socket\n");
+
+       /* Blank out the socket state */
+       s->socket = dead_socket;
+       s->ops->init(s);
+       s->ops->set_socket(s, &s->socket);
+       s->irq.AssignedIRQ = s->irq.Config = 0;
+       s->lock_count = 0;
+       destroy_cis_cache(s);
 #ifdef CONFIG_CARDBUS
-    cb_free(s);
+       cb_free(s);
 #endif
-    s->functions = 0;
-    if (s->config) {
-       kfree(s->config);
-       s->config = NULL;
-    }
-
-    {
-       int status;
-       s->ops->get_status(s, &status);
-       if (status & SS_POWERON) {
-               printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s);
+       s->functions = 0;
+       if (s->config) {
+               kfree(s->config);
+               s->config = NULL;
        }
-    }
-} /* shutdown_socket */
 
-/*======================================================================
+       {
+               int status;
+               s->ops->get_status(s, &status);
+               if (status & SS_POWERON) {
+                       printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s);
+               }
+       }
+} /* shutdown_socket */
 
-    The central event handler.  Send_event() sends an event to the
-    16-bit subsystem, which then calls the relevant device drivers.
-    Parse_events() interprets the event bits from
-    a card status change report.  Do_shutdown() handles the high
-    priority stuff associated with a card removal.
-    
-======================================================================*/
 
+/**
+ * The central event handler.  Send_event() sends an event to the
+ * 16-bit subsystem, which then calls the relevant device drivers.
+ * Parse_events() interprets the event bits from
+ * a card status change report.  Do_shutdown() handles the high
+ * priority stuff associated with a card removal.
+ */
 
 /* NOTE: send_event needs to be called with skt->sem held. */
 
@@ -718,7 +677,7 @@ static int pccardd(void *__skt)
                }
 
                schedule();
-               try_to_freeze(PF_FREEZE);
+               try_to_freeze();
 
                if (!skt->thread)
                        break;
@@ -746,420 +705,9 @@ void pcmcia_parse_events(struct pcmcia_socket *s, u_int events)
                wake_up(&s->thread_wait);
        }
 } /* pcmcia_parse_events */
+EXPORT_SYMBOL(pcmcia_parse_events);
 
 
-/*======================================================================
-
-    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)
-{
-    int i;
-    kio_addr_t try, align;
-
-    align = (*base) ? (lines ? 1<<lines : 0) : 1;
-    if (align && (align < num)) {
-       if (*base) {
-           cs_dbg(s, 0, "odd IO request: num %#x align %#lx\n",
-                  num, align);
-           align = 0;
-       } else
-           while (align && (align < num)) align <<= 1;
-    }
-    if (*base & ~(align-1)) {
-       cs_dbg(s, 0, "odd IO request: base %#x align %#lx\n",
-              *base, align);
-       align = 0;
-    }
-    if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) {
-       *base = s->io_offset | (*base & 0x0fff);
-       return 0;
-    }
-    /* Check for an already-allocated window that must conflict with
-       what was asked for.  It is a hack because it does not catch all
-       potential conflicts, just the most obvious ones. */
-    for (i = 0; i < MAX_IO_WIN; i++)
-       if ((s->io[i].NumPorts != 0) &&
-           ((s->io[i].BasePort & (align-1)) == *base))
-           return 1;
-    for (i = 0; i < MAX_IO_WIN; i++) {
-       if (s->io[i].NumPorts == 0) {
-           s->io[i].res = find_io_region(*base, num, align, s);
-           if (s->io[i].res) {
-               s->io[i].Attributes = attr;
-               s->io[i].BasePort = *base = s->io[i].res->start;
-               s->io[i].NumPorts = s->io[i].InUse = num;
-               break;
-           } else
-               return 1;
-       } else if (s->io[i].Attributes != attr)
-           continue;
-       /* Try to extend top of window */
-       try = s->io[i].BasePort + s->io[i].NumPorts;
-       if ((*base == 0) || (*base == try))
-           if (adjust_io_region(s->io[i].res, s->io[i].res->start,
-                                s->io[i].res->end + num, s) == 0) {
-               *base = try;
-               s->io[i].NumPorts += num;
-               s->io[i].InUse += num;
-               break;
-           }
-       /* Try to extend bottom of window */
-       try = s->io[i].BasePort - num;
-       if ((*base == 0) || (*base == try))
-           if (adjust_io_region(s->io[i].res, s->io[i].res->start - num,
-                                s->io[i].res->end, s) == 0) {
-               s->io[i].BasePort = *base = try;
-               s->io[i].NumPorts += num;
-               s->io[i].InUse += num;
-               break;
-           }
-    }
-    return (i == MAX_IO_WIN);
-} /* alloc_io_space */
-
-static void release_io_space(struct pcmcia_socket *s, ioaddr_t base,
-                            ioaddr_t num)
-{
-    int i;
-
-    for (i = 0; i < MAX_IO_WIN; i++) {
-       if ((s->io[i].BasePort <= base) &&
-           (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
-           s->io[i].InUse -= num;
-           /* Free the window if no one else is using it */
-           if (s->io[i].InUse == 0) {
-               s->io[i].NumPorts = 0;
-               release_resource(s->io[i].res);
-               kfree(s->io[i].res);
-               s->io[i].res = NULL;
-           }
-       }
-    }
-}
-
-/*======================================================================
-
-    Access_configuration_register() reads and writes configuration
-    registers in attribute memory.  Memory window 0 is reserved for
-    this and the tuple reading services.
-    
-======================================================================*/
-
-int pccard_access_configuration_register(struct pcmcia_socket *s,
-                                        unsigned int function,
-                                        conf_reg_t *reg)
-{
-    config_t *c;
-    int addr;
-    u_char val;
-
-    if (!s || !s->config)
-       return CS_NO_CARD;    
-
-    c = &s->config[function];
-
-    if (c == NULL)
-       return CS_NO_CARD;
-
-    if (!(c->state & CONFIG_LOCKED))
-       return CS_CONFIGURATION_LOCKED;
-
-    addr = (c->ConfigBase + reg->Offset) >> 1;
-    
-    switch (reg->Action) {
-    case CS_READ:
-       read_cis_mem(s, 1, addr, 1, &val);
-       reg->Value = val;
-       break;
-    case CS_WRITE:
-       val = reg->Value;
-       write_cis_mem(s, 1, addr, 1, &val);
-       break;
-    default:
-       return CS_BAD_ARGS;
-       break;
-    }
-    return CS_SUCCESS;
-} /* access_configuration_register */
-EXPORT_SYMBOL(pccard_access_configuration_register);
-
-
-/*====================================================================*/
-
-int pccard_get_configuration_info(struct pcmcia_socket *s,
-                                 unsigned int function,
-                                 config_info_t *config)
-{
-    config_t *c;
-    
-    if (!(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
-
-    config->Function = function;
-
-#ifdef CONFIG_CARDBUS
-    if (s->state & SOCKET_CARDBUS) {
-       memset(config, 0, sizeof(config_info_t));
-       config->Vcc = s->socket.Vcc;
-       config->Vpp1 = config->Vpp2 = s->socket.Vpp;
-       config->Option = s->cb_dev->subordinate->number;
-       if (s->state & SOCKET_CARDBUS_CONFIG) {
-           config->Attributes = CONF_VALID_CLIENT;
-           config->IntType = INT_CARDBUS;
-           config->AssignedIRQ = s->irq.AssignedIRQ;
-           if (config->AssignedIRQ)
-               config->Attributes |= CONF_ENABLE_IRQ;
-           config->BasePort1 = s->io[0].BasePort;
-           config->NumPorts1 = s->io[0].NumPorts;
-       }
-       return CS_SUCCESS;
-    }
-#endif
-    
-    c = (s->config != NULL) ? &s->config[function] : NULL;
-    
-    if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
-       config->Attributes = 0;
-       config->Vcc = s->socket.Vcc;
-       config->Vpp1 = config->Vpp2 = s->socket.Vpp;
-       return CS_SUCCESS;
-    }
-    
-    /* !!! This is a hack !!! */
-    memcpy(&config->Attributes, &c->Attributes, sizeof(config_t));
-    config->Attributes |= CONF_VALID_CLIENT;
-    config->CardValues = c->CardValues;
-    config->IRQAttributes = c->irq.Attributes;
-    config->AssignedIRQ = s->irq.AssignedIRQ;
-    config->BasePort1 = c->io.BasePort1;
-    config->NumPorts1 = c->io.NumPorts1;
-    config->Attributes1 = c->io.Attributes1;
-    config->BasePort2 = c->io.BasePort2;
-    config->NumPorts2 = c->io.NumPorts2;
-    config->Attributes2 = c->io.Attributes2;
-    config->IOAddrLines = c->io.IOAddrLines;
-    
-    return CS_SUCCESS;
-} /* get_configuration_info */
-EXPORT_SYMBOL(pccard_get_configuration_info);
-
-/*======================================================================
-
-    Return information about this version of Card Services.
-    
-======================================================================*/
-
-int pcmcia_get_card_services_info(servinfo_t *info)
-{
-    unsigned int socket_count = 0;
-    struct list_head *tmp;
-    info->Signature[0] = 'C';
-    info->Signature[1] = 'S';
-    down_read(&pcmcia_socket_list_rwsem);
-    list_for_each(tmp, &pcmcia_socket_list)
-           socket_count++;
-    up_read(&pcmcia_socket_list_rwsem);
-    info->Count = socket_count;
-    info->Revision = CS_RELEASE_CODE;
-    info->CSLevel = 0x0210;
-    info->VendorString = (char *)release;
-    return CS_SUCCESS;
-} /* get_card_services_info */
-
-
-/*====================================================================*/
-
-int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, int idx, win_req_t *req)
-{
-    window_t *win;
-    int w;
-
-    if (!s || !(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
-    for (w = idx; w < MAX_WIN; w++)
-       if (s->state & SOCKET_WIN_REQ(w)) break;
-    if (w == MAX_WIN)
-       return CS_NO_MORE_ITEMS;
-    win = &s->win[w];
-    req->Base = win->ctl.res->start;
-    req->Size = win->ctl.res->end - win->ctl.res->start + 1;
-    req->AccessSpeed = win->ctl.speed;
-    req->Attributes = 0;
-    if (win->ctl.flags & MAP_ATTRIB)
-       req->Attributes |= WIN_MEMORY_TYPE_AM;
-    if (win->ctl.flags & MAP_ACTIVE)
-       req->Attributes |= WIN_ENABLE;
-    if (win->ctl.flags & MAP_16BIT)
-       req->Attributes |= WIN_DATA_WIDTH_16;
-    if (win->ctl.flags & MAP_USE_WAIT)
-       req->Attributes |= WIN_USE_WAIT;
-    *handle = win;
-    return CS_SUCCESS;
-} /* get_window */
-EXPORT_SYMBOL(pcmcia_get_window);
-
-/*=====================================================================
-
-    Return the PCI device associated with a card..
-
-======================================================================*/
-
-#ifdef CONFIG_CARDBUS
-
-struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
-{
-       if (!s || !(s->state & SOCKET_CARDBUS))
-               return NULL;
-
-       return s->cb_dev->subordinate;
-}
-
-EXPORT_SYMBOL(pcmcia_lookup_bus);
-
-#endif
-
-/*======================================================================
-
-    Get the current socket state bits.  We don't support the latched
-    SocketState yet: I haven't seen any point for it.
-    
-======================================================================*/
-
-int pccard_get_status(struct pcmcia_socket *s, unsigned int function, cs_status_t *status)
-{
-    config_t *c;
-    int val;
-    
-    s->ops->get_status(s, &val);
-    status->CardState = status->SocketState = 0;
-    status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
-    status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
-    status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
-    status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
-    if (s->state & SOCKET_SUSPEND)
-       status->CardState |= CS_EVENT_PM_SUSPEND;
-    if (!(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
-    
-    c = (s->config != NULL) ? &s->config[function] : NULL;
-    if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
-       (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
-       u_char reg;
-       if (c->Present & PRESENT_PIN_REPLACE) {
-           read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
-           status->CardState |=
-               (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
-           status->CardState |=
-               (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
-           status->CardState |=
-               (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
-           status->CardState |=
-               (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
-       } else {
-           /* No PRR?  Then assume we're always ready */
-           status->CardState |= CS_EVENT_READY_CHANGE;
-       }
-       if (c->Present & PRESENT_EXT_STATUS) {
-           read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
-           status->CardState |=
-               (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
-       }
-       return CS_SUCCESS;
-    }
-    status->CardState |=
-       (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
-    status->CardState |=
-       (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
-    status->CardState |=
-       (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
-    status->CardState |=
-       (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
-    return CS_SUCCESS;
-} /* get_status */
-EXPORT_SYMBOL(pccard_get_status);
-
-/*======================================================================
-
-    Change the card address of an already open memory window.
-    
-======================================================================*/
-
-int pcmcia_get_mem_page(window_handle_t win, memreq_t *req)
-{
-    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
-       return CS_BAD_HANDLE;
-    req->Page = 0;
-    req->CardOffset = win->ctl.card_start;
-    return CS_SUCCESS;
-} /* get_mem_page */
-
-int pcmcia_map_mem_page(window_handle_t win, memreq_t *req)
-{
-    struct pcmcia_socket *s;
-    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
-       return CS_BAD_HANDLE;
-    if (req->Page != 0)
-       return CS_BAD_PAGE;
-    s = win->sock;
-    win->ctl.card_start = req->CardOffset;
-    if (s->ops->set_mem_map(s, &win->ctl) != 0)
-       return CS_BAD_OFFSET;
-    return CS_SUCCESS;
-} /* map_mem_page */
-
-/*======================================================================
-
-    Modify a locked socket configuration
-    
-======================================================================*/
-
-int pcmcia_modify_configuration(client_handle_t handle,
-                               modconf_t *mod)
-{
-    struct pcmcia_socket *s;
-    config_t *c;
-    
-    if (CHECK_HANDLE(handle))
-       return CS_BAD_HANDLE;
-    s = SOCKET(handle); c = CONFIG(handle);
-    if (!(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
-    if (!(c->state & CONFIG_LOCKED))
-       return CS_CONFIGURATION_LOCKED;
-    
-    if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
-       if (mod->Attributes & CONF_ENABLE_IRQ) {
-           c->Attributes |= CONF_ENABLE_IRQ;
-           s->socket.io_irq = s->irq.AssignedIRQ;
-       } else {
-           c->Attributes &= ~CONF_ENABLE_IRQ;
-           s->socket.io_irq = 0;
-       }
-       s->ops->set_socket(s, &s->socket);
-    }
-
-    if (mod->Attributes & CONF_VCC_CHANGE_VALID)
-       return CS_BAD_VCC;
-
-    /* We only allow changing Vpp1 and Vpp2 to the same value */
-    if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
-       (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
-       if (mod->Vpp1 != mod->Vpp2)
-           return CS_BAD_VPP;
-       c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1;
-       if (s->ops->set_socket(s, &s->socket))
-           return CS_BAD_VPP;
-    } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
-              (mod->Attributes & CONF_VPP2_CHANGE_VALID))
-       return CS_BAD_VPP;
-
-    return CS_SUCCESS;
-} /* modify_configuration */
-
 /* register pcmcia_callback */
 int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
 {
@@ -1188,543 +736,16 @@ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
 }
 EXPORT_SYMBOL(pccard_register_pcmcia);
 
-/*====================================================================*/
 
-int pcmcia_release_configuration(client_handle_t handle)
-{
-    pccard_io_map io = { 0, 0, 0, 0, 1 };
-    struct pcmcia_socket *s;
-    int i;
-    
-    if (CHECK_HANDLE(handle) ||
-       !(handle->state & CLIENT_CONFIG_LOCKED))
-       return CS_BAD_HANDLE;
-    handle->state &= ~CLIENT_CONFIG_LOCKED;
-    s = SOCKET(handle);
-    
-#ifdef CONFIG_CARDBUS
-    if (handle->state & CLIENT_CARDBUS)
-       return CS_SUCCESS;
-#endif
-    
-    if (!(handle->state & CLIENT_STALE)) {
-       config_t *c = CONFIG(handle);
-       if (--(s->lock_count) == 0) {
-           s->socket.flags = SS_OUTPUT_ENA;   /* Is this correct? */
-           s->socket.Vpp = 0;
-           s->socket.io_irq = 0;
-           s->ops->set_socket(s, &s->socket);
-       }
-       if (c->state & CONFIG_IO_REQ)
-           for (i = 0; i < MAX_IO_WIN; i++) {
-               if (s->io[i].NumPorts == 0)
-                   continue;
-               s->io[i].Config--;
-               if (s->io[i].Config != 0)
-                   continue;
-               io.map = i;
-               s->ops->set_io_map(s, &io);
-           }
-       c->state &= ~CONFIG_LOCKED;
-    }
-    
-    return CS_SUCCESS;
-} /* release_configuration */
-
-/*======================================================================
-
-    Release_io() releases the I/O ranges allocated by a client.  This
-    may be invoked some time after a card ejection has already dumped
-    the actual socket configuration, so if the client is "stale", we
-    don't bother checking the port ranges against the current socket
-    values.
-    
-======================================================================*/
-
-int pcmcia_release_io(client_handle_t handle, io_req_t *req)
-{
-    struct pcmcia_socket *s;
-    
-    if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ))
-       return CS_BAD_HANDLE;
-    handle->state &= ~CLIENT_IO_REQ;
-    s = SOCKET(handle);
-    
-#ifdef CONFIG_CARDBUS
-    if (handle->state & CLIENT_CARDBUS)
-       return CS_SUCCESS;
-#endif
-    
-    if (!(handle->state & CLIENT_STALE)) {
-       config_t *c = CONFIG(handle);
-       if (c->state & CONFIG_LOCKED)
-           return CS_CONFIGURATION_LOCKED;
-       if ((c->io.BasePort1 != req->BasePort1) ||
-           (c->io.NumPorts1 != req->NumPorts1) ||
-           (c->io.BasePort2 != req->BasePort2) ||
-           (c->io.NumPorts2 != req->NumPorts2))
-           return CS_BAD_ARGS;
-       c->state &= ~CONFIG_IO_REQ;
-    }
-
-    release_io_space(s, req->BasePort1, req->NumPorts1);
-    if (req->NumPorts2)
-       release_io_space(s, req->BasePort2, req->NumPorts2);
-    
-    return CS_SUCCESS;
-} /* release_io */
-
-/*====================================================================*/
-
-int pcmcia_release_irq(client_handle_t handle, irq_req_t *req)
-{
-    struct pcmcia_socket *s;
-    if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ))
-       return CS_BAD_HANDLE;
-    handle->state &= ~CLIENT_IRQ_REQ;
-    s = SOCKET(handle);
-    
-    if (!(handle->state & CLIENT_STALE)) {
-       config_t *c = CONFIG(handle);
-       if (c->state & CONFIG_LOCKED)
-           return CS_CONFIGURATION_LOCKED;
-       if (c->irq.Attributes != req->Attributes)
-           return CS_BAD_ATTRIBUTE;
-       if (s->irq.AssignedIRQ != req->AssignedIRQ)
-           return CS_BAD_IRQ;
-       if (--s->irq.Config == 0) {
-           c->state &= ~CONFIG_IRQ_REQ;
-           s->irq.AssignedIRQ = 0;
-       }
-    }
-    
-    if (req->Attributes & IRQ_HANDLE_PRESENT) {
-       free_irq(req->AssignedIRQ, req->Instance);
-    }
-
-#ifdef CONFIG_PCMCIA_PROBE
-    pcmcia_used_irq[req->AssignedIRQ]--;
-#endif
-
-    return CS_SUCCESS;
-} /* cs_release_irq */
-
-/*====================================================================*/
-
-int pcmcia_release_window(window_handle_t win)
-{
-    struct pcmcia_socket *s;
-    
-    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
-       return CS_BAD_HANDLE;
-    s = win->sock;
-    if (!(win->handle->state & CLIENT_WIN_REQ(win->index)))
-       return CS_BAD_HANDLE;
-
-    /* Shut down memory window */
-    win->ctl.flags &= ~MAP_ACTIVE;
-    s->ops->set_mem_map(s, &win->ctl);
-    s->state &= ~SOCKET_WIN_REQ(win->index);
-
-    /* Release system memory */
-    if (win->ctl.res) {
-       release_resource(win->ctl.res);
-       kfree(win->ctl.res);
-       win->ctl.res = NULL;
-    }
-    win->handle->state &= ~CLIENT_WIN_REQ(win->index);
-
-    win->magic = 0;
-    
-    return CS_SUCCESS;
-} /* release_window */
-
-/*====================================================================*/
-
-int pcmcia_request_configuration(client_handle_t handle,
-                                config_req_t *req)
-{
-    int i;
-    u_int base;
-    struct pcmcia_socket *s;
-    config_t *c;
-    pccard_io_map iomap;
-    
-    if (CHECK_HANDLE(handle))
-       return CS_BAD_HANDLE;
-    s = SOCKET(handle);
-    if (!(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
-    
-#ifdef CONFIG_CARDBUS
-    if (handle->state & CLIENT_CARDBUS)
-       return CS_UNSUPPORTED_MODE;
-#endif
-    
-    if (req->IntType & INT_CARDBUS)
-       return CS_UNSUPPORTED_MODE;
-    c = CONFIG(handle);
-    if (c->state & CONFIG_LOCKED)
-       return CS_CONFIGURATION_LOCKED;
-
-    /* Do power control.  We don't allow changes in Vcc. */
-    if (s->socket.Vcc != req->Vcc)
-       return CS_BAD_VCC;
-    if (req->Vpp1 != req->Vpp2)
-       return CS_BAD_VPP;
-    s->socket.Vpp = req->Vpp1;
-    if (s->ops->set_socket(s, &s->socket))
-       return CS_BAD_VPP;
-    
-    c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1;
-    
-    /* Pick memory or I/O card, DMA mode, interrupt */
-    c->IntType = req->IntType;
-    c->Attributes = req->Attributes;
-    if (req->IntType & INT_MEMORY_AND_IO)
-       s->socket.flags |= SS_IOCARD;
-    if (req->IntType & INT_ZOOMED_VIDEO)
-       s->socket.flags |= SS_ZVCARD | SS_IOCARD;
-    if (req->Attributes & CONF_ENABLE_DMA)
-       s->socket.flags |= SS_DMA_MODE;
-    if (req->Attributes & CONF_ENABLE_SPKR)
-       s->socket.flags |= SS_SPKR_ENA;
-    if (req->Attributes & CONF_ENABLE_IRQ)
-       s->socket.io_irq = s->irq.AssignedIRQ;
-    else
-       s->socket.io_irq = 0;
-    s->ops->set_socket(s, &s->socket);
-    s->lock_count++;
-    
-    /* Set up CIS configuration registers */
-    base = c->ConfigBase = req->ConfigBase;
-    c->Present = c->CardValues = req->Present;
-    if (req->Present & PRESENT_COPY) {
-       c->Copy = req->Copy;
-       write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);
-    }
-    if (req->Present & PRESENT_OPTION) {
-       if (s->functions == 1) {
-           c->Option = req->ConfigIndex & COR_CONFIG_MASK;
-       } else {
-           c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK;
-           c->Option |= COR_FUNC_ENA|COR_IREQ_ENA;
-           if (req->Present & PRESENT_IOBASE_0)
-               c->Option |= COR_ADDR_DECODE;
-       }
-       if (c->state & CONFIG_IRQ_REQ)
-           if (!(c->irq.Attributes & IRQ_FORCED_PULSE))
-               c->Option |= COR_LEVEL_REQ;
-       write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);
-       mdelay(40);
-    }
-    if (req->Present & PRESENT_STATUS) {
-       c->Status = req->Status;
-       write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status);
-    }
-    if (req->Present & PRESENT_PIN_REPLACE) {
-       c->Pin = req->Pin;
-       write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin);
-    }
-    if (req->Present & PRESENT_EXT_STATUS) {
-       c->ExtStatus = req->ExtStatus;
-       write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
-    }
-    if (req->Present & PRESENT_IOBASE_0) {
-       u_char b = c->io.BasePort1 & 0xff;
-       write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
-       b = (c->io.BasePort1 >> 8) & 0xff;
-       write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
-    }
-    if (req->Present & PRESENT_IOSIZE) {
-       u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1;
-       write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
-    }
-    
-    /* Configure I/O windows */
-    if (c->state & CONFIG_IO_REQ) {
-       iomap.speed = io_speed;
-       for (i = 0; i < MAX_IO_WIN; i++)
-           if (s->io[i].NumPorts != 0) {
-               iomap.map = i;
-               iomap.flags = MAP_ACTIVE;
-               switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) {
-               case IO_DATA_PATH_WIDTH_16:
-                   iomap.flags |= MAP_16BIT; break;
-               case IO_DATA_PATH_WIDTH_AUTO:
-                   iomap.flags |= MAP_AUTOSZ; break;
-               default:
-                   break;
-               }
-               iomap.start = s->io[i].BasePort;
-               iomap.stop = iomap.start + s->io[i].NumPorts - 1;
-               s->ops->set_io_map(s, &iomap);
-               s->io[i].Config++;
-           }
-    }
-    
-    c->state |= CONFIG_LOCKED;
-    handle->state |= CLIENT_CONFIG_LOCKED;
-    return CS_SUCCESS;
-} /* request_configuration */
-
-/*======================================================================
-  
-    Request_io() reserves ranges of port addresses for a socket.
-    I have not implemented range sharing or alias addressing.
-    
-======================================================================*/
-
-int pcmcia_request_io(client_handle_t handle, io_req_t *req)
-{
-    struct pcmcia_socket *s;
-    config_t *c;
-    
-    if (CHECK_HANDLE(handle))
-       return CS_BAD_HANDLE;
-    s = SOCKET(handle);
-    if (!(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
-
-    if (handle->state & CLIENT_CARDBUS) {
-#ifdef CONFIG_CARDBUS
-       handle->state |= CLIENT_IO_REQ;
-       return CS_SUCCESS;
-#else
-       return CS_UNSUPPORTED_FUNCTION;
-#endif
-    }
-
-    if (!req)
-       return CS_UNSUPPORTED_MODE;
-    c = CONFIG(handle);
-    if (c->state & CONFIG_LOCKED)
-       return CS_CONFIGURATION_LOCKED;
-    if (c->state & CONFIG_IO_REQ)
-       return CS_IN_USE;
-    if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))
-       return CS_BAD_ATTRIBUTE;
-    if ((req->NumPorts2 > 0) &&
-       (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)))
-       return CS_BAD_ATTRIBUTE;
-
-    if (alloc_io_space(s, req->Attributes1, &req->BasePort1,
-                      req->NumPorts1, req->IOAddrLines))
-       return CS_IN_USE;
-
-    if (req->NumPorts2) {
-       if (alloc_io_space(s, req->Attributes2, &req->BasePort2,
-                          req->NumPorts2, req->IOAddrLines)) {
-           release_io_space(s, req->BasePort1, req->NumPorts1);
-           return CS_IN_USE;
-       }
-    }
-
-    c->io = *req;
-    c->state |= CONFIG_IO_REQ;
-    handle->state |= CLIENT_IO_REQ;
-    return CS_SUCCESS;
-} /* request_io */
-
-/*======================================================================
-
-    Request_irq() reserves an irq for this client.
-
-    Also, since Linux only reserves irq's when they are actually
-    hooked, we don't guarantee that an irq will still be available
-    when the configuration is locked.  Now that I think about it,
-    there might be a way to fix this using a dummy handler.
-    
-======================================================================*/
-
-#ifdef CONFIG_PCMCIA_PROBE
-static irqreturn_t test_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-       return IRQ_NONE;
-}
-#endif
-
-int pcmcia_request_irq(client_handle_t handle, irq_req_t *req)
-{
-       struct pcmcia_socket *s;
-       config_t *c;
-       int ret = CS_IN_USE, irq = 0;
-       struct pcmcia_device *p_dev = handle_to_pdev(handle);
-
-       if (CHECK_HANDLE(handle))
-               return CS_BAD_HANDLE;
-       s = SOCKET(handle);
-       if (!(s->state & SOCKET_PRESENT))
-               return CS_NO_CARD;
-       c = CONFIG(handle);
-       if (c->state & CONFIG_LOCKED)
-               return CS_CONFIGURATION_LOCKED;
-       if (c->state & CONFIG_IRQ_REQ)
-               return CS_IN_USE;
-
-#ifdef CONFIG_PCMCIA_PROBE
-       if (s->irq.AssignedIRQ != 0) {
-               /* If the interrupt is already assigned, it must be the same */
-               irq = s->irq.AssignedIRQ;
-       } else {
-               int try;
-               u32 mask = s->irq_mask;
-               void *data = NULL;
-
-               for (try = 0; try < 64; try++) {
-                       irq = try % 32;
-
-                       /* marked as available by driver, and not blocked by userspace? */
-                       if (!((mask >> irq) & 1))
-                               continue;
-
-                       /* avoid an IRQ which is already used by a PCMCIA card */
-                       if ((try < 32) && pcmcia_used_irq[irq])
-                               continue;
-
-                       /* register the correct driver, if possible, of check whether
-                        * registering a dummy handle works, i.e. if the IRQ isn't
-                        * marked as used by the kernel resource management core */
-                       ret = request_irq(irq,
-                                         (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action,
-                                         ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
-                                          (s->functions > 1) ||
-                                          (irq == s->pci_irq)) ? SA_SHIRQ : 0,
-                                         p_dev->dev.bus_id,
-                                         (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data);
-                       if (!ret) {
-                               if (!(req->Attributes & IRQ_HANDLE_PRESENT))
-                                       free_irq(irq, data);
-                               break;
-                       }
-               }
-       }
-#endif
-       if (ret) {
-               if (!s->pci_irq)
-                       return ret;
-               irq = s->pci_irq;
-       }
-
-       if (ret && req->Attributes & IRQ_HANDLE_PRESENT) {
-               if (request_irq(irq, req->Handler,
-                               ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
-                                (s->functions > 1) ||
-                                (irq == s->pci_irq)) ? SA_SHIRQ : 0,
-                               p_dev->dev.bus_id, req->Instance))
-                       return CS_IN_USE;
-       }
-
-       c->irq.Attributes = req->Attributes;
-       s->irq.AssignedIRQ = req->AssignedIRQ = irq;
-       s->irq.Config++;
-
-       c->state |= CONFIG_IRQ_REQ;
-       handle->state |= CLIENT_IRQ_REQ;
-
-#ifdef CONFIG_PCMCIA_PROBE
-       pcmcia_used_irq[irq]++;
-#endif
-
-       return CS_SUCCESS;
-} /* pcmcia_request_irq */
-
-/*======================================================================
-
-    Request_window() establishes a mapping between card memory space
-    and system memory space.
-
-======================================================================*/
-
-int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh)
-{
-    struct pcmcia_socket *s;
-    window_t *win;
-    u_long align;
-    int w;
-    
-    if (CHECK_HANDLE(*handle))
-       return CS_BAD_HANDLE;
-    s = (*handle)->Socket;
-    if (!(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
-    if (req->Attributes & (WIN_PAGED | WIN_SHARED))
-       return CS_BAD_ATTRIBUTE;
-
-    /* Window size defaults to smallest available */
-    if (req->Size == 0)
-       req->Size = s->map_size;
-    align = (((s->features & SS_CAP_MEM_ALIGN) ||
-             (req->Attributes & WIN_STRICT_ALIGN)) ?
-            req->Size : s->map_size);
-    if (req->Size & (s->map_size-1))
-       return CS_BAD_SIZE;
-    if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) ||
-       (req->Base & (align-1)))
-       return CS_BAD_BASE;
-    if (req->Base)
-       align = 0;
-
-    /* Allocate system memory window */
-    for (w = 0; w < MAX_WIN; w++)
-       if (!(s->state & SOCKET_WIN_REQ(w))) break;
-    if (w == MAX_WIN)
-       return CS_OUT_OF_RESOURCE;
-
-    win = &s->win[w];
-    win->magic = WINDOW_MAGIC;
-    win->index = w;
-    win->handle = *handle;
-    win->sock = s;
-
-    if (!(s->features & SS_CAP_STATIC_MAP)) {
-       win->ctl.res = find_mem_region(req->Base, req->Size, align,
-                                      (req->Attributes & WIN_MAP_BELOW_1MB), s);
-       if (!win->ctl.res)
-           return CS_IN_USE;
-    }
-    (*handle)->state |= CLIENT_WIN_REQ(w);
-
-    /* Configure the socket controller */
-    win->ctl.map = w+1;
-    win->ctl.flags = 0;
-    win->ctl.speed = req->AccessSpeed;
-    if (req->Attributes & WIN_MEMORY_TYPE)
-       win->ctl.flags |= MAP_ATTRIB;
-    if (req->Attributes & WIN_ENABLE)
-       win->ctl.flags |= MAP_ACTIVE;
-    if (req->Attributes & WIN_DATA_WIDTH_16)
-       win->ctl.flags |= MAP_16BIT;
-    if (req->Attributes & WIN_USE_WAIT)
-       win->ctl.flags |= MAP_USE_WAIT;
-    win->ctl.card_start = 0;
-    if (s->ops->set_mem_map(s, &win->ctl) != 0)
-       return CS_BAD_ARGS;
-    s->state |= SOCKET_WIN_REQ(w);
-
-    /* Return window handle */
-    if (s->features & SS_CAP_STATIC_MAP) {
-       req->Base = win->ctl.static_start;
-    } else {
-       req->Base = win->ctl.res->start;
-    }
-    *wh = win;
-    
-    return CS_SUCCESS;
-} /* request_window */
-
-/*======================================================================
-
-    I'm not sure which "reset" function this is supposed to use,
-    but for now, it uses the low-level interface's reset, not the
-    CIS register.
-    
-======================================================================*/
+/* I'm not sure which "reset" function this is supposed to use,
+ * but for now, it uses the low-level interface's reset, not the
+ * CIS register.
+ */
 
 int pccard_reset_card(struct pcmcia_socket *skt)
 {
        int ret;
-    
+
        cs_dbg(skt, 1, "resetting socket\n");
 
        down(&skt->skt_sem);
@@ -1757,17 +778,14 @@ int pccard_reset_card(struct pcmcia_socket *skt)
 } /* reset_card */
 EXPORT_SYMBOL(pccard_reset_card);
 
-/*======================================================================
-
-    These shut down or wake up a socket.  They are sort of user
-    initiated versions of the APM suspend and resume actions.
-    
-======================================================================*/
 
+/* These shut down or wake up a socket.  They are sort of user
+ * initiated versions of the APM suspend and resume actions.
+ */
 int pcmcia_suspend_card(struct pcmcia_socket *skt)
 {
        int ret;
-    
+
        cs_dbg(skt, 1, "suspending socket\n");
 
        down(&skt->skt_sem);
@@ -1786,6 +804,8 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt)
 
        return ret;
 } /* suspend_card */
+EXPORT_SYMBOL(pcmcia_suspend_card);
+
 
 int pcmcia_resume_card(struct pcmcia_socket *skt)
 {
@@ -1809,13 +829,10 @@ int pcmcia_resume_card(struct pcmcia_socket *skt)
 
        return ret;
 } /* resume_card */
+EXPORT_SYMBOL(pcmcia_resume_card);
 
-/*======================================================================
-
-    These handle user requests to eject or insert a card.
-    
-======================================================================*/
 
+/* These handle user requests to eject or insert a card. */
 int pcmcia_eject_card(struct pcmcia_socket *skt)
 {
        int ret;
@@ -1842,6 +859,8 @@ int pcmcia_eject_card(struct pcmcia_socket *skt)
 
        return ret;
 } /* eject_card */
+EXPORT_SYMBOL(pcmcia_eject_card);
+
 
 int pcmcia_insert_card(struct pcmcia_socket *skt)
 {
@@ -1865,37 +884,38 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
 
        return ret;
 } /* insert_card */
+EXPORT_SYMBOL(pcmcia_insert_card);
 
-/*======================================================================
 
-    OS-specific module glue goes here
-    
-======================================================================*/
-/* in alpha order */
-EXPORT_SYMBOL(pcmcia_eject_card);
-EXPORT_SYMBOL(pcmcia_get_card_services_info);
-EXPORT_SYMBOL(pcmcia_get_mem_page);
-EXPORT_SYMBOL(pcmcia_insert_card);
-EXPORT_SYMBOL(pcmcia_map_mem_page);
-EXPORT_SYMBOL(pcmcia_modify_configuration);
-EXPORT_SYMBOL(pcmcia_release_configuration);
-EXPORT_SYMBOL(pcmcia_release_io);
-EXPORT_SYMBOL(pcmcia_release_irq);
-EXPORT_SYMBOL(pcmcia_release_window);
-EXPORT_SYMBOL(pcmcia_replace_cis);
-EXPORT_SYMBOL(pcmcia_request_configuration);
-EXPORT_SYMBOL(pcmcia_request_io);
-EXPORT_SYMBOL(pcmcia_request_irq);
-EXPORT_SYMBOL(pcmcia_request_window);
-EXPORT_SYMBOL(pcmcia_resume_card);
-EXPORT_SYMBOL(pcmcia_suspend_card);
+static int pcmcia_socket_hotplug(struct class_device *dev, char **envp,
+                               int num_envp, char *buffer, int buffer_size)
+{
+       struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
+       int i = 0, length = 0;
+
+       if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
+                               &length, "SOCKET_NO=%u", s->sock))
+               return -ENOMEM;
+
+       envp[i] = NULL;
+
+       return 0;
+}
+
+
+static struct completion pcmcia_unload;
+
+static void pcmcia_release_socket_class(struct class *data)
+{
+       complete(&pcmcia_unload);
+}
 
-EXPORT_SYMBOL(dead_socket);
-EXPORT_SYMBOL(pcmcia_parse_events);
 
 struct class pcmcia_socket_class = {
        .name = "pcmcia_socket",
+        .hotplug = pcmcia_socket_hotplug,
        .release = pcmcia_release_socket,
+       .class_release = pcmcia_release_socket_class,
 };
 EXPORT_SYMBOL(pcmcia_socket_class);
 
@@ -1903,9 +923,8 @@ EXPORT_SYMBOL(pcmcia_socket_class);
 static int __init init_pcmcia_cs(void)
 {
        int ret;
-       printk(KERN_INFO "%s\n", release);
-       printk(KERN_INFO "  %s\n", options);
 
+       init_completion(&pcmcia_unload);
        ret = class_register(&pcmcia_socket_class);
        if (ret)
                return (ret);
@@ -1914,13 +933,12 @@ static int __init init_pcmcia_cs(void)
 
 static void __exit exit_pcmcia_cs(void)
 {
-    printk(KERN_INFO "unloading Kernel Card Services\n");
-    class_interface_unregister(&pccard_sysfs_interface);
-    class_unregister(&pcmcia_socket_class);
+       class_interface_unregister(&pccard_sysfs_interface);
+       class_unregister(&pcmcia_socket_class);
+
+       wait_for_completion(&pcmcia_unload);
 }
 
 subsys_initcall(init_pcmcia_cs);
 module_exit(exit_pcmcia_cs);
 
-/*====================================================================*/
-
index 7933a7db49d325499efd79a5132b2f56815146cd..0b4c18edfa498ef02a21bb56894e91b6a95dc3e4 100644 (file)
@@ -123,9 +123,9 @@ void cb_free(struct pcmcia_socket *s);
 int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len, void *ptr);
 
 /* In cistpl.c */
-int read_cis_mem(struct pcmcia_socket *s, int attr,
+int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr,
                 u_int addr, u_int len, void *ptr);
-void write_cis_mem(struct pcmcia_socket *s, int attr,
+void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr,
                   u_int addr, u_int len, void *ptr);
 void release_cis_mem(struct pcmcia_socket *s);
 void destroy_cis_cache(struct pcmcia_socket *s);
@@ -134,13 +134,12 @@ int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t
 
 /* In rsrc_mgr */
 void pcmcia_validate_mem(struct pcmcia_socket *s);
-struct resource *find_io_region(unsigned long base, int num, unsigned long align,
+struct resource *pcmcia_find_io_region(unsigned long base, int num, unsigned long align,
                   struct pcmcia_socket *s);
-int adjust_io_region(struct resource *res, unsigned long r_start,
+int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start,
                     unsigned long r_end, struct pcmcia_socket *s);
-struct resource *find_mem_region(u_long base, u_long num, u_long align,
+struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
                    int low, struct pcmcia_socket *s);
-int adjust_resource_info(client_handle_t handle, adjust_t *adj);
 void release_resource_db(struct pcmcia_socket *s);
 
 /* In socket_sysfs.c */
@@ -159,7 +158,7 @@ int pccard_access_configuration_register(struct pcmcia_socket *s, unsigned int f
 struct pcmcia_callback{
        struct module   *owner;
        int             (*event) (struct pcmcia_socket *s, event_t event, int priority);
-       int             (*resources_done) (struct pcmcia_socket *s);
+       void            (*requery) (struct pcmcia_socket *s);
 };
 
 int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
index 569e55feecfd682c5563b594ac92d456717053f5..d5afd557fe370f8a9b0a92b076cd2f4a37d4e4f3 100644 (file)
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * (C) 1999            David A. Hinds
- * (C) 2003 - 2004     Dominik Brodowski
+ * (C) 2003 - 2005     Dominik Brodowski
  */
 
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/timer.h>
-#include <linux/ioctl.h>
-#include <linux/proc_fs.h>
-#include <linux/poll.h>
-#include <linux/pci.h>
 #include <linux/list.h>
 #include <linux/delay.h>
-#include <linux/kref.h>
 #include <linux/workqueue.h>
-
-#include <asm/atomic.h>
+#include <linux/crc32.h>
+#include <linux/firmware.h>
 
 #define IN_CARD_SERVICES
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/ss.h>
 
 #include "cs_internal.h"
+#include "ds_internal.h"
 
 /*====================================================================*/
 
@@ -70,49 +55,9 @@ module_param_named(pc_debug, ds_pc_debug, int, 0644);
 #define ds_dbg(lvl, fmt, arg...) do { } while (0)
 #endif
 
-/*====================================================================*/
+spinlock_t pcmcia_dev_list_lock;
 
-/* Device user information */
-#define MAX_EVENTS     32
-#define USER_MAGIC     0x7ea4
-#define CHECK_USER(u) \
-    (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
-typedef struct user_info_t {
-    u_int              user_magic;
-    int                        event_head, event_tail;
-    event_t            event[MAX_EVENTS];
-    struct user_info_t *next;
-    struct pcmcia_bus_socket *socket;
-} user_info_t;
-
-/* Socket state information */
-struct pcmcia_bus_socket {
-       struct kref             refcount;
-       struct pcmcia_callback  callback;
-       int                     state;
-       user_info_t             *user;
-       wait_queue_head_t       queue;
-       struct pcmcia_socket    *parent;
-
-       /* the PCMCIA devices connected to this socket (normally one, more
-        * for multifunction devices: */
-       struct list_head        devices_list;
-       u8                      device_count; /* the number of devices, used
-                                              * only internally and subject
-                                              * to incorrectness and change */
-};
-static spinlock_t pcmcia_dev_list_lock;
-
-#define DS_SOCKET_PRESENT              0x01
-#define DS_SOCKET_BUSY                 0x02
-#define DS_SOCKET_REMOVAL_PENDING      0x10
-#define DS_SOCKET_DEAD                 0x80
-
-/*====================================================================*/
-
-static int major_dev = -1;
-
-static int unbind_request(struct pcmcia_bus_socket *s);
+static int unbind_request(struct pcmcia_socket *s);
 
 /*====================================================================*/
 
@@ -213,7 +158,7 @@ static const lookup_t service_table[] = {
 };
 
 
-int pcmcia_report_error(client_handle_t handle, error_info_t *err)
+static int pcmcia_report_error(client_handle_t handle, error_info_t *err)
 {
        int i;
        char *serv;
@@ -243,7 +188,6 @@ int pcmcia_report_error(client_handle_t handle, error_info_t *err)
 
        return CS_SUCCESS;
 } /* report_error */
-EXPORT_SYMBOL(pcmcia_report_error);
 
 /* end of code which was in cs.c before */
 
@@ -256,29 +200,101 @@ void cs_error(client_handle_t handle, int func, int ret)
 }
 EXPORT_SYMBOL(cs_error);
 
-/*======================================================================*/
-
-static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info);
-static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr);
 
-static void pcmcia_release_bus_socket(struct kref *refcount)
+static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
 {
-       struct pcmcia_bus_socket *s = container_of(refcount, struct pcmcia_bus_socket, refcount);
-       pcmcia_put_socket(s->parent);
-       kfree(s);
+       struct pcmcia_device_id *did = p_drv->id_table;
+       unsigned int i;
+       u32 hash;
+
+       while (did && did->match_flags) {
+               for (i=0; i<4; i++) {
+                       if (!did->prod_id[i])
+                               continue;
+
+                       hash = crc32(0, did->prod_id[i], strlen(did->prod_id[i]));
+                       if (hash == did->prod_id_hash[i])
+                               continue;
+
+                       printk(KERN_DEBUG "pcmcia: %s: invalid hash for "
+                              "product string \"%s\": is 0x%x, should "
+                              "be 0x%x\n", p_drv->drv.name, did->prod_id[i],
+                              did->prod_id_hash[i], hash);
+                       printk(KERN_DEBUG "pcmcia: see "
+                               "Documentation/pcmcia/devicetable.txt for "
+                               "details\n");
+               }
+               did++;
+       }
+
+       return;
 }
 
-static void pcmcia_put_bus_socket(struct pcmcia_bus_socket *s)
+
+#ifdef CONFIG_PCMCIA_LOAD_CIS
+
+/**
+ * pcmcia_load_firmware - load CIS from userspace if device-provided is broken
+ * @dev - the pcmcia device which needs a CIS override
+ * @filename - requested filename in /lib/firmware/cis/
+ *
+ * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
+ * the one provided by the card is broken. The firmware files reside in
+ * /lib/firmware/cis/ in userspace.
+ */
+static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
 {
-       kref_put(&s->refcount, pcmcia_release_bus_socket);
+       struct pcmcia_socket *s = dev->socket;
+       const struct firmware *fw;
+       char path[20];
+       int ret=-ENOMEM;
+       cisdump_t *cis;
+
+       if (!filename)
+               return -EINVAL;
+
+       ds_dbg(1, "trying to load firmware %s\n", filename);
+
+       if (strlen(filename) > 14)
+               return -EINVAL;
+
+       snprintf(path, 20, "%s", filename);
+
+       if (request_firmware(&fw, path, &dev->dev) == 0) {
+               if (fw->size >= CISTPL_MAX_CIS_SIZE)
+                       goto release;
+
+               cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL);
+               if (!cis)
+                       goto release;
+
+               memset(cis, 0, sizeof(cisdump_t));
+
+               cis->Length = fw->size + 1;
+               memcpy(cis->Data, fw->data, fw->size);
+
+               if (!pcmcia_replace_cis(s, cis))
+                       ret = 0;
+       }
+ release:
+       release_firmware(fw);
+
+       return (ret);
 }
 
-static struct pcmcia_bus_socket *pcmcia_get_bus_socket(struct pcmcia_bus_socket *s)
+#else /* !CONFIG_PCMCIA_LOAD_CIS */
+
+static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
 {
-       kref_get(&s->refcount);
-       return (s);
+       return -ENODEV;
 }
 
+#endif
+
+
+/*======================================================================*/
+
+
 /**
  * pcmcia_register_driver - register a PCMCIA driver with the bus core
  *
@@ -292,6 +308,8 @@ int pcmcia_register_driver(struct pcmcia_driver *driver)
        if (!driver)
                return -EINVAL;
 
+       pcmcia_check_driver(driver);
+
        /* initialize common fields */
        driver->drv.bus = &pcmcia_bus_type;
        driver->drv.owner = driver->owner;
@@ -311,42 +329,10 @@ void pcmcia_unregister_driver(struct pcmcia_driver *driver)
 }
 EXPORT_SYMBOL(pcmcia_unregister_driver);
 
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry *proc_pccard = NULL;
-
-static int proc_read_drivers_callback(struct device_driver *driver, void *d)
-{
-       char **p = d;
-       struct pcmcia_driver *p_drv = container_of(driver,
-                                                  struct pcmcia_driver, drv);
-
-       *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
-#ifdef CONFIG_MODULE_UNLOAD
-                     (p_drv->owner) ? module_refcount(p_drv->owner) : 1
-#else
-                     1
-#endif
-       );
-       d = (void *) p;
-
-       return 0;
-}
-
-static int proc_read_drivers(char *buf, char **start, off_t pos,
-                            int count, int *eof, void *data)
-{
-       char *p = buf;
-
-       bus_for_each_drv(&pcmcia_bus_type, NULL, 
-                        (void *) &p, proc_read_drivers_callback);
-
-       return (p - buf);
-}
-#endif
 
 /* pcmcia_device handling */
 
-static struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev)
+struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev)
 {
        struct device *tmp_dev;
        tmp_dev = get_device(&p_dev->dev);
@@ -355,7 +341,7 @@ static struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev)
        return to_pcmcia_dev(tmp_dev);
 }
 
-static void pcmcia_put_dev(struct pcmcia_device *p_dev)
+void pcmcia_put_dev(struct pcmcia_device *p_dev)
 {
        if (p_dev)
                put_device(&p_dev->dev);
@@ -365,7 +351,7 @@ static void pcmcia_release_dev(struct device *dev)
 {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
        ds_dbg(1, "releasing dev %p\n", p_dev);
-       pcmcia_put_bus_socket(p_dev->socket->pcmcia);
+       pcmcia_put_socket(p_dev->socket);
        kfree(p_dev);
 }
 
@@ -500,34 +486,38 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
  */
 static DECLARE_MUTEX(device_add_lock);
 
-static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, unsigned int function)
+struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function)
 {
        struct pcmcia_device *p_dev;
        unsigned long flags;
 
-       s = pcmcia_get_bus_socket(s);
+       s = pcmcia_get_socket(s);
        if (!s)
                return NULL;
 
        down(&device_add_lock);
 
+       /* max of 2 devices per card */
+       if (s->device_count == 2)
+               goto err_put;
+
        p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
        if (!p_dev)
                goto err_put;
        memset(p_dev, 0, sizeof(struct pcmcia_device));
 
-       p_dev->socket = s->parent;
+       p_dev->socket = s;
        p_dev->device_no = (s->device_count++);
        p_dev->func   = function;
 
        p_dev->dev.bus = &pcmcia_bus_type;
-       p_dev->dev.parent = s->parent->dev.dev;
+       p_dev->dev.parent = s->dev.dev;
        p_dev->dev.release = pcmcia_release_dev;
        sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
 
        /* compat */
        p_dev->client.client_magic = CLIENT_MAGIC;
-       p_dev->client.Socket = s->parent;
+       p_dev->client.Socket = s;
        p_dev->client.Function = function;
        p_dev->client.state = CLIENT_UNBOUND;
 
@@ -536,6 +526,8 @@ static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, uns
        list_add_tail(&p_dev->socket_device_list, &s->devices_list);
        spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
+       pcmcia_device_query(p_dev);
+
        if (device_register(&p_dev->dev)) {
                spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
                list_del(&p_dev->socket_device_list);
@@ -553,7 +545,7 @@ static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, uns
        s->device_count--;
  err_put:
        up(&device_add_lock);
-       pcmcia_put_bus_socket(s);
+       pcmcia_put_socket(s);
 
        return NULL;
 }
@@ -584,23 +576,252 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
        /* this doesn't handle multifunction devices on one pcmcia function
         * yet. */
        for (i=0; i < no_funcs; i++)
-               pcmcia_device_add(s->pcmcia, i);
+               pcmcia_device_add(s, i);
 
        return (ret);
 }
 
 
+static void pcmcia_delayed_add_pseudo_device(void *data)
+{
+       struct pcmcia_socket *s = data;
+       pcmcia_device_add(s, 0);
+       s->pcmcia_state.device_add_pending = 0;
+}
+
+static inline void pcmcia_add_pseudo_device(struct pcmcia_socket *s)
+{
+       if (!s->pcmcia_state.device_add_pending) {
+               schedule_work(&s->device_add);
+               s->pcmcia_state.device_add_pending = 1;
+       }
+       return;
+}
+
+static int pcmcia_requery(struct device *dev, void * _data)
+{
+       struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+       if (!p_dev->dev.driver)
+               pcmcia_device_query(p_dev);
+
+       return 0;
+}
+
+static void pcmcia_bus_rescan(struct pcmcia_socket *skt)
+{
+       int no_devices=0;
+       unsigned long flags;
+
+       /* must be called with skt_sem held */
+       spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+       if (list_empty(&skt->devices_list))
+               no_devices=1;
+       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+       /* if no devices were added for this socket yet because of
+        * missing resource information or other trouble, we need to
+        * do this now. */
+       if (no_devices) {
+               int ret = pcmcia_card_add(skt);
+               if (ret)
+                       return;
+       }
+
+       /* some device information might have changed because of a CIS
+        * update or because we can finally read it correctly... so
+        * determine it again, overwriting old values if necessary. */
+       bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery);
+
+       /* we re-scan all devices, not just the ones connected to this
+        * socket. This does not matter, though. */
+       bus_rescan_devices(&pcmcia_bus_type);
+}
+
+static inline int pcmcia_devmatch(struct pcmcia_device *dev,
+                                 struct pcmcia_device_id *did)
+{
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {
+               if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) {
+               if ((!dev->has_card_id) || (dev->card_id != did->card_id))
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) {
+               if (dev->func != did->function)
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) {
+               if (!dev->prod_id[0])
+                       return 0;
+               if (strcmp(did->prod_id[0], dev->prod_id[0]))
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) {
+               if (!dev->prod_id[1])
+                       return 0;
+               if (strcmp(did->prod_id[1], dev->prod_id[1]))
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) {
+               if (!dev->prod_id[2])
+                       return 0;
+               if (strcmp(did->prod_id[2], dev->prod_id[2]))
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) {
+               if (!dev->prod_id[3])
+                       return 0;
+               if (strcmp(did->prod_id[3], dev->prod_id[3]))
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
+               /* handle pseudo multifunction devices:
+                * there are at most two pseudo multifunction devices.
+                * if we're matching against the first, schedule a
+                * call which will then check whether there are two
+                * pseudo devices, and if not, add the second one.
+                */
+               if (dev->device_no == 0)
+                       pcmcia_add_pseudo_device(dev->socket);
+
+               if (dev->device_no != did->device_no)
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
+               if ((!dev->has_func_id) || (dev->func_id != did->func_id))
+                       return 0;
+
+               /* if this is a pseudo-multi-function device,
+                * we need explicit matches */
+               if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO)
+                       return 0;
+               if (dev->device_no)
+                       return 0;
+
+               /* also, FUNC_ID matching needs to be activated by userspace
+                * after it has re-checked that there is no possible module
+                * with a prod_id/manf_id/card_id match.
+                */
+               if (!dev->allow_func_id_match)
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
+               if (!dev->socket->fake_cis)
+                       pcmcia_load_firmware(dev, did->cisfile);
+
+               if (!dev->socket->fake_cis)
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
+               int i;
+               for (i=0; i<4; i++)
+                       if (dev->prod_id[i])
+                               return 0;
+               if (dev->has_manf_id || dev->has_card_id || dev->has_func_id)
+                       return 0;
+       }
+
+       dev->dev.driver_data = (void *) did;
+
+       return 1;
+}
+
+
 static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
        struct pcmcia_device * p_dev = to_pcmcia_dev(dev);
        struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
+       struct pcmcia_device_id *did = p_drv->id_table;
 
        /* matching by cardmgr */
        if (p_dev->cardmgr == p_drv)
                return 1;
 
+       while (did && did->match_flags) {
+               if (pcmcia_devmatch(p_dev, did))
+                       return 1;
+               did++;
+       }
+
        return 0;
 }
 
+#ifdef CONFIG_HOTPLUG
+
+static int pcmcia_bus_hotplug(struct device *dev, char **envp, int num_envp,
+                             char *buffer, int buffer_size)
+{
+       struct pcmcia_device *p_dev;
+       int i, length = 0;
+       u32 hash[4] = { 0, 0, 0, 0};
+
+       if (!dev)
+               return -ENODEV;
+
+       p_dev = to_pcmcia_dev(dev);
+
+       /* calculate hashes */
+       for (i=0; i<4; i++) {
+               if (!p_dev->prod_id[i])
+                       continue;
+               hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
+       }
+
+       i = 0;
+
+       if (add_hotplug_env_var(envp, num_envp, &i,
+                               buffer, buffer_size, &length,
+                               "SOCKET_NO=%u",
+                               p_dev->socket->sock))
+               return -ENOMEM;
+
+       if (add_hotplug_env_var(envp, num_envp, &i,
+                               buffer, buffer_size, &length,
+                               "DEVICE_NO=%02X",
+                               p_dev->device_no))
+               return -ENOMEM;
+
+       if (add_hotplug_env_var(envp, num_envp, &i,
+                               buffer, buffer_size, &length,
+                               "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+                               "pa%08Xpb%08Xpc%08Xpd%08X",
+                               p_dev->has_manf_id ? p_dev->manf_id : 0,
+                               p_dev->has_card_id ? p_dev->card_id : 0,
+                               p_dev->has_func_id ? p_dev->func_id : 0,
+                               p_dev->func,
+                               p_dev->device_no,
+                               hash[0],
+                               hash[1],
+                               hash[2],
+                               hash[3]))
+               return -ENOMEM;
+
+       envp[i] = NULL;
+
+       return 0;
+}
+
+#else
+
+static int pcmcia_bus_hotplug(struct device *dev, char **envp, int num_envp,
+                             char *buffer, int buffer_size)
+{
+       return -ENODEV;
+}
+
+#endif
+
 /************************ per-device sysfs output ***************************/
 
 #define pcmcia_device_attr(field, test, format)                                \
@@ -626,6 +847,43 @@ pcmcia_device_stringattr(prod_id2, prod_id[1]);
 pcmcia_device_stringattr(prod_id3, prod_id[2]);
 pcmcia_device_stringattr(prod_id4, prod_id[3]);
 
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+       int i;
+       u32 hash[4] = { 0, 0, 0, 0};
+
+       /* calculate hashes */
+       for (i=0; i<4; i++) {
+               if (!p_dev->prod_id[i])
+                       continue;
+               hash[i] = crc32(0,p_dev->prod_id[i],strlen(p_dev->prod_id[i]));
+       }
+       return sprintf(buf, "pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+                               "pa%08Xpb%08Xpc%08Xpd%08X\n",
+                               p_dev->has_manf_id ? p_dev->manf_id : 0,
+                               p_dev->has_card_id ? p_dev->card_id : 0,
+                               p_dev->has_func_id ? p_dev->func_id : 0,
+                               p_dev->func, p_dev->device_no,
+                               hash[0], hash[1], hash[2], hash[3]);
+}
+
+static ssize_t pcmcia_store_allow_func_id_match(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+        if (!count)
+                return -EINVAL;
+
+       down(&p_dev->socket->skt_sem);
+       p_dev->allow_func_id_match = 1;
+       up(&p_dev->socket->skt_sem);
+
+       bus_rescan_devices(&pcmcia_bus_type);
+
+       return count;
+}
+
 static struct device_attribute pcmcia_dev_attrs[] = {
        __ATTR(function, 0444, func_show, NULL),
        __ATTR_RO(func_id),
@@ -635,44 +893,12 @@ static struct device_attribute pcmcia_dev_attrs[] = {
        __ATTR_RO(prod_id2),
        __ATTR_RO(prod_id3),
        __ATTR_RO(prod_id4),
+       __ATTR_RO(modalias),
+       __ATTR(allow_func_id_match, 0200, NULL, pcmcia_store_allow_func_id_match),
        __ATTR_NULL,
 };
 
 
-/*======================================================================
-
-    These manage a ring buffer of events pending for one user process
-    
-======================================================================*/
-
-static int queue_empty(user_info_t *user)
-{
-    return (user->event_head == user->event_tail);
-}
-
-static event_t get_queued_event(user_info_t *user)
-{
-    user->event_tail = (user->event_tail+1) % MAX_EVENTS;
-    return user->event[user->event_tail];
-}
-
-static void queue_event(user_info_t *user, event_t event)
-{
-    user->event_head = (user->event_head+1) % MAX_EVENTS;
-    if (user->event_head == user->event_tail)
-       user->event_tail = (user->event_tail+1) % MAX_EVENTS;
-    user->event[user->event_head] = event;
-}
-
-static void handle_event(struct pcmcia_bus_socket *s, event_t event)
-{
-    user_info_t *user;
-    for (user = s->user; user; user = user->next)
-       queue_event(user, event);
-    wake_up_interruptible(&s->queue);
-}
-
-
 /*======================================================================
 
     The card status event handler.
@@ -706,21 +932,13 @@ static int send_event_callback(struct device *dev, void * _data)
 
 static int send_event(struct pcmcia_socket *s, event_t event, int priority)
 {
-       int ret = 0;
        struct send_event_data private;
-       struct pcmcia_bus_socket *skt = pcmcia_get_bus_socket(s->pcmcia);
-
-       if (!skt)
-               return 0;
 
        private.skt = s;
        private.event = event;
        private.priority = priority;
 
-       ret = bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback);
-
-       pcmcia_put_bus_socket(skt);
-       return ret;
+       return bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback);
 } /* send_event */
 
 
@@ -731,25 +949,25 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority)
 
 static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
 {
-       struct pcmcia_bus_socket *s = skt->pcmcia;
+       struct pcmcia_socket *s = pcmcia_get_socket(skt);
        int ret = 0;
 
        ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
-              event, priority, s);
+              event, priority, skt);
     
        switch (event) {
 
        case CS_EVENT_CARD_REMOVAL:
-               s->state &= ~DS_SOCKET_PRESENT;
+               s->pcmcia_state.present = 0;
                send_event(skt, event, priority);
-               unbind_request(s);
-               handle_event(s, event);
+               unbind_request(skt);
+               handle_event(skt, event);
                break;
        
        case CS_EVENT_CARD_INSERTION:
-               s->state |= DS_SOCKET_PRESENT;
+               s->pcmcia_state.present = 1;
                pcmcia_card_add(skt);
-               handle_event(s, event);
+               handle_event(skt, event);
                break;
 
        case CS_EVENT_EJECTION_REQUEST:
@@ -757,137 +975,22 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
                break;
 
        default:
-               handle_event(s, event);
+               handle_event(skt, event);
                send_event(skt, event, priority);
                break;
     }
 
+    pcmcia_put_socket(s);
+
     return 0;
 } /* ds_event */
 
 
-/*======================================================================
-
-    bind_request() and bind_device() are merged by now. Register_client()
-    is called right at the end of bind_request(), during the driver's
-    ->attach() call. Individual descriptions:
-
-    bind_request() connects a socket to a particular client driver.
-    It looks up the specified device ID in the list of registered
-    drivers, binds it to the socket, and tries to create an instance
-    of the device.  unbind_request() deletes a driver instance.
-    
-    Bind_device() associates a device driver with a particular socket.
-    It is normally called by Driver Services after it has identified
-    a newly inserted card.  An instance of that driver will then be
-    eligible to register as a client of this socket.
-
-    Register_client() uses the dev_info_t handle to match the
-    caller with a socket.  The driver must have already been bound
-    to a socket with bind_device() -- in fact, bind_device()
-    allocates the client structure that will be used.
-
-======================================================================*/
-
-static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
-{
-       struct pcmcia_driver *p_drv;
-       struct pcmcia_device *p_dev;
-       int ret = 0;
-       unsigned long flags;
-
-       s = pcmcia_get_bus_socket(s);
-       if (!s)
-               return -EINVAL;
-
-       ds_dbg(2, "bind_request(%d, '%s')\n", s->parent->sock,
-              (char *)bind_info->dev_info);
-
-       p_drv = get_pcmcia_driver(&bind_info->dev_info);
-       if (!p_drv) {
-               ret = -EINVAL;
-               goto err_put;
-       }
-
-       if (!try_module_get(p_drv->owner)) {
-               ret = -EINVAL;
-               goto err_put_driver;
-       }
-
-       spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
-        list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
-               if (p_dev->func == bind_info->function) {
-                       if ((p_dev->dev.driver == &p_drv->drv)) {
-                               if (p_dev->cardmgr) {
-                                       /* if there's already a device
-                                        * registered, and it was registered
-                                        * by userspace before, we need to
-                                        * return the "instance". */
-                                       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-                                       bind_info->instance = p_dev->instance;
-                                       ret = -EBUSY;
-                                       goto err_put_module;
-                               } else {
-                                       /* the correct driver managed to bind
-                                        * itself magically to the correct
-                                        * device. */
-                                       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-                                       p_dev->cardmgr = p_drv;
-                                       ret = 0;
-                                       goto err_put_module;
-                               }
-                       } else if (!p_dev->dev.driver) {
-                               /* there's already a device available where
-                                * no device has been bound to yet. So we don't
-                                * need to register a device! */
-                               spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-                               goto rescan;
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-
-       p_dev = pcmcia_device_add(s, bind_info->function);
-       if (!p_dev) {
-               ret = -EIO;
-               goto err_put_module;
-       }
-
-rescan:
-       p_dev->cardmgr = p_drv;
-
-       pcmcia_device_query(p_dev);
-
-       /*
-        * Prevent this racing with a card insertion.
-        */
-       down(&s->parent->skt_sem);
-       bus_rescan_devices(&pcmcia_bus_type);
-       up(&s->parent->skt_sem);
-
-       /* check whether the driver indeed matched. I don't care if this
-        * is racy or not, because it can only happen on cardmgr access
-        * paths...
-        */
-       if (!(p_dev->dev.driver == &p_drv->drv))
-               p_dev->cardmgr = NULL;
-
- err_put_module:
-       module_put(p_drv->owner);
- err_put_driver:
-       put_driver(&p_drv->drv);
- err_put:
-       pcmcia_put_bus_socket(s);
-
-       return (ret);
-} /* bind_request */
-
 
 int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
 {
        client_t *client = NULL;
-       struct pcmcia_socket *s;
-       struct pcmcia_bus_socket *skt = NULL;
+       struct pcmcia_socket *s = NULL;
        struct pcmcia_device *p_dev = NULL;
 
        /* Look for unbound client with matching dev_info */
@@ -898,14 +1001,11 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
                if (s->state & SOCKET_CARDBUS)
                        continue;
 
-               skt = s->pcmcia;
-               if (!skt)
-                       continue;
-               skt = pcmcia_get_bus_socket(skt);
-               if (!skt)
+               s = pcmcia_get_socket(s);
+               if (!s)
                        continue;
                spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
-               list_for_each_entry(p_dev, &skt->devices_list, socket_device_list) {
+               list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
                        struct pcmcia_driver *p_drv;
                        p_dev = pcmcia_get_dev(p_dev);
                        if (!p_dev)
@@ -924,14 +1024,14 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
                        pcmcia_put_dev(p_dev);
                }
                spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-               pcmcia_put_bus_socket(skt);
+               pcmcia_put_socket(s);
        }
  found:
        up_read(&pcmcia_socket_list_rwsem);
        if (!p_dev || !client)
                return -ENODEV;
 
-       pcmcia_put_bus_socket(skt); /* safe, as we already hold a reference from bind_device */
+       pcmcia_put_socket(s); /* safe, as we already hold a reference from bind_device */
 
        *handle = client;
        client->state &= ~CLIENT_UNBOUND;
@@ -978,106 +1078,15 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
 EXPORT_SYMBOL(pcmcia_register_client);
 
 
-/*====================================================================*/
-
-extern struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s);
-
-static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info, int first)
-{
-       dev_node_t *node;
-       struct pcmcia_device *p_dev;
-       unsigned long flags;
-       int ret = 0;
-
-#ifdef CONFIG_CARDBUS
-       /*
-        * Some unbelievably ugly code to associate the PCI cardbus
-        * device and its driver with the PCMCIA "bind" information.
-        */
-       {
-               struct pci_bus *bus;
-
-               bus = pcmcia_lookup_bus(s->parent);
-               if (bus) {
-                       struct list_head *list;
-                       struct pci_dev *dev = NULL;
-
-                       list = bus->devices.next;
-                       while (list != &bus->devices) {
-                               struct pci_dev *pdev = pci_dev_b(list);
-                               list = list->next;
-
-                               if (first) {
-                                       dev = pdev;
-                                       break;
-                               }
-
-                               /* Try to handle "next" here some way? */
-                       }
-                       if (dev && dev->driver) {
-                               strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
-                               bind_info->major = 0;
-                               bind_info->minor = 0;
-                               bind_info->next = NULL;
-                               return 0;
-                       }
-               }
-       }
-#endif
-
-       spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
-       list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
-               if (p_dev->func == bind_info->function) {
-                       p_dev = pcmcia_get_dev(p_dev);
-                       if (!p_dev)
-                               continue;
-                       goto found;
-               }
-       }
-       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-       return -ENODEV;
-
- found:
-       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-
-       if ((!p_dev->instance) ||
-           (p_dev->instance->state & DEV_CONFIG_PENDING)) {
-               ret = -EAGAIN;
-               goto err_put;
-       }
-
-       if (first)
-               node = p_dev->instance->dev;
-       else
-               for (node = p_dev->instance->dev; node; node = node->next)
-                       if (node == bind_info->next)
-                               break;
-       if (!node) {
-               ret = -ENODEV;
-               goto err_put;
-       }
-
-       strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
-       bind_info->major = node->major;
-       bind_info->minor = node->minor;
-       bind_info->next = node->next;
-
- err_put:
-       pcmcia_put_dev(p_dev);
-       return (ret);
-} /* get_device_info */
-
-/*====================================================================*/
-
 /* unbind _all_ devices attached to a given pcmcia_bus_socket. The
  * drivers have been called with EVENT_CARD_REMOVAL before.
  */
-static int unbind_request(struct pcmcia_bus_socket *s)
+static int unbind_request(struct pcmcia_socket *s)
 {
        struct pcmcia_device    *p_dev;
        unsigned long           flags;
 
-       ds_dbg(2, "unbind_request(%d)\n", s->parent->sock);
+       ds_dbg(2, "unbind_request(%d)\n", s->sock);
 
        s->device_count = 0;
 
@@ -1133,433 +1142,58 @@ int pcmcia_deregister_client(client_handle_t handle)
 } /* deregister_client */
 EXPORT_SYMBOL(pcmcia_deregister_client);
 
-
-/*======================================================================
-
-    The user-mode PC Card device interface
-
-======================================================================*/
-
-static int ds_open(struct inode *inode, struct file *file)
-{
-    socket_t i = iminor(inode);
-    struct pcmcia_bus_socket *s;
-    user_info_t *user;
-
-    ds_dbg(0, "ds_open(socket %d)\n", i);
-
-    s = get_socket_info_by_nr(i);
-    if (!s)
-           return -ENODEV;
-    s = pcmcia_get_bus_socket(s);
-    if (!s)
-           return -ENODEV;
-
-    if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-           if (s->state & DS_SOCKET_BUSY) {
-                   pcmcia_put_bus_socket(s);
-                   return -EBUSY;
-           }
-       else
-           s->state |= DS_SOCKET_BUSY;
-    }
-    
-    user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
-    if (!user) {
-           pcmcia_put_bus_socket(s);
-           return -ENOMEM;
-    }
-    user->event_tail = user->event_head = 0;
-    user->next = s->user;
-    user->user_magic = USER_MAGIC;
-    user->socket = s;
-    s->user = user;
-    file->private_data = user;
-    
-    if (s->state & DS_SOCKET_PRESENT)
-       queue_event(user, CS_EVENT_CARD_INSERTION);
-    return 0;
-} /* ds_open */
-
-/*====================================================================*/
-
-static int ds_release(struct inode *inode, struct file *file)
-{
-    struct pcmcia_bus_socket *s;
-    user_info_t *user, **link;
-
-    ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
-
-    user = file->private_data;
-    if (CHECK_USER(user))
-       goto out;
-
-    s = user->socket;
-
-    /* Unlink user data structure */
-    if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-       s->state &= ~DS_SOCKET_BUSY;
-    }
-    file->private_data = NULL;
-    for (link = &s->user; *link; link = &(*link)->next)
-       if (*link == user) break;
-    if (link == NULL)
-       goto out;
-    *link = user->next;
-    user->user_magic = 0;
-    kfree(user);
-    pcmcia_put_bus_socket(s);
-out:
-    return 0;
-} /* ds_release */
-
-/*====================================================================*/
-
-static ssize_t ds_read(struct file *file, char __user *buf,
-                      size_t count, loff_t *ppos)
-{
-    struct pcmcia_bus_socket *s;
-    user_info_t *user;
-    int ret;
-
-    ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
-    
-    if (count < 4)
-       return -EINVAL;
-
-    user = file->private_data;
-    if (CHECK_USER(user))
-       return -EIO;
-    
-    s = user->socket;
-    if (s->state & DS_SOCKET_DEAD)
-        return -EIO;
-
-    ret = wait_event_interruptible(s->queue, !queue_empty(user));
-    if (ret == 0)
-       ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
-
-    return ret;
-} /* ds_read */
-
-/*====================================================================*/
-
-static ssize_t ds_write(struct file *file, const char __user *buf,
-                       size_t count, loff_t *ppos)
-{
-    ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
-
-    if (count != 4)
-       return -EINVAL;
-    if ((file->f_flags & O_ACCMODE) == O_RDONLY)
-       return -EBADF;
-
-    return -EIO;
-} /* ds_write */
-
-/*====================================================================*/
-
-/* No kernel lock - fine */
-static u_int ds_poll(struct file *file, poll_table *wait)
-{
-    struct pcmcia_bus_socket *s;
-    user_info_t *user;
-
-    ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
-    
-    user = file->private_data;
-    if (CHECK_USER(user))
-       return POLLERR;
-    s = user->socket;
-    /*
-     * We don't check for a dead socket here since that
-     * will send cardmgr into an endless spin.
-     */
-    poll_wait(file, &s->queue, wait);
-    if (!queue_empty(user))
-       return POLLIN | POLLRDNORM;
-    return 0;
-} /* ds_poll */
-
-/*====================================================================*/
-
-extern int pcmcia_adjust_resource_info(adjust_t *adj);
-
-static int ds_ioctl(struct inode * inode, struct file * file,
-                   u_int cmd, u_long arg)
-{
-    struct pcmcia_bus_socket *s;
-    void __user *uarg = (char __user *)arg;
-    u_int size;
-    int ret, err;
-    ds_ioctl_arg_t *buf;
-    user_info_t *user;
-
-    ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
-    
-    user = file->private_data;
-    if (CHECK_USER(user))
-       return -EIO;
-
-    s = user->socket;
-    if (s->state & DS_SOCKET_DEAD)
-        return -EIO;
-    
-    size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
-    if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
-
-    /* Permission check */
-    if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
-       return -EPERM;
-       
-    if (cmd & IOC_IN) {
-       if (!access_ok(VERIFY_READ, uarg, size)) {
-           ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
-           return -EFAULT;
-       }
-    }
-    if (cmd & IOC_OUT) {
-       if (!access_ok(VERIFY_WRITE, uarg, size)) {
-           ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
-           return -EFAULT;
-       }
-    }
-    buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
-    if (!buf)
-       return -ENOMEM;
-    
-    err = ret = 0;
-    
-    if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size);
-    
-    switch (cmd) {
-    case DS_ADJUST_RESOURCE_INFO:
-       ret = pcmcia_adjust_resource_info(&buf->adjust);
-       break;
-    case DS_GET_CARD_SERVICES_INFO:
-       ret = pcmcia_get_card_services_info(&buf->servinfo);
-       break;
-    case DS_GET_CONFIGURATION_INFO:
-       if (buf->config.Function &&
-          (buf->config.Function >= s->parent->functions))
-           ret = CS_BAD_ARGS;
-       else
-           ret = pccard_get_configuration_info(s->parent,
-                       buf->config.Function, &buf->config);
-       break;
-    case DS_GET_FIRST_TUPLE:
-       down(&s->parent->skt_sem);
-       pcmcia_validate_mem(s->parent);
-       up(&s->parent->skt_sem);
-       ret = pccard_get_first_tuple(s->parent, BIND_FN_ALL, &buf->tuple);
-       break;
-    case DS_GET_NEXT_TUPLE:
-       ret = pccard_get_next_tuple(s->parent, BIND_FN_ALL, &buf->tuple);
-       break;
-    case DS_GET_TUPLE_DATA:
-       buf->tuple.TupleData = buf->tuple_parse.data;
-       buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
-       ret = pccard_get_tuple_data(s->parent, &buf->tuple);
-       break;
-    case DS_PARSE_TUPLE:
-       buf->tuple.TupleData = buf->tuple_parse.data;
-       ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
-       break;
-    case DS_RESET_CARD:
-       ret = pccard_reset_card(s->parent);
-       break;
-    case DS_GET_STATUS:
-       if (buf->status.Function &&
-          (buf->status.Function >= s->parent->functions))
-           ret = CS_BAD_ARGS;
-       else
-       ret = pccard_get_status(s->parent, buf->status.Function, &buf->status);
-       break;
-    case DS_VALIDATE_CIS:
-       down(&s->parent->skt_sem);
-       pcmcia_validate_mem(s->parent);
-       up(&s->parent->skt_sem);
-       ret = pccard_validate_cis(s->parent, BIND_FN_ALL, &buf->cisinfo);
-       break;
-    case DS_SUSPEND_CARD:
-       ret = pcmcia_suspend_card(s->parent);
-       break;
-    case DS_RESUME_CARD:
-       ret = pcmcia_resume_card(s->parent);
-       break;
-    case DS_EJECT_CARD:
-       err = pcmcia_eject_card(s->parent);
-       break;
-    case DS_INSERT_CARD:
-       err = pcmcia_insert_card(s->parent);
-       break;
-    case DS_ACCESS_CONFIGURATION_REGISTER:
-       if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
-           err = -EPERM;
-           goto free_out;
-       }
-       if (buf->conf_reg.Function &&
-          (buf->conf_reg.Function >= s->parent->functions))
-           ret = CS_BAD_ARGS;
-       else
-           ret = pccard_access_configuration_register(s->parent,
-                       buf->conf_reg.Function, &buf->conf_reg);
-       break;
-    case DS_GET_FIRST_REGION:
-    case DS_GET_NEXT_REGION:
-    case DS_BIND_MTD:
-       if (!capable(CAP_SYS_ADMIN)) {
-               err = -EPERM;
-               goto free_out;
-       } else {
-               static int printed = 0;
-               if (!printed) {
-                       printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
-                       printk(KERN_WARNING "MTD handling any more.\n");
-                       printed++;
-               }
-       }
-       err = -EINVAL;
-       goto free_out;
-       break;
-    case DS_GET_FIRST_WINDOW:
-       ret = pcmcia_get_window(s->parent, &buf->win_info.handle, 0,
-                       &buf->win_info.window);
-       break;
-    case DS_GET_NEXT_WINDOW:
-       ret = pcmcia_get_window(s->parent, &buf->win_info.handle,
-                       buf->win_info.handle->index + 1, &buf->win_info.window);
-       break;
-    case DS_GET_MEM_PAGE:
-       ret = pcmcia_get_mem_page(buf->win_info.handle,
-                          &buf->win_info.map);
-       break;
-    case DS_REPLACE_CIS:
-       ret = pcmcia_replace_cis(s->parent, &buf->cisdump);
-       break;
-    case DS_BIND_REQUEST:
-       if (!capable(CAP_SYS_ADMIN)) {
-               err = -EPERM;
-               goto free_out;
-       }
-       err = bind_request(s, &buf->bind_info);
-       break;
-    case DS_GET_DEVICE_INFO:
-       err = get_device_info(s, &buf->bind_info, 1);
-       break;
-    case DS_GET_NEXT_DEVICE:
-       err = get_device_info(s, &buf->bind_info, 0);
-       break;
-    case DS_UNBIND_REQUEST:
-       err = 0;
-       break;
-    default:
-       err = -EINVAL;
-    }
-    
-    if ((err == 0) && (ret != CS_SUCCESS)) {
-       ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
-       switch (ret) {
-       case CS_BAD_SOCKET: case CS_NO_CARD:
-           err = -ENODEV; break;
-       case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
-       case CS_BAD_TUPLE:
-           err = -EINVAL; break;
-       case CS_IN_USE:
-           err = -EBUSY; break;
-       case CS_OUT_OF_RESOURCE:
-           err = -ENOSPC; break;
-       case CS_NO_MORE_ITEMS:
-           err = -ENODATA; break;
-       case CS_UNSUPPORTED_FUNCTION:
-           err = -ENOSYS; break;
-       default:
-           err = -EIO; break;
-       }
-    }
-
-    if (cmd & IOC_OUT) {
-        if (__copy_to_user(uarg, (char *)buf, size))
-            err = -EFAULT;
-    }
-
-free_out:
-    kfree(buf);
-    return err;
-} /* ds_ioctl */
-
-/*====================================================================*/
-
-static struct file_operations ds_fops = {
-       .owner          = THIS_MODULE,
-       .open           = ds_open,
-       .release        = ds_release,
-       .ioctl          = ds_ioctl,
-       .read           = ds_read,
-       .write          = ds_write,
-       .poll           = ds_poll,
+static struct pcmcia_callback pcmcia_bus_callback = {
+       .owner = THIS_MODULE,
+       .event = ds_event,
+       .requery = pcmcia_bus_rescan,
 };
 
 static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev)
 {
        struct pcmcia_socket *socket = class_get_devdata(class_dev);
-       struct pcmcia_bus_socket *s;
        int ret;
 
-       s = kmalloc(sizeof(struct pcmcia_bus_socket), GFP_KERNEL);
-       if(!s)
-               return -ENOMEM;
-       memset(s, 0, sizeof(struct pcmcia_bus_socket));
-
-       /* get reference to parent socket */
-       s->parent = pcmcia_get_socket(socket);
-       if (!s->parent) {
+       socket = pcmcia_get_socket(socket);
+       if (!socket) {
                printk(KERN_ERR "PCMCIA obtaining reference to socket %p failed\n", socket);
-               kfree (s);
                return -ENODEV;
        }
 
-       kref_init(&s->refcount);
-    
        /*
         * Ugly. But we want to wait for the socket threads to have started up.
         * We really should let the drivers themselves drive some of this..
         */
        msleep(250);
 
-       init_waitqueue_head(&s->queue);
-       INIT_LIST_HEAD(&s->devices_list);
-
-       /* Set up hotline to Card Services */
-       s->callback.owner = THIS_MODULE;
-       s->callback.event = &ds_event;
-       s->callback.resources_done = &pcmcia_card_add;
-       socket->pcmcia = s;
+#ifdef CONFIG_PCMCIA_IOCTL
+       init_waitqueue_head(&socket->queue);
+#endif
+       INIT_LIST_HEAD(&socket->devices_list);
+       INIT_WORK(&socket->device_add, pcmcia_delayed_add_pseudo_device, socket);
+       memset(&socket->pcmcia_state, 0, sizeof(u8));
+       socket->device_count = 0;
 
-       ret = pccard_register_pcmcia(socket, &s->callback);
+       ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback);
        if (ret) {
                printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket);
-               pcmcia_put_bus_socket(s);
-               socket->pcmcia = NULL;
+               pcmcia_put_socket(socket);
                return (ret);
        }
 
        return 0;
 }
 
-
 static void pcmcia_bus_remove_socket(struct class_device *class_dev)
 {
        struct pcmcia_socket *socket = class_get_devdata(class_dev);
 
-       if (!socket || !socket->pcmcia)
+       if (!socket)
                return;
 
+       socket->pcmcia_state.dead = 1;
        pccard_register_pcmcia(socket, NULL);
 
-       socket->pcmcia->state |= DS_SOCKET_DEAD;
-       pcmcia_put_bus_socket(socket->pcmcia);
-       socket->pcmcia = NULL;
+       pcmcia_put_socket(socket);
 
        return;
 }
@@ -1575,34 +1209,20 @@ static struct class_interface pcmcia_bus_interface = {
 
 struct bus_type pcmcia_bus_type = {
        .name = "pcmcia",
+       .hotplug = pcmcia_bus_hotplug,
        .match = pcmcia_bus_match,
        .dev_attrs = pcmcia_dev_attrs,
 };
-EXPORT_SYMBOL(pcmcia_bus_type);
 
 
 static int __init init_pcmcia_bus(void)
 {
-       int i;
-
        spin_lock_init(&pcmcia_dev_list_lock);
 
        bus_register(&pcmcia_bus_type);
        class_interface_register(&pcmcia_bus_interface);
 
-       /* Set up character device for user mode clients */
-       i = register_chrdev(0, "pcmcia", &ds_fops);
-       if (i < 0)
-               printk(KERN_NOTICE "unable to find a free device # for "
-                      "Driver Services (error=%d)\n", i);
-       else
-               major_dev = i;
-
-#ifdef CONFIG_PROC_FS
-       proc_pccard = proc_mkdir("pccard", proc_bus);
-       if (proc_pccard)
-               create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
-#endif
+       pcmcia_setup_ioctl();
 
        return 0;
 }
@@ -1612,48 +1232,13 @@ fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
 
 static void __exit exit_pcmcia_bus(void)
 {
-       class_interface_unregister(&pcmcia_bus_interface);
+       pcmcia_cleanup_ioctl();
 
-#ifdef CONFIG_PROC_FS
-       if (proc_pccard) {
-               remove_proc_entry("drivers", proc_pccard);
-               remove_proc_entry("pccard", proc_bus);
-       }
-#endif
-       if (major_dev != -1)
-               unregister_chrdev(major_dev, "pcmcia");
+       class_interface_unregister(&pcmcia_bus_interface);
 
        bus_unregister(&pcmcia_bus_type);
 }
 module_exit(exit_pcmcia_bus);
 
 
-
-/* helpers for backwards-compatible functions */
-
-static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr)
-{
-       struct pcmcia_socket * s = pcmcia_get_socket_by_nr(nr);
-       if (s && s->pcmcia)
-               return s->pcmcia;
-       else
-               return NULL;
-}
-
-/* backwards-compatible accessing of driver --- by name! */
-
-static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info)
-{
-       struct device_driver *drv;
-       struct pcmcia_driver *p_drv;
-
-       drv = driver_find((char *) dev_info, &pcmcia_bus_type);
-       if (!drv)
-               return NULL;
-
-       p_drv = container_of(drv, struct pcmcia_driver, drv);
-
-       return (p_drv);
-}
-
 MODULE_ALIAS("ds");
diff --git a/drivers/pcmcia/ds_internal.h b/drivers/pcmcia/ds_internal.h
new file mode 100644 (file)
index 0000000..d359bd2
--- /dev/null
@@ -0,0 +1,21 @@
+/* ds_internal.h - internal header for 16-bit PCMCIA devices management */
+
+extern spinlock_t pcmcia_dev_list_lock;
+extern struct bus_type pcmcia_bus_type;
+
+extern struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev);
+extern void pcmcia_put_dev(struct pcmcia_device *p_dev);
+
+struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function);
+
+#ifdef CONFIG_PCMCIA_IOCTL
+extern void __init pcmcia_setup_ioctl(void);
+extern void __exit pcmcia_cleanup_ioctl(void);
+extern void handle_event(struct pcmcia_socket *s, event_t event);
+extern int handle_request(struct pcmcia_socket *s, event_t event);
+#else
+static inline void __init pcmcia_setup_ioctl(void) { return; }
+static inline void __init pcmcia_cleanup_ioctl(void) { return; }
+static inline void handle_event(struct pcmcia_socket *s, event_t event) { return; }
+static inline int handle_request(struct pcmcia_socket *s, event_t event) { return CS_SUCCESS; }
+#endif
index 90a335a5d9fafe90aabdb0d833508c00440c3ab5..d72f9a35c8bdbf5566293001a153d6a3200749f2 100644 (file)
@@ -669,11 +669,13 @@ static int __init is_alive(u_short sock)
     if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
        (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) &&
        (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) &&
-       (check_region(start, stop-start+1) != 0) &&
-       ((start & 0xfeef) != 0x02e8))
-       return 1;
-    else
-       return 0;
+       ((start & 0xfeef) != 0x02e8)) {
+       if (!request_region(start, stop-start+1, "i82365"))
+           return 1;
+       release_region(start, stop-start+1);
+    }
+
+    return 0;
 }
 
 /*====================================================================*/
@@ -696,7 +698,13 @@ static void __init add_pcic(int ns, int type)
     struct i82365_socket *t = &socket[sockets-ns];
 
     base = sockets-ns;
-    if (t->ioaddr > 0) request_region(t->ioaddr, 2, "i82365");
+    if (t->ioaddr > 0) {
+       if (!request_region(t->ioaddr, 2, "i82365")) {
+           printk(KERN_ERR "i82365: IO region conflict at %#lx, not available\n",
+                       t->ioaddr);
+           return;
+       }
+    }
     
     if (base == 0) printk("\n");
     printk(KERN_INFO "  %s", pcic[type].name);
@@ -803,7 +811,7 @@ static void __init isa_probe(void)
     }
 #endif
 
-    if (check_region(i365_base, 2) != 0) {
+    if (!request_region(i365_base, 2, "i82365")) {
        if (sockets == 0)
            printk("port conflict at %#lx\n", i365_base);
        return;
@@ -1441,6 +1449,7 @@ static void __exit exit_i82365(void)
        i365_set(i, I365_CSCINT, 0);
        release_region(socket[i].ioaddr, 2);
     }
+    release_region(i365_base, 2);
 #ifdef CONFIG_PNP
     if (i82365_pnpdev)
                pnp_disable_dev(i82365_pnpdev);
index 68b80084f83f28f787c591afd6f2fed87a4e075d..1cc83317e7e34da05607b21070531786a559d0b3 100644 (file)
@@ -74,19 +74,6 @@ int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info)
 }
 EXPORT_SYMBOL(pcmcia_validate_cis);
 
-int pcmcia_get_configuration_info(client_handle_t handle,
-                                 config_info_t *config)
-{
-       struct pcmcia_socket *s;
-
-       if ((CHECK_HANDLE(handle)) || !config)
-               return CS_BAD_HANDLE;
-       s = SOCKET(handle);
-       if (!s)
-               return CS_BAD_HANDLE;
-       return pccard_get_configuration_info(s, handle->Function, config);
-}
-EXPORT_SYMBOL(pcmcia_get_configuration_info);
 
 int pcmcia_reset_card(client_handle_t handle, client_req_t *req)
 {
@@ -102,24 +89,3 @@ int pcmcia_reset_card(client_handle_t handle, client_req_t *req)
 }
 EXPORT_SYMBOL(pcmcia_reset_card);
 
-int pcmcia_get_status(client_handle_t handle, cs_status_t *status)
-{
-       struct pcmcia_socket *s;
-       if (CHECK_HANDLE(handle))
-               return CS_BAD_HANDLE;
-       s = SOCKET(handle);
-       return pccard_get_status(s, handle->Function, status);
-}
-EXPORT_SYMBOL(pcmcia_get_status);
-
-int pcmcia_access_configuration_register(client_handle_t handle,
-                                        conf_reg_t *reg)
-{
-       struct pcmcia_socket *s;
-       if (CHECK_HANDLE(handle))
-               return CS_BAD_HANDLE;
-       s = SOCKET(handle);
-       return pccard_access_configuration_register(s, handle->Function, reg);
-}
-EXPORT_SYMBOL(pcmcia_access_configuration_register);
-
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
new file mode 100644 (file)
index 0000000..b883bc1
--- /dev/null
@@ -0,0 +1,786 @@
+/*
+ * pcmcia_ioctl.c -- ioctl interface for cardmgr and cardctl
+ *
+ * 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.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * (C) 1999            David A. Hinds
+ * (C) 2003 - 2004     Dominik Brodowski
+ */
+
+/*
+ * This file will go away soon.
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+#include <linux/pci.h>
+#include <linux/workqueue.h>
+
+#define IN_CARD_SERVICES
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/ss.h>
+
+#include "cs_internal.h"
+#include "ds_internal.h"
+
+static int major_dev = -1;
+
+
+/* Device user information */
+#define MAX_EVENTS     32
+#define USER_MAGIC     0x7ea4
+#define CHECK_USER(u) \
+    (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
+
+typedef struct user_info_t {
+       u_int                   user_magic;
+       int                     event_head, event_tail;
+       event_t                 event[MAX_EVENTS];
+       struct user_info_t      *next;
+       struct pcmcia_socket    *socket;
+} user_info_t;
+
+
+#ifdef DEBUG
+extern int ds_pc_debug;
+#define cs_socket_name(skt)    ((skt)->dev.class_id)
+
+#define ds_dbg(lvl, fmt, arg...) do {          \
+       if (ds_pc_debug >= lvl)                         \
+               printk(KERN_DEBUG "ds: " fmt , ## arg);         \
+} while (0)
+#else
+#define ds_dbg(lvl, fmt, arg...) do { } while (0)
+#endif
+
+static const char *release = "Linux Kernel Card Services";
+
+/** pcmcia_get_card_services_info
+ *
+ * Return information about this version of Card Services
+ */
+static int pcmcia_get_card_services_info(servinfo_t *info)
+{
+       unsigned int socket_count = 0;
+       struct list_head *tmp;
+       info->Signature[0] = 'C';
+       info->Signature[1] = 'S';
+       down_read(&pcmcia_socket_list_rwsem);
+       list_for_each(tmp, &pcmcia_socket_list)
+               socket_count++;
+       up_read(&pcmcia_socket_list_rwsem);
+       info->Count = socket_count;
+       info->Revision = CS_RELEASE_CODE;
+       info->CSLevel = 0x0210;
+       info->VendorString = (char *)release;
+       return CS_SUCCESS;
+} /* get_card_services_info */
+
+
+/* backwards-compatible accessing of driver --- by name! */
+
+static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info)
+{
+       struct device_driver *drv;
+       struct pcmcia_driver *p_drv;
+
+       drv = driver_find((char *) dev_info, &pcmcia_bus_type);
+       if (!drv)
+               return NULL;
+
+       p_drv = container_of(drv, struct pcmcia_driver, drv);
+
+       return (p_drv);
+}
+
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *proc_pccard = NULL;
+
+static int proc_read_drivers_callback(struct device_driver *driver, void *d)
+{
+       char **p = d;
+       struct pcmcia_driver *p_drv = container_of(driver,
+                                                  struct pcmcia_driver, drv);
+
+       *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
+#ifdef CONFIG_MODULE_UNLOAD
+                     (p_drv->owner) ? module_refcount(p_drv->owner) : 1
+#else
+                     1
+#endif
+       );
+       d = (void *) p;
+
+       return 0;
+}
+
+static int proc_read_drivers(char *buf, char **start, off_t pos,
+                            int count, int *eof, void *data)
+{
+       char *p = buf;
+
+       bus_for_each_drv(&pcmcia_bus_type, NULL,
+                        (void *) &p, proc_read_drivers_callback);
+
+       return (p - buf);
+}
+#endif
+
+/*======================================================================
+
+    These manage a ring buffer of events pending for one user process
+
+======================================================================*/
+
+
+static int queue_empty(user_info_t *user)
+{
+    return (user->event_head == user->event_tail);
+}
+
+static event_t get_queued_event(user_info_t *user)
+{
+    user->event_tail = (user->event_tail+1) % MAX_EVENTS;
+    return user->event[user->event_tail];
+}
+
+static void queue_event(user_info_t *user, event_t event)
+{
+    user->event_head = (user->event_head+1) % MAX_EVENTS;
+    if (user->event_head == user->event_tail)
+       user->event_tail = (user->event_tail+1) % MAX_EVENTS;
+    user->event[user->event_head] = event;
+}
+
+void handle_event(struct pcmcia_socket *s, event_t event)
+{
+    user_info_t *user;
+    for (user = s->user; user; user = user->next)
+       queue_event(user, event);
+    wake_up_interruptible(&s->queue);
+}
+
+
+/*======================================================================
+
+    bind_request() and bind_device() are merged by now. Register_client()
+    is called right at the end of bind_request(), during the driver's
+    ->attach() call. Individual descriptions:
+
+    bind_request() connects a socket to a particular client driver.
+    It looks up the specified device ID in the list of registered
+    drivers, binds it to the socket, and tries to create an instance
+    of the device.  unbind_request() deletes a driver instance.
+
+    Bind_device() associates a device driver with a particular socket.
+    It is normally called by Driver Services after it has identified
+    a newly inserted card.  An instance of that driver will then be
+    eligible to register as a client of this socket.
+
+    Register_client() uses the dev_info_t handle to match the
+    caller with a socket.  The driver must have already been bound
+    to a socket with bind_device() -- in fact, bind_device()
+    allocates the client structure that will be used.
+
+======================================================================*/
+
+static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
+{
+       struct pcmcia_driver *p_drv;
+       struct pcmcia_device *p_dev;
+       int ret = 0;
+       unsigned long flags;
+
+       s = pcmcia_get_socket(s);
+       if (!s)
+               return -EINVAL;
+
+       ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
+              (char *)bind_info->dev_info);
+
+       p_drv = get_pcmcia_driver(&bind_info->dev_info);
+       if (!p_drv) {
+               ret = -EINVAL;
+               goto err_put;
+       }
+
+       if (!try_module_get(p_drv->owner)) {
+               ret = -EINVAL;
+               goto err_put_driver;
+       }
+
+       spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+        list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
+               if (p_dev->func == bind_info->function) {
+                       if ((p_dev->dev.driver == &p_drv->drv)) {
+                               if (p_dev->cardmgr) {
+                                       /* if there's already a device
+                                        * registered, and it was registered
+                                        * by userspace before, we need to
+                                        * return the "instance". */
+                                       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+                                       bind_info->instance = p_dev->instance;
+                                       ret = -EBUSY;
+                                       goto err_put_module;
+                               } else {
+                                       /* the correct driver managed to bind
+                                        * itself magically to the correct
+                                        * device. */
+                                       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+                                       p_dev->cardmgr = p_drv;
+                                       ret = 0;
+                                       goto err_put_module;
+                               }
+                       } else if (!p_dev->dev.driver) {
+                               /* there's already a device available where
+                                * no device has been bound to yet. So we don't
+                                * need to register a device! */
+                               spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+                               goto rescan;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+       p_dev = pcmcia_device_add(s, bind_info->function);
+       if (!p_dev) {
+               ret = -EIO;
+               goto err_put_module;
+       }
+
+rescan:
+       p_dev->cardmgr = p_drv;
+
+       /* if a driver is already running, we can abort */
+       if (p_dev->dev.driver)
+               goto err_put_module;
+
+       /*
+        * Prevent this racing with a card insertion.
+        */
+       down(&s->skt_sem);
+       bus_rescan_devices(&pcmcia_bus_type);
+       up(&s->skt_sem);
+
+       /* check whether the driver indeed matched. I don't care if this
+        * is racy or not, because it can only happen on cardmgr access
+        * paths...
+        */
+       if (!(p_dev->dev.driver == &p_drv->drv))
+               p_dev->cardmgr = NULL;
+
+ err_put_module:
+       module_put(p_drv->owner);
+ err_put_driver:
+       put_driver(&p_drv->drv);
+ err_put:
+       pcmcia_put_socket(s);
+
+       return (ret);
+} /* bind_request */
+
+#ifdef CONFIG_CARDBUS
+
+static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
+{
+       if (!s || !(s->state & SOCKET_CARDBUS))
+               return NULL;
+
+       return s->cb_dev->subordinate;
+}
+#endif
+
+static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
+{
+       dev_node_t *node;
+       struct pcmcia_device *p_dev;
+       unsigned long flags;
+       int ret = 0;
+
+#ifdef CONFIG_CARDBUS
+       /*
+        * Some unbelievably ugly code to associate the PCI cardbus
+        * device and its driver with the PCMCIA "bind" information.
+        */
+       {
+               struct pci_bus *bus;
+
+               bus = pcmcia_lookup_bus(s);
+               if (bus) {
+                       struct list_head *list;
+                       struct pci_dev *dev = NULL;
+
+                       list = bus->devices.next;
+                       while (list != &bus->devices) {
+                               struct pci_dev *pdev = pci_dev_b(list);
+                               list = list->next;
+
+                               if (first) {
+                                       dev = pdev;
+                                       break;
+                               }
+
+                               /* Try to handle "next" here some way? */
+                       }
+                       if (dev && dev->driver) {
+                               strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
+                               bind_info->major = 0;
+                               bind_info->minor = 0;
+                               bind_info->next = NULL;
+                               return 0;
+                       }
+               }
+       }
+#endif
+
+       spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+       list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
+               if (p_dev->func == bind_info->function) {
+                       p_dev = pcmcia_get_dev(p_dev);
+                       if (!p_dev)
+                               continue;
+                       goto found;
+               }
+       }
+       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+       return -ENODEV;
+
+ found:
+       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+       if ((!p_dev->instance) ||
+           (p_dev->instance->state & DEV_CONFIG_PENDING)) {
+               ret = -EAGAIN;
+               goto err_put;
+       }
+
+       if (first)
+               node = p_dev->instance->dev;
+       else
+               for (node = p_dev->instance->dev; node; node = node->next)
+                       if (node == bind_info->next)
+                               break;
+       if (!node) {
+               ret = -ENODEV;
+               goto err_put;
+       }
+
+       strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
+       bind_info->major = node->major;
+       bind_info->minor = node->minor;
+       bind_info->next = node->next;
+
+ err_put:
+       pcmcia_put_dev(p_dev);
+       return (ret);
+} /* get_device_info */
+
+
+static int ds_open(struct inode *inode, struct file *file)
+{
+    socket_t i = iminor(inode);
+    struct pcmcia_socket *s;
+    user_info_t *user;
+
+    ds_dbg(0, "ds_open(socket %d)\n", i);
+
+    s = pcmcia_get_socket_by_nr(i);
+    if (!s)
+           return -ENODEV;
+    s = pcmcia_get_socket(s);
+    if (!s)
+           return -ENODEV;
+
+    if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+           if (s->pcmcia_state.busy) {
+                   pcmcia_put_socket(s);
+                   return -EBUSY;
+           }
+       else
+           s->pcmcia_state.busy = 1;
+    }
+
+    user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
+    if (!user) {
+           pcmcia_put_socket(s);
+           return -ENOMEM;
+    }
+    user->event_tail = user->event_head = 0;
+    user->next = s->user;
+    user->user_magic = USER_MAGIC;
+    user->socket = s;
+    s->user = user;
+    file->private_data = user;
+
+    if (s->pcmcia_state.present)
+       queue_event(user, CS_EVENT_CARD_INSERTION);
+    return 0;
+} /* ds_open */
+
+/*====================================================================*/
+
+static int ds_release(struct inode *inode, struct file *file)
+{
+    struct pcmcia_socket *s;
+    user_info_t *user, **link;
+
+    ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
+
+    user = file->private_data;
+    if (CHECK_USER(user))
+       goto out;
+
+    s = user->socket;
+
+    /* Unlink user data structure */
+    if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+       s->pcmcia_state.busy = 0;
+    }
+    file->private_data = NULL;
+    for (link = &s->user; *link; link = &(*link)->next)
+       if (*link == user) break;
+    if (link == NULL)
+       goto out;
+    *link = user->next;
+    user->user_magic = 0;
+    kfree(user);
+    pcmcia_put_socket(s);
+out:
+    return 0;
+} /* ds_release */
+
+/*====================================================================*/
+
+static ssize_t ds_read(struct file *file, char __user *buf,
+                      size_t count, loff_t *ppos)
+{
+    struct pcmcia_socket *s;
+    user_info_t *user;
+    int ret;
+
+    ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
+
+    if (count < 4)
+       return -EINVAL;
+
+    user = file->private_data;
+    if (CHECK_USER(user))
+       return -EIO;
+
+    s = user->socket;
+    if (s->pcmcia_state.dead)
+        return -EIO;
+
+    ret = wait_event_interruptible(s->queue, !queue_empty(user));
+    if (ret == 0)
+       ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
+
+    return ret;
+} /* ds_read */
+
+/*====================================================================*/
+
+static ssize_t ds_write(struct file *file, const char __user *buf,
+                       size_t count, loff_t *ppos)
+{
+    ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
+
+    if (count != 4)
+       return -EINVAL;
+    if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+       return -EBADF;
+
+    return -EIO;
+} /* ds_write */
+
+/*====================================================================*/
+
+/* No kernel lock - fine */
+static u_int ds_poll(struct file *file, poll_table *wait)
+{
+    struct pcmcia_socket *s;
+    user_info_t *user;
+
+    ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
+
+    user = file->private_data;
+    if (CHECK_USER(user))
+       return POLLERR;
+    s = user->socket;
+    /*
+     * We don't check for a dead socket here since that
+     * will send cardmgr into an endless spin.
+     */
+    poll_wait(file, &s->queue, wait);
+    if (!queue_empty(user))
+       return POLLIN | POLLRDNORM;
+    return 0;
+} /* ds_poll */
+
+/*====================================================================*/
+
+extern int pcmcia_adjust_resource_info(adjust_t *adj);
+
+static int ds_ioctl(struct inode * inode, struct file * file,
+                   u_int cmd, u_long arg)
+{
+    struct pcmcia_socket *s;
+    void __user *uarg = (char __user *)arg;
+    u_int size;
+    int ret, err;
+    ds_ioctl_arg_t *buf;
+    user_info_t *user;
+
+    ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
+
+    user = file->private_data;
+    if (CHECK_USER(user))
+       return -EIO;
+
+    s = user->socket;
+    if (s->pcmcia_state.dead)
+        return -EIO;
+
+    size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+    if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
+
+    /* Permission check */
+    if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
+       return -EPERM;
+
+    if (cmd & IOC_IN) {
+       if (!access_ok(VERIFY_READ, uarg, size)) {
+           ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
+           return -EFAULT;
+       }
+    }
+    if (cmd & IOC_OUT) {
+       if (!access_ok(VERIFY_WRITE, uarg, size)) {
+           ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
+           return -EFAULT;
+       }
+    }
+    buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
+    if (!buf)
+       return -ENOMEM;
+
+    err = ret = 0;
+
+    if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size);
+
+    switch (cmd) {
+    case DS_ADJUST_RESOURCE_INFO:
+       ret = pcmcia_adjust_resource_info(&buf->adjust);
+       break;
+    case DS_GET_CARD_SERVICES_INFO:
+       ret = pcmcia_get_card_services_info(&buf->servinfo);
+       break;
+    case DS_GET_CONFIGURATION_INFO:
+       if (buf->config.Function &&
+          (buf->config.Function >= s->functions))
+           ret = CS_BAD_ARGS;
+       else
+           ret = pccard_get_configuration_info(s,
+                       buf->config.Function, &buf->config);
+       break;
+    case DS_GET_FIRST_TUPLE:
+       down(&s->skt_sem);
+       pcmcia_validate_mem(s);
+       up(&s->skt_sem);
+       ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
+       break;
+    case DS_GET_NEXT_TUPLE:
+       ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
+       break;
+    case DS_GET_TUPLE_DATA:
+       buf->tuple.TupleData = buf->tuple_parse.data;
+       buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
+       ret = pccard_get_tuple_data(s, &buf->tuple);
+       break;
+    case DS_PARSE_TUPLE:
+       buf->tuple.TupleData = buf->tuple_parse.data;
+       ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
+       break;
+    case DS_RESET_CARD:
+       ret = pccard_reset_card(s);
+       break;
+    case DS_GET_STATUS:
+       if (buf->status.Function &&
+          (buf->status.Function >= s->functions))
+           ret = CS_BAD_ARGS;
+       else
+       ret = pccard_get_status(s, buf->status.Function, &buf->status);
+       break;
+    case DS_VALIDATE_CIS:
+       down(&s->skt_sem);
+       pcmcia_validate_mem(s);
+       up(&s->skt_sem);
+       ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
+       break;
+    case DS_SUSPEND_CARD:
+       ret = pcmcia_suspend_card(s);
+       break;
+    case DS_RESUME_CARD:
+       ret = pcmcia_resume_card(s);
+       break;
+    case DS_EJECT_CARD:
+       err = pcmcia_eject_card(s);
+       break;
+    case DS_INSERT_CARD:
+       err = pcmcia_insert_card(s);
+       break;
+    case DS_ACCESS_CONFIGURATION_REGISTER:
+       if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
+           err = -EPERM;
+           goto free_out;
+       }
+       if (buf->conf_reg.Function &&
+          (buf->conf_reg.Function >= s->functions))
+           ret = CS_BAD_ARGS;
+       else
+           ret = pccard_access_configuration_register(s,
+                       buf->conf_reg.Function, &buf->conf_reg);
+       break;
+    case DS_GET_FIRST_REGION:
+    case DS_GET_NEXT_REGION:
+    case DS_BIND_MTD:
+       if (!capable(CAP_SYS_ADMIN)) {
+               err = -EPERM;
+               goto free_out;
+       } else {
+               static int printed = 0;
+               if (!printed) {
+                       printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
+                       printk(KERN_WARNING "MTD handling any more.\n");
+                       printed++;
+               }
+       }
+       err = -EINVAL;
+       goto free_out;
+       break;
+    case DS_GET_FIRST_WINDOW:
+       ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
+                       &buf->win_info.window);
+       break;
+    case DS_GET_NEXT_WINDOW:
+       ret = pcmcia_get_window(s, &buf->win_info.handle,
+                       buf->win_info.handle->index + 1, &buf->win_info.window);
+       break;
+    case DS_GET_MEM_PAGE:
+       ret = pcmcia_get_mem_page(buf->win_info.handle,
+                          &buf->win_info.map);
+       break;
+    case DS_REPLACE_CIS:
+       ret = pcmcia_replace_cis(s, &buf->cisdump);
+       break;
+    case DS_BIND_REQUEST:
+       if (!capable(CAP_SYS_ADMIN)) {
+               err = -EPERM;
+               goto free_out;
+       }
+       err = bind_request(s, &buf->bind_info);
+       break;
+    case DS_GET_DEVICE_INFO:
+       err = get_device_info(s, &buf->bind_info, 1);
+       break;
+    case DS_GET_NEXT_DEVICE:
+       err = get_device_info(s, &buf->bind_info, 0);
+       break;
+    case DS_UNBIND_REQUEST:
+       err = 0;
+       break;
+    default:
+       err = -EINVAL;
+    }
+
+    if ((err == 0) && (ret != CS_SUCCESS)) {
+       ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
+       switch (ret) {
+       case CS_BAD_SOCKET: case CS_NO_CARD:
+           err = -ENODEV; break;
+       case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
+       case CS_BAD_TUPLE:
+           err = -EINVAL; break;
+       case CS_IN_USE:
+           err = -EBUSY; break;
+       case CS_OUT_OF_RESOURCE:
+           err = -ENOSPC; break;
+       case CS_NO_MORE_ITEMS:
+           err = -ENODATA; break;
+       case CS_UNSUPPORTED_FUNCTION:
+           err = -ENOSYS; break;
+       default:
+           err = -EIO; break;
+       }
+    }
+
+    if (cmd & IOC_OUT) {
+        if (__copy_to_user(uarg, (char *)buf, size))
+            err = -EFAULT;
+    }
+
+free_out:
+    kfree(buf);
+    return err;
+} /* ds_ioctl */
+
+/*====================================================================*/
+
+static struct file_operations ds_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ds_open,
+       .release        = ds_release,
+       .ioctl          = ds_ioctl,
+       .read           = ds_read,
+       .write          = ds_write,
+       .poll           = ds_poll,
+};
+
+void __init pcmcia_setup_ioctl(void) {
+       int i;
+
+       /* Set up character device for user mode clients */
+       i = register_chrdev(0, "pcmcia", &ds_fops);
+       if (i < 0)
+               printk(KERN_NOTICE "unable to find a free device # for "
+                      "Driver Services (error=%d)\n", i);
+       else
+               major_dev = i;
+
+#ifdef CONFIG_PROC_FS
+       proc_pccard = proc_mkdir("pccard", proc_bus);
+       if (proc_pccard)
+               create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
+#endif
+}
+
+
+void __exit pcmcia_cleanup_ioctl(void) {
+#ifdef CONFIG_PROC_FS
+       if (proc_pccard) {
+               remove_proc_entry("drivers", proc_pccard);
+               remove_proc_entry("pccard", proc_bus);
+       }
+#endif
+       if (major_dev != -1)
+               unregister_chrdev(major_dev, "pcmcia");
+}
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
new file mode 100644 (file)
index 0000000..c01dc6b
--- /dev/null
@@ -0,0 +1,998 @@
+/*
+ * PCMCIA 16-bit resource management functions
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Copyright (C) 1999       David A. Hinds
+ * Copyright (C) 2004-2005   Dominik Brodowski
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+
+#define IN_CARD_SERVICES
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+#include "cs_internal.h"
+#include "ds_internal.h"
+
+
+/* Access speed for IO windows */
+static int io_speed = 0;
+module_param(io_speed, int, 0444);
+
+
+#ifdef CONFIG_PCMCIA_PROBE
+/* mask of IRQs already reserved by other cards, we should avoid using them */
+static u8 pcmcia_used_irq[NR_IRQS];
+#endif
+
+
+#ifdef DEBUG
+extern int ds_pc_debug;
+#define cs_socket_name(skt)    ((skt)->dev.class_id)
+
+#define ds_dbg(skt, lvl, fmt, arg...) do {                     \
+       if (ds_pc_debug >= lvl)                                 \
+               printk(KERN_DEBUG "pcmcia_resource: %s: " fmt,  \
+                       cs_socket_name(skt) , ## arg);          \
+} while (0)
+#else
+#define ds_dbg(lvl, fmt, arg...) do { } while (0)
+#endif
+
+
+
+/** alloc_io_space
+ *
+ * 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)
+{
+       int i;
+       kio_addr_t 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",
+                              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",
+                      *base, align);
+               align = 0;
+       }
+       if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) {
+               *base = s->io_offset | (*base & 0x0fff);
+               s->io[0].Attributes = attr;
+               return 0;
+       }
+       /* Check for an already-allocated window that must conflict with
+        * what was asked for.  It is a hack because it does not catch all
+        * potential conflicts, just the most obvious ones.
+        */
+       for (i = 0; i < MAX_IO_WIN; i++)
+               if ((s->io[i].NumPorts != 0) &&
+                   ((s->io[i].BasePort & (align-1)) == *base))
+                       return 1;
+       for (i = 0; i < MAX_IO_WIN; i++) {
+               if (s->io[i].NumPorts == 0) {
+                       s->io[i].res = pcmcia_find_io_region(*base, num, align, s);
+                       if (s->io[i].res) {
+                               s->io[i].Attributes = attr;
+                               s->io[i].BasePort = *base = s->io[i].res->start;
+                               s->io[i].NumPorts = s->io[i].InUse = num;
+                               break;
+                       } else
+                               return 1;
+               } else if (s->io[i].Attributes != attr)
+                       continue;
+               /* Try to extend top of window */
+               try = s->io[i].BasePort + s->io[i].NumPorts;
+               if ((*base == 0) || (*base == try))
+                       if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start,
+                                                   s->io[i].res->end + num, s) == 0) {
+                               *base = try;
+                               s->io[i].NumPorts += num;
+                               s->io[i].InUse += num;
+                               break;
+                       }
+               /* Try to extend bottom of window */
+               try = s->io[i].BasePort - num;
+               if ((*base == 0) || (*base == try))
+                       if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start - num,
+                                                   s->io[i].res->end, s) == 0) {
+                               s->io[i].BasePort = *base = try;
+                               s->io[i].NumPorts += num;
+                               s->io[i].InUse += num;
+                               break;
+                       }
+       }
+       return (i == MAX_IO_WIN);
+} /* alloc_io_space */
+
+
+static void release_io_space(struct pcmcia_socket *s, ioaddr_t base,
+                            ioaddr_t num)
+{
+       int i;
+
+       for (i = 0; i < MAX_IO_WIN; i++) {
+               if ((s->io[i].BasePort <= base) &&
+                   (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
+                       s->io[i].InUse -= num;
+                       /* Free the window if no one else is using it */
+                       if (s->io[i].InUse == 0) {
+                               s->io[i].NumPorts = 0;
+                               release_resource(s->io[i].res);
+                               kfree(s->io[i].res);
+                               s->io[i].res = NULL;
+                       }
+               }
+       }
+} /* release_io_space */
+
+
+/** pccard_access_configuration_register
+ *
+ * Access_configuration_register() reads and writes configuration
+ * registers in attribute memory.  Memory window 0 is reserved for
+ * this and the tuple reading services.
+ */
+
+int pccard_access_configuration_register(struct pcmcia_socket *s,
+                                        unsigned int function,
+                                        conf_reg_t *reg)
+{
+       config_t *c;
+       int addr;
+       u_char val;
+
+       if (!s || !s->config)
+               return CS_NO_CARD;
+
+       c = &s->config[function];
+
+       if (c == NULL)
+               return CS_NO_CARD;
+
+       if (!(c->state & CONFIG_LOCKED))
+               return CS_CONFIGURATION_LOCKED;
+
+       addr = (c->ConfigBase + reg->Offset) >> 1;
+
+       switch (reg->Action) {
+       case CS_READ:
+               pcmcia_read_cis_mem(s, 1, addr, 1, &val);
+               reg->Value = val;
+               break;
+       case CS_WRITE:
+               val = reg->Value;
+               pcmcia_write_cis_mem(s, 1, addr, 1, &val);
+               break;
+       default:
+               return CS_BAD_ARGS;
+               break;
+       }
+       return CS_SUCCESS;
+} /* pccard_access_configuration_register */
+
+int pcmcia_access_configuration_register(client_handle_t handle,
+                                        conf_reg_t *reg)
+{
+       struct pcmcia_socket *s;
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       return pccard_access_configuration_register(s, handle->Function, reg);
+}
+EXPORT_SYMBOL(pcmcia_access_configuration_register);
+
+
+
+int pccard_get_configuration_info(struct pcmcia_socket *s,
+                                 unsigned int function,
+                                 config_info_t *config)
+{
+       config_t *c;
+
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+
+       config->Function = function;
+
+#ifdef CONFIG_CARDBUS
+       if (s->state & SOCKET_CARDBUS) {
+               memset(config, 0, sizeof(config_info_t));
+               config->Vcc = s->socket.Vcc;
+               config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+               config->Option = s->cb_dev->subordinate->number;
+               if (s->state & SOCKET_CARDBUS_CONFIG) {
+                       config->Attributes = CONF_VALID_CLIENT;
+                       config->IntType = INT_CARDBUS;
+                       config->AssignedIRQ = s->irq.AssignedIRQ;
+                       if (config->AssignedIRQ)
+                               config->Attributes |= CONF_ENABLE_IRQ;
+                       config->BasePort1 = s->io[0].BasePort;
+                       config->NumPorts1 = s->io[0].NumPorts;
+               }
+               return CS_SUCCESS;
+       }
+#endif
+
+       c = (s->config != NULL) ? &s->config[function] : NULL;
+
+       if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
+               config->Attributes = 0;
+               config->Vcc = s->socket.Vcc;
+               config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+               return CS_SUCCESS;
+       }
+
+       /* !!! This is a hack !!! */
+       memcpy(&config->Attributes, &c->Attributes, sizeof(config_t));
+       config->Attributes |= CONF_VALID_CLIENT;
+       config->CardValues = c->CardValues;
+       config->IRQAttributes = c->irq.Attributes;
+       config->AssignedIRQ = s->irq.AssignedIRQ;
+       config->BasePort1 = c->io.BasePort1;
+       config->NumPorts1 = c->io.NumPorts1;
+       config->Attributes1 = c->io.Attributes1;
+       config->BasePort2 = c->io.BasePort2;
+       config->NumPorts2 = c->io.NumPorts2;
+       config->Attributes2 = c->io.Attributes2;
+       config->IOAddrLines = c->io.IOAddrLines;
+
+       return CS_SUCCESS;
+} /* pccard_get_configuration_info */
+
+int pcmcia_get_configuration_info(client_handle_t handle,
+                                 config_info_t *config)
+{
+       struct pcmcia_socket *s;
+
+       if ((CHECK_HANDLE(handle)) || !config)
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       if (!s)
+               return CS_BAD_HANDLE;
+       return pccard_get_configuration_info(s, handle->Function, config);
+}
+EXPORT_SYMBOL(pcmcia_get_configuration_info);
+
+
+/** pcmcia_get_window
+ */
+int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle,
+                     int idx, win_req_t *req)
+{
+       window_t *win;
+       int w;
+
+       if (!s || !(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+       for (w = idx; w < MAX_WIN; w++)
+               if (s->state & SOCKET_WIN_REQ(w))
+                       break;
+       if (w == MAX_WIN)
+               return CS_NO_MORE_ITEMS;
+       win = &s->win[w];
+       req->Base = win->ctl.res->start;
+       req->Size = win->ctl.res->end - win->ctl.res->start + 1;
+       req->AccessSpeed = win->ctl.speed;
+       req->Attributes = 0;
+       if (win->ctl.flags & MAP_ATTRIB)
+               req->Attributes |= WIN_MEMORY_TYPE_AM;
+       if (win->ctl.flags & MAP_ACTIVE)
+               req->Attributes |= WIN_ENABLE;
+       if (win->ctl.flags & MAP_16BIT)
+               req->Attributes |= WIN_DATA_WIDTH_16;
+       if (win->ctl.flags & MAP_USE_WAIT)
+               req->Attributes |= WIN_USE_WAIT;
+       *handle = win;
+       return CS_SUCCESS;
+} /* pcmcia_get_window */
+EXPORT_SYMBOL(pcmcia_get_window);
+
+
+/** pccard_get_status
+ *
+ * Get the current socket state bits.  We don't support the latched
+ * SocketState yet: I haven't seen any point for it.
+ */
+
+int pccard_get_status(struct pcmcia_socket *s, unsigned int function,
+                     cs_status_t *status)
+{
+       config_t *c;
+       int val;
+
+       s->ops->get_status(s, &val);
+       status->CardState = status->SocketState = 0;
+       status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
+       status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
+       status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
+       status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
+       if (s->state & SOCKET_SUSPEND)
+               status->CardState |= CS_EVENT_PM_SUSPEND;
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+
+       c = (s->config != NULL) ? &s->config[function] : NULL;
+       if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
+           (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
+               u_char reg;
+               if (c->Present & PRESENT_PIN_REPLACE) {
+                       pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
+                       status->CardState |=
+                               (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
+                       status->CardState |=
+                               (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
+                       status->CardState |=
+                               (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
+                       status->CardState |=
+                               (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
+               } else {
+                       /* No PRR?  Then assume we're always ready */
+                       status->CardState |= CS_EVENT_READY_CHANGE;
+               }
+               if (c->Present & PRESENT_EXT_STATUS) {
+                       pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
+                       status->CardState |=
+                               (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
+               }
+               return CS_SUCCESS;
+       }
+       status->CardState |=
+               (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
+       status->CardState |=
+               (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
+       status->CardState |=
+               (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
+       status->CardState |=
+               (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
+       return CS_SUCCESS;
+} /* pccard_get_status */
+
+int pcmcia_get_status(client_handle_t handle, cs_status_t *status)
+{
+       struct pcmcia_socket *s;
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       return pccard_get_status(s, handle->Function, status);
+}
+EXPORT_SYMBOL(pcmcia_get_status);
+
+
+
+/** pcmcia_get_mem_page
+ *
+ * Change the card address of an already open memory window.
+ */
+int pcmcia_get_mem_page(window_handle_t win, memreq_t *req)
+{
+       if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+               return CS_BAD_HANDLE;
+       req->Page = 0;
+       req->CardOffset = win->ctl.card_start;
+       return CS_SUCCESS;
+} /* pcmcia_get_mem_page */
+EXPORT_SYMBOL(pcmcia_get_mem_page);
+
+
+int pcmcia_map_mem_page(window_handle_t win, memreq_t *req)
+{
+       struct pcmcia_socket *s;
+       if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+               return CS_BAD_HANDLE;
+       if (req->Page != 0)
+               return CS_BAD_PAGE;
+       s = win->sock;
+       win->ctl.card_start = req->CardOffset;
+       if (s->ops->set_mem_map(s, &win->ctl) != 0)
+               return CS_BAD_OFFSET;
+       return CS_SUCCESS;
+} /* pcmcia_map_mem_page */
+EXPORT_SYMBOL(pcmcia_map_mem_page);
+
+
+/** pcmcia_modify_configuration
+ *
+ * Modify a locked socket configuration
+ */
+int pcmcia_modify_configuration(client_handle_t handle,
+                               modconf_t *mod)
+{
+       struct pcmcia_socket *s;
+       config_t *c;
+
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       c = CONFIG(handle);
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+       if (!(c->state & CONFIG_LOCKED))
+               return CS_CONFIGURATION_LOCKED;
+
+       if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
+               if (mod->Attributes & CONF_ENABLE_IRQ) {
+                       c->Attributes |= CONF_ENABLE_IRQ;
+                       s->socket.io_irq = s->irq.AssignedIRQ;
+               } else {
+                       c->Attributes &= ~CONF_ENABLE_IRQ;
+                       s->socket.io_irq = 0;
+               }
+               s->ops->set_socket(s, &s->socket);
+       }
+
+       if (mod->Attributes & CONF_VCC_CHANGE_VALID)
+               return CS_BAD_VCC;
+
+       /* We only allow changing Vpp1 and Vpp2 to the same value */
+       if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
+           (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
+               if (mod->Vpp1 != mod->Vpp2)
+                       return CS_BAD_VPP;
+               c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1;
+               if (s->ops->set_socket(s, &s->socket))
+                       return CS_BAD_VPP;
+       } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
+                  (mod->Attributes & CONF_VPP2_CHANGE_VALID))
+               return CS_BAD_VPP;
+
+       return CS_SUCCESS;
+} /* modify_configuration */
+EXPORT_SYMBOL(pcmcia_modify_configuration);
+
+
+int pcmcia_release_configuration(client_handle_t handle)
+{
+       pccard_io_map io = { 0, 0, 0, 0, 1 };
+       struct pcmcia_socket *s;
+       int i;
+
+       if (CHECK_HANDLE(handle) ||
+           !(handle->state & CLIENT_CONFIG_LOCKED))
+               return CS_BAD_HANDLE;
+       handle->state &= ~CLIENT_CONFIG_LOCKED;
+       s = SOCKET(handle);
+
+#ifdef CONFIG_CARDBUS
+       if (handle->state & CLIENT_CARDBUS)
+               return CS_SUCCESS;
+#endif
+
+       if (!(handle->state & CLIENT_STALE)) {
+               config_t *c = CONFIG(handle);
+               if (--(s->lock_count) == 0) {
+                       s->socket.flags = SS_OUTPUT_ENA;   /* Is this correct? */
+                       s->socket.Vpp = 0;
+                       s->socket.io_irq = 0;
+                       s->ops->set_socket(s, &s->socket);
+               }
+               if (c->state & CONFIG_IO_REQ)
+                       for (i = 0; i < MAX_IO_WIN; i++) {
+                               if (s->io[i].NumPorts == 0)
+                                       continue;
+                               s->io[i].Config--;
+                               if (s->io[i].Config != 0)
+                                       continue;
+                               io.map = i;
+                               s->ops->set_io_map(s, &io);
+                       }
+               c->state &= ~CONFIG_LOCKED;
+       }
+
+       return CS_SUCCESS;
+} /* pcmcia_release_configuration */
+EXPORT_SYMBOL(pcmcia_release_configuration);
+
+
+/** pcmcia_release_io
+ *
+ * Release_io() releases the I/O ranges allocated by a client.  This
+ * may be invoked some time after a card ejection has already dumped
+ * the actual socket configuration, so if the client is "stale", we
+ * don't bother checking the port ranges against the current socket
+ * values.
+ */
+int pcmcia_release_io(client_handle_t handle, io_req_t *req)
+{
+       struct pcmcia_socket *s;
+
+       if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ))
+               return CS_BAD_HANDLE;
+       handle->state &= ~CLIENT_IO_REQ;
+       s = SOCKET(handle);
+
+#ifdef CONFIG_CARDBUS
+       if (handle->state & CLIENT_CARDBUS)
+               return CS_SUCCESS;
+#endif
+
+       if (!(handle->state & CLIENT_STALE)) {
+               config_t *c = CONFIG(handle);
+               if (c->state & CONFIG_LOCKED)
+                       return CS_CONFIGURATION_LOCKED;
+               if ((c->io.BasePort1 != req->BasePort1) ||
+                   (c->io.NumPorts1 != req->NumPorts1) ||
+                   (c->io.BasePort2 != req->BasePort2) ||
+                   (c->io.NumPorts2 != req->NumPorts2))
+                       return CS_BAD_ARGS;
+               c->state &= ~CONFIG_IO_REQ;
+       }
+
+       release_io_space(s, req->BasePort1, req->NumPorts1);
+       if (req->NumPorts2)
+               release_io_space(s, req->BasePort2, req->NumPorts2);
+
+       return CS_SUCCESS;
+} /* pcmcia_release_io */
+EXPORT_SYMBOL(pcmcia_release_io);
+
+
+int pcmcia_release_irq(client_handle_t handle, irq_req_t *req)
+{
+       struct pcmcia_socket *s;
+       if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ))
+               return CS_BAD_HANDLE;
+       handle->state &= ~CLIENT_IRQ_REQ;
+       s = SOCKET(handle);
+
+       if (!(handle->state & CLIENT_STALE)) {
+               config_t *c = CONFIG(handle);
+               if (c->state & CONFIG_LOCKED)
+                       return CS_CONFIGURATION_LOCKED;
+               if (c->irq.Attributes != req->Attributes)
+                       return CS_BAD_ATTRIBUTE;
+               if (s->irq.AssignedIRQ != req->AssignedIRQ)
+                       return CS_BAD_IRQ;
+               if (--s->irq.Config == 0) {
+                       c->state &= ~CONFIG_IRQ_REQ;
+                       s->irq.AssignedIRQ = 0;
+               }
+       }
+
+       if (req->Attributes & IRQ_HANDLE_PRESENT) {
+               free_irq(req->AssignedIRQ, req->Instance);
+       }
+
+#ifdef CONFIG_PCMCIA_PROBE
+       pcmcia_used_irq[req->AssignedIRQ]--;
+#endif
+
+       return CS_SUCCESS;
+} /* pcmcia_release_irq */
+EXPORT_SYMBOL(pcmcia_release_irq);
+
+
+int pcmcia_release_window(window_handle_t win)
+{
+       struct pcmcia_socket *s;
+
+       if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+               return CS_BAD_HANDLE;
+       s = win->sock;
+       if (!(win->handle->state & CLIENT_WIN_REQ(win->index)))
+               return CS_BAD_HANDLE;
+
+       /* Shut down memory window */
+       win->ctl.flags &= ~MAP_ACTIVE;
+       s->ops->set_mem_map(s, &win->ctl);
+       s->state &= ~SOCKET_WIN_REQ(win->index);
+
+       /* Release system memory */
+       if (win->ctl.res) {
+               release_resource(win->ctl.res);
+               kfree(win->ctl.res);
+               win->ctl.res = NULL;
+       }
+       win->handle->state &= ~CLIENT_WIN_REQ(win->index);
+
+       win->magic = 0;
+
+       return CS_SUCCESS;
+} /* pcmcia_release_window */
+EXPORT_SYMBOL(pcmcia_release_window);
+
+
+int pcmcia_request_configuration(client_handle_t handle,
+                                config_req_t *req)
+{
+       int i;
+       u_int base;
+       struct pcmcia_socket *s;
+       config_t *c;
+       pccard_io_map iomap;
+
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+
+#ifdef CONFIG_CARDBUS
+       if (handle->state & CLIENT_CARDBUS)
+               return CS_UNSUPPORTED_MODE;
+#endif
+
+       if (req->IntType & INT_CARDBUS)
+               return CS_UNSUPPORTED_MODE;
+       c = CONFIG(handle);
+       if (c->state & CONFIG_LOCKED)
+               return CS_CONFIGURATION_LOCKED;
+
+       /* Do power control.  We don't allow changes in Vcc. */
+       if (s->socket.Vcc != req->Vcc)
+               return CS_BAD_VCC;
+       if (req->Vpp1 != req->Vpp2)
+               return CS_BAD_VPP;
+       s->socket.Vpp = req->Vpp1;
+       if (s->ops->set_socket(s, &s->socket))
+               return CS_BAD_VPP;
+
+       c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1;
+
+       /* Pick memory or I/O card, DMA mode, interrupt */
+       c->IntType = req->IntType;
+       c->Attributes = req->Attributes;
+       if (req->IntType & INT_MEMORY_AND_IO)
+               s->socket.flags |= SS_IOCARD;
+       if (req->IntType & INT_ZOOMED_VIDEO)
+               s->socket.flags |= SS_ZVCARD | SS_IOCARD;
+       if (req->Attributes & CONF_ENABLE_DMA)
+               s->socket.flags |= SS_DMA_MODE;
+       if (req->Attributes & CONF_ENABLE_SPKR)
+               s->socket.flags |= SS_SPKR_ENA;
+       if (req->Attributes & CONF_ENABLE_IRQ)
+               s->socket.io_irq = s->irq.AssignedIRQ;
+       else
+               s->socket.io_irq = 0;
+       s->ops->set_socket(s, &s->socket);
+       s->lock_count++;
+
+       /* Set up CIS configuration registers */
+       base = c->ConfigBase = req->ConfigBase;
+       c->Present = c->CardValues = req->Present;
+       if (req->Present & PRESENT_COPY) {
+               c->Copy = req->Copy;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);
+       }
+       if (req->Present & PRESENT_OPTION) {
+               if (s->functions == 1) {
+                       c->Option = req->ConfigIndex & COR_CONFIG_MASK;
+               } else {
+                       c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK;
+                       c->Option |= COR_FUNC_ENA|COR_IREQ_ENA;
+                       if (req->Present & PRESENT_IOBASE_0)
+                               c->Option |= COR_ADDR_DECODE;
+               }
+               if (c->state & CONFIG_IRQ_REQ)
+                       if (!(c->irq.Attributes & IRQ_FORCED_PULSE))
+                               c->Option |= COR_LEVEL_REQ;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);
+               mdelay(40);
+       }
+       if (req->Present & PRESENT_STATUS) {
+               c->Status = req->Status;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status);
+       }
+       if (req->Present & PRESENT_PIN_REPLACE) {
+               c->Pin = req->Pin;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin);
+       }
+       if (req->Present & PRESENT_EXT_STATUS) {
+               c->ExtStatus = req->ExtStatus;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
+       }
+       if (req->Present & PRESENT_IOBASE_0) {
+               u_char b = c->io.BasePort1 & 0xff;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
+               b = (c->io.BasePort1 >> 8) & 0xff;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
+       }
+       if (req->Present & PRESENT_IOSIZE) {
+               u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
+       }
+
+       /* Configure I/O windows */
+       if (c->state & CONFIG_IO_REQ) {
+               iomap.speed = io_speed;
+               for (i = 0; i < MAX_IO_WIN; i++)
+                       if (s->io[i].NumPorts != 0) {
+                               iomap.map = i;
+                               iomap.flags = MAP_ACTIVE;
+                               switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) {
+                               case IO_DATA_PATH_WIDTH_16:
+                                       iomap.flags |= MAP_16BIT; break;
+                               case IO_DATA_PATH_WIDTH_AUTO:
+                                       iomap.flags |= MAP_AUTOSZ; break;
+                               default:
+                                       break;
+                               }
+                               iomap.start = s->io[i].BasePort;
+                               iomap.stop = iomap.start + s->io[i].NumPorts - 1;
+                               s->ops->set_io_map(s, &iomap);
+                               s->io[i].Config++;
+                       }
+       }
+
+       c->state |= CONFIG_LOCKED;
+       handle->state |= CLIENT_CONFIG_LOCKED;
+       return CS_SUCCESS;
+} /* pcmcia_request_configuration */
+EXPORT_SYMBOL(pcmcia_request_configuration);
+
+
+/** pcmcia_request_io
+ *
+ * Request_io() reserves ranges of port addresses for a socket.
+ * I have not implemented range sharing or alias addressing.
+ */
+int pcmcia_request_io(client_handle_t handle, io_req_t *req)
+{
+       struct pcmcia_socket *s;
+       config_t *c;
+
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+
+       if (handle->state & CLIENT_CARDBUS) {
+#ifdef CONFIG_CARDBUS
+               handle->state |= CLIENT_IO_REQ;
+               return CS_SUCCESS;
+#else
+               return CS_UNSUPPORTED_FUNCTION;
+#endif
+       }
+
+       if (!req)
+               return CS_UNSUPPORTED_MODE;
+       c = CONFIG(handle);
+       if (c->state & CONFIG_LOCKED)
+               return CS_CONFIGURATION_LOCKED;
+       if (c->state & CONFIG_IO_REQ)
+               return CS_IN_USE;
+       if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))
+               return CS_BAD_ATTRIBUTE;
+       if ((req->NumPorts2 > 0) &&
+           (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)))
+               return CS_BAD_ATTRIBUTE;
+
+       if (alloc_io_space(s, req->Attributes1, &req->BasePort1,
+                          req->NumPorts1, req->IOAddrLines))
+               return CS_IN_USE;
+
+       if (req->NumPorts2) {
+               if (alloc_io_space(s, req->Attributes2, &req->BasePort2,
+                                  req->NumPorts2, req->IOAddrLines)) {
+                       release_io_space(s, req->BasePort1, req->NumPorts1);
+                       return CS_IN_USE;
+               }
+       }
+
+       c->io = *req;
+       c->state |= CONFIG_IO_REQ;
+       handle->state |= CLIENT_IO_REQ;
+       return CS_SUCCESS;
+} /* pcmcia_request_io */
+EXPORT_SYMBOL(pcmcia_request_io);
+
+
+/** pcmcia_request_irq
+ *
+ * Request_irq() reserves an irq for this client.
+ *
+ * Also, since Linux only reserves irq's when they are actually
+ * hooked, we don't guarantee that an irq will still be available
+ * when the configuration is locked.  Now that I think about it,
+ * there might be a way to fix this using a dummy handler.
+ */
+
+#ifdef CONFIG_PCMCIA_PROBE
+static irqreturn_t test_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+       return IRQ_NONE;
+}
+#endif
+
+int pcmcia_request_irq(client_handle_t handle, irq_req_t *req)
+{
+       struct pcmcia_socket *s;
+       config_t *c;
+       int ret = CS_IN_USE, irq = 0;
+       struct pcmcia_device *p_dev = handle_to_pdev(handle);
+
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+       c = CONFIG(handle);
+       if (c->state & CONFIG_LOCKED)
+               return CS_CONFIGURATION_LOCKED;
+       if (c->state & CONFIG_IRQ_REQ)
+               return CS_IN_USE;
+
+#ifdef CONFIG_PCMCIA_PROBE
+       if (s->irq.AssignedIRQ != 0) {
+               /* If the interrupt is already assigned, it must be the same */
+               irq = s->irq.AssignedIRQ;
+       } else {
+               int try;
+               u32 mask = s->irq_mask;
+               void *data = NULL;
+
+               for (try = 0; try < 64; try++) {
+                       irq = try % 32;
+
+                       /* marked as available by driver, and not blocked by userspace? */
+                       if (!((mask >> irq) & 1))
+                               continue;
+
+                       /* avoid an IRQ which is already used by a PCMCIA card */
+                       if ((try < 32) && pcmcia_used_irq[irq])
+                               continue;
+
+                       /* register the correct driver, if possible, of check whether
+                        * registering a dummy handle works, i.e. if the IRQ isn't
+                        * marked as used by the kernel resource management core */
+                       ret = request_irq(irq,
+                                         (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action,
+                                         ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
+                                          (s->functions > 1) ||
+                                          (irq == s->pci_irq)) ? SA_SHIRQ : 0,
+                                         p_dev->dev.bus_id,
+                                         (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data);
+                       if (!ret) {
+                               if (!(req->Attributes & IRQ_HANDLE_PRESENT))
+                                       free_irq(irq, data);
+                               break;
+                       }
+               }
+       }
+#endif
+       if (ret) {
+               if (!s->pci_irq)
+                       return ret;
+               irq = s->pci_irq;
+       }
+
+       if (ret && req->Attributes & IRQ_HANDLE_PRESENT) {
+               if (request_irq(irq, req->Handler,
+                               ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
+                                (s->functions > 1) ||
+                                (irq == s->pci_irq)) ? SA_SHIRQ : 0,
+                               p_dev->dev.bus_id, req->Instance))
+                       return CS_IN_USE;
+       }
+
+       c->irq.Attributes = req->Attributes;
+       s->irq.AssignedIRQ = req->AssignedIRQ = irq;
+       s->irq.Config++;
+
+       c->state |= CONFIG_IRQ_REQ;
+       handle->state |= CLIENT_IRQ_REQ;
+
+#ifdef CONFIG_PCMCIA_PROBE
+       pcmcia_used_irq[irq]++;
+#endif
+
+       return CS_SUCCESS;
+} /* pcmcia_request_irq */
+EXPORT_SYMBOL(pcmcia_request_irq);
+
+
+/** pcmcia_request_window
+ *
+ * Request_window() establishes a mapping between card memory space
+ * and system memory space.
+ */
+int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh)
+{
+       struct pcmcia_socket *s;
+       window_t *win;
+       u_long align;
+       int w;
+
+       if (CHECK_HANDLE(*handle))
+               return CS_BAD_HANDLE;
+       s = (*handle)->Socket;
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+       if (req->Attributes & (WIN_PAGED | WIN_SHARED))
+               return CS_BAD_ATTRIBUTE;
+
+       /* Window size defaults to smallest available */
+       if (req->Size == 0)
+               req->Size = s->map_size;
+       align = (((s->features & SS_CAP_MEM_ALIGN) ||
+                 (req->Attributes & WIN_STRICT_ALIGN)) ?
+                req->Size : s->map_size);
+       if (req->Size & (s->map_size-1))
+               return CS_BAD_SIZE;
+       if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) ||
+           (req->Base & (align-1)))
+               return CS_BAD_BASE;
+       if (req->Base)
+               align = 0;
+
+       /* Allocate system memory window */
+       for (w = 0; w < MAX_WIN; w++)
+               if (!(s->state & SOCKET_WIN_REQ(w))) break;
+       if (w == MAX_WIN)
+               return CS_OUT_OF_RESOURCE;
+
+       win = &s->win[w];
+       win->magic = WINDOW_MAGIC;
+       win->index = w;
+       win->handle = *handle;
+       win->sock = s;
+
+       if (!(s->features & SS_CAP_STATIC_MAP)) {
+               win->ctl.res = pcmcia_find_mem_region(req->Base, req->Size, align,
+                                                     (req->Attributes & WIN_MAP_BELOW_1MB), s);
+               if (!win->ctl.res)
+                       return CS_IN_USE;
+       }
+       (*handle)->state |= CLIENT_WIN_REQ(w);
+
+       /* Configure the socket controller */
+       win->ctl.map = w+1;
+       win->ctl.flags = 0;
+       win->ctl.speed = req->AccessSpeed;
+       if (req->Attributes & WIN_MEMORY_TYPE)
+               win->ctl.flags |= MAP_ATTRIB;
+       if (req->Attributes & WIN_ENABLE)
+               win->ctl.flags |= MAP_ACTIVE;
+       if (req->Attributes & WIN_DATA_WIDTH_16)
+               win->ctl.flags |= MAP_16BIT;
+       if (req->Attributes & WIN_USE_WAIT)
+               win->ctl.flags |= MAP_USE_WAIT;
+       win->ctl.card_start = 0;
+       if (s->ops->set_mem_map(s, &win->ctl) != 0)
+               return CS_BAD_ARGS;
+       s->state |= SOCKET_WIN_REQ(w);
+
+       /* Return window handle */
+       if (s->features & SS_CAP_STATIC_MAP) {
+               req->Base = win->ctl.static_start;
+       } else {
+               req->Base = win->ctl.res->start;
+       }
+       *wh = win;
+
+       return CS_SUCCESS;
+} /* pcmcia_request_window */
+EXPORT_SYMBOL(pcmcia_request_window);
index b6843f8d300d20a3d6d5f503917fbd0229685f2b..0668384ebc8bf8a4bbc0b43b522e5c7a221259c8 100644 (file)
@@ -72,7 +72,7 @@ int pcmcia_adjust_resource_info(adjust_t *adj)
                        /* you can't use the old interface if the new
                         * one was used before */
                        spin_lock_irqsave(&s->lock, flags);
-                       if ((s->resource_setup_done) &&
+                       if ((s->resource_setup_new) &&
                            !(s->resource_setup_old)) {
                                spin_unlock_irqrestore(&s->lock, flags);
                                continue;
@@ -105,29 +105,32 @@ void pcmcia_validate_mem(struct pcmcia_socket *s)
 }
 EXPORT_SYMBOL(pcmcia_validate_mem);
 
-int adjust_io_region(struct resource *res, unsigned long r_start,
+int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start,
                     unsigned long r_end, struct pcmcia_socket *s)
 {
        if (s->resource_ops->adjust_io_region)
                return s->resource_ops->adjust_io_region(res, r_start, r_end, s);
        return -ENOMEM;
 }
+EXPORT_SYMBOL(pcmcia_adjust_io_region);
 
-struct resource *find_io_region(unsigned long base, int num,
+struct resource *pcmcia_find_io_region(unsigned long base, int num,
                   unsigned long align, struct pcmcia_socket *s)
 {
        if (s->resource_ops->find_io)
                return s->resource_ops->find_io(base, num, align, s);
        return NULL;
 }
+EXPORT_SYMBOL(pcmcia_find_io_region);
 
-struct resource *find_mem_region(u_long base, u_long num, u_long align,
+struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
                                 int low, struct pcmcia_socket *s)
 {
        if (s->resource_ops->find_mem)
                return s->resource_ops->find_mem(base, num, align, low, s);
        return NULL;
 }
+EXPORT_SYMBOL(pcmcia_find_mem_region);
 
 void release_resource_db(struct pcmcia_socket *s)
 {
index 5876bab7c14c80354515e9c35e73135f33701e49..c42455d20eb683c6d2c99de733966ad403c5941d 100644 (file)
@@ -372,6 +372,9 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
           base, base+num-1);
     bad = fail = 0;
     step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
+    /* don't allow too large steps */
+    if (step > 0x800000)
+       step = 0x800000;
     /* cis_readable wants to map 2x map_size */
     if (step < 2 * s->map_size)
        step = 2 * s->map_size;
@@ -465,8 +468,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
 
        for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
                mm = *m;
-               if (do_mem_probe(mm.base, mm.num, s))
-                       break;
+               do_mem_probe(mm.base, mm.num, s);
        }
 }
 
@@ -601,7 +603,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
 
 ======================================================================*/
 
-struct resource *nonstatic_find_io_region(unsigned long base, int num,
+static struct resource *nonstatic_find_io_region(unsigned long base, int num,
                   unsigned long align, struct pcmcia_socket *s)
 {
        struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id);
@@ -635,8 +637,8 @@ struct resource *nonstatic_find_io_region(unsigned long base, int num,
        return res;
 }
 
-struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long align,
-                                int low, struct pcmcia_socket *s)
+static struct resource * nonstatic_find_mem_region(u_long base, u_long num,
+               u_long align, int low, struct pcmcia_socket *s)
 {
        struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id);
        struct socket_data *s_data = s->resource_data;
@@ -683,27 +685,23 @@ struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long alig
 }
 
 
-static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj)
+static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
 {
-       u_long base, num;
        struct socket_data *data = s->resource_data;
-       int ret;
-
-       base = adj->resource.memory.Base;
-       num = adj->resource.memory.Size;
-       if ((num == 0) || (base+num-1 < base))
-               return CS_BAD_SIZE;
+       unsigned long size = end - start + 1;
+       int ret = 0;
 
-       ret = CS_SUCCESS;
+       if (end <= start)
+               return -EINVAL;
 
        down(&rsrc_sem);
-       switch (adj->Action) {
+       switch (action) {
        case ADD_MANAGED_RESOURCE:
-               ret = add_interval(&data->mem_db, base, num);
+               ret = add_interval(&data->mem_db, start, size);
                break;
        case REMOVE_MANAGED_RESOURCE:
-               ret = sub_interval(&data->mem_db, base, num);
-               if (ret == CS_SUCCESS) {
+               ret = sub_interval(&data->mem_db, start, size);
+               if (!ret) {
                        struct pcmcia_socket *socket;
                        down_read(&pcmcia_socket_list_rwsem);
                        list_for_each_entry(socket, &pcmcia_socket_list, socket_list)
@@ -712,7 +710,7 @@ static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj)
                }
                break;
        default:
-               ret = CS_UNSUPPORTED_FUNCTION;
+               ret = -EINVAL;
        }
        up(&rsrc_sem);
 
@@ -720,36 +718,35 @@ static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj)
 }
 
 
-static int adjust_io(struct pcmcia_socket *s, adjust_t *adj)
+static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
 {
        struct socket_data *data = s->resource_data;
-       kio_addr_t base, num;
-       int ret = CS_SUCCESS;
+       unsigned long size = end - start + 1;
+       int ret = 0;
 
-       base = adj->resource.io.BasePort;
-       num = adj->resource.io.NumPorts;
-       if ((base < 0) || (base > 0xffff))
-               return CS_BAD_BASE;
-       if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
-               return CS_BAD_SIZE;
+       if (end <= start)
+               return -EINVAL;
+
+       if (end > IO_SPACE_LIMIT)
+               return -EINVAL;
 
        down(&rsrc_sem);
-       switch (adj->Action) {
+       switch (action) {
        case ADD_MANAGED_RESOURCE:
-               if (add_interval(&data->io_db, base, num) != 0) {
-                       ret = CS_IN_USE;
+               if (add_interval(&data->io_db, start, size) != 0) {
+                       ret = -EBUSY;
                        break;
                }
 #ifdef CONFIG_PCMCIA_PROBE
                if (probe_io)
-                       do_io_probe(s, base, num);
+                       do_io_probe(s, start, size);
 #endif
                break;
        case REMOVE_MANAGED_RESOURCE:
-               sub_interval(&data->io_db, base, num);
+               sub_interval(&data->io_db, start, size);
                break;
        default:
-               ret = CS_UNSUPPORTED_FUNCTION;
+               ret = -EINVAL;
                break;
        }
        up(&rsrc_sem);
@@ -760,15 +757,82 @@ static int adjust_io(struct pcmcia_socket *s, adjust_t *adj)
 
 static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj)
 {
+       unsigned long end;
+
        switch (adj->Resource) {
        case RES_MEMORY_RANGE:
-               return adjust_memory(s, adj);
+               end = adj->resource.memory.Base + adj->resource.memory.Size - 1;
+               return adjust_memory(s, adj->Action, adj->resource.memory.Base, end);
        case RES_IO_RANGE:
-               return adjust_io(s, adj);
+               end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1;
+               return adjust_io(s, adj->Action, adj->resource.io.BasePort, end);
        }
        return CS_UNSUPPORTED_FUNCTION;
 }
 
+#ifdef CONFIG_PCI
+static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
+{
+       struct resource *res;
+       int i, done = 0;
+
+       if (!s->cb_dev || !s->cb_dev->bus)
+               return -ENODEV;
+
+#if defined(CONFIG_X86) || defined(CONFIG_X86_64)
+       /* If this is the root bus, the risk of hitting
+        * some strange system devices which aren't protected
+        * by either ACPI resource tables or properly requested
+        * resources is too big. Therefore, don't do auto-adding
+        * of resources at the moment.
+        */
+       if (s->cb_dev->bus->number == 0)
+               return -EINVAL;
+#endif
+
+       for (i=0; i < PCI_BUS_NUM_RESOURCES; i++) {
+               res = s->cb_dev->bus->resource[i];
+               if (!res)
+                       continue;
+
+               if (res->flags & IORESOURCE_IO) {
+                       if (res == &ioport_resource)
+                               continue;
+                       printk(KERN_INFO "pcmcia: parent PCI bridge I/O window: 0x%lx - 0x%lx\n",
+                              res->start, res->end);
+                       if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
+                               done |= IORESOURCE_IO;
+
+               }
+
+               if (res->flags & IORESOURCE_MEM) {
+                       if (res == &iomem_resource)
+                               continue;
+                       printk(KERN_INFO "pcmcia: parent PCI bridge Memory window: 0x%lx - 0x%lx\n",
+                              res->start, res->end);
+                       if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
+                               done |= IORESOURCE_MEM;
+               }
+       }
+
+       /* if we got at least one of IO, and one of MEM, we can be glad and
+        * activate the PCMCIA subsystem */
+       if (done & (IORESOURCE_MEM | IORESOURCE_IO))
+               s->resource_setup_done = 1;
+
+       return 0;
+}
+
+#else
+
+static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
+{
+       return -ENODEV;
+}
+
+#endif
+
+
 static int nonstatic_init(struct pcmcia_socket *s)
 {
        struct socket_data *data;
@@ -783,6 +847,8 @@ static int nonstatic_init(struct pcmcia_socket *s)
 
        s->resource_data = (void *) data;
 
+       nonstatic_autoadd_resources(s);
+
        return 0;
 }
 
@@ -845,17 +911,16 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size
 {
        struct pcmcia_socket *s = class_get_devdata(class_dev);
        unsigned long start_addr, end_addr;
-       unsigned int add = 1;
-       adjust_t adj;
+       unsigned int add = ADD_MANAGED_RESOURCE;
        ssize_t ret = 0;
 
        ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
        if (ret != 2) {
                ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
-               add = 0;
+               add = REMOVE_MANAGED_RESOURCE;
                if (ret != 2) {
                        ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
-                       add = 1;
+                       add = ADD_MANAGED_RESOURCE;
                        if (ret != 2)
                                return -EINVAL;
                }
@@ -863,12 +928,9 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size
        if (end_addr <= start_addr)
                return -EINVAL;
 
-       adj.Action = add ? ADD_MANAGED_RESOURCE : REMOVE_MANAGED_RESOURCE;
-       adj.Resource = RES_IO_RANGE;
-       adj.resource.io.BasePort = start_addr;
-       adj.resource.io.NumPorts = end_addr - start_addr + 1;
-
-       ret = adjust_io(s, &adj);
+       ret = adjust_io(s, add, start_addr, end_addr);
+       if (!ret)
+               s->resource_setup_new = 1;
 
        return ret ? ret : count;
 }
@@ -901,17 +963,16 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz
 {
        struct pcmcia_socket *s = class_get_devdata(class_dev);
        unsigned long start_addr, end_addr;
-       unsigned int add = 1;
-       adjust_t adj;
+       unsigned int add = ADD_MANAGED_RESOURCE;
        ssize_t ret = 0;
 
        ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
        if (ret != 2) {
                ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
-               add = 0;
+               add = REMOVE_MANAGED_RESOURCE;
                if (ret != 2) {
                        ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
-                       add = 1;
+                       add = ADD_MANAGED_RESOURCE;
                        if (ret != 2)
                                return -EINVAL;
                }
@@ -919,12 +980,9 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz
        if (end_addr <= start_addr)
                return -EINVAL;
 
-       adj.Action = add ? ADD_MANAGED_RESOURCE : REMOVE_MANAGED_RESOURCE;
-       adj.Resource = RES_MEMORY_RANGE;
-       adj.resource.memory.Base = start_addr;
-       adj.resource.memory.Size = end_addr - start_addr + 1;
-
-       ret = adjust_memory(s, &adj);
+       ret = adjust_memory(s, add, start_addr, end_addr);
+       if (!ret)
+               s->resource_setup_new = 1;
 
        return ret ? ret : count;
 }
index 8eed0393821471e1807ba6040bb950e0f24f8571..fcef54c1c2da5c5e17c0113c29a7a36b08c63c5b 100644 (file)
@@ -163,28 +163,164 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf,
                return -EINVAL;
 
        spin_lock_irqsave(&s->lock, flags);
-       if (!s->resource_setup_done) {
+       if (!s->resource_setup_done)
                s->resource_setup_done = 1;
-               spin_unlock_irqrestore(&s->lock, flags);
+       spin_unlock_irqrestore(&s->lock, flags);
+
+       down(&s->skt_sem);
+       if ((s->callback) &&
+           (s->state & SOCKET_PRESENT) &&
+           !(s->state & SOCKET_CARDBUS)) {
+               if (try_module_get(s->callback->owner)) {
+                       s->callback->requery(s);
+                       module_put(s->callback->owner);
+               }
+       }
+       up(&s->skt_sem);
+
+       return count;
+}
+static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
+
+
+static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count)
+{
+       tuple_t tuple;
+       int status, i;
+       loff_t pointer = 0;
+       ssize_t ret = 0;
+       u_char *tuplebuffer;
+       u_char *tempbuffer;
+
+       tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL);
+       if (!tuplebuffer)
+               return -ENOMEM;
+
+       tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL);
+       if (!tempbuffer) {
+               ret = -ENOMEM;
+               goto free_tuple;
+       }
+
+       memset(&tuple, 0, sizeof(tuple_t));
+
+       tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
+       tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+       tuple.TupleOffset = 0;
+
+       status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple);
+       while (!status) {
+               tuple.TupleData = tuplebuffer;
+               tuple.TupleDataMax = 255;
+               memset(tuplebuffer, 0, sizeof(u_char) * 255);
 
+               status = pccard_get_tuple_data(s, &tuple);
+               if (status)
+                       break;
+
+               if (off < (pointer + 2 + tuple.TupleDataLen)) {
+                       tempbuffer[0] = tuple.TupleCode & 0xff;
+                       tempbuffer[1] = tuple.TupleLink & 0xff;
+                       for (i = 0; i < tuple.TupleDataLen; i++)
+                               tempbuffer[i + 2] = tuplebuffer[i] & 0xff;
+
+                       for (i = 0; i < (2 + tuple.TupleDataLen); i++) {
+                               if (((i + pointer) >= off) &&
+                                   (i + pointer) < (off + count)) {
+                                       buf[ret] = tempbuffer[i];
+                                       ret++;
+                               }
+                       }
+               }
+
+               pointer += 2 + tuple.TupleDataLen;
+
+               if (pointer >= (off + count))
+                       break;
+
+               if (tuple.TupleCode == CISTPL_END)
+                       break;
+               status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple);
+       }
+
+       kfree(tempbuffer);
+ free_tuple:
+       kfree(tuplebuffer);
+
+       return (ret);
+}
+
+static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+       unsigned int size = 0x200;
+
+       if (off >= size)
+               count = 0;
+       else {
+               struct pcmcia_socket *s;
+               cisinfo_t cisinfo;
+
+               if (off + count > size)
+                       count = size - off;
+
+               s = to_socket(container_of(kobj, struct class_device, kobj));
+
+               if (!(s->state & SOCKET_PRESENT))
+                       return -ENODEV;
+               if (pccard_validate_cis(s, BIND_FN_ALL, &cisinfo))
+                       return -EIO;
+               if (!cisinfo.Chains)
+                       return -ENODATA;
+
+               count = pccard_extract_cis(s, buf, off, count);
+       }
+
+       return (count);
+}
+
+static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+       struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj));
+       cisdump_t *cis;
+       ssize_t ret = count;
+
+       if (off)
+               return -EINVAL;
+
+       if (count >= 0x200)
+               return -EINVAL;
+
+       if (!(s->state & SOCKET_PRESENT))
+               return -ENODEV;
+
+       cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL);
+       if (!cis)
+               return -ENOMEM;
+       memset(cis, 0, sizeof(cisdump_t));
+
+       cis->Length = count + 1;
+       memcpy(cis->Data, buf, count);
+
+       if (pcmcia_replace_cis(s, cis))
+               ret  = -EIO;
+
+       kfree(cis);
+
+       if (!ret) {
                down(&s->skt_sem);
-               if ((s->callback) &&
-                   (s->state & SOCKET_PRESENT) &&
+               if ((s->callback) && (s->state & SOCKET_PRESENT) &&
                    !(s->state & SOCKET_CARDBUS)) {
                        if (try_module_get(s->callback->owner)) {
-                               s->callback->resources_done(s);
+                               s->callback->requery(s);
                                module_put(s->callback->owner);
                        }
                }
                up(&s->skt_sem);
-
-               return count;
        }
-       spin_unlock_irqrestore(&s->lock, flags);
 
-       return count;
+
+       return (ret);
 }
-static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
 
 
 static struct class_device_attribute *pccard_socket_attributes[] = {
@@ -199,6 +335,13 @@ static struct class_device_attribute *pccard_socket_attributes[] = {
        NULL,
 };
 
+static struct bin_attribute pccard_cis_attr = {
+       .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR, .owner = THIS_MODULE},
+       .size = 0x200,
+       .read = pccard_show_cis,
+       .write = pccard_store_cis,
+};
+
 static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev)
 {
        struct class_device_attribute **attr;
@@ -209,6 +352,8 @@ static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev)
                if (ret)
                        break;
        }
+       if (!ret)
+               ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr);
 
        return ret;
 }
@@ -217,6 +362,7 @@ static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev)
 {
        struct class_device_attribute **attr;
 
+       sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr);
        for (attr = pccard_socket_attributes; *attr; attr++)
                class_device_remove_file(class_dev, *attr);
 }
index bee05362fd244dc46762a0979e3c009c62752a24..02b23abc2df143edfac93a8985b6f1e9dc8084dd 100644 (file)
@@ -549,6 +549,11 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ
        unsigned offset;
        unsigned mask;
 
+       res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr;
+       /* Already allocated? */
+       if (res->parent)
+               return 0;
+
        /* The granularity of the memory limit is 4kB, on IO it's 4 bytes */
        mask = ~0xfff;
        if (type & IORESOURCE_IO)
@@ -556,7 +561,6 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ
 
        offset = 0x1c + 8*nr;
        bus = socket->dev->subordinate;
-       res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr;
        res->name = bus->name;
        res->flags = type;
        res->start = 0;
index 3252662958d3cf3f2cb66bd562acef0fb9147a86..add12f7c489a9666b53983c13077505465c33bd4 100644 (file)
@@ -259,7 +259,6 @@ int pnp_add_card_device(struct pnp_card * card, struct pnp_dev * dev)
 
 /**
  * pnp_remove_card_device- removes a device from the specified card
- * @card: pointer to the card to remove from
  * @dev: pointer to the device to remove
  */
 
@@ -274,7 +273,7 @@ void pnp_remove_card_device(struct pnp_dev * dev)
 
 /**
  * pnp_request_card_device - Searches for a PnP device under the specified card
- * @lcard: pointer to the card link, cannot be NULL
+ * @clink: pointer to the card link, cannot be NULL
  * @id: pointer to a PnP ID structure that explains the rules for finding the device
  * @from: Starting place to search from. If NULL it will start from the begining.
  */
index 65ecef7385373248708d3dc001d442d5965ae0c1..6c510c19ad7d9097581d70ac25fd5983b13df76d 100644 (file)
@@ -390,6 +390,7 @@ fail:
  * pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table
  * @dev: pointer to the desired device
  * @res: pointer to the new resource config
+ * @mode: 0 or PNP_CONFIG_FORCE
  *
  * This function can be used by drivers that want to manually set thier resources.
  */
index e939c93a931cf6ea29d3c5be86bf6f81455fb8da..778a324028f4135bdb90bb4e655bac513c17e43d 100644 (file)
@@ -182,7 +182,7 @@ static int pnp_dock_thread(void * unused)
                msleep_interruptible(2000);
 
                if(signal_pending(current)) {
-                       if (try_to_freeze(PF_FREEZE))
+                       if (try_to_freeze())
                                continue;
                        break;
                }
index 96413c2cd1ade4b02137a29f664ac1d82f030914..a86a650f3d6df13684cb07526469d9e8e7d283e3 100644 (file)
@@ -187,6 +187,13 @@ config VMLOGRDR
          *SYMPTOM.
          This driver depends on the IUCV support driver.
 
+config VMCP
+       tristate "Support for the z/VM CP interface (VM only)"
+       help
+         Select this option if you want to be able to interact with the control
+         program on z/VM
+
+
 config MONREADER
        tristate "API for reading z/VM monitor service records"
        depends on IUCV
index ceeb3cf64a16ccc10aa521c550889fc0cad5edcd..6527ff6f470648a3698a774c0222a5c83b6fd1f7 100644 (file)
@@ -176,7 +176,7 @@ dasd_state_known_to_basic(struct dasd_device * device)
                return rc;
 
        /* register 'device' debug area, used for all DBF_DEV_XXX calls */
-       device->debug_area = debug_register(device->cdev->dev.bus_id, 0, 2,
+       device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 2,
                                            8 * sizeof (long));
        debug_register_view(device->debug_area, &debug_sprintf_view);
        debug_set_level(device->debug_area, DBF_EMERG);
@@ -1952,26 +1952,24 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
  * Automatically online either all dasd devices (dasd_autodetect) or
  * all devices specified with dasd= parameters.
  */
+static int
+__dasd_auto_online(struct device *dev, void *data)
+{
+       struct ccw_device *cdev;
+
+       cdev = to_ccwdev(dev);
+       if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0)
+               ccw_device_set_online(cdev);
+       return 0;
+}
+
 void
 dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
 {
        struct device_driver *drv;
-       struct device *d, *dev;
-       struct ccw_device *cdev;
 
        drv = get_driver(&dasd_discipline_driver->driver);
-       down_read(&drv->bus->subsys.rwsem);
-       dev = NULL;
-       list_for_each_entry(d, &drv->devices, driver_list) {
-               dev = get_device(d);
-               if (!dev)
-                       continue;
-               cdev = to_ccwdev(dev);
-               if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0)
-                       ccw_device_set_online(cdev);
-               put_device(dev);
-       }
-       up_read(&drv->bus->subsys.rwsem);
+       driver_for_each_device(drv, NULL, NULL, __dasd_auto_online);
        put_driver(drv);
 }
 
@@ -1983,7 +1981,7 @@ dasd_init(void)
        init_waitqueue_head(&dasd_init_waitq);
 
        /* register 'common' DASD debug area, used for all DBF_XXX calls */
-       dasd_debug_area = debug_register("dasd", 0, 2, 8 * sizeof (long));
+       dasd_debug_area = debug_register("dasd", 1, 2, 8 * sizeof (long));
        if (dasd_debug_area == NULL) {
                rc = -ENOMEM;
                goto failed;
index d7f19745911f09b4fa391e450a7d18da2d0d60f7..43c34f8c5e685336daeaf87021d4a683720adaa8 100644 (file)
@@ -9,13 +9,14 @@
  *
  * /proc interface for the dasd driver.
  *
- * $Revision: 1.31 $
+ * $Revision: 1.32 $
  */
 
 #include <linux/config.h>
 #include <linux/ctype.h>
 #include <linux/seq_file.h>
 #include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
 
 #include <asm/debug.h>
 #include <asm/uaccess.h>
index 16ab8d363ac6ccdab63714ea6920996b7dd8052b..4fde41188996e6ba82231e16592e5f5535e4e3da 100644 (file)
 static int dcssblk_open(struct inode *inode, struct file *filp);
 static int dcssblk_release(struct inode *inode, struct file *filp);
 static int dcssblk_make_request(struct request_queue *q, struct bio *bio);
+static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
+                                unsigned long *data);
 
 static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
 
 static int dcssblk_major;
 static struct block_device_operations dcssblk_devops = {
-       .owner   = THIS_MODULE,
-       .open    = dcssblk_open,
-       .release = dcssblk_release,
+       .owner          = THIS_MODULE,
+       .open           = dcssblk_open,
+       .release        = dcssblk_release,
+       .direct_access  = dcssblk_direct_access,
 };
 
 static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf,
@@ -641,6 +644,20 @@ dcssblk_make_request(request_queue_t *q, struct bio *bio)
                /* Request beyond end of DCSS segment. */
                goto fail;
        }
+       /* verify data transfer direction */
+       if (dev_info->is_shared) {
+               switch (dev_info->segment_type) {
+               case SEG_TYPE_SR:
+               case SEG_TYPE_ER:
+               case SEG_TYPE_SC:
+                       /* cannot write to these segments */
+                       if (bio_data_dir(bio) == WRITE) {
+                               PRINT_WARN("rejecting write to ro segment %s\n", dev_info->dev.bus_id);
+                               goto fail;
+                       }
+               }
+       }
+
        index = (bio->bi_sector >> 3);
        bio_for_each_segment(bvec, bio, i) {
                page_addr = (unsigned long)
@@ -661,7 +678,26 @@ dcssblk_make_request(request_queue_t *q, struct bio *bio)
        bio_endio(bio, bytes_done, 0);
        return 0;
 fail:
-       bio_io_error(bio, bytes_done);
+       bio_io_error(bio, bio->bi_size);
+       return 0;
+}
+
+static int
+dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
+                       unsigned long *data)
+{
+       struct dcssblk_dev_info *dev_info;
+       unsigned long pgoff;
+
+       dev_info = bdev->bd_disk->private_data;
+       if (!dev_info)
+               return -ENODEV;
+       if (secnum % (PAGE_SIZE/512))
+               return -EINVAL;
+       pgoff = secnum / (PAGE_SIZE / 512);
+       if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start)
+               return -ERANGE;
+       *data = (unsigned long) (dev_info->start+pgoff*PAGE_SIZE);
        return 0;
 }
 
@@ -682,7 +718,7 @@ dcssblk_check_params(void)
                        buf[j-i] = dcssblk_segments[j];
                }
                buf[j-i] = '\0';
-               rc = dcssblk_add_store(dcssblk_root_dev, buf, j-i);
+               rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i);
                if ((rc >= 0) && (dcssblk_segments[j] == '(')) {
                        for (k = 0; buf[k] != '\0'; k++)
                                buf[k] = toupper(buf[k]);
@@ -692,7 +728,7 @@ dcssblk_check_params(void)
                                up_read(&dcssblk_devices_sem);
                                if (dev_info)
                                        dcssblk_shared_store(&dev_info->dev,
-                                                            "0\n", 2);
+                                                            NULL, "0\n", 2);
                        }
                }
                while ((dcssblk_segments[j] != ',') &&
index 14e8cce9f862a4bc92e53121da52fa7c0b703781..6377a96735df87ccbd5d506b56ee964817940f9c 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o
 
 obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o
 obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o
+obj-$(CONFIG_VMCP) += vmcp.o
 
 tape-$(CONFIG_S390_TAPE_BLOCK) += tape_block.o
 tape-$(CONFIG_PROC_FS) += tape_proc.o
index 022f17bff7314e2f2ce140ddfcfc709eb248865f..f11a67fda40e55a4a009ff04f16a6217b8fa76c1 100644 (file)
@@ -860,8 +860,8 @@ con3215_init(void)
 
        /* Set the console mode for VM */
        if (MACHINE_IS_VM) {
-               cpcmd("TERM CONMODE 3215", NULL, 0);
-               cpcmd("TERM AUTOCR OFF", NULL, 0);
+               cpcmd("TERM CONMODE 3215", NULL, 0, NULL);
+               cpcmd("TERM AUTOCR OFF", NULL, 0, NULL);
        }
 
        /* allocate 3215 request structures */
index d52fb57a6b197d64efa9c418bc9e863b2b3a36dd..fc7a213e591f5962f78084bbb7416db5a402aee9 100644 (file)
@@ -591,8 +591,8 @@ con3270_init(void)
 
        /* Set the console mode for VM */
        if (MACHINE_IS_VM) {
-               cpcmd("TERM CONMODE 3270", 0, 0);
-               cpcmd("TERM AUTOCR OFF", 0, 0);
+               cpcmd("TERM CONMODE 3270", NULL, 0, NULL);
+               cpcmd("TERM AUTOCR OFF", NULL, 0, NULL);
        }
 
        cdev = ccw_device_probe_console();
index 480ec87976fb0db5a7d1afd472ce5a696d7cb698..20be88e91fa1a7abff383f8e0aac20976f8beac0 100644 (file)
@@ -1351,13 +1351,13 @@ tape_34xx_init (void)
 {
        int rc;
 
-       TAPE_DBF_AREA = debug_register ( "tape_34xx", 1, 2, 4*sizeof(long));
+       TAPE_DBF_AREA = debug_register ( "tape_34xx", 2, 2, 4*sizeof(long));
        debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view);
 #ifdef DBF_LIKE_HELL
        debug_set_level(TAPE_DBF_AREA, 6);
 #endif
 
-       DBF_EVENT(3, "34xx init: $Revision: 1.21 $\n");
+       DBF_EVENT(3, "34xx init: $Revision: 1.23 $\n");
        /* Register driver for 3480/3490 tapes. */
        rc = ccw_driver_register(&tape_34xx_driver);
        if (rc)
@@ -1378,7 +1378,7 @@ tape_34xx_exit(void)
 MODULE_DEVICE_TABLE(ccw, tape_34xx_ids);
 MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH");
 MODULE_DESCRIPTION("Linux on zSeries channel attached 3480 tape "
-                  "device driver ($Revision: 1.21 $)");
+                  "device driver ($Revision: 1.23 $)");
 MODULE_LICENSE("GPL");
 
 module_init(tape_34xx_init);
index b4df4a515b1256056b5bc7708b12708b177154a4..0597aa0e27ee00c48928256813674c7704df50d1 100644 (file)
@@ -1186,7 +1186,7 @@ tape_mtop(struct tape_device *device, int mt_op, int mt_count)
 static int
 tape_init (void)
 {
-       TAPE_DBF_AREA = debug_register ( "tape", 1, 2, 4*sizeof(long));
+       TAPE_DBF_AREA = debug_register ( "tape", 2, 2, 4*sizeof(long));
        debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view);
 #ifdef DBF_LIKE_HELL
        debug_set_level(TAPE_DBF_AREA, 6);
index 801d17cca34ea06c0e4a3ed9584668002085292c..5fec0a10cc3d089b172da95a59acbe6aaca7e744 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/seq_file.h>
+#include <linux/proc_fs.h>
 
 #define TAPE_DBF_AREA  tape_core_dbf
 
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
new file mode 100644 (file)
index 0000000..7f11a60
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2004,2005 IBM Corporation
+ * Interface implementation for communication with the v/VM control program
+ * Author(s): Christian Borntraeger <cborntra@de.ibm.com>
+ *
+ *
+ * z/VMs CP offers the possibility to issue commands via the diagnose code 8
+ * this driver implements a character device that issues these commands and
+ * returns the answer of CP.
+
+ * The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <asm/cpcmd.h>
+#include <asm/debug.h>
+#include <asm/uaccess.h>
+#include "vmcp.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Borntraeger <cborntra@de.ibm.com>");
+MODULE_DESCRIPTION("z/VM CP interface");
+
+static debug_info_t *vmcp_debug;
+
+static int vmcp_open(struct inode *inode, struct file *file)
+{
+       struct vmcp_session *session;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       session = kmalloc(sizeof(*session), GFP_KERNEL);
+       if (!session)
+               return -ENOMEM;
+       session->bufsize = PAGE_SIZE;
+       session->response = NULL;
+       session->resp_size = 0;
+       init_MUTEX(&session->mutex);
+       file->private_data = session;
+       return nonseekable_open(inode, file);
+}
+
+static int vmcp_release(struct inode *inode, struct file *file)
+{
+       struct vmcp_session *session;
+
+       session = (struct vmcp_session *)file->private_data;
+       file->private_data = NULL;
+       free_pages((unsigned long)session->response, get_order(session->bufsize));
+       kfree(session);
+       return 0;
+}
+
+static ssize_t
+vmcp_read(struct file *file, char __user * buff, size_t count, loff_t * ppos)
+{
+       size_t tocopy;
+       struct vmcp_session *session;
+
+       session = (struct vmcp_session *)file->private_data;
+       if (down_interruptible(&session->mutex))
+               return -ERESTARTSYS;
+       if (!session->response) {
+               up(&session->mutex);
+               return 0;
+       }
+       if (*ppos > session->resp_size) {
+               up(&session->mutex);
+               return 0;
+       }
+       tocopy = min(session->resp_size - (size_t) (*ppos), count);
+       tocopy = min(tocopy,session->bufsize - (size_t) (*ppos));
+
+       if (copy_to_user(buff, session->response + (*ppos), tocopy)) {
+               up(&session->mutex);
+               return -EFAULT;
+       }
+       up(&session->mutex);
+       *ppos += tocopy;
+       return tocopy;
+}
+
+static ssize_t
+vmcp_write(struct file *file, const char __user * buff, size_t count,
+          loff_t * ppos)
+{
+       char *cmd;
+       struct vmcp_session *session;
+
+       if (count > 240)
+               return -EINVAL;
+       cmd = kmalloc(count + 1, GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+       if (copy_from_user(cmd, buff, count)) {
+               kfree(cmd);
+               return -EFAULT;
+       }
+       cmd[count] = '\0';
+       session = (struct vmcp_session *)file->private_data;
+       if (down_interruptible(&session->mutex))
+               return -ERESTARTSYS;
+       if (!session->response)
+               session->response = (char *)__get_free_pages(GFP_KERNEL
+                                               | __GFP_REPEAT  | GFP_DMA,
+                                               get_order(session->bufsize));
+       if (!session->response) {
+               up(&session->mutex);
+               kfree(cmd);
+               return -ENOMEM;
+       }
+       debug_text_event(vmcp_debug, 1, cmd);
+       session->resp_size = cpcmd(cmd, session->response,
+                                  session->bufsize,
+                                  &session->resp_code);
+       up(&session->mutex);
+       kfree(cmd);
+       *ppos = 0;              /* reset the file pointer after a command */
+       return count;
+}
+
+
+/*
+ * These ioctls are available, as the semantics of the diagnose 8 call
+ * does not fit very well into a Linux call. Diagnose X'08' is described in
+ * CP Programming Services SC24-6084-00
+ *
+ * VMCP_GETCODE: gives the CP return code back to user space
+ * VMCP_SETBUF: sets the response buffer for the next write call. diagnose 8
+ * expects adjacent pages in real storage and to make matters worse, we
+ * dont know the size of the response. Therefore we default to PAGESIZE and
+ * let userspace to change the response size, if userspace expects a bigger
+ * response
+ */
+static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct vmcp_session *session;
+       int temp;
+
+       session = (struct vmcp_session *)file->private_data;
+       if (down_interruptible(&session->mutex))
+               return -ERESTARTSYS;
+       switch (cmd) {
+       case VMCP_GETCODE:
+               temp = session->resp_code;
+               up(&session->mutex);
+               return put_user(temp, (int __user *)arg);
+       case VMCP_SETBUF:
+               free_pages((unsigned long)session->response,
+                               get_order(session->bufsize));
+               session->response=NULL;
+               temp = get_user(session->bufsize, (int __user *)arg);
+               if (get_order(session->bufsize) > 8) {
+                       session->bufsize = PAGE_SIZE;
+                       temp = -EINVAL;
+               }
+               up(&session->mutex);
+               return temp;
+       case VMCP_GETSIZE:
+               temp = session->resp_size;
+               up(&session->mutex);
+               return put_user(temp, (int __user *)arg);
+       default:
+               up(&session->mutex);
+               return -ENOIOCTLCMD;
+       }
+}
+
+static struct file_operations vmcp_fops = {
+       .owner          = THIS_MODULE,
+       .open           = &vmcp_open,
+       .release        = &vmcp_release,
+       .read           = &vmcp_read,
+       .llseek         = &no_llseek,
+       .write          = &vmcp_write,
+       .unlocked_ioctl = &vmcp_ioctl,
+       .compat_ioctl   = &vmcp_ioctl
+};
+
+static struct miscdevice vmcp_dev = {
+       .name   = "vmcp",
+       .minor  = MISC_DYNAMIC_MINOR,
+       .fops   = &vmcp_fops,
+};
+
+static int __init vmcp_init(void)
+{
+       int ret;
+
+       if (!MACHINE_IS_VM) {
+               printk(KERN_WARNING
+                      "z/VM CP interface is only available under z/VM\n");
+               return -ENODEV;
+       }
+       ret = misc_register(&vmcp_dev);
+       if (!ret)
+               printk(KERN_INFO "z/VM CP interface loaded\n");
+       else
+               printk(KERN_WARNING
+                      "z/VM CP interface not loaded. Could not register misc device.\n");
+       vmcp_debug = debug_register("vmcp", 1, 1, 240);
+       debug_register_view(vmcp_debug, &debug_hex_ascii_view);
+       return ret;
+}
+
+static void __exit vmcp_exit(void)
+{
+       WARN_ON(misc_deregister(&vmcp_dev) != 0);
+       debug_unregister(vmcp_debug);
+       printk(KERN_INFO "z/VM CP interface unloaded.\n");
+}
+
+module_init(vmcp_init);
+module_exit(vmcp_exit);
diff --git a/drivers/s390/char/vmcp.h b/drivers/s390/char/vmcp.h
new file mode 100644 (file)
index 0000000..87389e7
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2004, 2005 IBM Corporation
+ * Interface implementation for communication with the v/VM control program
+ * Version 1.0
+ * Author(s): Christian Borntraeger <cborntra@de.ibm.com>
+ *
+ *
+ * z/VMs CP offers the possibility to issue commands via the diagnose code 8
+ * this driver implements a character device that issues these commands and
+ * returns the answer of CP.
+ *
+ * The idea of this driver is based on cpint from Neale Ferguson
+ */
+
+#include <asm/semaphore.h>
+#include <linux/ioctl.h>
+
+#define VMCP_GETCODE _IOR(0x10, 1, int)
+#define VMCP_SETBUF _IOW(0x10, 2, int)
+#define VMCP_GETSIZE _IOR(0x10, 3, int)
+
+struct vmcp_session {
+       unsigned int bufsize;
+       char *response;
+       int resp_size;
+       int resp_code;
+       /* As we use copy_from/to_user, which might     *
+        * sleep and cannot use a spinlock              */
+       struct semaphore mutex;
+};
index f7717327d15e1f7a666ac243ae0b04b8d2c63dc1..491f00c032e88dade6b7fa5ac5af0cea9bc1e4d7 100644 (file)
@@ -236,7 +236,7 @@ vmlogrdr_get_recording_class_AB(void) {
        int len,i;
 
        printk (KERN_DEBUG "vmlogrdr: query command: %s\n", cp_command);
-       cpcmd(cp_command, cp_response, sizeof(cp_response));
+       cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
        printk (KERN_DEBUG "vmlogrdr: response: %s", cp_response);
        len = strnlen(cp_response,sizeof(cp_response));
        // now the parsing
@@ -288,7 +288,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) {
 
                printk (KERN_DEBUG "vmlogrdr: recording command: %s\n",
                        cp_command);
-               cpcmd(cp_command, cp_response, sizeof(cp_response));
+               cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
                printk (KERN_DEBUG "vmlogrdr: recording response: %s",
                        cp_response);
        }
@@ -301,7 +301,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) {
                qid_string);
 
        printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command);
-       cpcmd(cp_command, cp_response, sizeof(cp_response));
+       cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
        printk (KERN_DEBUG "vmlogrdr: recording response: %s",
                cp_response);
        /* The recording command will usually answer with 'Command complete'
@@ -607,7 +607,7 @@ vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const c
                         priv->recording_name);
 
        printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command);
-       cpcmd(cp_command, cp_response, sizeof(cp_response));
+       cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
        printk (KERN_DEBUG "vmlogrdr: recording response: %s",
                cp_response);
 
@@ -682,7 +682,7 @@ vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) {
        char cp_command[] = "QUERY RECORDING ";
        int len;
 
-       cpcmd(cp_command, buf, 4096);
+       cpcmd(cp_command, buf, 4096, NULL);
        len = strlen(buf);
        return len;
 }
index 306525acb9f829d8a51e700e0ac458a4cccaf1a2..91ea8e4777f340b2c47fe76ac5f68cab43e54ffa 100644 (file)
@@ -403,34 +403,22 @@ ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
        return driver_register(&cdriver->driver);
 }
 
-static inline struct device *
-__get_next_ccwgroup_device(struct device_driver *drv)
+static int
+__ccwgroup_driver_unregister_device(struct device *dev, void *data)
 {
-       struct device *dev, *d;
-
-       down_read(&drv->bus->subsys.rwsem);
-       dev = NULL;
-       list_for_each_entry(d, &drv->devices, driver_list) {
-               dev = get_device(d);
-               if (dev)
-                       break;
-       }
-       up_read(&drv->bus->subsys.rwsem);
-       return dev;
+       __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
+       device_unregister(dev);
+       put_device(dev);
+       return 0;
 }
 
 void
 ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
 {
-       struct device *dev;
-
        /* We don't want ccwgroup devices to live longer than their driver. */
        get_driver(&cdriver->driver);
-       while ((dev = __get_next_ccwgroup_device(&cdriver->driver))) {
-               __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
-               device_unregister(dev);
-               put_device(dev);
-       };
+       driver_for_each_device(&cdriver->driver, NULL, NULL,
+                              __ccwgroup_driver_unregister_device);
        put_driver(&cdriver->driver);
        driver_unregister(&cdriver->driver);
 }
@@ -449,7 +437,7 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
        if (cdev->dev.driver_data) {
                gdev = (struct ccwgroup_device *)cdev->dev.driver_data;
                if (get_device(&gdev->dev)) {
-                       if (!list_empty(&gdev->dev.node))
+                       if (klist_node_attached(&gdev->dev.knode_bus))
                                return gdev;
                        put_device(&gdev->dev);
                }
index 1d9b3f18d8debddcdd63464295f3fce03ee9c611..ea813bdce1d63a8617ddb2881b98a679bfb17445 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/cio.c
  *   S/390 common I/O routines -- low level i/o calls
- *   $Revision: 1.133 $
+ *   $Revision: 1.134 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *                           IBM Corporation
@@ -63,17 +63,17 @@ __setup ("cio_msg=", cio_setup);
 static int __init
 cio_debug_init (void)
 {
-       cio_debug_msg_id = debug_register ("cio_msg", 4, 4, 16*sizeof (long));
+       cio_debug_msg_id = debug_register ("cio_msg", 16, 4, 16*sizeof (long));
        if (!cio_debug_msg_id)
                goto out_unregister;
        debug_register_view (cio_debug_msg_id, &debug_sprintf_view);
        debug_set_level (cio_debug_msg_id, 2);
-       cio_debug_trace_id = debug_register ("cio_trace", 4, 4, 8);
+       cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 8);
        if (!cio_debug_trace_id)
                goto out_unregister;
        debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view);
        debug_set_level (cio_debug_trace_id, 2);
-       cio_debug_crw_id = debug_register ("cio_crw", 2, 4, 16*sizeof (long));
+       cio_debug_crw_id = debug_register ("cio_crw", 4, 4, 16*sizeof (long));
        if (!cio_debug_crw_id)
                goto out_unregister;
        debug_register_view (cio_debug_crw_id, &debug_sprintf_view);
index 87bd70eeabed78f416e36c0a8d13480b8f7f10b9..555119cacc279c07c59372892fba6d4983153a13 100644 (file)
@@ -128,34 +128,28 @@ css_probe_device(int irq)
        return ret;
 }
 
+static int
+check_subchannel(struct device * dev, void * data)
+{
+       struct subchannel *sch;
+       int irq = (unsigned long)data;
+
+       sch = to_subchannel(dev);
+       return (sch->irq == irq);
+}
+
 struct subchannel *
 get_subchannel_by_schid(int irq)
 {
-       struct subchannel *sch;
-       struct list_head *entry;
        struct device *dev;
 
-       if (!get_bus(&css_bus_type))
-               return NULL;
-       down_read(&css_bus_type.subsys.rwsem);
-       sch = NULL;
-       list_for_each(entry, &css_bus_type.devices.list) {
-               dev = get_device(container_of(entry,
-                                             struct device, bus_list));
-               if (!dev)
-                       continue;
-               sch = to_subchannel(dev);
-               if (sch->irq == irq)
-                       break;
-               put_device(dev);
-               sch = NULL;
-       }
-       up_read(&css_bus_type.subsys.rwsem);
-       put_bus(&css_bus_type);
+       dev = bus_find_device(&css_bus_type, NULL,
+                             (void *)(unsigned long)irq, check_subchannel);
 
-       return sch;
+       return dev ? to_subchannel(dev) : NULL;
 }
 
+
 static inline int
 css_get_subchannel_status(struct subchannel *sch, int schid)
 {
index 809e1108a06ef40c00603133d98a38bcc9eaceba..14c76f5e417708ebbd22321ebda46ed9cd5d79b3 100644 (file)
@@ -514,36 +514,39 @@ ccw_device_register(struct ccw_device *cdev)
        return ret;
 }
 
+struct match_data {
+       unsigned int  devno;
+       struct ccw_device * sibling;
+};
+
+static int
+match_devno(struct device * dev, void * data)
+{
+       struct match_data * d = (struct match_data *)data;
+       struct ccw_device * cdev;
+
+       cdev = to_ccwdev(dev);
+       if ((cdev->private->state == DEV_STATE_DISCONNECTED) &&
+           (cdev->private->devno == d->devno) &&
+           (cdev != d->sibling)) {
+               cdev->private->state = DEV_STATE_NOT_OPER;
+               return 1;
+       }
+       return 0;
+}
+
 static struct ccw_device *
 get_disc_ccwdev_by_devno(unsigned int devno, struct ccw_device *sibling)
 {
-       struct ccw_device *cdev;
-       struct list_head *entry;
        struct device *dev;
+       struct match_data data = {
+               .devno  = devno,
+               .sibling = sibling,
+       };
 
-       if (!get_bus(&ccw_bus_type))
-               return NULL;
-       down_read(&ccw_bus_type.subsys.rwsem);
-       cdev = NULL;
-       list_for_each(entry, &ccw_bus_type.devices.list) {
-               dev = get_device(container_of(entry,
-                                             struct device, bus_list));
-               if (!dev)
-                       continue;
-               cdev = to_ccwdev(dev);
-               if ((cdev->private->state == DEV_STATE_DISCONNECTED) &&
-                   (cdev->private->devno == devno) &&
-                   (cdev != sibling)) {
-                       cdev->private->state = DEV_STATE_NOT_OPER;
-                       break;
-               }
-               put_device(dev);
-               cdev = NULL;
-       }
-       up_read(&ccw_bus_type.subsys.rwsem);
-       put_bus(&ccw_bus_type);
+       dev = bus_find_device(&css_bus_type, NULL, &data, match_devno);
 
-       return cdev;
+       return dev ? to_ccwdev(dev) : NULL;
 }
 
 static void
@@ -647,7 +650,7 @@ io_subchannel_register(void *data)
        cdev = (struct ccw_device *) data;
        sch = to_subchannel(cdev->dev.parent);
 
-       if (!list_empty(&sch->dev.children)) {
+       if (klist_node_attached(&cdev->dev.knode_parent)) {
                bus_rescan_devices(&ccw_bus_type);
                goto out;
        }
@@ -1019,30 +1022,29 @@ ccw_device_probe_console(void)
 /*
  * get ccw_device matching the busid, but only if owned by cdrv
  */
+static int
+__ccwdev_check_busid(struct device *dev, void *id)
+{
+       char *bus_id;
+
+       bus_id = (char *)id;
+
+       return (strncmp(bus_id, dev->bus_id, BUS_ID_SIZE) == 0);
+}
+
+
 struct ccw_device *
 get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id)
 {
-       struct device *d, *dev;
+       struct device *dev;
        struct device_driver *drv;
 
        drv = get_driver(&cdrv->driver);
        if (!drv)
-               return 0;
-
-       down_read(&drv->bus->subsys.rwsem);
-
-       dev = NULL;
-       list_for_each_entry(d, &drv->devices, driver_list) {
-               dev = get_device(d);
+               return NULL;
 
-               if (dev && !strncmp(bus_id, dev->bus_id, BUS_ID_SIZE))
-                       break;
-               else if (dev) {
-                       put_device(dev);
-                       dev = NULL;
-               }
-       }
-       up_read(&drv->bus->subsys.rwsem);
+       dev = driver_find_device(drv, NULL, (void *)bus_id,
+                                __ccwdev_check_busid);
        put_driver(drv);
 
        return dev ? to_ccwdev(dev) : 0;
index bbe9f45d1438e3b7a0c868af5cf76765dcbbb862..82194c4eadfb59844511be40adff6a5f1fed94a6 100644 (file)
@@ -56,7 +56,7 @@
 #include "ioasm.h"
 #include "chsc.h"
 
-#define VERSION_QDIO_C "$Revision: 1.98 $"
+#define VERSION_QDIO_C "$Revision: 1.101 $"
 
 /****************** MODULE PARAMETER VARIABLES ********************/
 MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
@@ -3342,7 +3342,7 @@ static int
 qdio_register_dbf_views(void)
 {
        qdio_dbf_setup=debug_register(QDIO_DBF_SETUP_NAME,
-                                     QDIO_DBF_SETUP_INDEX,
+                                     QDIO_DBF_SETUP_PAGES,
                                      QDIO_DBF_SETUP_NR_AREAS,
                                      QDIO_DBF_SETUP_LEN);
        if (!qdio_dbf_setup)
@@ -3351,7 +3351,7 @@ qdio_register_dbf_views(void)
        debug_set_level(qdio_dbf_setup,QDIO_DBF_SETUP_LEVEL);
 
        qdio_dbf_sbal=debug_register(QDIO_DBF_SBAL_NAME,
-                                    QDIO_DBF_SBAL_INDEX,
+                                    QDIO_DBF_SBAL_PAGES,
                                     QDIO_DBF_SBAL_NR_AREAS,
                                     QDIO_DBF_SBAL_LEN);
        if (!qdio_dbf_sbal)
@@ -3361,7 +3361,7 @@ qdio_register_dbf_views(void)
        debug_set_level(qdio_dbf_sbal,QDIO_DBF_SBAL_LEVEL);
 
        qdio_dbf_sense=debug_register(QDIO_DBF_SENSE_NAME,
-                                     QDIO_DBF_SENSE_INDEX,
+                                     QDIO_DBF_SENSE_PAGES,
                                      QDIO_DBF_SENSE_NR_AREAS,
                                      QDIO_DBF_SENSE_LEN);
        if (!qdio_dbf_sense)
@@ -3371,7 +3371,7 @@ qdio_register_dbf_views(void)
        debug_set_level(qdio_dbf_sense,QDIO_DBF_SENSE_LEVEL);
 
        qdio_dbf_trace=debug_register(QDIO_DBF_TRACE_NAME,
-                                     QDIO_DBF_TRACE_INDEX,
+                                     QDIO_DBF_TRACE_PAGES,
                                      QDIO_DBF_TRACE_NR_AREAS,
                                      QDIO_DBF_TRACE_LEN);
        if (!qdio_dbf_trace)
@@ -3382,7 +3382,7 @@ qdio_register_dbf_views(void)
 
 #ifdef CONFIG_QDIO_DEBUG
         qdio_dbf_slsb_out=debug_register(QDIO_DBF_SLSB_OUT_NAME,
-                                         QDIO_DBF_SLSB_OUT_INDEX,
+                                         QDIO_DBF_SLSB_OUT_PAGES,
                                          QDIO_DBF_SLSB_OUT_NR_AREAS,
                                          QDIO_DBF_SLSB_OUT_LEN);
         if (!qdio_dbf_slsb_out)
@@ -3391,7 +3391,7 @@ qdio_register_dbf_views(void)
         debug_set_level(qdio_dbf_slsb_out,QDIO_DBF_SLSB_OUT_LEVEL);
 
         qdio_dbf_slsb_in=debug_register(QDIO_DBF_SLSB_IN_NAME,
-                                        QDIO_DBF_SLSB_IN_INDEX,
+                                        QDIO_DBF_SLSB_IN_PAGES,
                                         QDIO_DBF_SLSB_IN_NR_AREAS,
                                         QDIO_DBF_SLSB_IN_LEN);
         if (!qdio_dbf_slsb_in)
index b6daadac4e8b65a0091e3134c33e0029bceba065..6b8aa6a852bedb5230a9964edefca539da3c688a 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <asm/page.h>
 
-#define VERSION_CIO_QDIO_H "$Revision: 1.32 $"
+#define VERSION_CIO_QDIO_H "$Revision: 1.33 $"
 
 #ifdef CONFIG_QDIO_DEBUG
 #define QDIO_VERBOSE_LEVEL 9
@@ -132,7 +132,7 @@ enum qdio_irq_states {
 
 #define QDIO_DBF_SETUP_NAME "qdio_setup"
 #define QDIO_DBF_SETUP_LEN 8
-#define QDIO_DBF_SETUP_INDEX 2
+#define QDIO_DBF_SETUP_PAGES 4
 #define QDIO_DBF_SETUP_NR_AREAS 1
 #ifdef CONFIG_QDIO_DEBUG
 #define QDIO_DBF_SETUP_LEVEL 6
@@ -142,7 +142,7 @@ enum qdio_irq_states {
 
 #define QDIO_DBF_SBAL_NAME "qdio_labs" /* sbal */
 #define QDIO_DBF_SBAL_LEN 256
-#define QDIO_DBF_SBAL_INDEX 2
+#define QDIO_DBF_SBAL_PAGES 4
 #define QDIO_DBF_SBAL_NR_AREAS 2
 #ifdef CONFIG_QDIO_DEBUG
 #define QDIO_DBF_SBAL_LEVEL 6
@@ -154,16 +154,16 @@ enum qdio_irq_states {
 #define QDIO_DBF_TRACE_LEN 8
 #define QDIO_DBF_TRACE_NR_AREAS 2
 #ifdef CONFIG_QDIO_DEBUG
-#define QDIO_DBF_TRACE_INDEX 4
+#define QDIO_DBF_TRACE_PAGES 16
 #define QDIO_DBF_TRACE_LEVEL 4 /* -------- could be even more verbose here */
 #else /* CONFIG_QDIO_DEBUG */
-#define QDIO_DBF_TRACE_INDEX 2
+#define QDIO_DBF_TRACE_PAGES 4
 #define QDIO_DBF_TRACE_LEVEL 2
 #endif /* CONFIG_QDIO_DEBUG */
 
 #define QDIO_DBF_SENSE_NAME "qdio_sense"
 #define QDIO_DBF_SENSE_LEN 64
-#define QDIO_DBF_SENSE_INDEX 1
+#define QDIO_DBF_SENSE_PAGES 2
 #define QDIO_DBF_SENSE_NR_AREAS 1
 #ifdef CONFIG_QDIO_DEBUG
 #define QDIO_DBF_SENSE_LEVEL 6
@@ -176,13 +176,13 @@ enum qdio_irq_states {
 
 #define QDIO_DBF_SLSB_OUT_NAME "qdio_slsb_out"
 #define QDIO_DBF_SLSB_OUT_LEN QDIO_MAX_BUFFERS_PER_Q
-#define QDIO_DBF_SLSB_OUT_INDEX 8
+#define QDIO_DBF_SLSB_OUT_PAGES 256
 #define QDIO_DBF_SLSB_OUT_NR_AREAS 1
 #define QDIO_DBF_SLSB_OUT_LEVEL 6
 
 #define QDIO_DBF_SLSB_IN_NAME "qdio_slsb_in"
 #define QDIO_DBF_SLSB_IN_LEN QDIO_MAX_BUFFERS_PER_Q
-#define QDIO_DBF_SLSB_IN_INDEX 8
+#define QDIO_DBF_SLSB_IN_PAGES 256
 #define QDIO_DBF_SLSB_IN_NR_AREAS 1
 #define QDIO_DBF_SLSB_IN_LEVEL 6
 #endif /* CONFIG_QDIO_DEBUG */
index a99927d54ebb5bb1c40efa9ec20b36169a511d4d..60440dbe3a2764168056bf2b48acbaaf4d64cecb 100644 (file)
@@ -146,8 +146,8 @@ claw_unregister_debug_facility(void)
 static int
 claw_register_debug_facility(void)
 {
-       claw_dbf_setup = debug_register("claw_setup", 1, 1, 8);
-       claw_dbf_trace = debug_register("claw_trace", 1, 2, 8);
+       claw_dbf_setup = debug_register("claw_setup", 2, 1, 8);
+       claw_dbf_trace = debug_register("claw_trace", 2, 2, 8);
        if (claw_dbf_setup == NULL || claw_dbf_trace == NULL) {
                printk(KERN_WARNING "Not enough memory for debug facility.\n");
                claw_unregister_debug_facility();
index 2c86bfa11b2f2bb6b2f2eb4ebddc9c8948406fca..0e2a8bb930322ec9d4f6aacc4c8c5924df8a04ad 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * linux/drivers/s390/net/ctcdbug.c ($Revision: 1.4 $)
+ * linux/drivers/s390/net/ctcdbug.c ($Revision: 1.6 $)
  *
  * CTC / ESCON network driver - s390 dbf exploit.
  *
@@ -9,7 +9,7 @@
  *    Author(s): Original Code written by
  *                       Peter Tiedemann (ptiedem@de.ibm.com)
  *
- *    $Revision: 1.4 $  $Date: 2004/08/04 10:11:59 $
+ *    $Revision: 1.6 $  $Date: 2005/05/11 08:10:17 $
  *
  * 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
@@ -51,15 +51,15 @@ int
 ctc_register_dbf_views(void)
 {
        ctc_dbf_setup = debug_register(CTC_DBF_SETUP_NAME,
-                                       CTC_DBF_SETUP_INDEX,
+                                       CTC_DBF_SETUP_PAGES,
                                        CTC_DBF_SETUP_NR_AREAS,
                                        CTC_DBF_SETUP_LEN);
        ctc_dbf_data = debug_register(CTC_DBF_DATA_NAME,
-                                      CTC_DBF_DATA_INDEX,
+                                      CTC_DBF_DATA_PAGES,
                                       CTC_DBF_DATA_NR_AREAS,
                                       CTC_DBF_DATA_LEN);
        ctc_dbf_trace = debug_register(CTC_DBF_TRACE_NAME,
-                                       CTC_DBF_TRACE_INDEX,
+                                       CTC_DBF_TRACE_PAGES,
                                        CTC_DBF_TRACE_NR_AREAS,
                                        CTC_DBF_TRACE_LEN);
 
index 7fe2ebd1792dc6de5cbe1ee4a30af420fd76d8fb..7d6afa1627c3534cc86f1805f9f4da45c92fa47e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.5 $)
+ * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.6 $)
  *
  * CTC / ESCON network driver - s390 dbf exploit.
  *
@@ -9,7 +9,7 @@
  *    Author(s): Original Code written by
  *                       Peter Tiedemann (ptiedem@de.ibm.com)
  *
- *    $Revision: 1.5 $  $Date: 2005/02/27 19:46:44 $
+ *    $Revision: 1.6 $  $Date: 2005/05/11 08:10:17 $
  *
  * 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
  */
 #define CTC_DBF_SETUP_NAME "ctc_setup"
 #define CTC_DBF_SETUP_LEN 16
-#define CTC_DBF_SETUP_INDEX 3
+#define CTC_DBF_SETUP_PAGES 8
 #define CTC_DBF_SETUP_NR_AREAS 1
 #define CTC_DBF_SETUP_LEVEL 3
 
 #define CTC_DBF_DATA_NAME "ctc_data"
 #define CTC_DBF_DATA_LEN 128
-#define CTC_DBF_DATA_INDEX 3
+#define CTC_DBF_DATA_PAGES 8
 #define CTC_DBF_DATA_NR_AREAS 1
 #define CTC_DBF_DATA_LEVEL 3
 
 #define CTC_DBF_TRACE_NAME "ctc_trace"
 #define CTC_DBF_TRACE_LEN 16
-#define CTC_DBF_TRACE_INDEX 2
+#define CTC_DBF_TRACE_PAGES 4
 #define CTC_DBF_TRACE_NR_AREAS 2
 #define CTC_DBF_TRACE_LEVEL 3
 
index 198330217eff86c04af62dd4f7ee66cb04bf667c..0c4644d3d2f35e76a3529284b9a9b0aeceaf7b06 100644 (file)
  */
 #define IUCV_DBF_SETUP_NAME "iucv_setup"
 #define IUCV_DBF_SETUP_LEN 32
-#define IUCV_DBF_SETUP_INDEX 1
+#define IUCV_DBF_SETUP_PAGES 2
 #define IUCV_DBF_SETUP_NR_AREAS 1
 #define IUCV_DBF_SETUP_LEVEL 3
 
 #define IUCV_DBF_DATA_NAME "iucv_data"
 #define IUCV_DBF_DATA_LEN 128
-#define IUCV_DBF_DATA_INDEX 1
+#define IUCV_DBF_DATA_PAGES 2
 #define IUCV_DBF_DATA_NR_AREAS 1
 #define IUCV_DBF_DATA_LEVEL 2
 
 #define IUCV_DBF_TRACE_NAME "iucv_trace"
 #define IUCV_DBF_TRACE_LEN 16
-#define IUCV_DBF_TRACE_INDEX 2
+#define IUCV_DBF_TRACE_PAGES 4
 #define IUCV_DBF_TRACE_NR_AREAS 1
 #define IUCV_DBF_TRACE_LEVEL 3
 
index ab086242d305a490e80f88f518c156d44ba05b01..46f34ba93ac5c76de5a821a38e6d75eb94fafea6 100644 (file)
@@ -11,7 +11,7 @@
  *                       Frank Pavlic (pavlic@de.ibm.com) and
  *                       Martin Schwidefsky <schwidefsky@de.ibm.com>
  *
- *    $Revision: 1.98 $         $Date: 2005/04/18 13:41:29 $
+ *    $Revision: 1.99 $         $Date: 2005/05/11 08:10:17 $
  *
  * 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
@@ -59,7 +59,7 @@
 /**
  * initialization string for output
  */
-#define VERSION_LCS_C  "$Revision: 1.98 $"
+#define VERSION_LCS_C  "$Revision: 1.99 $"
 
 static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
 static char debug_buffer[255];
@@ -93,8 +93,8 @@ lcs_unregister_debug_facility(void)
 static int
 lcs_register_debug_facility(void)
 {
-       lcs_dbf_setup = debug_register("lcs_setup", 1, 1, 8);
-       lcs_dbf_trace = debug_register("lcs_trace", 1, 2, 8);
+       lcs_dbf_setup = debug_register("lcs_setup", 2, 1, 8);
+       lcs_dbf_trace = debug_register("lcs_trace", 2, 2, 8);
        if (lcs_dbf_setup == NULL || lcs_dbf_trace == NULL) {
                PRINT_ERR("Not enough memory for debug facility.\n");
                lcs_unregister_debug_facility();
index 3fd4fb754b2d4736502235012b41d8c54ab7a444..69425a7a6e98a5b71f4fbb6df2826ad61c1bb2a7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: netiucv.c,v 1.63 2004/07/27 13:36:05 mschwide Exp $
+ * $Id: netiucv.c,v 1.66 2005/05/11 08:10:17 holzheu Exp $
  *
  * IUCV network driver
  *
@@ -30,7 +30,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV network driver $Revision: 1.63 $
+ * RELEASE-TAG: IUCV network driver $Revision: 1.66 $
  *
  */
 \f
@@ -391,15 +391,15 @@ static int
 iucv_register_dbf_views(void)
 {
        iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME,
-                                       IUCV_DBF_SETUP_INDEX,
+                                       IUCV_DBF_SETUP_PAGES,
                                        IUCV_DBF_SETUP_NR_AREAS,
                                        IUCV_DBF_SETUP_LEN);
        iucv_dbf_data = debug_register(IUCV_DBF_DATA_NAME,
-                                      IUCV_DBF_DATA_INDEX,
+                                      IUCV_DBF_DATA_PAGES,
                                       IUCV_DBF_DATA_NR_AREAS,
                                       IUCV_DBF_DATA_LEN);
        iucv_dbf_trace = debug_register(IUCV_DBF_TRACE_NAME,
-                                       IUCV_DBF_TRACE_INDEX,
+                                       IUCV_DBF_TRACE_PAGES,
                                        IUCV_DBF_TRACE_NR_AREAS,
                                        IUCV_DBF_TRACE_LEN);
 
@@ -2076,7 +2076,7 @@ DRIVER_ATTR(remove, 0200, NULL, remove_write);
 static void
 netiucv_banner(void)
 {
-       char vbuf[] = "$Revision: 1.63 $";
+       char vbuf[] = "$Revision: 1.66 $";
        char *version = vbuf;
 
        if ((version = strchr(version, ':'))) {
index a755b57db46b359c9cb632919fc71ef7fd9c52fd..008e0a5d2eb38073958aafbe89fffab3c0f77de3 100644 (file)
  */
 #define QETH_DBF_SETUP_NAME "qeth_setup"
 #define QETH_DBF_SETUP_LEN 8
-#define QETH_DBF_SETUP_INDEX 3
+#define QETH_DBF_SETUP_PAGES 8
 #define QETH_DBF_SETUP_NR_AREAS 1
 #define QETH_DBF_SETUP_LEVEL 5
 
 #define QETH_DBF_MISC_NAME "qeth_misc"
 #define QETH_DBF_MISC_LEN 128
-#define QETH_DBF_MISC_INDEX 1
+#define QETH_DBF_MISC_PAGES 2
 #define QETH_DBF_MISC_NR_AREAS 1
 #define QETH_DBF_MISC_LEVEL 2
 
 #define QETH_DBF_DATA_NAME "qeth_data"
 #define QETH_DBF_DATA_LEN 96
-#define QETH_DBF_DATA_INDEX 3
+#define QETH_DBF_DATA_PAGES 8
 #define QETH_DBF_DATA_NR_AREAS 1
 #define QETH_DBF_DATA_LEVEL 2
 
 #define QETH_DBF_CONTROL_NAME "qeth_control"
 #define QETH_DBF_CONTROL_LEN 256
-#define QETH_DBF_CONTROL_INDEX 3
+#define QETH_DBF_CONTROL_PAGES 8
 #define QETH_DBF_CONTROL_NR_AREAS 2
 #define QETH_DBF_CONTROL_LEVEL 5
 
 #define QETH_DBF_TRACE_NAME "qeth_trace"
 #define QETH_DBF_TRACE_LEN 8
-#define QETH_DBF_TRACE_INDEX 2
+#define QETH_DBF_TRACE_PAGES 4
 #define QETH_DBF_TRACE_NR_AREAS 2
 #define QETH_DBF_TRACE_LEVEL 3
 extern debug_info_t *qeth_dbf_trace;
 
 #define QETH_DBF_SENSE_NAME "qeth_sense"
 #define QETH_DBF_SENSE_LEN 64
-#define QETH_DBF_SENSE_INDEX 1
+#define QETH_DBF_SENSE_PAGES 2
 #define QETH_DBF_SENSE_NR_AREAS 1
 #define QETH_DBF_SENSE_LEVEL 2
 
 #define QETH_DBF_QERR_NAME "qeth_qerr"
 #define QETH_DBF_QERR_LEN 8
-#define QETH_DBF_QERR_INDEX 1
+#define QETH_DBF_QERR_PAGES 2
 #define QETH_DBF_QERR_NR_AREAS 2
 #define QETH_DBF_QERR_LEVEL 2
 
index 208127a5033ae707ffdb1168d2c0f7da979cab4d..3cb88c770037fd306490b39e07b06ad38ab1ce09 100644 (file)
@@ -7639,31 +7639,31 @@ static int
 qeth_register_dbf_views(void)
 {
        qeth_dbf_setup = debug_register(QETH_DBF_SETUP_NAME,
-                                       QETH_DBF_SETUP_INDEX,
+                                       QETH_DBF_SETUP_PAGES,
                                        QETH_DBF_SETUP_NR_AREAS,
                                        QETH_DBF_SETUP_LEN);
        qeth_dbf_misc = debug_register(QETH_DBF_MISC_NAME,
-                                      QETH_DBF_MISC_INDEX,
+                                      QETH_DBF_MISC_PAGES,
                                       QETH_DBF_MISC_NR_AREAS,
                                       QETH_DBF_MISC_LEN);
        qeth_dbf_data = debug_register(QETH_DBF_DATA_NAME,
-                                      QETH_DBF_DATA_INDEX,
+                                      QETH_DBF_DATA_PAGES,
                                       QETH_DBF_DATA_NR_AREAS,
                                       QETH_DBF_DATA_LEN);
        qeth_dbf_control = debug_register(QETH_DBF_CONTROL_NAME,
-                                         QETH_DBF_CONTROL_INDEX,
+                                         QETH_DBF_CONTROL_PAGES,
                                          QETH_DBF_CONTROL_NR_AREAS,
                                          QETH_DBF_CONTROL_LEN);
        qeth_dbf_sense = debug_register(QETH_DBF_SENSE_NAME,
-                                       QETH_DBF_SENSE_INDEX,
+                                       QETH_DBF_SENSE_PAGES,
                                        QETH_DBF_SENSE_NR_AREAS,
                                        QETH_DBF_SENSE_LEN);
        qeth_dbf_qerr = debug_register(QETH_DBF_QERR_NAME,
-                                      QETH_DBF_QERR_INDEX,
+                                      QETH_DBF_QERR_PAGES,
                                       QETH_DBF_QERR_NR_AREAS,
                                       QETH_DBF_QERR_LEN);
        qeth_dbf_trace = debug_register(QETH_DBF_TRACE_NAME,
-                                       QETH_DBF_TRACE_INDEX,
+                                       QETH_DBF_TRACE_PAGES,
                                        QETH_DBF_TRACE_NR_AREAS,
                                        QETH_DBF_TRACE_LEN);
 
index 1e3f7f3c662ff53ea09e93d9b14313ba19aed7e8..d6469baa7e16ef1698d7ff9ff27436aca11fc723 100644 (file)
@@ -138,7 +138,7 @@ static void __exit
 smsg_exit(void)
 {
        if (smsg_handle > 0) {
-               cpcmd("SET SMSG OFF", 0, 0);
+               cpcmd("SET SMSG OFF", NULL, 0, NULL);
                iucv_sever(smsg_pathid, 0);
                iucv_unregister_program(smsg_handle);
                driver_unregister(&smsg_driver);
@@ -177,7 +177,7 @@ smsg_init(void)
                smsg_handle = 0;
                return -EIO;
        }
-       cpcmd("SET SMSG IUCV", 0, 0);
+       cpcmd("SET SMSG IUCV", NULL, 0, NULL);
        return 0;
 }
 
index ffa996c8a9082eb1b1e49ed1fd427283e17f255c..5bb255e02acc653f9f93b0ba1e0bcc4392aa83d1 100644 (file)
@@ -31,14 +31,14 @@ extern void css_reiterate_subchannels(void);
 extern struct workqueue_struct *slow_path_wq;
 extern struct work_struct slow_path_work;
 
-static void
+static NORET_TYPE void
 s390_handle_damage(char *msg)
 {
-       printk(KERN_EMERG "%s\n", msg);
 #ifdef CONFIG_SMP
        smp_send_stop();
 #endif
        disabled_wait((unsigned long) __builtin_return_address(0));
+       for(;;);
 }
 
 /*
@@ -122,40 +122,39 @@ repeat:
        return 0;
 }
 
+struct mcck_struct {
+       int kill_task;
+       int channel_report;
+       int warning;
+       unsigned long long mcck_code;
+};
+
+static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck);
+
 /*
- * machine check handler.
+ * Main machine check handler function. Will be called with interrupts enabled
+ * or disabled and machine checks enabled or disabled.
  */
 void
-s390_do_machine_check(void)
+s390_handle_mcck(void)
 {
-       struct mci *mci;
-
-       mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
+       unsigned long flags;
+       struct mcck_struct mcck;
 
-       if (mci->sd)            /* system damage */
-               s390_handle_damage("received system damage machine check\n");
+       /*
+        * Disable machine checks and get the current state of accumulated
+        * machine checks. Afterwards delete the old state and enable machine
+        * checks again.
+        */
+       local_irq_save(flags);
+       local_mcck_disable();
+       mcck = __get_cpu_var(cpu_mcck);
+       memset(&__get_cpu_var(cpu_mcck), 0, sizeof(struct mcck_struct));
+       clear_thread_flag(TIF_MCCK_PENDING);
+       local_mcck_enable();
+       local_irq_restore(flags);
 
-       if (mci->pd)            /* instruction processing damage */
-               s390_handle_damage("received instruction processing "
-                                  "damage machine check\n");
-
-       if (mci->se)            /* storage error uncorrected */
-               s390_handle_damage("received storage error uncorrected "
-                                  "machine check\n");
-
-       if (mci->sc)            /* storage error corrected */
-               printk(KERN_WARNING
-                      "received storage error corrected machine check\n");
-
-       if (mci->ke)            /* storage key-error uncorrected */
-               s390_handle_damage("received storage key-error uncorrected "
-                                  "machine check\n");
-
-       if (mci->ds && mci->fa) /* storage degradation */
-               s390_handle_damage("received storage degradation machine "
-                                  "check\n");
-
-       if (mci->cp)            /* channel report word pending */
+       if (mcck.channel_report)
                up(&m_sem);
 
 #ifdef CONFIG_MACHCHK_WARNING
@@ -168,7 +167,7 @@ s390_do_machine_check(void)
  * On VM we only get one interrupt per virtally presented machinecheck.
  * Though one suffices, we may get one interrupt per (virtual) processor.
  */
-       if (mci->w) {   /* WARNING pending ? */
+       if (mcck.warning) {     /* WARNING pending ? */
                static int mchchk_wng_posted = 0;
                /*
                 * Use single machine clear, as we cannot handle smp right now
@@ -178,6 +177,261 @@ s390_do_machine_check(void)
                        kill_proc(1, SIGPWR, 1);
        }
 #endif
+
+       if (mcck.kill_task) {
+               local_irq_enable();
+               printk(KERN_EMERG "mcck: Terminating task because of machine "
+                      "malfunction (code 0x%016llx).\n", mcck.mcck_code);
+               printk(KERN_EMERG "mcck: task: %s, pid: %d.\n",
+                      current->comm, current->pid);
+               do_exit(SIGSEGV);
+       }
+}
+
+/*
+ * returns 0 if all registers could be validated
+ * returns 1 otherwise
+ */
+static int
+s390_revalidate_registers(struct mci *mci)
+{
+       int kill_task;
+       u64 tmpclock;
+       u64 zero;
+       void *fpt_save_area, *fpt_creg_save_area;
+
+       kill_task = 0;
+       zero = 0;
+       /* General purpose registers */
+       if (!mci->gr)
+               /*
+                * General purpose registers couldn't be restored and have
+                * unknown contents. Process needs to be terminated.
+                */
+               kill_task = 1;
+
+       /* Revalidate floating point registers */
+       if (!mci->fp)
+               /*
+                * Floating point registers can't be restored and
+                * therefore the process needs to be terminated.
+                */
+               kill_task = 1;
+
+#ifndef __s390x__
+       asm volatile("ld 0,0(%0)\n"
+                    "ld 2,8(%0)\n"
+                    "ld 4,16(%0)\n"
+                    "ld 6,24(%0)"
+                    : : "a" (&S390_lowcore.floating_pt_save_area));
+#endif
+
+       if (MACHINE_HAS_IEEE) {
+#ifdef __s390x__
+               fpt_save_area = &S390_lowcore.floating_pt_save_area;
+               fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area;
+#else
+               fpt_save_area = (void *) S390_lowcore.extended_save_area_addr;
+               fpt_creg_save_area = fpt_save_area+128;
+#endif
+               /* Floating point control register */
+               if (!mci->fc) {
+                       /*
+                        * Floating point control register can't be restored.
+                        * Task will be terminated.
+                        */
+                       asm volatile ("lfpc 0(%0)" : : "a" (&zero));
+                       kill_task = 1;
+
+               }
+               else
+                       asm volatile (
+                               "lfpc 0(%0)"
+                               : : "a" (fpt_creg_save_area));
+
+               asm volatile("ld  0,0(%0)\n"
+                            "ld  1,8(%0)\n"
+                            "ld  2,16(%0)\n"
+                            "ld  3,24(%0)\n"
+                            "ld  4,32(%0)\n"
+                            "ld  5,40(%0)\n"
+                            "ld  6,48(%0)\n"
+                            "ld  7,56(%0)\n"
+                            "ld  8,64(%0)\n"
+                            "ld  9,72(%0)\n"
+                            "ld 10,80(%0)\n"
+                            "ld 11,88(%0)\n"
+                            "ld 12,96(%0)\n"
+                            "ld 13,104(%0)\n"
+                            "ld 14,112(%0)\n"
+                            "ld 15,120(%0)\n"
+                            : : "a" (fpt_save_area));
+       }
+
+       /* Revalidate access registers */
+       asm volatile("lam 0,15,0(%0)"
+                    : : "a" (&S390_lowcore.access_regs_save_area));
+       if (!mci->ar)
+               /*
+                * Access registers have unknown contents.
+                * Terminating task.
+                */
+               kill_task = 1;
+
+       /* Revalidate control registers */
+       if (!mci->cr)
+               /*
+                * Control registers have unknown contents.
+                * Can't recover and therefore stopping machine.
+                */
+               s390_handle_damage("invalid control registers.");
+       else
+#ifdef __s390x__
+               asm volatile("lctlg 0,15,0(%0)"
+                            : : "a" (&S390_lowcore.cregs_save_area));
+#else
+               asm volatile("lctl 0,15,0(%0)"
+                            : : "a" (&S390_lowcore.cregs_save_area));
+#endif
+
+       /*
+        * We don't even try to revalidate the TOD register, since we simply
+        * can't write something sensible into that register.
+        */
+
+#ifdef __s390x__
+       /*
+        * See if we can revalidate the TOD programmable register with its
+        * old contents (should be zero) otherwise set it to zero.
+        */
+       if (!mci->pr)
+               asm volatile("sr 0,0\n"
+                            "sckpf"
+                            : : : "0", "cc");
+       else
+               asm volatile(
+                       "l 0,0(%0)\n"
+                       "sckpf"
+                       : : "a" (&S390_lowcore.tod_progreg_save_area) : "0", "cc");
+#endif
+
+       /* Revalidate clock comparator register */
+       asm volatile ("stck 0(%1)\n"
+                     "sckc 0(%1)"
+                     : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory");
+
+       /* Check if old PSW is valid */
+       if (!mci->wp)
+               /*
+                * Can't tell if we come from user or kernel mode
+                * -> stopping machine.
+                */
+               s390_handle_damage("old psw invalid.");
+
+       if (!mci->ms || !mci->pm || !mci->ia)
+               kill_task = 1;
+
+       return kill_task;
+}
+
+/*
+ * machine check handler.
+ */
+void
+s390_do_machine_check(struct pt_regs *regs)
+{
+       struct mci *mci;
+       struct mcck_struct *mcck;
+       int umode;
+
+       mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
+       mcck = &__get_cpu_var(cpu_mcck);
+       umode = user_mode(regs);
+
+       if (mci->sd)
+               /* System damage -> stopping machine */
+               s390_handle_damage("received system damage machine check.");
+
+       if (mci->pd) {
+               if (mci->b) {
+                       /* Processing backup -> verify if we can survive this */
+                       u64 z_mcic, o_mcic, t_mcic;
+#ifdef __s390x__
+                       z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<29);
+                       o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 |
+                                 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 |
+                                 1ULL<<30 | 1ULL<<21 | 1ULL<<20 | 1ULL<<17 |
+                                 1ULL<<16);
+#else
+                       z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<57 | 1ULL<<50 |
+                                 1ULL<<29);
+                       o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 |
+                                 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 |
+                                 1ULL<<30 | 1ULL<<20 | 1ULL<<17 | 1ULL<<16);
+#endif
+                       t_mcic = *(u64 *)mci;
+
+                       if (((t_mcic & z_mcic) != 0) ||
+                           ((t_mcic & o_mcic) != o_mcic)) {
+                               s390_handle_damage("processing backup machine "
+                                                  "check with damage.");
+                       }
+                       if (!umode)
+                               s390_handle_damage("processing backup machine "
+                                                  "check in kernel mode.");
+                       mcck->kill_task = 1;
+                       mcck->mcck_code = *(unsigned long long *) mci;
+               }
+               else {
+                       /* Processing damage -> stopping machine */
+                       s390_handle_damage("received instruction processing "
+                                          "damage machine check.");
+               }
+       }
+       if (s390_revalidate_registers(mci)) {
+               if (umode) {
+                       /*
+                        * Couldn't restore all register contents while in
+                        * user mode -> mark task for termination.
+                        */
+                       mcck->kill_task = 1;
+                       mcck->mcck_code = *(unsigned long long *) mci;
+                       set_thread_flag(TIF_MCCK_PENDING);
+               }
+               else
+                       /*
+                        * Couldn't restore all register contents while in
+                        * kernel mode -> stopping machine.
+                        */
+                       s390_handle_damage("unable to revalidate registers.");
+       }
+
+       if (mci->se)
+               /* Storage error uncorrected */
+               s390_handle_damage("received storage error uncorrected "
+                                  "machine check.");
+
+       if (mci->ke)
+               /* Storage key-error uncorrected */
+               s390_handle_damage("received storage key-error uncorrected "
+                                  "machine check.");
+
+       if (mci->ds && mci->fa)
+               /* Storage degradation */
+               s390_handle_damage("received storage degradation machine "
+                                  "check.");
+
+       if (mci->cp) {
+               /* Channel report word pending */
+               mcck->channel_report = 1;
+               set_thread_flag(TIF_MCCK_PENDING);
+       }
+
+       if (mci->w) {
+               /* Warning pending */
+               mcck->warning = 1;
+               set_thread_flag(TIF_MCCK_PENDING);
+       }
 }
 
 /*
@@ -189,9 +443,8 @@ static int
 machine_check_init(void)
 {
        init_MUTEX_LOCKED(&m_sem);
-       ctl_clear_bit(14, 25);  /* disable damage MCH */
-       ctl_set_bit(14, 26);    /* enable degradation MCH */
-       ctl_set_bit(14, 27);    /* enable system recovery MCH */
+       ctl_clear_bit(14, 25);  /* disable external damage MCH */
+       ctl_set_bit(14, 27);    /* enable system recovery MCH */
 #ifdef CONFIG_MACHCHK_WARNING
        ctl_set_bit(14, 24);    /* enable warning MCH */
 #endif
index 7e26f0f1b0dcbd2f79d45d954be44953f29507b4..4eaa70179182a62e9b28ef8d4a356f3b3e09096b 100644 (file)
@@ -16,20 +16,45 @@ struct mci {
        __u32   sd              :  1; /* 00 system damage */
        __u32   pd              :  1; /* 01 instruction-processing damage */
        __u32   sr              :  1; /* 02 system recovery */
-       __u32   to_be_defined_1 :  4; /* 03-06 */
+       __u32   to_be_defined_1 :  1; /* 03 */
+       __u32   cd              :  1; /* 04 timing-facility damage */
+       __u32   ed              :  1; /* 05 external damage */
+       __u32   to_be_defined_2 :  1; /* 06 */
        __u32   dg              :  1; /* 07 degradation */
        __u32   w               :  1; /* 08 warning pending */
        __u32   cp              :  1; /* 09 channel-report pending */
-       __u32   to_be_defined_2 :  6; /* 10-15 */
+       __u32   sp              :  1; /* 10 service-processor damage */
+       __u32   ck              :  1; /* 11 channel-subsystem damage */
+       __u32   to_be_defined_3 :  2; /* 12-13 */
+       __u32   b               :  1; /* 14 backed up */
+       __u32   to_be_defined_4 :  1; /* 15 */
        __u32   se              :  1; /* 16 storage error uncorrected */
        __u32   sc              :  1; /* 17 storage error corrected */
        __u32   ke              :  1; /* 18 storage-key error uncorrected */
        __u32   ds              :  1; /* 19 storage degradation */
-       __u32   to_be_defined_3 :  4; /* 20-23 */
+       __u32   wp              :  1; /* 20 psw mwp validity */
+       __u32   ms              :  1; /* 21 psw mask and key validity */
+       __u32   pm              :  1; /* 22 psw program mask and cc validity */
+       __u32   ia              :  1; /* 23 psw instruction address validity */
        __u32   fa              :  1; /* 24 failing storage address validity */
-       __u32   to_be_defined_4 :  7; /* 25-31 */
+       __u32   to_be_defined_5 :  1; /* 25 */
+       __u32   ec              :  1; /* 26 external damage code validity */
+       __u32   fp              :  1; /* 27 floating point register validity */
+       __u32   gr              :  1; /* 28 general register validity */
+       __u32   cr              :  1; /* 29 control register validity */
+       __u32   to_be_defined_6 :  1; /* 30 */
+       __u32   st              :  1; /* 31 storage logical validity */
        __u32   ie              :  1; /* 32 indirect storage error */
-       __u32   to_be_defined_5 : 31; /* 33-63 */
+       __u32   ar              :  1; /* 33 access register validity */
+       __u32   da              :  1; /* 34 delayed access exception */
+       __u32   to_be_defined_7 :  7; /* 35-41 */
+       __u32   pr              :  1; /* 42 tod programmable register validity */
+       __u32   fc              :  1; /* 43 fp control register validity */
+       __u32   ap              :  1; /* 44 ancillary report */
+       __u32   to_be_defined_8 :  1; /* 45 */
+       __u32   ct              :  1; /* 46 cpu timer validity */
+       __u32   cc              :  1; /* 47 clock comparator validity */
+       __u32   to_be_defined_9 : 16; /* 47-63 */
 };
 
 /*
index 34dbc37a79d4991f8b40d9e61ad01c32b07000a9..bc6e4627c7a1e450b097b9a117e01e03e667f293 100644 (file)
@@ -1916,9 +1916,9 @@ static void __twa_shutdown(TW_Device_Extension *tw_dev)
 } /* End __twa_shutdown() */
 
 /* Wrapper for __twa_shutdown */
-static void twa_shutdown(struct device *dev)
+static void twa_shutdown(struct pci_dev *pdev)
 {
-       struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+       struct Scsi_Host *host = pci_get_drvdata(pdev);
        TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
 
        __twa_shutdown(tw_dev);
@@ -2140,9 +2140,7 @@ static struct pci_driver twa_driver = {
        .id_table       = twa_pci_tbl,
        .probe          = twa_probe,
        .remove         = twa_remove,
-       .driver         = {
-               .shutdown = twa_shutdown
-       }
+       .shutdown       = twa_shutdown
 };
 
 /* This function is called on driver initialization */
index b6dc576da4306f28f861ffe853bb536444410627..973c51fb0fe22b45aeda77a98fc4800224797697 100644 (file)
@@ -2264,9 +2264,9 @@ static void __tw_shutdown(TW_Device_Extension *tw_dev)
 } /* End __tw_shutdown() */
 
 /* Wrapper for __tw_shutdown */
-static void tw_shutdown(struct device *dev)
+static void tw_shutdown(struct pci_dev *pdev)
 {
-       struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+       struct Scsi_Host *host = pci_get_drvdata(pdev);
        TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
 
        __tw_shutdown(tw_dev);
@@ -2451,9 +2451,7 @@ static struct pci_driver tw_driver = {
        .id_table       = tw_pci_tbl,
        .probe          = tw_probe,
        .remove         = tw_remove,
-       .driver         = {
-               .shutdown = tw_shutdown
-       }
+       .shutdown       = tw_shutdown,
 };
 
 /* This function is called on driver initialization */
index 9a547ca9c8648fe2c0fb7daa345f156a11f843fd..c5623694d10f56a25ddc1c6f6073deaa3f250232 100644 (file)
@@ -304,26 +304,19 @@ static int ahci_port_start(struct ata_port *ap)
        struct device *dev = ap->host_set->dev;
        struct ahci_host_priv *hpriv = ap->host_set->private_data;
        struct ahci_port_priv *pp;
-       int rc;
        void *mem, *mmio = ap->host_set->mmio_base;
        void *port_mmio = ahci_port_base(mmio, ap->port_no);
        dma_addr_t mem_dma;
 
-       rc = ata_port_start(ap);
-       if (rc)
-               return rc;
-
        pp = kmalloc(sizeof(*pp), GFP_KERNEL);
-       if (!pp) {
-               rc = -ENOMEM;
-               goto err_out;
-       }
+       if (!pp)
+               return -ENOMEM;
        memset(pp, 0, sizeof(*pp));
 
        mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
        if (!mem) {
-               rc = -ENOMEM;
-               goto err_out_kfree;
+               kfree(pp);
+               return -ENOMEM;
        }
        memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
 
@@ -373,12 +366,6 @@ static int ahci_port_start(struct ata_port *ap)
        readl(port_mmio + PORT_CMD); /* flush */
 
        return 0;
-
-err_out_kfree:
-       kfree(pp);
-err_out:
-       ata_port_stop(ap);
-       return rc;
 }
 
 
@@ -404,7 +391,6 @@ static void ahci_port_stop(struct ata_port *ap)
        dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
                          pp->cmd_slot, pp->cmd_slot_dma);
        kfree(pp);
-       ata_port_stop(ap);
 }
 
 static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
index a699c30b26627937850989f928b41fa0938db391..bbe346bd3cb8f476e8f012abd7e5e6f7a3e2f41f 100644 (file)
@@ -34,7 +34,6 @@
 
 #define ADDR32 (0)
 
-#include <linux/version.h>
 #include <linux/module.h>
 
 MODULE_AUTHOR("Deanna Bonds, with _lots_ of help from Mark Salyzyn");
@@ -1811,9 +1810,9 @@ static int adpt_system_info(void __user *buffer)
        memset(&si, 0, sizeof(si));
 
        si.osType = OS_LINUX;
-       si.osMajorVersion = (u8) (LINUX_VERSION_CODE >> 16);
-       si.osMinorVersion = (u8) (LINUX_VERSION_CODE >> 8 & 0x0ff);
-       si.osRevision =     (u8) (LINUX_VERSION_CODE & 0x0ff);
+       si.osMajorVersion = 0;
+       si.osMinorVersion = 0;
+       si.osRevision = 0;
        si.busType = SI_PCI_BUS;
        si.processorFamily = DPTI_sig.dsProcessorFamily;
 
index 9821783c0164f051bb619cd6b70b8ecb4948f5ff..489194af43d03229c5f15efe42e4a272fc684f16 100644 (file)
 #ifndef _DPT_H
 #define _DPT_H
 
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,00)
-#define MAX_TO_IOP_MESSAGES   (210)
-#else
 #define MAX_TO_IOP_MESSAGES   (255)
-#endif
 #define MAX_FROM_IOP_MESSAGES (255)
 
 
@@ -321,10 +313,6 @@ static int adpt_close(struct inode *inode, struct file *file);
 static void adpt_delay(int millisec);
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-static struct pci_dev* adpt_pci_find_device(uint vendor, struct pci_dev* from);
-#endif
-
 #if defined __ia64__ 
 static void adpt_ia64_info(sysInfo_S* si);
 #endif
index ba347576d99b0cae8d88b3ecb6f935632d009c3d..d7a38b6713f958b1c4023544b3de1869b5a22bcf 100644 (file)
@@ -56,7 +56,7 @@ static struct class shost_class = {
  * @shost:     pointer to struct Scsi_Host
  * recovery:   recovery requested to run.
  **/
-void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
+static void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
 {
        struct scsi_device *sdev;
 
index f7ddc9f1ba41d19628c22c1e5d01627c93adf097..2094d4811d61c859f2dd3399ee01b7710c89909f 100644 (file)
@@ -223,7 +223,7 @@ static void tul_select_atn(HCS * pCurHcb, SCB * pCurScb);
 static void tul_select_atn3(HCS * pCurHcb, SCB * pCurScb);
 static void tul_select_atn_stop(HCS * pCurHcb, SCB * pCurScb);
 static int int_tul_busfree(HCS * pCurHcb);
-int int_tul_scsi_rst(HCS * pCurHcb);
+static int int_tul_scsi_rst(HCS * pCurHcb);
 static int int_tul_bad_seq(HCS * pCurHcb);
 static int int_tul_resel(HCS * pCurHcb);
 static int tul_sync_done(HCS * pCurHcb);
@@ -240,9 +240,8 @@ static int tul_se2_rd_all(WORD CurBase);
 static void tul_se2_update_all(WORD CurBase);  /* setup default pattern */
 static void tul_read_eeprom(WORD CurBase);
 
-                               /* ---- EXTERNAL VARIABLES ---- */
-HCS tul_hcs[MAX_SUPPORTED_ADAPTERS];
                                /* ---- INTERNAL VARIABLES ---- */
+static HCS tul_hcs[MAX_SUPPORTED_ADAPTERS];
 static INI_ADPT_STRUCT i91u_adpt[MAX_SUPPORTED_ADAPTERS];
 
 /*NVRAM nvram, *nvramp = &nvram; */
@@ -381,7 +380,7 @@ void tul_se2_wait(void)
 
 
 ******************************************************************/
-void tul_se2_instr(WORD CurBase, UCHAR instr)
+static void tul_se2_instr(WORD CurBase, UCHAR instr)
 {
        int i;
        UCHAR b;
@@ -437,7 +436,7 @@ void tul_se2_ew_ds(WORD CurBase)
        Input  :address of Serial E2PROM
        Output :value stored in  Serial E2PROM
 *******************************************************************/
-USHORT tul_se2_rd(WORD CurBase, ULONG adr)
+static USHORT tul_se2_rd(WORD CurBase, ULONG adr)
 {
        UCHAR instr, readByte;
        USHORT readWord;
@@ -468,7 +467,7 @@ USHORT tul_se2_rd(WORD CurBase, ULONG adr)
 /******************************************************************
  Input: new value in  Serial E2PROM, address of Serial E2PROM
 *******************************************************************/
-void tul_se2_wr(WORD CurBase, UCHAR adr, USHORT writeWord)
+static void tul_se2_wr(WORD CurBase, UCHAR adr, USHORT writeWord)
 {
        UCHAR readByte;
        UCHAR instr;
@@ -584,8 +583,8 @@ void tul_read_eeprom(WORD CurBase)
        TUL_WR(CurBase + TUL_GCTRL, gctrl & ~TUL_GCTRL_EEPROM_BIT);
 }                              /* read_eeprom */
 
-int Addi91u_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
-                              BYTE bBus, BYTE bDevice)
+static int Addi91u_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
+                                     BYTE bBus, BYTE bDevice)
 {
        int i, j;
 
@@ -616,7 +615,7 @@ int Addi91u_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
        return 1;
 }
 
-void init_i91uAdapter_table(void)
+static void init_i91uAdapter_table(void)
 {
        int i;
 
@@ -630,7 +629,7 @@ void init_i91uAdapter_table(void)
        return;
 }
 
-void tul_stop_bm(HCS * pCurHcb)
+static void tul_stop_bm(HCS * pCurHcb)
 {
 
        if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {   /* if DMA xfer is pending, abort DMA xfer */
@@ -642,7 +641,7 @@ void tul_stop_bm(HCS * pCurHcb)
 }
 
 /***************************************************************************/
-void get_tulipPCIConfig(HCS * pCurHcb, int ch_idx)
+static void get_tulipPCIConfig(HCS * pCurHcb, int ch_idx)
 {
        pCurHcb->HCS_Base = i91u_adpt[ch_idx].ADPT_BASE;        /* Supply base address  */
        pCurHcb->HCS_BIOS = i91u_adpt[ch_idx].ADPT_BIOS;        /* Supply BIOS address  */
@@ -651,7 +650,7 @@ void get_tulipPCIConfig(HCS * pCurHcb, int ch_idx)
 }
 
 /***************************************************************************/
-int tul_reset_scsi(HCS * pCurHcb, int seconds)
+static int tul_reset_scsi(HCS * pCurHcb, int seconds)
 {
        TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_BUS);
 
@@ -670,7 +669,8 @@ int tul_reset_scsi(HCS * pCurHcb, int seconds)
 }
 
 /***************************************************************************/
-int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb, BYTE * pbBiosAdr, int seconds)
+static int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb,
+                     BYTE * pbBiosAdr, int seconds)
 {
        int i;
        BYTE *pwFlags;
@@ -788,7 +788,7 @@ int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb, BYTE * pbBiosAdr, int
 }
 
 /***************************************************************************/
-SCB *tul_alloc_scb(HCS * hcsp)
+static SCB *tul_alloc_scb(HCS * hcsp)
 {
        SCB *pTmpScb;
        ULONG flags;
@@ -807,7 +807,7 @@ SCB *tul_alloc_scb(HCS * hcsp)
 }
 
 /***************************************************************************/
-void tul_release_scb(HCS * hcsp, SCB * scbp)
+static void tul_release_scb(HCS * hcsp, SCB * scbp)
 {
        ULONG flags;
 
@@ -829,7 +829,7 @@ void tul_release_scb(HCS * hcsp, SCB * scbp)
 }
 
 /***************************************************************************/
-void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp)
+static void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp)
 {
 
 #if DEBUG_QUEUE
@@ -847,7 +847,7 @@ void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp)
 }
 
 /***************************************************************************/
-void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp)
+static void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp)
 {
 
 #if DEBUG_QUEUE
@@ -863,7 +863,7 @@ void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp)
 }
 
 /***************************************************************************/
-SCB *tul_find_first_pend_scb(HCS * pCurHcb)
+static SCB *tul_find_first_pend_scb(HCS * pCurHcb)
 {
        SCB *pFirstPend;
 
@@ -894,24 +894,7 @@ SCB *tul_find_first_pend_scb(HCS * pCurHcb)
        return (pFirstPend);
 }
 /***************************************************************************/
-SCB *tul_pop_pend_scb(HCS * pCurHcb)
-{
-       SCB *pTmpScb;
-
-       if ((pTmpScb = pCurHcb->HCS_FirstPend) != NULL) {
-               if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
-                       pCurHcb->HCS_LastPend = NULL;
-               pTmpScb->SCB_NxtScb = NULL;
-       }
-#if DEBUG_QUEUE
-       printk("Pop pend SCB %lx; ", (ULONG) pTmpScb);
-#endif
-       return (pTmpScb);
-}
-
-
-/***************************************************************************/
-void tul_unlink_pend_scb(HCS * pCurHcb, SCB * pCurScb)
+static void tul_unlink_pend_scb(HCS * pCurHcb, SCB * pCurScb)
 {
        SCB *pTmpScb, *pPrevScb;
 
@@ -939,7 +922,7 @@ void tul_unlink_pend_scb(HCS * pCurHcb, SCB * pCurScb)
        return;
 }
 /***************************************************************************/
-void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp)
+static void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp)
 {
 
 #if DEBUG_QUEUE
@@ -961,7 +944,7 @@ void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp)
 }
 
 /***************************************************************************/
-SCB *tul_pop_busy_scb(HCS * pCurHcb)
+static SCB *tul_pop_busy_scb(HCS * pCurHcb)
 {
        SCB *pTmpScb;
 
@@ -982,7 +965,7 @@ SCB *tul_pop_busy_scb(HCS * pCurHcb)
 }
 
 /***************************************************************************/
-void tul_unlink_busy_scb(HCS * pCurHcb, SCB * pCurScb)
+static void tul_unlink_busy_scb(HCS * pCurHcb, SCB * pCurScb)
 {
        SCB *pTmpScb, *pPrevScb;
 
@@ -1037,7 +1020,7 @@ SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun)
 }
 
 /***************************************************************************/
-void tul_append_done_scb(HCS * pCurHcb, SCB * scbp)
+static void tul_append_done_scb(HCS * pCurHcb, SCB * scbp)
 {
 
 #if DEBUG_QUEUE
@@ -1073,7 +1056,7 @@ SCB *tul_find_done_scb(HCS * pCurHcb)
 }
 
 /***************************************************************************/
-int tul_abort_srb(HCS * pCurHcb, struct scsi_cmnd *srbp)
+static int tul_abort_srb(HCS * pCurHcb, struct scsi_cmnd *srbp)
 {
        ULONG flags;
        SCB *pTmpScb, *pPrevScb;
@@ -1163,7 +1146,7 @@ int tul_abort_srb(HCS * pCurHcb, struct scsi_cmnd *srbp)
 }
 
 /***************************************************************************/
-int tul_bad_seq(HCS * pCurHcb)
+static int tul_bad_seq(HCS * pCurHcb)
 {
        SCB *pCurScb;
 
@@ -1182,9 +1165,11 @@ int tul_bad_seq(HCS * pCurHcb)
        return (tul_post_scsi_rst(pCurHcb));
 }
 
+#if 0
+
 /************************************************************************/
-int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb,
-               unsigned int target, unsigned int ResetFlags)
+static int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb,
+                           unsigned int target, unsigned int ResetFlags)
 {
        ULONG flags;
        SCB *pScb;
@@ -1255,7 +1240,7 @@ int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb,
        return SCSI_RESET_PENDING;
 }
 
-int tul_reset_scsi_bus(HCS * pCurHcb)
+static int tul_reset_scsi_bus(HCS * pCurHcb)
 {
        ULONG flags;
 
@@ -1284,8 +1269,10 @@ int tul_reset_scsi_bus(HCS * pCurHcb)
        return (SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET);
 }
 
+#endif  /*  0  */
+
 /************************************************************************/
-void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb)
+static void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb)
 {
        ULONG flags;
 
@@ -1318,7 +1305,7 @@ void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb)
 }
 
 /***************************************************************************/
-int tul_isr(HCS * pCurHcb)
+static int tul_isr(HCS * pCurHcb)
 {
        /* Enter critical section       */
 
@@ -2108,7 +2095,7 @@ int int_tul_busfree(HCS * pCurHcb)
 
 /***************************************************************************/
 /* scsi bus reset */
-int int_tul_scsi_rst(HCS * pCurHcb)
+static int int_tul_scsi_rst(HCS * pCurHcb)
 {
        SCB *pCurScb;
        int i;
@@ -2214,7 +2201,7 @@ int int_tul_resel(HCS * pCurHcb)
 
 
 /***************************************************************************/
-int int_tul_bad_seq(HCS * pCurHcb)
+static int int_tul_bad_seq(HCS * pCurHcb)
 {                              /* target wrong phase           */
        SCB *pCurScb;
        int i;
index df3ed7c1cee364c0645cd2dbaaf263662c67315d..3efb1184fc39ea66230eea7bd5c08530dc31f9d2 100644 (file)
@@ -719,21 +719,3 @@ typedef struct _HCSinfo {
 #define SCSI_RESET_HOST_RESET 0x200
 #define SCSI_RESET_ACTION   0xff
 
-extern void init_i91uAdapter_table(void);
-extern int Addi91u_into_Adapter_table(WORD, WORD, BYTE, BYTE, BYTE);
-extern int tul_ReturnNumberOfAdapters(void);
-extern void get_tulipPCIConfig(HCS * pHCB, int iChannel_index);
-extern int init_tulip(HCS * pHCB, SCB * pSCB, int tul_num_scb, BYTE * pbBiosAdr, int reset_time);
-extern SCB *tul_alloc_scb(HCS * pHCB);
-extern int tul_abort_srb(HCS * pHCB, struct scsi_cmnd * pSRB);
-extern void tul_exec_scb(HCS * pHCB, SCB * pSCB);
-extern void tul_release_scb(HCS * pHCB, SCB * pSCB);
-extern void tul_stop_bm(HCS * pHCB);
-extern int tul_reset_scsi(HCS * pCurHcb, int seconds);
-extern int tul_isr(HCS * pHCB);
-extern int tul_reset(HCS * pHCB, struct scsi_cmnd * pSRB, unsigned char target);
-extern int tul_reset_scsi_bus(HCS * pCurHcb);
-extern int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb,
-               unsigned int target, unsigned int ResetFlags);
-                               /* ---- EXTERNAL VARIABLES ---- */
-extern HCS tul_hcs[];
index 80d022625c82e25ccb8eb06f905631746e3d7113..babd48363402b6e1031f0f516ceec0d034766757 100644 (file)
@@ -6012,7 +6012,7 @@ static int __devinit ipr_probe(struct pci_dev *pdev,
 
 /**
  * ipr_shutdown - Shutdown handler.
- * @dev:       device struct
+ * @pdev:      pci device struct
  *
  * This function is invoked upon system shutdown/reboot. It will issue
  * an adapter shutdown to the adapter to flush the write cache.
@@ -6020,9 +6020,9 @@ static int __devinit ipr_probe(struct pci_dev *pdev,
  * Return value:
  *     none
  **/
-static void ipr_shutdown(struct device *dev)
+static void ipr_shutdown(struct pci_dev *pdev)
 {
-       struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(to_pci_dev(dev));
+       struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
        unsigned long lock_flags = 0;
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@@ -6068,9 +6068,7 @@ static struct pci_driver ipr_driver = {
        .id_table = ipr_pci_table,
        .probe = ipr_probe,
        .remove = ipr_remove,
-       .driver = {
-               .shutdown = ipr_shutdown,
-       },
+       .shutdown = ipr_shutdown,
 };
 
 /**
index 36b401fee1f184d0ba6edcebd48a21e463bab89f..cb535fa185b93453ca535bf8a28fe2366a904a06 100644 (file)
@@ -1408,7 +1408,9 @@ void __sata_phy_reset(struct ata_port *ap)
        if (ap->flags & ATA_FLAG_SATA_RESET) {
                /* issue phy wake/reset */
                scr_write_flush(ap, SCR_CONTROL, 0x301);
-               udelay(400);                    /* FIXME: a guess */
+               /* Couldn't find anything in SATA I/II specs, but
+                * AHCI-1.1 10.4.2 says at least 1 ms. */
+               mdelay(1);
        }
        scr_write_flush(ap, SCR_CONTROL, 0x300); /* phy wake/clear reset */
 
@@ -1920,6 +1922,7 @@ static const char * ata_dma_blacklist [] = {
        "HITACHI CDR-8335",
        "HITACHI CDR-8435",
        "Toshiba CD-ROM XM-6202B",
+       "TOSHIBA CD-ROM XM-1702BC",
        "CD-532E-A",
        "E-IDE CD-ROM CR-840",
        "CD-ROM Drive/F5A",
@@ -1927,7 +1930,6 @@ static const char * ata_dma_blacklist [] = {
        "SAMSUNG CD-ROM SC-148C",
        "SAMSUNG CD-ROM SC",
        "SanDisk SDP3B-64",
-       "SAMSUNG CD-ROM SN-124",
        "ATAPI CD-ROM DRIVE 40X MAXIMUM",
        "_NEC DV5800A",
 };
index 7a4adc4c8f09d6ef9cdb7460f4e6846d0def4647..794fb559efb080aa9986df125cd3730ff48ee5ae 100644 (file)
@@ -1176,8 +1176,12 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
                n_sectors = ata_id_u32(args->id, 60);
        n_sectors--;            /* ATA TotalUserSectors - 1 */
 
-       tmp = n_sectors;        /* note: truncates, if lba48 */
        if (args->cmd->cmnd[0] == READ_CAPACITY) {
+               if( n_sectors >= 0xffffffffULL )
+                       tmp = 0xffffffff ;  /* Return max count on overflow */
+               else
+                       tmp = n_sectors ;
+
                /* sector count, 32-bit */
                rbuf[0] = tmp >> (8 * 3);
                rbuf[1] = tmp >> (8 * 2);
@@ -1191,10 +1195,12 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
 
        } else {
                /* sector count, 64-bit */
-               rbuf[2] = n_sectors >> (8 * 7);
-               rbuf[3] = n_sectors >> (8 * 6);
-               rbuf[4] = n_sectors >> (8 * 5);
-               rbuf[5] = n_sectors >> (8 * 4);
+               tmp = n_sectors >> (8 * 4);
+               rbuf[2] = tmp >> (8 * 3);
+               rbuf[3] = tmp >> (8 * 2);
+               rbuf[4] = tmp >> (8 * 1);
+               rbuf[5] = tmp;
+               tmp = n_sectors;
                rbuf[6] = tmp >> (8 * 3);
                rbuf[7] = tmp >> (8 * 2);
                rbuf[8] = tmp >> (8 * 1);
index ec81532eb8455b5af006f0d34f25f685e1f2b698..a70cdf31311cc8b7841952ccb8138935eb228e75 100644 (file)
@@ -5036,9 +5036,9 @@ megaraid_remove_one(struct pci_dev *pdev)
 }
 
 static void
-megaraid_shutdown(struct device *dev)
+megaraid_shutdown(struct pci_dev *pdev)
 {
-       struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+       struct Scsi_Host *host = pci_get_drvdata(pdev);
        adapter_t *adapter = (adapter_t *)host->hostdata;
 
        __megaraid_shutdown(adapter);
@@ -5070,9 +5070,7 @@ static struct pci_driver megaraid_pci_driver = {
        .id_table       = megaraid_pci_tbl,
        .probe          = megaraid_probe_one,
        .remove         = __devexit_p(megaraid_remove_one),
-       .driver         = {
-               .shutdown = megaraid_shutdown,
-       },
+       .shutdown       = megaraid_shutdown,
 };
 
 static int __init megaraid_init(void)
index e60b4c0a842753ca79d4dbf328ae96191cfff2b6..f1f6bf596dc9f9206521d0b8855863c598ee489f 100644 (file)
@@ -318,6 +318,16 @@ static int aha152x_event(event_t event, int priority,
     return 0;
 }
 
+static struct pcmcia_device_id aha152x_ids[] = {
+       PCMCIA_DEVICE_PROD_ID123("New Media", "SCSI", "Bus Toaster", 0xcdf7e4cc, 0x35f26476, 0xa8851d6e),
+       PCMCIA_DEVICE_PROD_ID123("NOTEWORTHY", "SCSI", "Bus Toaster", 0xad89c6e8, 0x35f26476, 0xa8851d6e),
+       PCMCIA_DEVICE_PROD_ID12("Adaptec, Inc.", "APA-1460 SCSI Host Adapter", 0x24ba9738, 0x3a3c3d20),
+       PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Multimedia Sound/SCSI", 0x085a850b, 0x80a6535c),
+       PCMCIA_DEVICE_PROD_ID12("NOTEWORTHY", "NWCOMB02 SCSI/AUDIO COMBO CARD", 0xad89c6e8, 0x5f9a615b),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, aha152x_ids);
+
 static struct pcmcia_driver aha152x_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -325,6 +335,7 @@ static struct pcmcia_driver aha152x_cs_driver = {
        },
        .attach         = aha152x_attach,
        .detach         = aha152x_detach,
+       .id_table       = aha152x_ids,
 };
 
 static int __init init_aha152x_cs(void)
index 3df7bc72e354f8755dbf434a3bfc2817b97b2e66..853e6ee9b71a2e7acec53132ef01cae7ca3f92c0 100644 (file)
@@ -299,6 +299,15 @@ static int fdomain_event(event_t event, int priority,
     return 0;
 } /* fdomain_event */
 
+
+static struct pcmcia_device_id fdomain_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88, 0x859cad20),
+       PCMCIA_DEVICE_PROD_ID1("SCSI PCMCIA Adapter Card", 0x8dacb57e),
+       PCMCIA_DEVICE_PROD_ID12(" SIMPLE TECHNOLOGY Corporation", "SCSI PCMCIA Credit Card Controller", 0x182bdafe, 0xc80d106f),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, fdomain_ids);
+
 static struct pcmcia_driver fdomain_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -306,6 +315,7 @@ static struct pcmcia_driver fdomain_cs_driver = {
        },
        .attach         = fdomain_attach,
        .detach         = fdomain_detach,
+       .id_table       = fdomain_ids,
 };
 
 static int __init init_fdomain_cs(void)
index 3dddb323e7186a1224a6f3d0b8a6715ffeeced45..91b3f28e7a19ddc3dd66942124c7bd5cd2fc786c 100644 (file)
@@ -2125,6 +2125,18 @@ static int nsp_cs_event(event_t                 event,
  *     module entry point
  *====================================================================*/
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
+static struct pcmcia_device_id nsp_cs_ids[] = {
+       PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16       ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
+       PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
+       PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a),
+       PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a),
+       PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a),
+       PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e),
+       PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
+
 static struct pcmcia_driver nsp_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -2132,6 +2144,7 @@ static struct pcmcia_driver nsp_driver = {
        },
        .attach         = nsp_cs_attach,
        .detach         = nsp_cs_detach,
+       .id_table       = nsp_cs_ids,
 };
 #endif
 
index a0175f5d11cd3e2430fada5124a42dc59abd58f6..0dcf41102abf0c685fc313e99b5bbdd2bbd09713 100644 (file)
@@ -395,6 +395,27 @@ static int qlogic_event(event_t event, int priority, event_callback_args_t * arg
        return 0;
 }                              /* qlogic_event */
 
+static struct pcmcia_device_id qlogic_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6),
+       PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751),
+       PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d),
+       PCMCIA_DEVICE_PROD_ID12("MIDORI ELECTRONICS ", "CN-SC43", 0x6534382a, 0xd67eee79),
+       PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J03R", 0x18df0ba0, 0x24662e8a),
+       PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC003", 0x82375a27, 0xf68e5bf7),
+       PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC004", 0x82375a27, 0x68eace54),
+       PCMCIA_DEVICE_PROD_ID12("KME", "KXLC101", 0x3faee676, 0x194250ec),
+       PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05", 0xd77b2930, 0xa85b2735),
+       PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05 rev 1.10", 0xd77b2930, 0x70f8b5f8),
+       PCMCIA_DEVICE_PROD_ID123("KME", "KXLC002", "00", 0x3faee676, 0x81896b61, 0xf99f065f),
+       PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "SCSI2 CARD 37", 0x85c10e17, 0x1a2640c1),
+       PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200A PC CARD SCSI", 0xb4585a1a, 0xa6f06ebe),
+       PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200B PC CARD SCSI-10", 0xb4585a1a, 0x0a88dea0),
+       /* these conflict with other cards! */
+       /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
+       /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, qlogic_ids);
 
 static struct pcmcia_driver qlogic_cs_driver = {
        .owner          = THIS_MODULE,
@@ -403,6 +424,7 @@ static struct pcmcia_driver qlogic_cs_driver = {
        },
        .attach         = qlogic_attach,
        .detach         = qlogic_detach,
+       .id_table       = qlogic_ids,
 };
 
 static int __init init_qlogic_cs(void)
index 1667da9508b4a2d34c667b5bb1d92a30ac3df240..7d4b16b6797dac2562431a73326b5ad8e4d6ac15 100644 (file)
@@ -999,6 +999,14 @@ MODULE_AUTHOR("Bob Tracy <rct@frus.com>");
 MODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver");
 MODULE_LICENSE("GPL");
 
+static struct pcmcia_device_id sym53c500_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("BASICS by New Media Corporation", "SCSI Sym53C500", 0x23c78a9d, 0x0099e7f7),
+       PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "SCSI Bus Toaster Sym53C500", 0x085a850b, 0x45432eb8),
+       PCMCIA_DEVICE_PROD_ID2("SCSI9000", 0x21648f44),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, sym53c500_ids);
+
 static struct pcmcia_driver sym53c500_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -1006,6 +1014,7 @@ static struct pcmcia_driver sym53c500_cs_driver = {
        },
        .attach         = SYM53C500_attach,
        .detach         = SYM53C500_detach,
+       .id_table       = sym53c500_ids,
 };
 
 static int __init
index 5578ae9a9e45f9f60c99f767e878799f58fda13a..1cb5f7d4f2784d0b0730169a9dc047a1f1a284f7 100644 (file)
@@ -68,6 +68,8 @@
 #include "scsi_priv.h"
 #include "scsi_logging.h"
 
+static void scsi_done(struct scsi_cmnd *cmd);
+static int scsi_retry_command(struct scsi_cmnd *cmd);
 
 /*
  * Definitions and constants.
@@ -741,7 +743,7 @@ static DEFINE_PER_CPU(struct list_head, scsi_done_q);
  *
  * This function is interrupt context safe.
  */
-void scsi_done(struct scsi_cmnd *cmd)
+static void scsi_done(struct scsi_cmnd *cmd)
 {
        /*
         * We don't have to worry about this one timing out any more.
@@ -836,7 +838,7 @@ static void scsi_softirq(struct softirq_action *h)
  *              level drivers should not become re-entrant as a result of
  *              this.
  */
-int scsi_retry_command(struct scsi_cmnd *cmd)
+static int scsi_retry_command(struct scsi_cmnd *cmd)
 {
        /*
         * Restore the SCSI command state.
index e0208886b45e3cf509fddb83b9cb328153d6c07b..322b5a41a36ff10046021f4e289eac7ddb630568 100644 (file)
@@ -1783,7 +1783,7 @@ static void __exit scsi_debug_exit(void)
 device_initcall(scsi_debug_init);
 module_exit(scsi_debug_exit);
 
-void pseudo_0_release(struct device * dev)
+static void pseudo_0_release(struct device * dev)
 {
        if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
                printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
index 9f996499fa9d2b44dbdf9431040a47bce15855c5..10506f9cd0c929da622b667c22fcee071c522bd2 100644 (file)
@@ -44,7 +44,7 @@ struct scsi_host_sg_pool {
 #endif
 
 #define SP(x) { x, "sgpool-" #x } 
-struct scsi_host_sg_pool scsi_sg_pools[] = { 
+static struct scsi_host_sg_pool scsi_sg_pools[] = {
        SP(8),
        SP(16),
        SP(32),
@@ -632,7 +632,7 @@ static void scsi_free_sgtable(struct scatterlist *sgl, int index)
 {
        struct scsi_host_sg_pool *sgp;
 
-       BUG_ON(index > SG_MEMPOOL_NR);
+       BUG_ON(index >= SG_MEMPOOL_NR);
 
        sgp = scsi_sg_pools + index;
        mempool_free(sgl, sgp->pool);
index c01580df4476bc1acc70a41bd23434cc067fdf67..96d4f745975c67a366e4887cf170d79910ab0e84 100644 (file)
@@ -61,8 +61,6 @@ extern void scsi_exit_hosts(void);
 extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
 extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
 extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
-extern void scsi_done(struct scsi_cmnd *cmd);
-extern int scsi_retry_command(struct scsi_cmnd *cmd);
 extern int scsi_insert_special_req(struct scsi_request *sreq, int);
 extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd,
                struct scsi_request *sreq);
@@ -136,7 +134,6 @@ extern void scsi_exit_sysctl(void);
 #endif /* CONFIG_SYSCTL */
 
 /* scsi_sysfs.c */
-extern void scsi_device_dev_release(struct device *);
 extern int scsi_sysfs_add_sdev(struct scsi_device *);
 extern int scsi_sysfs_add_host(struct Scsi_Host *);
 extern int scsi_sysfs_register(void);
@@ -145,7 +142,6 @@ extern void scsi_sysfs_device_initialize(struct scsi_device *);
 extern int scsi_sysfs_target_initialize(struct scsi_device *);
 extern struct scsi_transport_template blank_transport_template;
 
-extern struct class sdev_class;
 extern struct bus_type scsi_bus_type;
 
 /* 
index 93b41100a6d8c6055cbbd96fdf88fe08a0f282fc..beed7fbe1cbe5c111622d966482e8c9e511281de 100644 (file)
@@ -150,7 +150,7 @@ static void scsi_device_cls_release(struct class_device *class_dev)
        put_device(&sdev->sdev_gendev);
 }
 
-void scsi_device_dev_release(struct device *dev)
+static void scsi_device_dev_release(struct device *dev)
 {
        struct scsi_device *sdev;
        struct device *parent;
@@ -185,7 +185,7 @@ void scsi_device_dev_release(struct device *dev)
                put_device(parent);
 }
 
-struct class sdev_class = {
+static struct class sdev_class = {
        .name           = "scsi_device",
        .release        = scsi_device_cls_release,
 };
index db92a0ceda79fa4b71444dcea16b0b06a1406ea8..d27fb4c881d24104dc13215598ae8937cb04cc80 100644 (file)
@@ -992,18 +992,17 @@ static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
 /*
  * This routine sends a break character out the serial port.
  */
-static void send_break(        struct m68k_serial * info, int duration)
+static void send_break(struct m68k_serial * info, unsigned int duration)
 {
        m68328_uart *uart = &uart_addr[info->line];
         unsigned long flags;
         if (!info->port)
                 return;
-        set_current_state(TASK_INTERRUPTIBLE);
         save_flags(flags);
         cli();
 #ifdef USE_INTS        
        uart->utx.w |= UTX_SEND_BREAK;
-        schedule_timeout(duration);
+       msleep_interruptible(duration);
        uart->utx.w &= ~UTX_SEND_BREAK;
 #endif         
         restore_flags(flags);
@@ -1033,14 +1032,14 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                                return retval;
                        tty_wait_until_sent(tty, 0);
                        if (!arg)
-                               send_break(info, HZ/4); /* 1/4 second */
+                               send_break(info, 250);  /* 1/4 second */
                        return 0;
                case TCSBRKP:   /* support for POSIX tcsendbreak() */
                        retval = tty_check_change(tty);
                        if (retval)
                                return retval;
                        tty_wait_until_sent(tty, 0);
-                       send_break(info, arg ? arg*(HZ/10) : HZ/4);
+                       send_break(info, arg ? arg*(100) : 250);
                        return 0;
                case TIOCGSOFTCAR:
                        error = put_user(C_CLOCAL(tty) ? 1 : 0,
@@ -1498,23 +1497,6 @@ rs68328_init(void)
        return 0;
 }
 
-
-
-/*
- * register_serial and unregister_serial allows for serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-/* SPARC: Unused at this time, just here to make things link. */
-int register_serial(struct serial_struct *req)
-{
-       return -1;
-}
-
-void unregister_serial(int line)
-{
-       return;
-}
-       
 module_init(rs68328_init);
 
 
index f148022b6b4e739e729fbe52f24bada0acd4646a..b116122e569ab3592b5e3abaa23f24d83c39e9d5 100644 (file)
@@ -1394,14 +1394,13 @@ static void end_break(ser_info_t *info)
 /*
  * This routine sends a break character out the serial port.
  */
-static void send_break(ser_info_t *info, int duration)
+static void send_break(ser_info_t *info, unsigned int duration)
 {
-       set_current_state(TASK_INTERRUPTIBLE);
 #ifdef SERIAL_DEBUG_SEND_BREAK
        printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
 #endif
        begin_break(info);
-       schedule_timeout(duration);
+       msleep_interruptible(duration);
        end_break(info);
 #ifdef SERIAL_DEBUG_SEND_BREAK
        printk("done jiffies=%lu\n", jiffies);
@@ -1436,7 +1435,7 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
                        if (signal_pending(current))
                                return -EINTR;
                        if (!arg) {
-                               send_break(info, HZ/4); /* 1/4 second */
+                               send_break(info, 250);  /* 1/4 second */
                                if (signal_pending(current))
                                        return -EINTR;
                        }
@@ -1448,7 +1447,7 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
                        tty_wait_until_sent(tty, 0);
                        if (signal_pending(current))
                                return -EINTR;
-                       send_break(info, arg ? arg*(HZ/10) : HZ/4);
+                       send_break(info, arg ? arg*100 : 250);
                        if (signal_pending(current))
                                return -EINTR;
                        return 0;
index 79f67fd863ec7941f92c60b14ca8fcb5397088ea..9224fc3184ea35d5296f3d369cc85114440a5c0c 100644 (file)
@@ -77,23 +77,9 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
  */
 #define is_real_interrupt(irq) ((irq) != 0)
 
-/*
- * This converts from our new CONFIG_ symbols to the symbols
- * that asm/serial.h expects.  You _NEED_ to comment out the
- * linux/config.h include contained inside asm/serial.h for
- * this to work.
- */
-#undef CONFIG_SERIAL_MANY_PORTS
-#undef CONFIG_SERIAL_DETECT_IRQ
-#undef CONFIG_SERIAL_MULTIPORT
-#undef CONFIG_HUB6
-
 #ifdef CONFIG_SERIAL_8250_DETECT_IRQ
 #define CONFIG_SERIAL_DETECT_IRQ 1
 #endif
-#ifdef CONFIG_SERIAL_8250_MULTIPORT
-#define CONFIG_SERIAL_MULTIPORT 1
-#endif
 #ifdef CONFIG_SERIAL_8250_MANY_PORTS
 #define CONFIG_SERIAL_MANY_PORTS 1
 #endif
@@ -119,7 +105,7 @@ static struct old_serial_port old_serial_port[] = {
        SERIAL_PORT_DFNS /* defined in asm/serial.h */
 };
 
-#define UART_NR        (ARRAY_SIZE(old_serial_port) + CONFIG_SERIAL_8250_NR_UARTS)
+#define UART_NR        CONFIG_SERIAL_8250_NR_UARTS
 
 #ifdef CONFIG_SERIAL_8250_RSA
 
@@ -1007,21 +993,24 @@ static void autoconfig_irq(struct uart_8250_port *up)
        up->port.irq = (irq > 0) ? irq : 0;
 }
 
+static inline void __stop_tx(struct uart_8250_port *p)
+{
+       if (p->ier & UART_IER_THRI) {
+               p->ier &= ~UART_IER_THRI;
+               serial_out(p, UART_IER, p->ier);
+       }
+}
+
 static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
 
-       if (up->ier & UART_IER_THRI) {
-               up->ier &= ~UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
+       __stop_tx(up);
 
        /*
-        * We only do this from uart_stop - if we run out of
-        * characters to send, we don't want to prevent the
-        * FIFO from emptying.
+        * We really want to stop the transmitter from sending.
         */
-       if (up->port.type == PORT_16C950 && tty_stop) {
+       if (up->port.type == PORT_16C950) {
                up->acr |= UART_ACR_TXDIS;
                serial_icr_write(up, UART_ACR, up->acr);
        }
@@ -1045,10 +1034,11 @@ static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start)
                                transmit_chars(up);
                }
        }
+
        /*
-        * We only do this from uart_start
+        * Re-enable the transmitter if we disabled it.
         */
-       if (tty_start && up->port.type == PORT_16C950) {
+       if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
                up->acr &= ~UART_ACR_TXDIS;
                serial_icr_write(up, UART_ACR, up->acr);
        }
@@ -1169,7 +1159,7 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up)
                return;
        }
        if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               serial8250_stop_tx(&up->port, 0);
+               __stop_tx(up);
                return;
        }
 
@@ -1188,7 +1178,7 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up)
        DEBUG_INTR("THRE...");
 
        if (uart_circ_empty(xmit))
-               serial8250_stop_tx(&up->port, 0);
+               __stop_tx(up);
 }
 
 static _INLINE_ void check_modem_status(struct uart_8250_port *up)
@@ -1390,13 +1380,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
 static unsigned int serial8250_get_mctrl(struct uart_port *port)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
-       unsigned long flags;
        unsigned char status;
        unsigned int ret;
 
-       spin_lock_irqsave(&up->port.lock, flags);
        status = serial_in(up, UART_MSR);
-       spin_unlock_irqrestore(&up->port.lock, flags);
 
        ret = 0;
        if (status & UART_MSR_DCD)
@@ -1682,22 +1669,22 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
 
        switch (termios->c_cflag & CSIZE) {
        case CS5:
-               cval = 0x00;
+               cval = UART_LCR_WLEN5;
                break;
        case CS6:
-               cval = 0x01;
+               cval = UART_LCR_WLEN6;
                break;
        case CS7:
-               cval = 0x02;
+               cval = UART_LCR_WLEN7;
                break;
        default:
        case CS8:
-               cval = 0x03;
+               cval = UART_LCR_WLEN8;
                break;
        }
 
        if (termios->c_cflag & CSTOPB)
-               cval |= 0x04;
+               cval |= UART_LCR_STOP;
        if (termios->c_cflag & PARENB)
                cval |= UART_LCR_PARITY;
        if (!(termios->c_cflag & PARODD))
@@ -2323,10 +2310,11 @@ static int __devinit serial8250_probe(struct device *dev)
 {
        struct plat_serial8250_port *p = dev->platform_data;
        struct uart_port port;
+       int ret, i;
 
        memset(&port, 0, sizeof(struct uart_port));
 
-       for (; p && p->flags != 0; p++) {
+       for (i = 0; p && p->flags != 0; p++, i++) {
                port.iobase     = p->iobase;
                port.membase    = p->membase;
                port.irq        = p->irq;
@@ -2335,10 +2323,16 @@ static int __devinit serial8250_probe(struct device *dev)
                port.iotype     = p->iotype;
                port.flags      = p->flags;
                port.mapbase    = p->mapbase;
+               port.hub6       = p->hub6;
                port.dev        = dev;
                if (share_irqs)
                        port.flags |= UPF_SHARE_IRQ;
-               serial8250_register_port(&port);
+               ret = serial8250_register_port(&port);
+               if (ret < 0) {
+                       dev_err(dev, "unable to register port at index %d "
+                               "(IO%lx MEM%lx IRQ%d): %d\n", i,
+                               p->iobase, p->mapbase, p->irq, ret);
+               }
        }
        return 0;
 }
diff --git a/drivers/serial/8250_accent.c b/drivers/serial/8250_accent.c
new file mode 100644 (file)
index 0000000..1f2c276
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *  linux/drivers/serial/8250_accent.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * 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/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq)                               \
+       {                                               \
+               .iobase         = _base,                \
+               .irq            = _irq,                 \
+               .uartclk        = 1843200,              \
+               .iotype         = UPIO_PORT,            \
+               .flags          = UPF_BOOT_AUTOCONF,    \
+       }
+
+static struct plat_serial8250_port accent_data[] = {
+       PORT(0x330, 4),
+       PORT(0x338, 4),
+       { },
+};
+
+static struct platform_device accent_device = {
+       .name                   = "serial8250",
+       .id                     = 2,
+       .dev                    = {
+               .platform_data  = accent_data,
+       },
+};
+
+static int __init accent_init(void)
+{
+       return platform_device_register(&accent_device);
+}
+
+module_init(accent_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Accent Async cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_boca.c b/drivers/serial/8250_boca.c
new file mode 100644 (file)
index 0000000..465c9ea
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *  linux/drivers/serial/8250_boca.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * 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/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq)                               \
+       {                                               \
+               .iobase         = _base,                \
+               .irq            = _irq,                 \
+               .uartclk        = 1843200,              \
+               .iotype         = UPIO_PORT,            \
+               .flags          = UPF_BOOT_AUTOCONF,    \
+       }
+
+static struct plat_serial8250_port boca_data[] = {
+       PORT(0x100, 12),
+       PORT(0x108, 12),
+       PORT(0x110, 12),
+       PORT(0x118, 12),
+       PORT(0x120, 12),
+       PORT(0x128, 12),
+       PORT(0x130, 12),
+       PORT(0x138, 12),
+       PORT(0x140, 12),
+       PORT(0x148, 12),
+       PORT(0x150, 12),
+       PORT(0x158, 12),
+       PORT(0x160, 12),
+       PORT(0x168, 12),
+       PORT(0x170, 12),
+       PORT(0x178, 12),
+       { },
+};
+
+static struct platform_device boca_device = {
+       .name                   = "serial8250",
+       .id                     = 3,
+       .dev                    = {
+               .platform_data  = boca_data,
+       },
+};
+
+static int __init boca_init(void)
+{
+       return platform_device_register(&boca_device);
+}
+
+module_init(boca_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Boca cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_fourport.c b/drivers/serial/8250_fourport.c
new file mode 100644 (file)
index 0000000..e9b4d90
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  linux/drivers/serial/8250_fourport.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * 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/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq)                                               \
+       {                                                               \
+               .iobase         = _base,                                \
+               .irq            = _irq,                                 \
+               .uartclk        = 1843200,                              \
+               .iotype         = UPIO_PORT,                            \
+               .flags          = UPF_BOOT_AUTOCONF | UPF_FOURPORT,     \
+       }
+
+static struct plat_serial8250_port fourport_data[] = {
+       PORT(0x1a0, 9),
+       PORT(0x1a8, 9),
+       PORT(0x1b0, 9),
+       PORT(0x1b8, 9),
+       PORT(0x2a0, 5),
+       PORT(0x2a8, 5),
+       PORT(0x2b0, 5),
+       PORT(0x2b8, 5),
+       { },
+};
+
+static struct platform_device fourport_device = {
+       .name                   = "serial8250",
+       .id                     = 1,
+       .dev                    = {
+               .platform_data  = fourport_data,
+       },
+};
+
+static int __init fourport_init(void)
+{
+       return platform_device_register(&fourport_device);
+}
+
+module_init(fourport_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for AST Fourport cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_hub6.c b/drivers/serial/8250_hub6.c
new file mode 100644 (file)
index 0000000..77f396f
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *  linux/drivers/serial/8250_hub6.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * 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/init.h>
+#include <linux/serial_8250.h>
+
+#define HUB6(card,port)                                                        \
+       {                                                               \
+               .iobase         = 0x302,                                \
+               .irq            = 3,                                    \
+               .uartclk        = 1843200,                              \
+               .iotype         = UPIO_HUB6,                            \
+               .flags          = UPF_BOOT_AUTOCONF,                    \
+               .hub6           = (card) << 6 | (port) << 3 | 1,        \
+       }
+
+static struct plat_serial8250_port hub6_data[] = {
+       HUB6(0,0),
+       HUB6(0,1),
+       HUB6(0,2),
+       HUB6(0,3),
+       HUB6(0,4),
+       HUB6(0,5),
+       HUB6(1,0),
+       HUB6(1,1),
+       HUB6(1,2),
+       HUB6(1,3),
+       HUB6(1,4),
+       HUB6(1,5),
+       { },
+};
+
+static struct platform_device hub6_device = {
+       .name                   = "serial8250",
+       .id                     = 4,
+       .dev                    = {
+               .platform_data  = hub6_data,
+       },
+};
+
+static int __init hub6_init(void)
+{
+       return platform_device_register(&hub6_device);
+}
+
+module_init(hub6_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Hub6 cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_mca.c b/drivers/serial/8250_mca.c
new file mode 100644 (file)
index 0000000..f0c40d6
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *  linux/drivers/serial/8250_mca.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mca.h>
+#include <linux/serial_8250.h>
+
+/*
+ * FIXME: Should we be doing AUTO_IRQ here?
+ */
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
+#define MCA_FLAGS      UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ
+#else
+#define MCA_FLAGS      UPF_BOOT_AUTOCONF | UPF_SKIP_TEST
+#endif
+
+#define PORT(_base,_irq)                       \
+       {                                       \
+               .iobase         = _base,        \
+               .irq            = _irq,         \
+               .uartclk        = 1843200,      \
+               .iotype         = UPIO_PORT,    \
+               .flags          = MCA_FLAGS,    \
+       }
+
+static struct plat_serial8250_port mca_data[] = {
+       PORT(0x3220, 3),
+       PORT(0x3228, 3),
+       PORT(0x4220, 3),
+       PORT(0x4228, 3),
+       PORT(0x5220, 3),
+       PORT(0x5228, 3),
+       { },
+};
+
+static struct platform_device mca_device = {
+       .name                   = "serial8250",
+       .id                     = 5,
+       .dev                    = {
+               .platform_data  = mca_data,
+       },
+};
+
+static int __init mca_init(void)
+{
+       if (!MCA_bus)
+               return -ENODEV;
+       return platform_device_register(&mca_device);
+}
+
+module_init(mca_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for MCA ports");
+MODULE_LICENSE("GPL");
index 25fcef2c42deeb8a1cee6716d12c7e1ec2d19456..e0d0a470ddfcc765c0f750da4adccca5850ade7a 100644 (file)
@@ -86,14 +86,14 @@ config SERIAL_8250_ACPI
          namespace, say Y here.  If unsure, say N.
 
 config SERIAL_8250_NR_UARTS
-       int "Maximum number of non-legacy 8250/16550 serial ports"
+       int "Maximum number of 8250/16550 serial ports"
        depends on SERIAL_8250
        default "4"
-       ---help---
-         Set this to the number of non-legacy serial ports you want
-         the driver to support.  This includes any ports discovered
-         via ACPI or PCI enumeration and any ports that may be added
-         at run-time via hot-plug.
+       help
+         Set this to the number of serial ports you want the driver
+         to support.  This includes any ports discovered via ACPI or
+         PCI enumeration and any ports that may be added at run-time
+         via hot-plug, or any ISA multi-port serial cards.
 
 config SERIAL_8250_EXTENDED
        bool "Extended 8250/16550 serial driver options"
@@ -141,31 +141,74 @@ config SERIAL_8250_DETECT_IRQ
 
          If unsure, say N.
 
-config SERIAL_8250_MULTIPORT
-       bool "Support special multiport boards"
-       depends on SERIAL_8250_EXTENDED
-       help
-         Some multiport serial ports have special ports which are used to
-         signal when there are any serial ports on the board which need
-         servicing. Say Y here to enable the serial driver to take advantage
-         of those special I/O ports.
-
 config SERIAL_8250_RSA
        bool "Support RSA serial ports"
        depends on SERIAL_8250_EXTENDED
        help
          ::: To be written :::
 
-comment "Non-8250 serial port support"
+#
+# Multi-port serial cards
+#
+
+config SERIAL_8250_FOURPORT
+       tristate "Support Fourport cards"
+       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+       help
+         Say Y here if you have an AST FourPort serial board.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_fourport.
+
+config SERIAL_8250_ACCENT
+       tristate "Support Accent cards"
+       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+       help
+         Say Y here if you have an Accent Async serial board.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_accent.
+
+
+config SERIAL_8250_BOCA
+       tristate "Support Boca cards"
+       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+       help
+         Say Y here if you have a Boca serial board.  Please read the Boca
+         mini-HOWTO, avaialble from <http://www.tldp.org/docs.html#howto>
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_boca.
+
+
+config SERIAL_8250_HUB6
+       tristate "Support Hub6 cards"
+       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+       help
+         Say Y here if you have a HUB6 serial board.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_hub6.
+
+config SERIAL_8250_MCA
+       tristate "Support 8250-type ports on MCA buses"
+       depends on SERIAL_8250 != n && MCA
+       help
+         Say Y here if you have a MCA serial ports.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_mca.
 
 config SERIAL_8250_ACORN
        tristate "Acorn expansion card serial port support"
-       depends on ARM && ARCH_ACORN && SERIAL_8250
+       depends on ARCH_ACORN && SERIAL_8250
        help
          If you have an Atomwide Serial card or Serial Port card for an Acorn
          system, say Y to this option.  The driver can handle 1, 2, or 3 port
          cards.  If unsure, say N.
 
+comment "Non-8250 serial port support"
+
 config SERIAL_AMBA_PL010
        tristate "ARM AMBA PL010 serial port support"
        depends on ARM_AMBA
index 8f1cdde7dbed7c57bf7daf379d3dfc529c5eb9a2..65bd4381685e312134befbf87ff214b49b98a9d8 100644 (file)
@@ -17,6 +17,11 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y)
 obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
 obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
 obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
+obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
+obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
+obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
+obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
+obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
 obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
 obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
 obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
index b6d3d503494070908e3a15b42254825a712132b9..6104aeef12439e156928a16f77267d2215b19d6f 100644 (file)
@@ -556,13 +556,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
 static unsigned int serial8250_get_mctrl(struct uart_port *port)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
-       unsigned long flags;
        unsigned char status;
        unsigned int ret;
 
-       spin_lock_irqsave(&up->port.lock, flags);
        status = serial_in(up, UART_MSR);
-       spin_unlock_irqrestore(&up->port.lock, flags);
 
        ret = 0;
        if (status & UART_MSR_DCD)
@@ -773,22 +770,22 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
 
        switch (termios->c_cflag & CSIZE) {
        case CS5:
-               cval = 0x00;
+               cval = UART_LCR_WLEN5;
                break;
        case CS6:
-               cval = 0x01;
+               cval = UART_LCR_WLEN6;
                break;
        case CS7:
-               cval = 0x02;
+               cval = UART_LCR_WLEN7;
                break;
        default:
        case CS8:
-               cval = 0x03;
+               cval = UART_LCR_WLEN8;
                break;
        }
 
        if (termios->c_cflag & CSTOPB)
-               cval |= 0x04;
+               cval |= UART_LCR_STOP;
        if (termios->c_cflag & PARENB)
                cval |= UART_LCR_PARITY;
        if (!(termios->c_cflag & PARODD))
index 23dc0f7ddf8bb6712613ba0274374f609e1c4412..798f1ef237128e8e5d3a672247c8b53faab67bcd 100644 (file)
@@ -286,5 +286,3 @@ struct lookup_int_table {
        u32     __iomem *global_int_mask;
        unsigned long   processor_id;
 };
-
-#define MSECS_TO_JIFFIES(ms) (((ms)*HZ+999)/1000)
index 3ea46c069f6f1c00ea73858ee83ebd1e5e4e1284..ea5bf4d4daa3016db79933b268ae5240fa63e952 100644 (file)
@@ -518,27 +518,28 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *re
 static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port)
 {
        struct zilog_channel *channel;
-       unsigned long flags;
        unsigned char status;
 
-       spin_lock_irqsave(&port->lock, flags);
-
        channel = ZILOG_CHANNEL_FROM_PORT(port);
        status = readb(&channel->control);
        ZSDELAY();
 
-       spin_unlock_irqrestore(&port->lock, flags);
-
        return status;
 }
 
 /* The port lock is not held.  */
 static unsigned int ip22zilog_tx_empty(struct uart_port *port)
 {
+       unsigned long flags;
        unsigned char status;
        unsigned int ret;
 
+       spin_lock_irqsave(&port->lock, flags);
+
        status = ip22zilog_read_channel_status(port);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
        if (status & Tx_BUF_EMP)
                ret = TIOCSER_TEMT;
        else
@@ -547,7 +548,7 @@ static unsigned int ip22zilog_tx_empty(struct uart_port *port)
        return ret;
 }
 
-/* The port lock is not held.  */
+/* The port lock is held and interrupts are disabled.  */
 static unsigned int ip22zilog_get_mctrl(struct uart_port *port)
 {
        unsigned char status;
index 08d61f13edc61501f4aa8d5e34a46806b98bb346..0301feacbde49f0b57ca842767c8df4086ea1357 100644 (file)
@@ -724,22 +724,22 @@ static void m32r_sio_set_termios(struct uart_port *port,
 
        switch (termios->c_cflag & CSIZE) {
        case CS5:
-               cval = 0x00;
+               cval = UART_LCR_WLEN5;
                break;
        case CS6:
-               cval = 0x01;
+               cval = UART_LCR_WLEN6;
                break;
        case CS7:
-               cval = 0x02;
+               cval = UART_LCR_WLEN7;
                break;
        default:
        case CS8:
-               cval = 0x03;
+               cval = UART_LCR_WLEN8;
                break;
        }
 
        if (termios->c_cflag & CSTOPB)
-               cval |= 0x04;
+               cval |= UART_LCR_STOP;
        if (termios->c_cflag & PARENB)
                cval |= UART_LCR_PARITY;
        if (!(termios->c_cflag & PARODD))
index a8314aee2ab8b7a32e8e67f2f6e0c2e82c8f39b4..e43276c6a954d611021745375b5e2344bc85d266 100644 (file)
 
 static struct mpsc_port_info mpsc_ports[MPSC_NUM_CTLRS];
 static struct mpsc_shared_regs mpsc_shared_regs;
+static struct uart_driver mpsc_reg;
 
+static void mpsc_start_rx(struct mpsc_port_info *pi);
+static void mpsc_free_ring_mem(struct mpsc_port_info *pi);
+static void mpsc_release_port(struct uart_port *port);
 /*
  ******************************************************************************
  *
@@ -546,7 +550,6 @@ static int
 mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
 {
        int rc = 0;
-       static void mpsc_free_ring_mem(struct mpsc_port_info *pi);
 
        pr_debug("mpsc_alloc_ring_mem[%d]: Allocating ring mem\n",
                pi->port.line);
@@ -745,7 +748,6 @@ mpsc_rx_intr(struct mpsc_port_info *pi, struct pt_regs *regs)
        int     rc = 0;
        u8      *bp;
        char    flag = TTY_NORMAL;
-       static void mpsc_start_rx(struct mpsc_port_info *pi);
 
        pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
 
@@ -1056,12 +1058,9 @@ mpsc_get_mctrl(struct uart_port *port)
 {
        struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
        u32 mflags, status;
-       ulong iflags;
 
-       spin_lock_irqsave(&pi->port.lock, iflags);
        status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m :
                readl(pi->mpsc_base + MPSC_CHR_10);
-       spin_unlock_irqrestore(&pi->port.lock, iflags);
 
        mflags = 0;
        if (status & 0x1)
@@ -1178,7 +1177,6 @@ static void
 mpsc_shutdown(struct uart_port *port)
 {
        struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       static void mpsc_release_port(struct uart_port *port);
 
        pr_debug("mpsc_shutdown[%d]: Shutting down MPSC\n", port->line);
 
@@ -1448,7 +1446,6 @@ mpsc_console_setup(struct console *co, char *options)
        return uart_set_options(&pi->port, co, baud, parity, bits, flow);
 }
 
-extern struct uart_driver mpsc_reg;
 static struct console mpsc_console = {
        .name   = MPSC_DEV_NAME,
        .write  = mpsc_console_write,
index 85abd8a045e088cf2c6414aa52cf91fa1c22dba6..1c9f71617123ad4ecf80674f9a737e22feddabf1 100644 (file)
@@ -604,7 +604,7 @@ static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl)
 /* 
  * Get Modem Control bits (only the input ones, the core will
  * or that with a cached value of the control ones)
- * The port lock is not held.
+ * The port lock is held and interrupts are disabled.
  */
 static unsigned int pmz_get_mctrl(struct uart_port *port)
 {
@@ -615,7 +615,7 @@ static unsigned int pmz_get_mctrl(struct uart_port *port)
        if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
                return 0;
 
-       status = pmz_peek_status(to_pmz(port));
+       status = read_zsreg(uap, R0);
 
        ret = 0;
        if (status & DCD)
index 9dc151d8fa612bb16554f6d4d15382a5d4eaf7ab..461c81c93207809381c0f2bc9afe5ecfa23d8d9e 100644 (file)
@@ -274,14 +274,11 @@ static unsigned int serial_pxa_tx_empty(struct uart_port *port)
 static unsigned int serial_pxa_get_mctrl(struct uart_port *port)
 {
        struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned long flags;
        unsigned char status;
        unsigned int ret;
 
 return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-       spin_lock_irqsave(&up->port.lock, flags);
        status = serial_in(up, UART_MSR);
-       spin_unlock_irqrestore(&up->port.lock, flags);
 
        ret = 0;
        if (status & UART_MSR_DCD)
@@ -455,22 +452,22 @@ serial_pxa_set_termios(struct uart_port *port, struct termios *termios,
 
        switch (termios->c_cflag & CSIZE) {
        case CS5:
-               cval = 0x00;
+               cval = UART_LCR_WLEN5;
                break;
        case CS6:
-               cval = 0x01;
+               cval = UART_LCR_WLEN6;
                break;
        case CS7:
-               cval = 0x02;
+               cval = UART_LCR_WLEN7;
                break;
        default:
        case CS8:
-               cval = 0x03;
+               cval = UART_LCR_WLEN8;
                break;
        }
 
        if (termios->c_cflag & CSTOPB)
-               cval |= 0x04;
+               cval |= UART_LCR_STOP;
        if (termios->c_cflag & PARENB)
                cval |= UART_LCR_PARITY;
        if (!(termios->c_cflag & PARODD))
index 36b1ae083fb7b1574d4b8951fdf1efcfec2a68df..139863a787f37836e8587efced95c796ed7892dc 100644 (file)
@@ -182,6 +182,13 @@ static int uart_startup(struct uart_state *state, int init_hw)
                                uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
                }
 
+               if (info->flags & UIF_CTS_FLOW) {
+                       spin_lock_irq(&port->lock);
+                       if (!(port->ops->get_mctrl(port) & TIOCM_CTS))
+                               info->tty->hw_stopped = 1;
+                       spin_unlock_irq(&port->lock);
+               }
+
                info->flags |= UIF_INITIALIZED;
 
                clear_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -828,7 +835,10 @@ static int uart_tiocmget(struct tty_struct *tty, struct file *file)
        if ((!file || !tty_hung_up_p(file)) &&
            !(tty->flags & (1 << TTY_IO_ERROR))) {
                result = port->mctrl;
+
+               spin_lock_irq(&port->lock);
                result |= port->ops->get_mctrl(port);
+               spin_unlock_irq(&port->lock);
        }
        up(&state->sem);
 
@@ -1131,6 +1141,16 @@ static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios
                spin_unlock_irqrestore(&state->port->lock, flags);
        }
 
+       /* Handle turning on CRTSCTS */
+       if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
+               spin_lock_irqsave(&state->port->lock, flags);
+               if (!(state->port->ops->get_mctrl(state->port) & TIOCM_CTS)) {
+                       tty->hw_stopped = 1;
+                       state->port->ops->stop_tx(state->port, 0);
+               }
+               spin_unlock_irqrestore(&state->port->lock, flags);
+       }
+
 #if 0
        /*
         * No need to wake up processes in open wait, since they
@@ -1369,6 +1389,7 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
        DECLARE_WAITQUEUE(wait, current);
        struct uart_info *info = state->info;
        struct uart_port *port = state->port;
+       unsigned int mctrl;
 
        info->blocked_open++;
        state->count--;
@@ -1416,7 +1437,10 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
                 * and wait for the carrier to indicate that the
                 * modem is ready for us.
                 */
-               if (port->ops->get_mctrl(port) & TIOCM_CAR)
+               spin_lock_irq(&port->lock);
+               mctrl = port->ops->get_mctrl(port);
+               spin_unlock_irq(&port->lock);
+               if (mctrl & TIOCM_CAR)
                        break;
 
                up(&state->sem);
@@ -1618,7 +1642,9 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
 
        if(capable(CAP_SYS_ADMIN))
        {
+               spin_lock_irq(&port->lock);
                status = port->ops->get_mctrl(port);
+               spin_unlock_irq(&port->lock);
 
                ret += sprintf(buf + ret, " tx:%d rx:%d",
                                port->icount.tx, port->icount.rx);
index 0d7b65f93e8de505602dbf26d0dd8734f84e3d23..73a34b18866f405ee8a5d147a42ce9e46108a83d 100644 (file)
@@ -772,6 +772,111 @@ serial_event(event_t event, int priority, event_callback_args_t * args)
        return 0;
 }
 
+static struct pcmcia_device_id serial_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0140, 0x000a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0x3341),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0xc0ab),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet ", 0x578ba6e7, 0x02d92d1e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet", 0x2e3ee845, 0xc0e778c2),
+       PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
+       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
+       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070),
+       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x016c, 0x0020),
+       PCMCIA_MFC_DEVICE_PROD_ID123(1, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away 28.8 PC Card       ", 0xb569a6e5, 0x5bd4ff2c),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
+       PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77),
+       PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
+       PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301),
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039),
+       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006),
+       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052),
+       PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae),
+       PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef),
+       PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef),
+       PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef),
+       PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0),
+       PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a),
+       PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02),
+       PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa),
+       PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 28800 FAX/DATA MODEM", 0xa3a3062c, 0x8cbd7c76),
+       PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95),
+       PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed),
+       PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65),
+       PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6),
+       PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400", 0x816cc815, 0x23539b80),
+       PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f),
+       PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f),
+       PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383),
+       PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e),
+       PCMCIA_DEVICE_PROD_ID12("OEM      ", "C288MX     ", 0xb572d360, 0xd2385b7a),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA   ", "C336MX     ", 0x99bcafe9, 0xaa25bcab),
+       PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "PCMLM28.cis"),
+       PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "3CCFEM556.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "3CXEM556.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "3CXEM556.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "MT5634ZLX.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "COMpad4.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "COMpad2.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "RS-COM-2P.cis"),
+       /* too generic */
+       /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
+       /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */
+       PCMCIA_DEVICE_FUNC_ID(2),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, serial_ids);
+
 static struct pcmcia_driver serial_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -779,6 +884,7 @@ static struct pcmcia_driver serial_cs_driver = {
        },
        .attach         = serial_attach,
        .detach         = serial_detach,
+       .id_table       = serial_ids,
 };
 
 static int __init init_serial_cs(void)
index 3f1051a4a13f8f51cab2efa2783f287e734c8ecb..d085030df70ba5bd321a0fd5716df8ab31af39e1 100644 (file)
@@ -442,13 +442,10 @@ static unsigned int serial_txx9_tx_empty(struct uart_port *port)
 static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
 {
        struct uart_txx9_port *up = (struct uart_txx9_port *)port;
-       unsigned long flags;
        unsigned int ret;
 
-       spin_lock_irqsave(&up->port.lock, flags);
        ret =  ((sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS)
                | ((sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS);
-       spin_unlock_irqrestore(&up->port.lock, flags);
 
        return ret;
 }
index 10e2990a40d42a2453780c5e045642c28866411e..8d198880756a6a3aef034eb55ca6ca7ea5a212e5 100644 (file)
@@ -426,18 +426,15 @@ static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl)
                sunsab_tx_idle(up);
 }
 
-/* port->lock is not held.  */
+/* port->lock is held by caller and interrupts are disabled.  */
 static unsigned int sunsab_get_mctrl(struct uart_port *port)
 {
        struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       unsigned long flags;
        unsigned char val;
        unsigned int result;
 
        result = 0;
 
-       spin_lock_irqsave(&up->port.lock, flags);
-
        val = readb(&up->regs->r.pvr);
        result |= (val & up->pvr_dsr_bit) ? 0 : TIOCM_DSR;
 
@@ -447,8 +444,6 @@ static unsigned int sunsab_get_mctrl(struct uart_port *port)
        val = readb(&up->regs->r.star);
        result |= (val & SAB82532_STAR_CTS) ? TIOCM_CTS : 0;
 
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
        return result;
 }
 
index ddc97c905e14cc7a158a22f339379d0129e81551..d57a3553aea359ac7a3123ae62261f2ed9abbb0d 100644 (file)
@@ -572,13 +572,10 @@ static unsigned int sunsu_tx_empty(struct uart_port *port)
 static unsigned int sunsu_get_mctrl(struct uart_port *port)
 {
        struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned long flags;
        unsigned char status;
        unsigned int ret;
 
-       spin_lock_irqsave(&up->port.lock, flags);
        status = serial_in(up, UART_MSR);
-       spin_unlock_irqrestore(&up->port.lock, flags);
 
        ret = 0;
        if (status & UART_MSR_DCD)
index 5c4231ae295b05cf7750a4ba3bd7533f154532f3..bff42a7b89d0ec6e02862fcd656a12500ccc144b 100644 (file)
@@ -610,27 +610,28 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
 static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *port)
 {
        struct zilog_channel __iomem *channel;
-       unsigned long flags;
        unsigned char status;
 
-       spin_lock_irqsave(&port->lock, flags);
-
        channel = ZILOG_CHANNEL_FROM_PORT(port);
        status = sbus_readb(&channel->control);
        ZSDELAY();
 
-       spin_unlock_irqrestore(&port->lock, flags);
-
        return status;
 }
 
 /* The port lock is not held.  */
 static unsigned int sunzilog_tx_empty(struct uart_port *port)
 {
+       unsigned long flags;
        unsigned char status;
        unsigned int ret;
 
+       spin_lock_irqsave(&port->lock, flags);
+
        status = sunzilog_read_channel_status(port);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
        if (status & Tx_BUF_EMP)
                ret = TIOCSER_TEMT;
        else
@@ -639,7 +640,7 @@ static unsigned int sunzilog_tx_empty(struct uart_port *port)
        return ret;
 }
 
-/* The port lock is not held.  */
+/* The port lock is held and interrupts are disabled.  */
 static unsigned int sunzilog_get_mctrl(struct uart_port *port)
 {
        unsigned char status;
@@ -1071,7 +1072,7 @@ static void __init sunzilog_alloc_tables(void)
  */
 static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode)
 {
-       unsigned long mapped_addr;
+       void __iomem *mapped_addr;
        unsigned int sun4u_ino;
        struct sbus_bus *sbus = NULL;
        struct sbus_dev *sdev = NULL;
@@ -1111,9 +1112,9 @@ static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode)
                apply_fhc_ranges(central_bus->child,
                                 &zsregs[0], 1);
                apply_central_ranges(central_bus, &zsregs[0], 1);
-               mapped_addr =
-                       (((u64)zsregs[0].which_io)<<32UL) |
-                       ((u64)zsregs[0].phys_addr);
+               mapped_addr = (void __iomem *)
+                       ((((u64)zsregs[0].which_io)<<32UL) |
+                       ((u64)zsregs[0].phys_addr));
        }
 
        if (zilog_irq == -1) {
index d5863b8b56eeaf00745a03f3d3a76c11c12a512f..f2c9fa423d402d1262b6af64e3d3180c567f39cf 100644 (file)
@@ -329,10 +329,8 @@ static IXJ *ixj_alloc()
 
 static void ixj_fsk_free(IXJ *j)
 {
-       if(j->fskdata != NULL) {
-               kfree(j->fskdata);
-               j->fskdata = NULL;
-       }
+       kfree(j->fskdata);
+       j->fskdata = NULL;
 }
 
 static void ixj_fsk_alloc(IXJ *j)
@@ -3867,13 +3865,11 @@ static int set_rec_codec(IXJ *j, int rate)
                j->rec_mode = 7;
                break;
        default:
+               kfree(j->read_buffer);
                j->rec_frame_size = 0;
                j->rec_mode = -1;
-               if (j->read_buffer) {
-                       kfree(j->read_buffer);
-                       j->read_buffer = NULL;
-                       j->read_buffer_size = 0;
-               }
+               j->read_buffer = NULL;
+               j->read_buffer_size = 0;
                retval = 1;
                break;
        }
@@ -3991,14 +3987,12 @@ static int ixj_record_start(IXJ *j)
 
 static void ixj_record_stop(IXJ *j)
 {
-       if(ixjdebug & 0x0002)
+       if (ixjdebug & 0x0002)
                printk("IXJ %d Stopping Record Codec %d at %ld\n", j->board, j->rec_codec, jiffies);
 
-       if (j->read_buffer) {
-               kfree(j->read_buffer);
-               j->read_buffer = NULL;
-               j->read_buffer_size = 0;
-       }
+       kfree(j->read_buffer);
+       j->read_buffer = NULL;
+       j->read_buffer_size = 0;
        if (j->rec_mode > -1) {
                ixj_WriteDSPCommand(0x5120, j);
                j->rec_mode = -1;
@@ -4449,13 +4443,11 @@ static int set_play_codec(IXJ *j, int rate)
                j->play_mode = 5;
                break;
        default:
+               kfree(j->write_buffer);
                j->play_frame_size = 0;
                j->play_mode = -1;
-               if (j->write_buffer) {
-                       kfree(j->write_buffer);
-                       j->write_buffer = NULL;
-                       j->write_buffer_size = 0;
-               }
+               j->write_buffer = NULL;
+               j->write_buffer_size = 0;
                retval = 1;
                break;
        }
@@ -4578,14 +4570,12 @@ static int ixj_play_start(IXJ *j)
 
 static void ixj_play_stop(IXJ *j)
 {
-       if(ixjdebug & 0x0002)
+       if (ixjdebug & 0x0002)
                printk("IXJ %d Stopping Play Codec %d at %ld\n", j->board, j->play_codec, jiffies);
 
-       if (j->write_buffer) {
-               kfree(j->write_buffer);
-               j->write_buffer = NULL;
-               j->write_buffer_size = 0;
-       }
+       kfree(j->write_buffer);
+       j->write_buffer = NULL;
+       j->write_buffer_size = 0;
        if (j->play_mode > -1) {
                ixj_WriteDSPCommand(0x5221, j); /* Stop playback and flush buffers.  8022 reference page 9-40 */
 
@@ -5810,9 +5800,7 @@ static void ixj_cpt_stop(IXJ *j)
                ixj_play_tone(j, 0);
                j->tone_state = j->tone_cadence_state = 0;
                if (j->cadence_t) {
-                       if (j->cadence_t->ce) {
-                               kfree(j->cadence_t->ce);
-                       }
+                       kfree(j->cadence_t->ce);
                        kfree(j->cadence_t);
                        j->cadence_t = NULL;
                }
@@ -7497,10 +7485,8 @@ static void cleanup(void)
                                        printk(KERN_INFO "IXJ: Releasing XILINX address for /dev/phone%d\n", cnt);
                                release_region(j->XILINXbase, 4);
                        }
-                       if (j->read_buffer)
-                               kfree(j->read_buffer);
-                       if (j->write_buffer)
-                               kfree(j->write_buffer);
+                       kfree(j->read_buffer);
+                       kfree(j->write_buffer);
                        if (j->dev)
                                pnp_device_detach(j->dev);
                        if (ixjdebug & 0x0002)
index e1ef0d7ee8d129e9200009cfd8ab36724488817d..ce5ebfe4af2b5e36e3a632aaeade29ecc9811022 100644 (file)
@@ -295,6 +295,12 @@ static int ixj_event(event_t event, int priority, event_callback_args_t * args)
        return 0;
 }
 
+static struct pcmcia_device_id ixj_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x0257, 0x0600),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, ixj_ids);
+
 static struct pcmcia_driver ixj_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -302,6 +308,7 @@ static struct pcmcia_driver ixj_driver = {
        },
        .attach         = ixj_attach,
        .detach         = ixj_detach,
+       .id_table       = ixj_ids,
 };
 
 static int __init ixj_pcmcia_init(void)
index a61d4433a989f2f309c78866be1870db6519da3f..d79cd218a55145768682d3b8e750f373a7f897ee 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_USB)               += core/
 obj-$(CONFIG_USB_MON)          += mon/
 
 obj-$(CONFIG_USB_EHCI_HCD)     += host/
+obj-$(CONFIG_USB_ISP116X_HCD)  += host/
 obj-$(CONFIG_USB_OHCI_HCD)     += host/
 obj-$(CONFIG_USB_UHCI_HCD)     += host/
 obj-$(CONFIG_USB_SL811_HCD)    += host/
@@ -31,6 +32,7 @@ obj-$(CONFIG_USB_MOUSE)               += input/
 obj-$(CONFIG_USB_MTOUCH)       += input/
 obj-$(CONFIG_USB_POWERMATE)    += input/
 obj-$(CONFIG_USB_WACOM)                += input/
+obj-$(CONFIG_USB_ACECAD)       += input/
 obj-$(CONFIG_USB_XPAD)         += input/
 
 obj-$(CONFIG_USB_DABUSB)       += media/
index 0d9f5379b8cf905b553888b974f89972490568eb..f429862e0974b2d7e3f1285daefa5d77d219f606 100644 (file)
@@ -1,30 +1,60 @@
 #
-# USB ATM driver configuration
+# USB/ATM DSL configuration
 #
-comment "USB ATM/DSL drivers"
+
+menu "USB DSL modem support"
        depends on USB
 
 config USB_ATM
-       tristate "Generic USB ATM/DSL core I/O support"
+       tristate "USB DSL modem support"
        depends on USB && ATM
        select CRC32
        default n
        help
-         This provides a library which is used for packet I/O by USB DSL
-         modems, such as the SpeedTouch driver below. 
+         Say Y here if you want to connect a USB Digital Subscriber Line (DSL)
+         modem to your computer's USB port.  You will then need to choose your
+         modem from the list below.
 
          To compile this driver as a module, choose M here: the
-         module will be called usb_atm.
+         module will be called usbatm.
 
 config USB_SPEEDTOUCH
-       tristate "Alcatel Speedtouch USB support"
-       depends on USB && ATM
-       select USB_ATM
+       tristate "Speedtouch USB support"
+       depends on USB_ATM
+       select FW_LOADER
        help
-         Say Y here if you have an Alcatel SpeedTouch USB or SpeedTouch 330
+         Say Y here if you have an SpeedTouch USB or SpeedTouch 330
          modem.  In order to use your modem you will need to install the 
          two parts of the firmware, extracted by the user space tools; see
          <http://www.linux-usb.org/SpeedTouch/> for details.
 
          To compile this driver as a module, choose M here: the
          module will be called speedtch.
+
+config USB_CXACRU
+       tristate "Conexant AccessRunner USB support"
+       depends on USB_ATM
+       select FW_LOADER
+       help
+         Say Y here if you have an ADSL USB modem based on the Conexant
+         AccessRunner chipset.  In order to use your modem you will need to
+         install the firmware, extracted by the user space tools; see
+         <http://accessrunner.sourceforge.net/> for details.
+
+         To compile this driver as a module, choose M here: the
+         module will be called cxacru.
+
+config USB_XUSBATM
+       tristate "Other USB DSL modem support"
+       depends on USB_ATM
+       help
+         Say Y here if you have a DSL USB modem not explicitly supported by
+         another USB DSL drivers.  In order to use your modem you will need to
+         pass the vendor ID, product ID, and endpoint numbers for transmission
+         and reception as module parameters.  You may need to initialize the
+         the modem using a user space utility (a firmware loader for example).
+
+         To compile this driver as a module, choose M here: the
+         module will be called xusbatm.
+
+endmenu
index 9213b8b975875f149639db5a7345834b3ec8a58b..751f297be2ef3ea275104858d111b08c17e55219 100644 (file)
@@ -1,7 +1,8 @@
 #
-# Makefile for the rest of the USB drivers
-# (the ones that don't fit into any other categories)
+# Makefile for USB ATM/xDSL drivers
 #
 
-obj-$(CONFIG_USB_ATM)          += usb_atm.o
+obj-$(CONFIG_USB_CXACRU)       += cxacru.o
 obj-$(CONFIG_USB_SPEEDTOUCH)   += speedtch.o
+obj-$(CONFIG_USB_ATM)          += usbatm.o
+obj-$(CONFIG_USB_XUSBATM)      += xusbatm.o
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
new file mode 100644 (file)
index 0000000..cbd4a7d
--- /dev/null
@@ -0,0 +1,878 @@
+/******************************************************************************
+ *  cxacru.c  -  driver for USB ADSL modems based on
+ *               Conexant AccessRunner chipset
+ *
+ *  Copyright (C) 2004 David Woodhouse, Duncan Sands, Roman Kagan
+ *  Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with
+ *  this program; if not, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ ******************************************************************************/
+
+/*
+ *  Credit is due for Josep Comas, who created the original patch to speedtch.c
+ *  to support the different padding used by the AccessRunner (now generalized
+ *  into usbatm), and the userspace firmware loading utility.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/device.h>      /* FIXME: linux/firmware.h should include it itself */
+#include <linux/firmware.h>
+
+#include "usbatm.h"
+
+#define DRIVER_AUTHOR  "Roman Kagan, David Woodhouse, Duncan Sands"
+#define DRIVER_VERSION "0.2"
+#define DRIVER_DESC    "Conexant AccessRunner ADSL USB modem driver"
+
+static const char cxacru_driver_name[] = "cxacru";
+
+#define CXACRU_EP_CMD          0x01    /* Bulk/interrupt in/out */
+#define CXACRU_EP_DATA         0x02    /* Bulk in/out */
+
+#define CMD_PACKET_SIZE                64      /* Should be maxpacket(ep)? */
+
+/* Addresses */
+#define PLLFCLK_ADDR   0x00350068
+#define PLLBCLK_ADDR   0x0035006c
+#define SDRAMEN_ADDR   0x00350010
+#define FW_ADDR                0x00801000
+#define BR_ADDR                0x00180600
+#define SIG_ADDR       0x00180500
+#define BR_STACK_ADDR  0x00187f10
+
+/* Values */
+#define SDRAM_ENA      0x1
+
+#define CMD_TIMEOUT    2000    /* msecs */
+#define POLL_INTERVAL  5000    /* msecs */
+
+/* commands for interaction with the modem through the control channel before
+ * firmware is loaded  */
+enum cxacru_fw_request {
+       FW_CMD_ERR,
+       FW_GET_VER,
+       FW_READ_MEM,
+       FW_WRITE_MEM,
+       FW_RMW_MEM,
+       FW_CHECKSUM_MEM,
+       FW_GOTO_MEM,
+};
+
+/* commands for interaction with the modem through the control channel once
+ * firmware is loaded  */
+enum cxacru_cm_request {
+       CM_REQUEST_UNDEFINED = 0x80,
+       CM_REQUEST_TEST,
+       CM_REQUEST_CHIP_GET_MAC_ADDRESS,
+       CM_REQUEST_CHIP_GET_DP_VERSIONS,
+       CM_REQUEST_CHIP_ADSL_LINE_START,
+       CM_REQUEST_CHIP_ADSL_LINE_STOP,
+       CM_REQUEST_CHIP_ADSL_LINE_GET_STATUS,
+       CM_REQUEST_CHIP_ADSL_LINE_GET_SPEED,
+       CM_REQUEST_CARD_INFO_GET,
+       CM_REQUEST_CARD_DATA_GET,
+       CM_REQUEST_CARD_DATA_SET,
+       CM_REQUEST_COMMAND_HW_IO,
+       CM_REQUEST_INTERFACE_HW_IO,
+       CM_REQUEST_CARD_SERIAL_DATA_PATH_GET,
+       CM_REQUEST_CARD_SERIAL_DATA_PATH_SET,
+       CM_REQUEST_CARD_CONTROLLER_VERSION_GET,
+       CM_REQUEST_CARD_GET_STATUS,
+       CM_REQUEST_CARD_GET_MAC_ADDRESS,
+       CM_REQUEST_CARD_GET_DATA_LINK_STATUS,
+       CM_REQUEST_MAX,
+};
+
+/* reply codes to the commands above */
+enum cxacru_cm_status {
+       CM_STATUS_UNDEFINED,
+       CM_STATUS_SUCCESS,
+       CM_STATUS_ERROR,
+       CM_STATUS_UNSUPPORTED,
+       CM_STATUS_UNIMPLEMENTED,
+       CM_STATUS_PARAMETER_ERROR,
+       CM_STATUS_DBG_LOOPBACK,
+       CM_STATUS_MAX,
+};
+
+/* indices into CARD_INFO_GET return array */
+enum cxacru_info_idx {
+       CXINF_DOWNSTREAM_RATE,
+       CXINF_UPSTREAM_RATE,
+       CXINF_LINK_STATUS,
+       CXINF_LINE_STATUS,
+       CXINF_MAC_ADDRESS_HIGH,
+       CXINF_MAC_ADDRESS_LOW,
+       CXINF_UPSTREAM_SNR_MARGIN,
+       CXINF_DOWNSTREAM_SNR_MARGIN,
+       CXINF_UPSTREAM_ATTENUATION,
+       CXINF_DOWNSTREAM_ATTENUATION,
+       CXINF_TRANSMITTER_POWER,
+       CXINF_UPSTREAM_BITS_PER_FRAME,
+       CXINF_DOWNSTREAM_BITS_PER_FRAME,
+       CXINF_STARTUP_ATTEMPTS,
+       CXINF_UPSTREAM_CRC_ERRORS,
+       CXINF_DOWNSTREAM_CRC_ERRORS,
+       CXINF_UPSTREAM_FEC_ERRORS,
+       CXINF_DOWNSTREAM_FEC_ERRORS,
+       CXINF_UPSTREAM_HEC_ERRORS,
+       CXINF_DOWNSTREAM_HEC_ERRORS,
+       CXINF_LINE_STARTABLE,
+       CXINF_MODULATION,
+       CXINF_ADSL_HEADEND,
+       CXINF_ADSL_HEADEND_ENVIRONMENT,
+       CXINF_CONTROLLER_VERSION,
+       /* dunno what the missing two mean */
+       CXINF_MAX = 0x1c,
+};
+
+struct cxacru_modem_type {
+       u32 pll_f_clk;
+       u32 pll_b_clk;
+       int boot_rom_patch;
+};
+
+struct cxacru_data {
+       struct usbatm_data *usbatm;
+
+       const struct cxacru_modem_type *modem_type;
+
+       int line_status;
+       struct work_struct poll_work;
+
+       /* contol handles */
+       struct semaphore cm_serialize;
+       u8 *rcv_buf;
+       u8 *snd_buf;
+       struct urb *rcv_urb;
+       struct urb *snd_urb;
+       struct completion rcv_done;
+       struct completion snd_done;
+};
+
+/* the following three functions are stolen from drivers/usb/core/message.c */
+static void cxacru_blocking_completion(struct urb *urb, struct pt_regs *regs)
+{
+       complete((struct completion *)urb->context);
+}
+
+static void cxacru_timeout_kill(unsigned long data)
+{
+       usb_unlink_urb((struct urb *) data);
+}
+
+static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
+                                int* actual_length)
+{
+       struct timer_list timer;
+       int status;
+
+       init_timer(&timer);
+       timer.expires = jiffies + msecs_to_jiffies(CMD_TIMEOUT);
+       timer.data = (unsigned long) urb;
+       timer.function = cxacru_timeout_kill;
+       add_timer(&timer);
+       wait_for_completion(done);
+       status = urb->status;
+       if (status == -ECONNRESET)
+               status = -ETIMEDOUT;
+       del_timer_sync(&timer);
+
+       if (actual_length)
+               *actual_length = urb->actual_length;
+       return status;
+}
+
+static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
+                    u8 *wdata, int wsize, u8 *rdata, int rsize)
+{
+       int ret, actlen;
+       int offb, offd;
+       const int stride = CMD_PACKET_SIZE - 4;
+       u8 *wbuf = instance->snd_buf;
+       u8 *rbuf = instance->rcv_buf;
+       int wbuflen = ((wsize - 1) / stride + 1) * CMD_PACKET_SIZE;
+       int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
+
+       if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
+               dbg("too big transfer requested");
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       down(&instance->cm_serialize);
+
+       /* submit reading urb before the writing one */
+       init_completion(&instance->rcv_done);
+       ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
+       if (ret < 0) {
+               dbg("submitting read urb for cm %#x failed", cm);
+               ret = ret;
+               goto fail;
+       }
+
+       memset(wbuf, 0, wbuflen);
+       /* handle wsize == 0 */
+       wbuf[0] = cm;
+       for (offb = offd = 0; offd < wsize; offd += stride, offb += CMD_PACKET_SIZE) {
+               wbuf[offb] = cm;
+               memcpy(wbuf + offb + 4, wdata + offd, min_t(int, stride, wsize - offd));
+       }
+
+       instance->snd_urb->transfer_buffer_length = wbuflen;
+       init_completion(&instance->snd_done);
+       ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
+       if (ret < 0) {
+               dbg("submitting write urb for cm %#x failed", cm);
+               ret = ret;
+               goto fail;
+       }
+
+       ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
+       if (ret < 0) {
+               dbg("sending cm %#x failed", cm);
+               ret = ret;
+               goto fail;
+       }
+
+       ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
+       if (ret < 0) {
+               dbg("receiving cm %#x failed", cm);
+               ret = ret;
+               goto fail;
+       }
+       if (actlen % CMD_PACKET_SIZE || !actlen) {
+               dbg("response is not a positive multiple of %d: %#x",
+                               CMD_PACKET_SIZE, actlen);
+               ret = -EIO;
+               goto fail;
+       }
+
+       /* check the return status and copy the data to the output buffer, if needed */
+       for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
+               if (rbuf[offb] != cm) {
+                       dbg("wrong cm %#x in response", rbuf[offb]);
+                       ret = -EIO;
+                       goto fail;
+               }
+               if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
+                       dbg("response failed: %#x", rbuf[offb + 1]);
+                       ret = -EIO;
+                       goto fail;
+               }
+               if (offd >= rsize)
+                       break;
+               memcpy(rdata + offd, rbuf + offb + 4, min_t(int, stride, rsize - offd));
+               offd += stride;
+       }
+
+       ret = offd;
+       dbg("cm %#x", cm);
+fail:
+       up(&instance->cm_serialize);
+       return ret;
+}
+
+static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_request cm,
+                              u32 *data, int size)
+{
+       int ret, len;
+       u32 *buf;
+       int offb, offd;
+       const int stride = CMD_PACKET_SIZE / (4 * 2) - 1;
+       int buflen =  ((size - 1) / stride + 1 + size * 2) * 4;
+
+       buf = kmalloc(buflen, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = cxacru_cm(instance, cm, NULL, 0, (u8 *) buf, buflen);
+       if (ret < 0)
+               goto cleanup;
+
+       /* len > 0 && len % 4 == 0 guaranteed by cxacru_cm() */
+       len = ret / 4;
+       for (offb = 0; offb < len; ) {
+               int l = le32_to_cpu(buf[offb++]);
+               if (l > stride || l > (len - offb) / 2) {
+                       dbg("wrong data length %#x in response", l);
+                       ret = -EIO;
+                       goto cleanup;
+               }
+               while (l--) {
+                       offd = le32_to_cpu(buf[offb++]);
+                       if (offd >= size) {
+                               dbg("wrong index %#x in response", offd);
+                               ret = -EIO;
+                               goto cleanup;
+                       }
+                       data[offd] = le32_to_cpu(buf[offb++]);
+               }
+       }
+
+       ret = 0;
+
+cleanup:
+       kfree(buf);
+       return ret;
+}
+
+static int cxacru_card_status(struct cxacru_data *instance)
+{
+       int ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0);
+       if (ret < 0) {          /* firmware not loaded */
+               dbg("cxacru_adsl_start: CARD_GET_STATUS returned %d", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static void cxacru_poll_status(struct cxacru_data *instance);
+
+static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
+               struct atm_dev *atm_dev)
+{
+       struct cxacru_data *instance = usbatm_instance->driver_data;
+       struct device *dev = &usbatm_instance->usb_intf->dev;
+       /*
+       struct atm_dev *atm_dev = usbatm_instance->atm_dev;
+       */
+       int ret;
+
+       dbg("cxacru_atm_start");
+
+       /* Read MAC address */
+       ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_MAC_ADDRESS, NULL, 0,
+                       atm_dev->esi, sizeof(atm_dev->esi));
+       if (ret < 0) {
+               dev_err(dev, "cxacru_atm_start: CARD_GET_MAC_ADDRESS returned %d\n", ret);
+               return ret;
+       }
+
+       /* start ADSL */
+       ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
+       if (ret < 0) {
+               dev_err(dev, "cxacru_atm_start: CHIP_ADSL_LINE_START returned %d\n", ret);
+               return ret;
+       }
+
+       /* Start status polling */
+       cxacru_poll_status(instance);
+       return 0;
+}
+
+static void cxacru_poll_status(struct cxacru_data *instance)
+{
+       u32 buf[CXINF_MAX] = {};
+       struct device *dev = &instance->usbatm->usb_intf->dev;
+       struct atm_dev *atm_dev = instance->usbatm->atm_dev;
+       int ret;
+
+       ret = cxacru_cm_get_array(instance, CM_REQUEST_CARD_INFO_GET, buf, CXINF_MAX);
+       if (ret < 0) {
+               dev_warn(dev, "poll status: error %d\n", ret);
+               goto reschedule;
+       }
+
+       if (instance->line_status == buf[CXINF_LINE_STATUS])
+               goto reschedule;
+
+       instance->line_status = buf[CXINF_LINE_STATUS];
+       switch (instance->line_status) {
+       case 0:
+               atm_dev->signal = ATM_PHY_SIG_LOST;
+               dev_info(dev, "ADSL line: down\n");
+               break;
+
+       case 1:
+               atm_dev->signal = ATM_PHY_SIG_LOST;
+               dev_info(dev, "ADSL line: attemtping to activate\n");
+               break;
+
+       case 2:
+               atm_dev->signal = ATM_PHY_SIG_LOST;
+               dev_info(dev, "ADSL line: training\n");
+               break;
+
+       case 3:
+               atm_dev->signal = ATM_PHY_SIG_LOST;
+               dev_info(dev, "ADSL line: channel analysis\n");
+               break;
+
+       case 4:
+               atm_dev->signal = ATM_PHY_SIG_LOST;
+               dev_info(dev, "ADSL line: exchange\n");
+               break;
+
+       case 5:
+               atm_dev->link_rate = buf[CXINF_DOWNSTREAM_RATE] * 1000 / 424;
+               atm_dev->signal = ATM_PHY_SIG_FOUND;
+
+               dev_info(dev, "ADSL line: up (%d Kib/s down | %d Kib/s up)\n",
+                    buf[CXINF_DOWNSTREAM_RATE], buf[CXINF_UPSTREAM_RATE]);
+               break;
+
+       case 6:
+               atm_dev->signal = ATM_PHY_SIG_LOST;
+               dev_info(dev, "ADSL line: waiting\n");
+               break;
+
+       case 7:
+               atm_dev->signal = ATM_PHY_SIG_LOST;
+               dev_info(dev, "ADSL line: initializing\n");
+               break;
+
+       default:
+               atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+               dev_info(dev, "Unknown line state %02x\n", instance->line_status);
+               break;
+       }
+reschedule:
+       schedule_delayed_work(&instance->poll_work, msecs_to_jiffies(POLL_INTERVAL));
+}
+
+static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw,
+                    u8 code1, u8 code2, u32 addr, u8 *data, int size)
+{
+       int ret;
+       u8 *buf;
+       int offd, offb;
+       const int stride = CMD_PACKET_SIZE - 8;
+
+       buf = (u8 *) __get_free_page(GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       offb = offd = 0;
+       do {
+               int l = min_t(int, stride, size - offd);
+               buf[offb++] = fw;
+               buf[offb++] = l;
+               buf[offb++] = code1;
+               buf[offb++] = code2;
+               *((u32 *) (buf + offb)) = cpu_to_le32(addr);
+               offb += 4;
+               addr += l;
+               if(l)
+                       memcpy(buf + offb, data + offd, l);
+               if (l < stride)
+                       memset(buf + offb + l, 0, stride - l);
+               offb += stride;
+               offd += stride;
+               if ((offb >= PAGE_SIZE) || (offd >= size)) {
+                       ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD),
+                                          buf, offb, NULL, CMD_TIMEOUT);
+                       if (ret < 0) {
+                               dbg("sending fw %#x failed", fw);
+                               goto cleanup;
+                       }
+                       offb = 0;
+               }
+       } while(offd < size);
+       dbg("sent fw %#x", fw);
+
+       ret = 0;
+
+cleanup:
+       free_page((unsigned long) buf);
+       return ret;
+}
+
+static void cxacru_upload_firmware(struct cxacru_data *instance,
+                                  const struct firmware *fw,
+                                  const struct firmware *bp,
+                                  const struct firmware *cf)
+{
+       int ret;
+       int off;
+       struct usb_device *usb_dev = instance->usbatm->usb_dev;
+       struct device *dev = &instance->usbatm->usb_intf->dev;
+       u16 signature[] = { usb_dev->descriptor.idVendor, usb_dev->descriptor.idProduct };
+       u32 val;
+
+       dbg("cxacru_upload_firmware");
+
+       /* FirmwarePllFClkValue */
+       val = cpu_to_le32(instance->modem_type->pll_f_clk);
+       ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLFCLK_ADDR, (u8 *) &val, 4);
+       if (ret) {
+               dev_err(dev, "FirmwarePllFClkValue failed: %d\n", ret);
+               return;
+       }
+
+       /* FirmwarePllBClkValue */
+       val = cpu_to_le32(instance->modem_type->pll_b_clk);
+       ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLBCLK_ADDR, (u8 *) &val, 4);
+       if (ret) {
+               dev_err(dev, "FirmwarePllBClkValue failed: %d\n", ret);
+               return;
+       }
+
+       /* Enable SDRAM */
+       val = cpu_to_le32(SDRAM_ENA);
+       ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SDRAMEN_ADDR, (u8 *) &val, 4);
+       if (ret) {
+               dev_err(dev, "Enable SDRAM failed: %d\n", ret);
+               return;
+       }
+
+       /* Firmware */
+       ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size);
+       if (ret) {
+               dev_err(dev, "Firmware upload failed: %d\n", ret);
+               return;
+       }
+
+       /* Boot ROM patch */
+       if (instance->modem_type->boot_rom_patch) {
+               ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size);
+               if (ret) {
+                       dev_err(dev, "Boot ROM patching failed: %d\n", ret);
+                       return;
+               }
+       }
+
+       /* Signature */
+       ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SIG_ADDR, (u8 *) signature, 4);
+       if (ret) {
+               dev_err(dev, "Signature storing failed: %d\n", ret);
+               return;
+       }
+
+       if (instance->modem_type->boot_rom_patch) {
+               val = cpu_to_le32(BR_ADDR);
+               ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4);
+       }
+       else {
+               ret = cxacru_fw(usb_dev, FW_GOTO_MEM, 0x0, 0x0, FW_ADDR, NULL, 0);
+       }
+       if (ret) {
+               dev_err(dev, "Passing control to firmware failed: %d\n", ret);
+               return;
+       }
+
+       /* Delay to allow firmware to start up. */
+       msleep_interruptible(1000);
+
+       usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD));
+       usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_CMD));
+       usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_DATA));
+       usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_DATA));
+
+       ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0);
+       if (ret < 0) {
+               dev_err(dev, "modem failed to initialize: %d\n", ret);
+               return;
+       }
+
+       /* Load config data (le32), doing one packet at a time */
+       if (cf)
+               for (off = 0; off < cf->size / 4; ) {
+                       u32 buf[CMD_PACKET_SIZE / 4 - 1];
+                       int i, len = min_t(int, cf->size / 4 - off, CMD_PACKET_SIZE / 4 / 2 - 1);
+                       buf[0] = cpu_to_le32(len);
+                       for (i = 0; i < len; i++, off++) {
+                               buf[i * 2 + 1] = cpu_to_le32(off);
+                               memcpy(buf + i * 2 + 2, cf->data + off * 4, 4);
+                       }
+                       ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET,
+                                       (u8 *) buf, len, NULL, 0);
+                       if (ret < 0) {
+                               dev_err(dev, "load config data failed: %d\n", ret);
+                               return;
+                       }
+               }
+
+       msleep_interruptible(4000);
+}
+
+static int cxacru_find_firmware(struct cxacru_data *instance,
+                               char* phase, const struct firmware **fw_p)
+{
+       struct device *dev = &instance->usbatm->usb_intf->dev;
+       char buf[16];
+
+       sprintf(buf, "cxacru-%s.bin", phase);
+       dbg("cxacru_find_firmware: looking for %s", buf);
+
+       if (request_firmware(fw_p, buf, dev)) {
+               dev_dbg(dev, "no stage %s firmware found\n", phase);
+               return -ENOENT;
+       }
+
+       dev_info(dev, "found firmware %s\n", buf);
+
+       return 0;
+}
+
+static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
+                            struct usb_interface *usb_intf)
+{
+       struct device *dev = &usbatm_instance->usb_intf->dev;
+       const struct firmware *fw, *bp, *cf;
+       struct cxacru_data *instance = usbatm_instance->driver_data;
+
+       int ret = cxacru_find_firmware(instance, "fw", &fw);
+       if (ret) {
+               dev_warn(dev, "firmware (cxacru-fw.bin) unavailable (hotplug misconfiguration?)\n");
+               return ret;
+       }
+
+       if (instance->modem_type->boot_rom_patch) {
+               ret = cxacru_find_firmware(instance, "bp", &bp);
+               if (ret) {
+                       dev_warn(dev, "boot ROM patch (cxacru-bp.bin) unavailable (hotplug misconfiguration?)\n");
+                       release_firmware(fw);
+                       return ret;
+               }
+       }
+
+       if (cxacru_find_firmware(instance, "cf", &cf))          /* optional */
+               cf = NULL;
+
+       cxacru_upload_firmware(instance, fw, bp, cf);
+
+       if (cf)
+               release_firmware(cf);
+       if (instance->modem_type->boot_rom_patch)
+               release_firmware(bp);
+       release_firmware(fw);
+
+       ret = cxacru_card_status(instance);
+       if (ret)
+               dbg("modem initialisation failed");
+       else
+               dbg("done setting up the modem");
+
+       return ret;
+}
+
+static int cxacru_bind(struct usbatm_data *usbatm_instance,
+                      struct usb_interface *intf, const struct usb_device_id *id,
+                      int *need_heavy_init)
+{
+       struct cxacru_data *instance;
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
+       int ret;
+
+       /* instance init */
+       instance = kmalloc(sizeof(*instance), GFP_KERNEL);
+       if (!instance) {
+               dbg("cxacru_bind: no memory for instance data");
+               return -ENOMEM;
+       }
+
+       memset(instance, 0, sizeof(*instance));
+
+       instance->usbatm = usbatm_instance;
+       instance->modem_type = (struct cxacru_modem_type *) id->driver_info;
+
+       instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL);
+       if (!instance->rcv_buf) {
+               dbg("cxacru_bind: no memory for rcv_buf");
+               ret = -ENOMEM;
+               goto fail;
+       }
+       instance->snd_buf = (u8 *) __get_free_page(GFP_KERNEL);
+       if (!instance->snd_buf) {
+               dbg("cxacru_bind: no memory for snd_buf");
+               ret = -ENOMEM;
+               goto fail;
+       }
+       instance->rcv_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!instance->rcv_urb) {
+               dbg("cxacru_bind: no memory for rcv_urb");
+               ret = -ENOMEM;
+               goto fail;
+       }
+       instance->snd_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!instance->snd_urb) {
+               dbg("cxacru_bind: no memory for snd_urb");
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       usb_fill_int_urb(instance->rcv_urb,
+                       usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD),
+                       instance->rcv_buf, PAGE_SIZE,
+                       cxacru_blocking_completion, &instance->rcv_done, 1);
+       instance->rcv_urb->transfer_flags |= URB_ASYNC_UNLINK;
+
+       usb_fill_int_urb(instance->snd_urb,
+                       usb_dev, usb_sndintpipe(usb_dev, CXACRU_EP_CMD),
+                       instance->snd_buf, PAGE_SIZE,
+                       cxacru_blocking_completion, &instance->snd_done, 4);
+       instance->snd_urb->transfer_flags |= URB_ASYNC_UNLINK;
+
+       init_MUTEX(&instance->cm_serialize);
+
+       INIT_WORK(&instance->poll_work, (void *)cxacru_poll_status, instance);
+
+       usbatm_instance->driver_data = instance;
+
+       *need_heavy_init = cxacru_card_status(instance);
+
+       return 0;
+
+ fail:
+       free_page((unsigned long) instance->snd_buf);
+       free_page((unsigned long) instance->rcv_buf);
+       usb_free_urb(instance->snd_urb);
+       usb_free_urb(instance->rcv_urb);
+       kfree(instance);
+
+       return ret;
+}
+
+static void cxacru_unbind(struct usbatm_data *usbatm_instance,
+               struct usb_interface *intf)
+{
+       struct cxacru_data *instance = usbatm_instance->driver_data;
+
+       dbg("cxacru_unbind entered");
+
+       if (!instance) {
+               dbg("cxacru_unbind: NULL instance!");
+               return;
+       }
+
+       while (!cancel_delayed_work(&instance->poll_work))
+              flush_scheduled_work();
+
+       usb_kill_urb(instance->snd_urb);
+       usb_kill_urb(instance->rcv_urb);
+       usb_free_urb(instance->snd_urb);
+       usb_free_urb(instance->rcv_urb);
+
+       free_page((unsigned long) instance->snd_buf);
+       free_page((unsigned long) instance->rcv_buf);
+       kfree(instance);
+
+       usbatm_instance->driver_data = NULL;
+}
+
+static const struct cxacru_modem_type cxacru_cafe = {
+       .pll_f_clk = 0x02d874df,
+       .pll_b_clk = 0x0196a51a,
+       .boot_rom_patch = 1,
+};
+
+static const struct cxacru_modem_type cxacru_cb00 = {
+       .pll_f_clk = 0x5,
+       .pll_b_clk = 0x3,
+       .boot_rom_patch = 0,
+};
+
+static const struct usb_device_id cxacru_usb_ids[] = {
+       { /* V = Conexant                       P = ADSL modem (Euphrates project)      */
+               USB_DEVICE(0x0572, 0xcafe),     .driver_info = (unsigned long) &cxacru_cafe
+       },
+       { /* V = Conexant                       P = ADSL modem (Hasbani project)        */
+               USB_DEVICE(0x0572, 0xcb00),     .driver_info = (unsigned long) &cxacru_cb00
+       },
+       { /* V = Conexant                       P = ADSL modem                          */
+               USB_DEVICE(0x0572, 0xcb01),     .driver_info = (unsigned long) &cxacru_cb00
+       },
+       { /* V = Conexant                       P = ADSL modem                          */
+               USB_DEVICE(0x0572, 0xcb06),     .driver_info = (unsigned long) &cxacru_cb00
+       },
+       { /* V = Olitec                         P = ADSL modem version 2                */
+               USB_DEVICE(0x08e3, 0x0100),     .driver_info = (unsigned long) &cxacru_cafe
+       },
+       { /* V = Olitec                         P = ADSL modem version 3                */
+               USB_DEVICE(0x08e3, 0x0102),     .driver_info = (unsigned long) &cxacru_cb00
+       },
+       { /* V = Trust/Amigo Technology Co.     P = AMX-CA86U                           */
+               USB_DEVICE(0x0eb0, 0x3457),     .driver_info = (unsigned long) &cxacru_cafe
+       },
+       { /* V = Zoom                           P = 5510                                */
+               USB_DEVICE(0x1803, 0x5510),     .driver_info = (unsigned long) &cxacru_cb00
+       },
+       { /* V = Draytek                        P = Vigor 318                           */
+               USB_DEVICE(0x0675, 0x0200),     .driver_info = (unsigned long) &cxacru_cb00
+       },
+       { /* V = Zyxel                          P = 630-C1 aka OMNI ADSL USB (Annex A)  */
+               USB_DEVICE(0x0586, 0x330a),     .driver_info = (unsigned long) &cxacru_cb00
+       },
+       { /* V = Zyxel                          P = 630-C3 aka OMNI ADSL USB (Annex B)  */
+               USB_DEVICE(0x0586, 0x330b),     .driver_info = (unsigned long) &cxacru_cb00
+       },
+       { /* V = Aethra                         P = Starmodem UM1020                    */
+               USB_DEVICE(0x0659, 0x0020),     .driver_info = (unsigned long) &cxacru_cb00
+       },
+       { /* V = Aztech Systems                 P = ? AKA Pirelli AUA-010               */
+               USB_DEVICE(0x0509, 0x0812),     .driver_info = (unsigned long) &cxacru_cb00
+       },
+       { /* V = Netopia                        P = Cayman 3341(Annex A)/3351(Annex B)  */
+               USB_DEVICE(0x100d, 0xcb01),     .driver_info = (unsigned long) &cxacru_cb00
+       },
+       { /* V = Netopia                        P = Cayman 3342(Annex A)/3352(Annex B)  */
+               USB_DEVICE(0x100d, 0x3342),     .driver_info = (unsigned long) &cxacru_cb00
+       },
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, cxacru_usb_ids);
+
+static struct usbatm_driver cxacru_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = cxacru_driver_name,
+       .bind           = cxacru_bind,
+       .heavy_init     = cxacru_heavy_init,
+       .unbind         = cxacru_unbind,
+       .atm_start      = cxacru_atm_start,
+       .in             = CXACRU_EP_DATA,
+       .out            = CXACRU_EP_DATA,
+       .rx_padding     = 3,
+       .tx_padding     = 11,
+};
+
+static int cxacru_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       return usbatm_usb_probe(intf, id, &cxacru_driver);
+}
+
+static struct usb_driver cxacru_usb_driver = {
+       .owner          = THIS_MODULE,
+       .name           = cxacru_driver_name,
+       .probe          = cxacru_usb_probe,
+       .disconnect     = usbatm_usb_disconnect,
+       .id_table       = cxacru_usb_ids
+};
+
+static int __init cxacru_init(void)
+{
+       return usb_register(&cxacru_usb_driver);
+}
+
+static void __exit cxacru_cleanup(void)
+{
+       usb_deregister(&cxacru_usb_driver);
+}
+
+module_init(cxacru_init);
+module_exit(cxacru_cleanup);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
index 2a1697bfd69579c11543931813f10b1dd1ddde0e..6a6eaa2a3b1cc9f6a68e3ad38c6b260cf5702ab9 100644 (file)
@@ -5,6 +5,8 @@
  *  Copyright (C) 2003, Duncan Sands
  *  Copyright (C) 2004, David Woodhouse
  *
+ *  Based on "modem_run.c", copyright (C) 2001, Benoit Papillault
+ *
  *  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)
  *
  ******************************************************************************/
 
-#include <linux/module.h>
-#include <linux/moduleparam.h>
+#include <asm/page.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/firmware.h>
 #include <linux/gfp.h>
+#include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <asm/processor.h>
-#include <asm/uaccess.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <linux/crc32.h>
-#include <linux/init.h>
-#include <linux/firmware.h>
-
-#include "usb_atm.h"
+#include <linux/stat.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
 
-#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
-#      define USE_FW_LOADER
-#endif
+#include "usbatm.h"
 
 #define DRIVER_AUTHOR  "Johan Verrept, Duncan Sands <duncan.sands@free.fr>"
-#define DRIVER_VERSION "1.8"
+#define DRIVER_VERSION "1.9"
 #define DRIVER_DESC    "Alcatel SpeedTouch USB driver version " DRIVER_VERSION
 
 static const char speedtch_driver_name[] = "speedtch";
 
-#define SPEEDTOUCH_VENDORID            0x06b9
-#define SPEEDTOUCH_PRODUCTID           0x4061
+#define CTRL_TIMEOUT 2000      /* milliseconds */
+#define DATA_TIMEOUT 2000      /* milliseconds */
 
-/* Timeout in jiffies */
-#define CTRL_TIMEOUT 2000
-#define DATA_TIMEOUT 2000
+#define OFFSET_7       0               /* size 1 */
+#define OFFSET_b       1               /* size 8 */
+#define OFFSET_d       9               /* size 4 */
+#define OFFSET_e       13              /* size 1 */
+#define OFFSET_f       14              /* size 1 */
+#define TOTAL          15
 
-#define OFFSET_7  0            /* size 1 */
-#define OFFSET_b  1            /* size 8 */
-#define OFFSET_d  9            /* size 4 */
-#define OFFSET_e 13            /* size 1 */
-#define OFFSET_f 14            /* size 1 */
-#define TOTAL    15
+#define SIZE_7         1
+#define SIZE_b         8
+#define SIZE_d         4
+#define SIZE_e         1
+#define SIZE_f         1
 
-#define SIZE_7 1
-#define SIZE_b 8
-#define SIZE_d 4
-#define SIZE_e 1
-#define SIZE_f 1
+#define MIN_POLL_DELAY         5000    /* milliseconds */
+#define MAX_POLL_DELAY         60000   /* milliseconds */
 
-static int dl_512_first = 0;
-static int sw_buffering = 0;
+#define RESUBMIT_DELAY         1000    /* milliseconds */
 
-module_param(dl_512_first, bool, 0444);
-MODULE_PARM_DESC(dl_512_first, "Read 512 bytes before sending firmware");
+#define DEFAULT_ALTSETTING     1
+#define DEFAULT_DL_512_FIRST   0
+#define DEFAULT_SW_BUFFERING   0
 
-module_param(sw_buffering, uint, 0444);
-MODULE_PARM_DESC(sw_buffering, "Enable software buffering");
+static int altsetting = DEFAULT_ALTSETTING;
+static int dl_512_first = DEFAULT_DL_512_FIRST;
+static int sw_buffering = DEFAULT_SW_BUFFERING;
 
-#define UDSL_IOCTL_LINE_UP             1
-#define UDSL_IOCTL_LINE_DOWN           2
+module_param(altsetting, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(altsetting,
+                "Alternative setting for data interface (default: "
+                __MODULE_STRING(DEFAULT_ALTSETTING) ")");
 
-#define SPEEDTCH_ENDPOINT_INT          0x81
-#define SPEEDTCH_ENDPOINT_DATA         0x07
-#define SPEEDTCH_ENDPOINT_FIRMWARE     0x05
+module_param(dl_512_first, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dl_512_first,
+                "Read 512 bytes before sending firmware (default: "
+                __MODULE_STRING(DEFAULT_DL_512_FIRST) ")");
 
-#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
+module_param(sw_buffering, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(sw_buffering,
+                "Enable software buffering (default: "
+                __MODULE_STRING(DEFAULT_SW_BUFFERING) ")");
 
-static struct usb_device_id speedtch_usb_ids[] = {
-       {USB_DEVICE(SPEEDTOUCH_VENDORID, SPEEDTOUCH_PRODUCTID)},
-       {}
-};
+#define ENDPOINT_INT           0x81
+#define ENDPOINT_DATA          0x07
+#define ENDPOINT_FIRMWARE      0x05
 
-MODULE_DEVICE_TABLE(usb, speedtch_usb_ids);
+#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
 
 struct speedtch_instance_data {
-       struct udsl_instance_data u;
+       struct usbatm_data *usbatm;
+
+       struct work_struct status_checker;
 
-       /* Status */
+       int poll_delay; /* milliseconds */
+
+       struct timer_list resubmit_timer;
        struct urb *int_urb;
        unsigned char int_data[16];
-       struct work_struct poll_work;
-       struct timer_list poll_timer;
-};
-/* USB */
-
-static int speedtch_usb_probe(struct usb_interface *intf,
-                             const struct usb_device_id *id);
-static void speedtch_usb_disconnect(struct usb_interface *intf);
-static int speedtch_usb_ioctl(struct usb_interface *intf, unsigned int code,
-                             void *user_data);
-static void speedtch_handle_int(struct urb *urb, struct pt_regs *regs);
-static void speedtch_poll_status(struct speedtch_instance_data *instance);
 
-static struct usb_driver speedtch_usb_driver = {
-       .owner          = THIS_MODULE,
-       .name           = speedtch_driver_name,
-       .probe          = speedtch_usb_probe,
-       .disconnect     = speedtch_usb_disconnect,
-       .ioctl          = speedtch_usb_ioctl,
-       .id_table       = speedtch_usb_ids,
+       unsigned char scratch_buffer[TOTAL];
 };
 
 /***************
 **  firmware  **
 ***************/
 
-static void speedtch_got_firmware(struct speedtch_instance_data *instance,
-                                 int got_it)
+static void speedtch_set_swbuff(struct speedtch_instance_data *instance, int state)
 {
-       int err;
-       struct usb_interface *intf;
-
-       down(&instance->u.serialize);   /* vs self, speedtch_firmware_start */
-       if (instance->u.status == UDSL_LOADED_FIRMWARE)
-               goto out;
-       if (!got_it) {
-               instance->u.status = UDSL_NO_FIRMWARE;
-               goto out;
-       }
-       if ((err = usb_set_interface(instance->u.usb_dev, 1, 1)) < 0) {
-               dbg("speedtch_got_firmware: usb_set_interface returned %d!", err);
-               instance->u.status = UDSL_NO_FIRMWARE;
-               goto out;
-       }
-
-       /* Set up interrupt endpoint */
-       intf = usb_ifnum_to_if(instance->u.usb_dev, 0);
-       if (intf && !usb_driver_claim_interface(&speedtch_usb_driver, intf, NULL)) {
-
-               instance->int_urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (instance->int_urb) {
-
-                       usb_fill_int_urb(instance->int_urb, instance->u.usb_dev,
-                                        usb_rcvintpipe(instance->u.usb_dev, SPEEDTCH_ENDPOINT_INT),
-                                        instance->int_data,
-                                        sizeof(instance->int_data),
-                                        speedtch_handle_int, instance, 50);
-                       err = usb_submit_urb(instance->int_urb, GFP_KERNEL);
-                       if (err) {
-                               /* Doesn't matter; we'll poll anyway */
-                               dbg("speedtch_got_firmware: Submission of interrupt URB failed %d", err);
-                               usb_free_urb(instance->int_urb);
-                               instance->int_urb = NULL;
-                               usb_driver_release_interface(&speedtch_usb_driver, intf);
-                       }
-               }
-       }
-       /* Start status polling */
-       mod_timer(&instance->poll_timer, jiffies + (1 * HZ));
-
-       instance->u.status = UDSL_LOADED_FIRMWARE;
-       tasklet_schedule(&instance->u.receive_tasklet);
- out:
-       up(&instance->u.serialize);
-       wake_up_interruptible(&instance->u.firmware_waiters);
-}
-
-static int speedtch_set_swbuff(struct speedtch_instance_data *instance,
-                              int state)
-{
-       struct usb_device *dev = instance->u.usb_dev;
+       struct usbatm_data *usbatm = instance->usbatm;
+       struct usb_device *usb_dev = usbatm->usb_dev;
        int ret;
 
-       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                             0x32, 0x40, state ? 0x01 : 0x00,
-                             0x00, NULL, 0, 100);
-       if (ret < 0) {
-               printk("Warning: %sabling SW buffering: usb_control_msg returned %d\n",
-                    state ? "En" : "Dis", ret);
-               return ret;
-       }
-
-       dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis");
-       return 0;
+       ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+                             0x32, 0x40, state ? 0x01 : 0x00, 0x00, NULL, 0, CTRL_TIMEOUT);
+       if (ret < 0)
+               usb_warn(usbatm,
+                        "%sabling SW buffering: usb_control_msg returned %d\n",
+                        state ? "En" : "Dis", ret);
+       else
+               dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis");
 }
 
 static void speedtch_test_sequence(struct speedtch_instance_data *instance)
 {
-       struct usb_device *dev = instance->u.usb_dev;
-       unsigned char buf[10];
+       struct usbatm_data *usbatm = instance->usbatm;
+       struct usb_device *usb_dev = usbatm->usb_dev;
+       unsigned char *buf = instance->scratch_buffer;
        int ret;
 
        /* URB 147 */
        buf[0] = 0x1c;
        buf[1] = 0x50;
-       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                             0x01, 0x40, 0x0b, 0x00, buf, 2, 100);
+       ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+                             0x01, 0x40, 0x0b, 0x00, buf, 2, CTRL_TIMEOUT);
        if (ret < 0)
-               printk(KERN_WARNING "%s failed on URB147: %d\n", __func__, ret);
+               usb_warn(usbatm, "%s failed on URB147: %d\n", __func__, ret);
 
        /* URB 148 */
        buf[0] = 0x32;
        buf[1] = 0x00;
-       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                             0x01, 0x40, 0x02, 0x00, buf, 2, 100);
+       ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+                             0x01, 0x40, 0x02, 0x00, buf, 2, CTRL_TIMEOUT);
        if (ret < 0)
-               printk(KERN_WARNING "%s failed on URB148: %d\n", __func__, ret);
+               usb_warn(usbatm, "%s failed on URB148: %d\n", __func__, ret);
 
        /* URB 149 */
        buf[0] = 0x01;
        buf[1] = 0x00;
        buf[2] = 0x01;
-       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                             0x01, 0x40, 0x03, 0x00, buf, 3, 100);
+       ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+                             0x01, 0x40, 0x03, 0x00, buf, 3, CTRL_TIMEOUT);
        if (ret < 0)
-               printk(KERN_WARNING "%s failed on URB149: %d\n", __func__, ret);
+               usb_warn(usbatm, "%s failed on URB149: %d\n", __func__, ret);
 
        /* URB 150 */
        buf[0] = 0x01;
        buf[1] = 0x00;
        buf[2] = 0x01;
-       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                             0x01, 0x40, 0x04, 0x00, buf, 3, 100);
+       ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+                             0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT);
        if (ret < 0)
-               printk(KERN_WARNING "%s failed on URB150: %d\n", __func__, ret);
+               usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret);
 }
 
-static int speedtch_start_synchro(struct speedtch_instance_data *instance)
+static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
+                                    const struct firmware *fw1,
+                                    const struct firmware *fw2)
 {
-       struct usb_device *dev = instance->u.usb_dev;
-       unsigned char buf[2];
-       int ret;
+       unsigned char *buffer;
+       struct usbatm_data *usbatm = instance->usbatm;
+       struct usb_interface *intf;
+       struct usb_device *usb_dev = usbatm->usb_dev;
+       int actual_length;
+       int ret = 0;
+       int offset;
+
+       usb_dbg(usbatm, "%s entered\n", __func__);
+
+       if (!(buffer = (unsigned char *)__get_free_page(GFP_KERNEL))) {
+               ret = -ENOMEM;
+               usb_dbg(usbatm, "%s: no memory for buffer!\n", __func__);
+               goto out;
+       }
+
+       if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
+               ret = -ENODEV;
+               usb_dbg(usbatm, "%s: interface not found!\n", __func__);
+               goto out_free;
+       }
+
+       /* URB 7 */
+       if (dl_512_first) {     /* some modems need a read before writing the firmware */
+               ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
+                                  buffer, 0x200, &actual_length, 2000);
+
+               if (ret < 0 && ret != -ETIMEDOUT)
+                       usb_dbg(usbatm, "%s: read BLOCK0 from modem failed (%d)!\n", __func__, ret);
+               else
+                       usb_dbg(usbatm, "%s: BLOCK0 downloaded (%d bytes)\n", __func__, ret);
+       }
+
+       /* URB 8 : both leds are static green */
+       for (offset = 0; offset < fw1->size; offset += PAGE_SIZE) {
+               int thislen = min_t(int, PAGE_SIZE, fw1->size - offset);
+               memcpy(buffer, fw1->data + offset, thislen);
+
+               ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
+                                  buffer, thislen, &actual_length, DATA_TIMEOUT);
+
+               if (ret < 0) {
+                       usb_dbg(usbatm, "%s: write BLOCK1 to modem failed (%d)!\n", __func__, ret);
+                       goto out_free;
+               }
+               usb_dbg(usbatm, "%s: BLOCK1 uploaded (%zu bytes)\n", __func__, fw1->size);
+       }
+
+       /* USB led blinking green, ADSL led off */
+
+       /* URB 11 */
+       ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
+                          buffer, 0x200, &actual_length, DATA_TIMEOUT);
 
-       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-                             0x12, 0xc0, 0x04, 0x00,
-                             buf, sizeof(buf), CTRL_TIMEOUT);
        if (ret < 0) {
-               printk(KERN_WARNING "SpeedTouch: Failed to start ADSL synchronisation: %d\n", ret);
-               return ret;
+               usb_dbg(usbatm, "%s: read BLOCK2 from modem failed (%d)!\n", __func__, ret);
+               goto out_free;
        }
+       usb_dbg(usbatm, "%s: BLOCK2 downloaded (%d bytes)\n", __func__, actual_length);
 
-       dbg("speedtch_start_synchro: modem prodded. %d Bytes returned: %02x %02x", ret, buf[0], buf[1]);
-       return 0;
+       /* URBs 12 to 139 - USB led blinking green, ADSL led off */
+       for (offset = 0; offset < fw2->size; offset += PAGE_SIZE) {
+               int thislen = min_t(int, PAGE_SIZE, fw2->size - offset);
+               memcpy(buffer, fw2->data + offset, thislen);
+
+               ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
+                                  buffer, thislen, &actual_length, DATA_TIMEOUT);
+
+               if (ret < 0) {
+                       usb_dbg(usbatm, "%s: write BLOCK3 to modem failed (%d)!\n", __func__, ret);
+                       goto out_free;
+               }
+       }
+       usb_dbg(usbatm, "%s: BLOCK3 uploaded (%zu bytes)\n", __func__, fw2->size);
+
+       /* USB led static green, ADSL led static red */
+
+       /* URB 142 */
+       ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
+                          buffer, 0x200, &actual_length, DATA_TIMEOUT);
+
+       if (ret < 0) {
+               usb_dbg(usbatm, "%s: read BLOCK4 from modem failed (%d)!\n", __func__, ret);
+               goto out_free;
+       }
+
+       /* success */
+       usb_dbg(usbatm, "%s: BLOCK4 downloaded (%d bytes)\n", __func__, actual_length);
+
+       /* Delay to allow firmware to start up. We can do this here
+          because we're in our own kernel thread anyway. */
+       msleep_interruptible(1000);
+
+       /* Enable software buffering, if requested */
+       if (sw_buffering)
+               speedtch_set_swbuff(instance, 1);
+
+       /* Magic spell; don't ask us what this does */
+       speedtch_test_sequence(instance);
+
+       ret = 0;
+
+out_free:
+       free_page((unsigned long)buffer);
+out:
+       return ret;
 }
 
-static void speedtch_handle_int(struct urb *urb, struct pt_regs *regs)
+static int speedtch_find_firmware(struct usb_interface *intf, int phase,
+                                 const struct firmware **fw_p)
 {
-       struct speedtch_instance_data *instance = urb->context;
-       unsigned int count = urb->actual_length;
-       int ret;
+       struct device *dev = &intf->dev;
+       const u16 bcdDevice = le16_to_cpu(interface_to_usbdev(intf)->descriptor.bcdDevice);
+       const u8 major_revision = bcdDevice >> 8;
+       const u8 minor_revision = bcdDevice & 0xff;
+       char buf[24];
 
-       /* The magic interrupt for "up state" */
-       const static unsigned char up_int[6]   = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };
-       /* The magic interrupt for "down state" */
-       const static unsigned char down_int[6] = { 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       sprintf(buf, "speedtch-%d.bin.%x.%02x", phase, major_revision, minor_revision);
+       dev_dbg(dev, "%s: looking for %s\n", __func__, buf);
 
-       switch (urb->status) {
-       case 0:
-               /* success */
-               break;
-       case -ECONNRESET:
-       case -ENOENT:
-       case -ESHUTDOWN:
-               /* this urb is terminated; clean up */
-               dbg("%s - urb shutting down with status: %d", __func__, urb->status);
-               return;
-       default:
-               dbg("%s - nonzero urb status received: %d", __func__, urb->status);
-               goto exit;
-       }
+       if (request_firmware(fw_p, buf, dev)) {
+               sprintf(buf, "speedtch-%d.bin.%x", phase, major_revision);
+               dev_dbg(dev, "%s: looking for %s\n", __func__, buf);
 
-       if (count < 6) {
-               dbg("%s - int packet too short", __func__);
-               goto exit;
+               if (request_firmware(fw_p, buf, dev)) {
+                       sprintf(buf, "speedtch-%d.bin", phase);
+                       dev_dbg(dev, "%s: looking for %s\n", __func__, buf);
+
+                       if (request_firmware(fw_p, buf, dev)) {
+                               dev_warn(dev, "no stage %d firmware found!\n", phase);
+                               return -ENOENT;
+                       }
+               }
        }
 
-       if (!memcmp(up_int, instance->int_data, 6)) {
-               del_timer(&instance->poll_timer);
-               printk(KERN_NOTICE "DSL line goes up\n");
-       } else if (!memcmp(down_int, instance->int_data, 6)) {
-               printk(KERN_NOTICE "DSL line goes down\n");
-       } else {
-               int i;
+       dev_info(dev, "found stage %d firmware %s\n", phase, buf);
 
-               printk(KERN_DEBUG "Unknown interrupt packet of %d bytes:", count);
-               for (i = 0; i < count; i++)
-                       printk(" %02x", instance->int_data[i]);
-               printk("\n");
+       return 0;
+}
+
+static int speedtch_heavy_init(struct usbatm_data *usbatm, struct usb_interface *intf)
+{
+       const struct firmware *fw1, *fw2;
+       struct speedtch_instance_data *instance = usbatm->driver_data;
+       int ret;
+
+       if ((ret = speedtch_find_firmware(intf, 1, &fw1)) < 0)
+                       return ret;
+
+       if ((ret = speedtch_find_firmware(intf, 2, &fw2)) < 0) {
+               release_firmware(fw1);
+               return ret;
        }
-       schedule_work(&instance->poll_work);
 
- exit:
-       rmb();
-       if (!instance->int_urb)
-               return;
+       ret = speedtch_upload_firmware(instance, fw1, fw2);
+
+       release_firmware(fw2);
+       release_firmware(fw1);
 
-       ret = usb_submit_urb(urb, GFP_ATOMIC);
-       if (ret)
-               err("%s - usb_submit_urb failed with result %d", __func__, ret);
+       return ret;
 }
 
-static int speedtch_get_status(struct speedtch_instance_data *instance,
-                              unsigned char *buf)
+
+/**********
+**  ATM  **
+**********/
+
+static int speedtch_read_status(struct speedtch_instance_data *instance)
 {
-       struct usb_device *dev = instance->u.usb_dev;
+       struct usbatm_data *usbatm = instance->usbatm;
+       struct usb_device *usb_dev = usbatm->usb_dev;
+       unsigned char *buf = instance->scratch_buffer;
        int ret;
 
        memset(buf, 0, TOTAL);
 
-       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+       ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
                              0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7,
                              CTRL_TIMEOUT);
        if (ret < 0) {
-               dbg("MSG 7 failed");
+               atm_dbg(usbatm, "%s: MSG 7 failed\n", __func__);
                return ret;
        }
 
-       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+       ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
                              0x12, 0xc0, 0x0b, 0x00, buf + OFFSET_b, SIZE_b,
                              CTRL_TIMEOUT);
        if (ret < 0) {
-               dbg("MSG B failed");
+               atm_dbg(usbatm, "%s: MSG B failed\n", __func__);
                return ret;
        }
 
-       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+       ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
                              0x12, 0xc0, 0x0d, 0x00, buf + OFFSET_d, SIZE_d,
                              CTRL_TIMEOUT);
        if (ret < 0) {
-               dbg("MSG D failed");
+               atm_dbg(usbatm, "%s: MSG D failed\n", __func__);
                return ret;
        }
 
-       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+       ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
                              0x01, 0xc0, 0x0e, 0x00, buf + OFFSET_e, SIZE_e,
                              CTRL_TIMEOUT);
        if (ret < 0) {
-               dbg("MSG E failed");
+               atm_dbg(usbatm, "%s: MSG E failed\n", __func__);
                return ret;
        }
 
-       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+       ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
                              0x01, 0xc0, 0x0f, 0x00, buf + OFFSET_f, SIZE_f,
                              CTRL_TIMEOUT);
        if (ret < 0) {
-               dbg("MSG F failed");
+               atm_dbg(usbatm, "%s: MSG F failed\n", __func__);
                return ret;
        }
 
        return 0;
 }
 
-static void speedtch_poll_status(struct speedtch_instance_data *instance)
+static int speedtch_start_synchro(struct speedtch_instance_data *instance)
 {
-       unsigned char buf[TOTAL];
+       struct usbatm_data *usbatm = instance->usbatm;
+       struct usb_device *usb_dev = usbatm->usb_dev;
+       unsigned char *buf = instance->scratch_buffer;
        int ret;
 
-       ret = speedtch_get_status(instance, buf);
-       if (ret) {
-               printk(KERN_WARNING
-                      "SpeedTouch: Error %d fetching device status\n", ret);
+       atm_dbg(usbatm, "%s entered\n", __func__);
+
+       memset(buf, 0, 2);
+
+       ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+                             0x12, 0xc0, 0x04, 0x00,
+                             buf, 2, CTRL_TIMEOUT);
+
+       if (ret < 0)
+               atm_warn(usbatm, "failed to start ADSL synchronisation: %d\n", ret);
+       else
+               atm_dbg(usbatm, "%s: modem prodded. %d bytes returned: %02x %02x\n",
+                       __func__, ret, buf[0], buf[1]);
+
+       return ret;
+}
+
+static void speedtch_check_status(struct speedtch_instance_data *instance)
+{
+       struct usbatm_data *usbatm = instance->usbatm;
+       struct atm_dev *atm_dev = usbatm->atm_dev;
+       unsigned char *buf = instance->scratch_buffer;
+       int ret;
+
+       atm_dbg(usbatm, "%s entered\n", __func__);
+
+       ret = speedtch_read_status(instance);
+       if (ret < 0) {
+               atm_warn(usbatm, "error %d fetching device status\n", ret);
+               if (instance->poll_delay < MAX_POLL_DELAY)
+                       instance->poll_delay *= 2;
                return;
        }
 
-       dbg("Line state %02x", buf[OFFSET_7]);
+       if (instance->poll_delay > MIN_POLL_DELAY)
+               instance->poll_delay /= 2;
+
+       atm_dbg(usbatm, "%s: line state %02x\n", __func__, buf[OFFSET_7]);
 
        switch (buf[OFFSET_7]) {
        case 0:
-               if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) {
-                       instance->u.atm_dev->signal = ATM_PHY_SIG_LOST;
-                       printk(KERN_NOTICE "ADSL line is down\n");
+               if (atm_dev->signal != ATM_PHY_SIG_LOST) {
+                       atm_dev->signal = ATM_PHY_SIG_LOST;
+                       atm_info(usbatm, "ADSL line is down\n");
                        /* It'll never resync again unless we ask it to... */
-                       speedtch_start_synchro(instance);
+                       ret = speedtch_start_synchro(instance);
                }
                break;
 
        case 0x08:
-               if (instance->u.atm_dev->signal != ATM_PHY_SIG_UNKNOWN) {
-                       instance->u.atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
-                       printk(KERN_NOTICE "ADSL line is blocked?\n");
+               if (atm_dev->signal != ATM_PHY_SIG_UNKNOWN) {
+                       atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+                       atm_info(usbatm, "ADSL line is blocked?\n");
                }
                break;
 
        case 0x10:
-               if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) {
-                       instance->u.atm_dev->signal = ATM_PHY_SIG_LOST;
-                       printk(KERN_NOTICE "ADSL line is synchronising\n");
+               if (atm_dev->signal != ATM_PHY_SIG_LOST) {
+                       atm_dev->signal = ATM_PHY_SIG_LOST;
+                       atm_info(usbatm, "ADSL line is synchronising\n");
                }
                break;
 
        case 0x20:
-               if (instance->u.atm_dev->signal != ATM_PHY_SIG_FOUND) {
+               if (atm_dev->signal != ATM_PHY_SIG_FOUND) {
                        int down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8)
                                | (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24);
                        int up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8)
                                | (buf[OFFSET_b + 6] << 16) | (buf[OFFSET_b + 7] << 24);
 
-                       if (!(down_speed & 0x0000ffff) &&
-                           !(up_speed & 0x0000ffff)) {
+                       if (!(down_speed & 0x0000ffff) && !(up_speed & 0x0000ffff)) {
                                down_speed >>= 16;
                                up_speed >>= 16;
                        }
-                       instance->u.atm_dev->link_rate = down_speed * 1000 / 424;
-                       instance->u.atm_dev->signal = ATM_PHY_SIG_FOUND;
 
-                       printk(KERN_NOTICE
-                              "ADSL line is up (%d Kib/s down | %d Kib/s up)\n",
-                              down_speed, up_speed);
+                       atm_dev->link_rate = down_speed * 1000 / 424;
+                       atm_dev->signal = ATM_PHY_SIG_FOUND;
+
+                       atm_info(usbatm,
+                                "ADSL line is up (%d Kib/s down | %d Kib/s up)\n",
+                                down_speed, up_speed);
                }
                break;
 
        default:
-               if (instance->u.atm_dev->signal != ATM_PHY_SIG_UNKNOWN) {
-                       instance->u.atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
-                       printk(KERN_NOTICE "Unknown line state %02x\n", buf[OFFSET_7]);
+               if (atm_dev->signal != ATM_PHY_SIG_UNKNOWN) {
+                       atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+                       atm_info(usbatm, "Unknown line state %02x\n", buf[OFFSET_7]);
                }
                break;
        }
 }
 
-static void speedtch_timer_poll(unsigned long data)
+static void speedtch_status_poll(unsigned long data)
 {
        struct speedtch_instance_data *instance = (void *)data;
 
-       schedule_work(&instance->poll_work);
-       mod_timer(&instance->poll_timer, jiffies + (5 * HZ));
+       schedule_work(&instance->status_checker);
+
+       /* The following check is racy, but the race is harmless */
+       if (instance->poll_delay < MAX_POLL_DELAY)
+               mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(instance->poll_delay));
+       else
+               atm_warn(instance->usbatm, "Too many failures - disabling line status polling\n");
 }
 
-#ifdef USE_FW_LOADER
-static void speedtch_upload_firmware(struct speedtch_instance_data *instance,
-                                    const struct firmware *fw1,
-                                    const struct firmware *fw2)
+static void speedtch_resubmit_int(unsigned long data)
 {
-       unsigned char *buffer;
-       struct usb_device *usb_dev = instance->u.usb_dev;
-       struct usb_interface *intf;
-       int actual_length, ret;
-       int offset;
-
-       dbg("speedtch_upload_firmware");
-
-       if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
-               dbg("speedtch_upload_firmware: interface not found!");
-               goto fail;
-       }
-
-       if (!(buffer = (unsigned char *)__get_free_page(GFP_KERNEL))) {
-               dbg("speedtch_upload_firmware: no memory for buffer!");
-               goto fail;
-       }
-
-       /* A user-space firmware loader may already have claimed interface #2 */
-       if ((ret =
-            usb_driver_claim_interface(&speedtch_usb_driver, intf, NULL)) < 0) {
-               dbg("speedtch_upload_firmware: interface in use (%d)!", ret);
-               goto fail_free;
-       }
-
-       /* URB 7 */
-       if (dl_512_first) {     /* some modems need a read before writing the firmware */
-               ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
-                                  buffer, 0x200, &actual_length, 2000);
-
-               if (ret < 0 && ret != -ETIMEDOUT)
-                       dbg("speedtch_upload_firmware: read BLOCK0 from modem failed (%d)!", ret);
-               else
-                       dbg("speedtch_upload_firmware: BLOCK0 downloaded (%d bytes)", ret);
-       }
-
-       /* URB 8 : both leds are static green */
-       for (offset = 0; offset < fw1->size; offset += PAGE_SIZE) {
-               int thislen = min_t(int, PAGE_SIZE, fw1->size - offset);
-               memcpy(buffer, fw1->data + offset, thislen);
+       struct speedtch_instance_data *instance = (void *)data;
+       struct urb *int_urb = instance->int_urb;
+       int ret;
 
-               ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
-                                  buffer, thislen, &actual_length, DATA_TIMEOUT);
+       atm_dbg(instance->usbatm, "%s entered\n", __func__);
 
-               if (ret < 0) {
-                       dbg("speedtch_upload_firmware: write BLOCK1 to modem failed (%d)!", ret);
-                       goto fail_release;
+       if (int_urb) {
+               ret = usb_submit_urb(int_urb, GFP_ATOMIC);
+               if (!ret)
+                       schedule_work(&instance->status_checker);
+               else {
+                       atm_dbg(instance->usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);
+                       mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY));
                }
-               dbg("speedtch_upload_firmware: BLOCK1 uploaded (%zu bytes)", fw1->size);
        }
+}
 
-       /* USB led blinking green, ADSL led off */
+static void speedtch_handle_int(struct urb *int_urb, struct pt_regs *regs)
+{
+       struct speedtch_instance_data *instance = int_urb->context;
+       struct usbatm_data *usbatm = instance->usbatm;
+       unsigned int count = int_urb->actual_length;
+       int ret = int_urb->status;
 
-       /* URB 11 */
-       ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
-                          buffer, 0x200, &actual_length, DATA_TIMEOUT);
+       /* The magic interrupt for "up state" */
+       const static unsigned char up_int[6]   = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };
+       /* The magic interrupt for "down state" */
+       const static unsigned char down_int[6] = { 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+       atm_dbg(usbatm, "%s entered\n", __func__);
 
        if (ret < 0) {
-               dbg("speedtch_upload_firmware: read BLOCK2 from modem failed (%d)!", ret);
-               goto fail_release;
+               atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, ret);
+               goto fail;
        }
-       dbg("speedtch_upload_firmware: BLOCK2 downloaded (%d bytes)", actual_length);
 
-       /* URBs 12 to 139 - USB led blinking green, ADSL led off */
-       for (offset = 0; offset < fw2->size; offset += PAGE_SIZE) {
-               int thislen = min_t(int, PAGE_SIZE, fw2->size - offset);
-               memcpy(buffer, fw2->data + offset, thislen);
+       if ((count == 6) && !memcmp(up_int, instance->int_data, 6)) {
+               del_timer(&instance->status_checker.timer);
+               atm_info(usbatm, "DSL line goes up\n");
+       } else if ((count == 6) && !memcmp(down_int, instance->int_data, 6)) {
+               atm_info(usbatm, "DSL line goes down\n");
+       } else {
+               int i;
 
-               ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
-                                  buffer, thislen, &actual_length, DATA_TIMEOUT);
+               atm_dbg(usbatm, "%s: unknown interrupt packet of length %d:", __func__, count);
+               for (i = 0; i < count; i++)
+                       printk(" %02x", instance->int_data[i]);
+               printk("\n");
+               goto fail;
+       }
 
+       if ((int_urb = instance->int_urb)) {
+               ret = usb_submit_urb(int_urb, GFP_ATOMIC);
+               schedule_work(&instance->status_checker);
                if (ret < 0) {
-                       dbg("speedtch_upload_firmware: write BLOCK3 to modem failed (%d)!", ret);
-                       goto fail_release;
+                       atm_dbg(usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);
+                       goto fail;
                }
        }
-       dbg("speedtch_upload_firmware: BLOCK3 uploaded (%zu bytes)", fw2->size);
-
-       /* USB led static green, ADSL led static red */
-
-       /* URB 142 */
-       ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
-                          buffer, 0x200, &actual_length, DATA_TIMEOUT);
-
-       if (ret < 0) {
-               dbg("speedtch_upload_firmware: read BLOCK4 from modem failed (%d)!", ret);
-               goto fail_release;
-       }
-
-       /* success */
-       dbg("speedtch_upload_firmware: BLOCK4 downloaded (%d bytes)", actual_length);
-
-       /* Delay to allow firmware to start up. We can do this here
-          because we're in our own kernel thread anyway. */
-       msleep(1000);
-
-       /* Enable software buffering, if requested */
-       if (sw_buffering)
-               speedtch_set_swbuff(instance, 1);
-
-       /* Magic spell; don't ask us what this does */
-       speedtch_test_sequence(instance);
-
-       /* Start modem synchronisation */
-       if (speedtch_start_synchro(instance))
-               dbg("speedtch_start_synchro: failed");
-
-       speedtch_got_firmware(instance, 1);
 
-       free_page((unsigned long)buffer);
        return;
 
- fail_release:
-       /* Only release interface #2 if uploading failed; we don't release it
-          we succeeded.  This prevents the userspace tools from trying to load
-          the firmware themselves */
-       usb_driver_release_interface(&speedtch_usb_driver, intf);
- fail_free:
-       free_page((unsigned long)buffer);
- fail:
-       speedtch_got_firmware(instance, 0);
+fail:
+       if ((int_urb = instance->int_urb))
+               mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY));
 }
 
-static int speedtch_find_firmware(struct speedtch_instance_data
-                                 *instance, int phase,
-                                 const struct firmware **fw_p)
+static int speedtch_atm_start(struct usbatm_data *usbatm, struct atm_dev *atm_dev)
 {
-       char buf[24];
-       const u16 bcdDevice = le16_to_cpu(instance->u.usb_dev->descriptor.bcdDevice);
-       const u8 major_revision = bcdDevice >> 8;
-       const u8 minor_revision = bcdDevice & 0xff;
-
-       sprintf(buf, "speedtch-%d.bin.%x.%02x", phase, major_revision, minor_revision);
-       dbg("speedtch_find_firmware: looking for %s", buf);
-
-       if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) {
-               sprintf(buf, "speedtch-%d.bin.%x", phase, major_revision);
-               dbg("speedtch_find_firmware: looking for %s", buf);
+       struct usb_device *usb_dev = usbatm->usb_dev;
+       struct speedtch_instance_data *instance = usbatm->driver_data;
+       int i, ret;
+       unsigned char mac_str[13];
 
-               if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) {
-                       sprintf(buf, "speedtch-%d.bin", phase);
-                       dbg("speedtch_find_firmware: looking for %s", buf);
+       atm_dbg(usbatm, "%s entered\n", __func__);
 
-                       if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) {
-                               dev_warn(&instance->u.usb_dev->dev, "no stage %d firmware found!", phase);
-                               return -ENOENT;
-                       }
-               }
+       if ((ret = usb_set_interface(usb_dev, 1, altsetting)) < 0) {
+               atm_dbg(usbatm, "%s: usb_set_interface returned %d!\n", __func__, ret);
+               return ret;
        }
 
-       dev_info(&instance->u.usb_dev->dev, "found stage %d firmware %s\n", phase, buf);
-
-       return 0;
-}
-
-static int speedtch_load_firmware(void *arg)
-{
-       const struct firmware *fw1, *fw2;
-       struct speedtch_instance_data *instance = arg;
-
-       BUG_ON(!instance);
+       /* Set MAC address, it is stored in the serial number */
+       memset(atm_dev->esi, 0, sizeof(atm_dev->esi));
+       if (usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) {
+               for (i = 0; i < 6; i++)
+                       atm_dev->esi[i] = (hex2int(mac_str[i * 2]) * 16) + (hex2int(mac_str[i * 2 + 1]));
+       }
 
-       daemonize("firmware/speedtch");
+       /* Start modem synchronisation */
+       ret = speedtch_start_synchro(instance);
 
-       if (!speedtch_find_firmware(instance, 1, &fw1)) {
-               if (!speedtch_find_firmware(instance, 2, &fw2)) {
-                       speedtch_upload_firmware(instance, fw1, fw2);
-                       release_firmware(fw2);
+       /* Set up interrupt endpoint */
+       if (instance->int_urb) {
+               ret = usb_submit_urb(instance->int_urb, GFP_KERNEL);
+               if (ret < 0) {
+                       /* Doesn't matter; we'll poll anyway */
+                       atm_dbg(usbatm, "%s: submission of interrupt URB failed (%d)!\n", __func__, ret);
+                       usb_free_urb(instance->int_urb);
+                       instance->int_urb = NULL;
                }
-               release_firmware(fw1);
        }
 
-       /* In case we failed, set state back to NO_FIRMWARE so that
-          another later attempt may work. Otherwise, we never actually
-          manage to recover if, for example, the firmware is on /usr and
-          we look for it too early. */
-       speedtch_got_firmware(instance, 0);
+       /* Start status polling */
+       mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(1000));
 
-       module_put(THIS_MODULE);
-       udsl_put_instance(&instance->u);
        return 0;
 }
-#endif /* USE_FW_LOADER */
 
-static void speedtch_firmware_start(struct speedtch_instance_data *instance)
+static void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_dev)
 {
-#ifdef USE_FW_LOADER
-       int ret;
-#endif
-
-       dbg("speedtch_firmware_start");
-
-       down(&instance->u.serialize);   /* vs self, speedtch_got_firmware */
-
-       if (instance->u.status >= UDSL_LOADING_FIRMWARE) {
-               up(&instance->u.serialize);
-               return;
-       }
+       struct speedtch_instance_data *instance = usbatm->driver_data;
+       struct urb *int_urb = instance->int_urb;
+
+       atm_dbg(usbatm, "%s entered\n", __func__);
+
+       del_timer_sync(&instance->status_checker.timer);
+
+       /*
+        * Since resubmit_timer and int_urb can schedule themselves and
+        * each other, shutting them down correctly takes some care
+        */
+       instance->int_urb = NULL; /* signal shutdown */
+       mb();
+       usb_kill_urb(int_urb);
+       del_timer_sync(&instance->resubmit_timer);
+       /*
+        * At this point, speedtch_handle_int and speedtch_resubmit_int
+        * can run or be running, but instance->int_urb == NULL means that
+        * they will not reschedule
+        */
+       usb_kill_urb(int_urb);
+       del_timer_sync(&instance->resubmit_timer);
+       usb_free_urb(int_urb);
 
-       instance->u.status = UDSL_LOADING_FIRMWARE;
-       up(&instance->u.serialize);
+       flush_scheduled_work();
+}
 
-#ifdef USE_FW_LOADER
-       udsl_get_instance(&instance->u);
-       try_module_get(THIS_MODULE);
 
-       ret = kernel_thread(speedtch_load_firmware, instance,
-                           CLONE_FS | CLONE_FILES);
+/**********
+**  USB  **
+**********/
 
-       if (ret >= 0)
-               return;         /* OK */
+static struct usb_device_id speedtch_usb_ids[] = {
+       {USB_DEVICE(0x06b9, 0x4061)},
+       {}
+};
 
-       dbg("speedtch_firmware_start: kernel_thread failed (%d)!", ret);
+MODULE_DEVICE_TABLE(usb, speedtch_usb_ids);
 
-       module_put(THIS_MODULE);
-       udsl_put_instance(&instance->u);
-       /* Just pretend it never happened... hope modem_run happens */
-#endif                         /* USE_FW_LOADER */
+static int speedtch_usb_probe(struct usb_interface *, const struct usb_device_id *);
 
-       speedtch_got_firmware(instance, 0);
-}
-
-static int speedtch_firmware_wait(struct udsl_instance_data *instance)
-{
-       speedtch_firmware_start((void *)instance);
+static struct usb_driver speedtch_usb_driver = {
+       .owner          = THIS_MODULE,
+       .name           = speedtch_driver_name,
+       .probe          = speedtch_usb_probe,
+       .disconnect     = usbatm_usb_disconnect,
+       .id_table       = speedtch_usb_ids
+};
 
-       if (wait_event_interruptible(instance->firmware_waiters, instance->status != UDSL_LOADING_FIRMWARE) < 0)
-               return -ERESTARTSYS;
+static void speedtch_release_interfaces(struct usb_device *usb_dev, int num_interfaces) {
+       struct usb_interface *cur_intf;
+       int i;
 
-       return (instance->status == UDSL_LOADED_FIRMWARE) ? 0 : -EAGAIN;
+       for(i = 0; i < num_interfaces; i++)
+               if ((cur_intf = usb_ifnum_to_if(usb_dev, i))) {
+                       usb_set_intfdata(cur_intf, NULL);
+                       usb_driver_release_interface(&speedtch_usb_driver, cur_intf);
+               }
 }
 
-/**********
-**  USB  **
-**********/
-
-static int speedtch_usb_ioctl(struct usb_interface *intf, unsigned int code,
-                             void *user_data)
+static int speedtch_bind(struct usbatm_data *usbatm,
+                        struct usb_interface *intf,
+                        const struct usb_device_id *id,
+                        int *need_heavy_init)
 {
-       struct speedtch_instance_data *instance = usb_get_intfdata(intf);
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
+       struct usb_interface *cur_intf;
+       struct speedtch_instance_data *instance;
+       int ifnum = intf->altsetting->desc.bInterfaceNumber;
+       int num_interfaces = usb_dev->actconfig->desc.bNumInterfaces;
+       int i, ret;
 
-       dbg("speedtch_usb_ioctl entered");
+       usb_dbg(usbatm, "%s entered\n", __func__);
 
-       if (!instance) {
-               dbg("speedtch_usb_ioctl: NULL instance!");
+       if (usb_dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) {
+               usb_dbg(usbatm, "%s: wrong device class %d\n", __func__, usb_dev->descriptor.bDeviceClass);
                return -ENODEV;
        }
 
-       switch (code) {
-       case UDSL_IOCTL_LINE_UP:
-               instance->u.atm_dev->signal = ATM_PHY_SIG_FOUND;
-               speedtch_got_firmware(instance, 1);
-               return (instance->u.status == UDSL_LOADED_FIRMWARE) ? 0 : -EIO;
-       case UDSL_IOCTL_LINE_DOWN:
-               instance->u.atm_dev->signal = ATM_PHY_SIG_LOST;
-               return 0;
-       default:
-               return -ENOTTY;
-       }
-}
+       /* claim all interfaces */
 
-static int speedtch_usb_probe(struct usb_interface *intf,
-                             const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       int ifnum = intf->altsetting->desc.bInterfaceNumber;
-       struct speedtch_instance_data *instance;
-       unsigned char mac_str[13];
-       int ret, i;
-       char buf7[SIZE_7];
+       for (i=0; i < num_interfaces; i++) {
+               cur_intf = usb_ifnum_to_if(usb_dev, i);
 
-       dbg("speedtch_usb_probe: trying device with vendor=0x%x, product=0x%x, ifnum %d",
-           le16_to_cpu(dev->descriptor.idVendor),
-           le16_to_cpu(dev->descriptor.idProduct), ifnum);
+               if ((i != ifnum) && cur_intf) {
+                       ret = usb_driver_claim_interface(&speedtch_usb_driver, cur_intf, usbatm);
 
-       if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) || 
-           (ifnum != 1))
-               return -ENODEV;
-
-       dbg("speedtch_usb_probe: device accepted");
+                       if (ret < 0) {
+                               usb_dbg(usbatm, "%s: failed to claim interface %d (%d)\n", __func__, i, ret);
+                               speedtch_release_interfaces(usb_dev, i);
+                               return ret;
+                       }
+               }
+       }
 
-       /* instance init */
        instance = kmalloc(sizeof(*instance), GFP_KERNEL);
+
        if (!instance) {
-               dbg("speedtch_usb_probe: no memory for instance data!");
-               return -ENOMEM;
+               usb_dbg(usbatm, "%s: no memory for instance data!\n", __func__);
+               ret = -ENOMEM;
+               goto fail_release;
        }
 
        memset(instance, 0, sizeof(struct speedtch_instance_data));
 
-       if ((ret = usb_set_interface(dev, 0, 0)) < 0)
-               goto fail;
+       instance->usbatm = usbatm;
 
-       if ((ret = usb_set_interface(dev, 2, 0)) < 0)
-               goto fail;
+       INIT_WORK(&instance->status_checker, (void *)speedtch_check_status, instance);
 
-       instance->u.data_endpoint = SPEEDTCH_ENDPOINT_DATA;
-       instance->u.firmware_wait = speedtch_firmware_wait;
-       instance->u.driver_name = speedtch_driver_name;
+       instance->status_checker.timer.function = speedtch_status_poll;
+       instance->status_checker.timer.data = (unsigned long)instance;
+       instance->poll_delay = MIN_POLL_DELAY;
 
-       ret = udsl_instance_setup(dev, &instance->u);
-       if (ret)
-               goto fail;
+       init_timer(&instance->resubmit_timer);
+       instance->resubmit_timer.function = speedtch_resubmit_int;
+       instance->resubmit_timer.data = (unsigned long)instance;
 
-       init_timer(&instance->poll_timer);
-       instance->poll_timer.function = speedtch_timer_poll;
-       instance->poll_timer.data = (unsigned long)instance;
+       instance->int_urb = usb_alloc_urb(0, GFP_KERNEL);
 
-       INIT_WORK(&instance->poll_work, (void *)speedtch_poll_status, instance);
+       if (instance->int_urb)
+               usb_fill_int_urb(instance->int_urb, usb_dev,
+                                usb_rcvintpipe(usb_dev, ENDPOINT_INT),
+                                instance->int_data, sizeof(instance->int_data),
+                                speedtch_handle_int, instance, 50);
+       else
+               usb_dbg(usbatm, "%s: no memory for interrupt urb!\n", __func__);
 
-       /* set MAC address, it is stored in the serial number */
-       memset(instance->u.atm_dev->esi, 0, sizeof(instance->u.atm_dev->esi));
-       if (usb_string(dev, dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) {
-               for (i = 0; i < 6; i++)
-                       instance->u.atm_dev->esi[i] =
-                               (hex2int(mac_str[i * 2]) * 16) + (hex2int(mac_str[i * 2 + 1]));
-       }
+       /* check whether the modem already seems to be alive */
+       ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+                             0x12, 0xc0, 0x07, 0x00,
+                             instance->scratch_buffer + OFFSET_7, SIZE_7, 500);
 
-       /* First check whether the modem already seems to be alive */
-       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-                             0x12, 0xc0, 0x07, 0x00, buf7, SIZE_7, 500);
+       *need_heavy_init = (ret != SIZE_7);
 
-       if (ret == SIZE_7) {
-               dbg("firmware appears to be already loaded");
-               speedtch_got_firmware(instance, 1);
-               speedtch_poll_status(instance);
-       } else {
-               speedtch_firmware_start(instance);
-       }
+       usb_dbg(usbatm, "%s: firmware %s loaded\n", __func__, need_heavy_init ? "not" : "already");
+
+       if (*need_heavy_init)
+               if ((ret = usb_reset_device(usb_dev)) < 0)
+                       goto fail_free;
 
-       usb_set_intfdata(intf, instance);
+        usbatm->driver_data = instance;
 
        return 0;
 
- fail:
+fail_free:
+       usb_free_urb(instance->int_urb);
        kfree(instance);
-
-       return -ENOMEM;
+fail_release:
+       speedtch_release_interfaces(usb_dev, num_interfaces);
+       return ret;
 }
 
-static void speedtch_usb_disconnect(struct usb_interface *intf)
+static void speedtch_unbind(struct usbatm_data *usbatm, struct usb_interface *intf)
 {
-       struct speedtch_instance_data *instance = usb_get_intfdata(intf);
-
-       dbg("speedtch_usb_disconnect entered");
-
-       if (!instance) {
-               dbg("speedtch_usb_disconnect: NULL instance!");
-               return;
-       }
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
+       struct speedtch_instance_data *instance = usbatm->driver_data;
 
-/*QQ need to handle disconnects on interface #2 while uploading firmware */
-/*QQ and what about interface #1? */
-
-       if (instance->int_urb) {
-               struct urb *int_urb = instance->int_urb;
-               instance->int_urb = NULL;
-               wmb();
-               usb_unlink_urb(int_urb);
-               usb_free_urb(int_urb);
-       }
+       usb_dbg(usbatm, "%s entered\n", __func__);
 
-       instance->int_data[0] = 1;
-       del_timer_sync(&instance->poll_timer);
-       wmb();
-       flush_scheduled_work();
-
-       udsl_instance_disconnect(&instance->u);
-
-       /* clean up */
-       usb_set_intfdata(intf, NULL);
-       udsl_put_instance(&instance->u);
+       speedtch_release_interfaces(usb_dev, usb_dev->actconfig->desc.bNumInterfaces);
+       usb_free_urb(instance->int_urb);
+       kfree(instance);
 }
 
+
 /***********
 **  init  **
 ***********/
 
+static struct usbatm_driver speedtch_usbatm_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = speedtch_driver_name,
+       .bind           = speedtch_bind,
+       .heavy_init     = speedtch_heavy_init,
+       .unbind         = speedtch_unbind,
+       .atm_start      = speedtch_atm_start,
+       .atm_stop       = speedtch_atm_stop,
+       .in             = ENDPOINT_DATA,
+       .out            = ENDPOINT_DATA
+};
+
+static int speedtch_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       return usbatm_usb_probe(intf, id, &speedtch_usbatm_driver);
+}
+
 static int __init speedtch_usb_init(void)
 {
-       dbg("speedtch_usb_init: driver version " DRIVER_VERSION);
+       dbg("%s: driver version %s", __func__, DRIVER_VERSION);
 
        return usb_register(&speedtch_usb_driver);
 }
 
 static void __exit speedtch_usb_cleanup(void)
 {
-       dbg("speedtch_usb_cleanup entered");
+       dbg("%s", __func__);
 
        usb_deregister(&speedtch_usb_driver);
 }
diff --git a/drivers/usb/atm/usb_atm.c b/drivers/usb/atm/usb_atm.c
deleted file mode 100644 (file)
index a4cd447..0000000
+++ /dev/null
@@ -1,1188 +0,0 @@
-/******************************************************************************
- *  usb_atm.c - Generic USB xDSL driver core
- *
- *  Copyright (C) 2001, Alcatel
- *  Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
- *  Copyright (C) 2004, David Woodhouse
- *
- *  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.
- *
- ******************************************************************************/
-
-/*
- *  Written by Johan Verrept, maintained by Duncan Sands (duncan.sands@free.fr)
- *
- *  1.7+:      - See the check-in logs
- *
- *  1.6:       - No longer opens a connection if the firmware is not loaded
- *             - Added support for the speedtouch 330
- *             - Removed the limit on the number of devices
- *             - Module now autoloads on device plugin
- *             - Merged relevant parts of sarlib
- *             - Replaced the kernel thread with a tasklet
- *             - New packet transmission code
- *             - Changed proc file contents
- *             - Fixed all known SMP races
- *             - Many fixes and cleanups
- *             - Various fixes by Oliver Neukum (oliver@neukum.name)
- *
- *  1.5A:      - Version for inclusion in 2.5 series kernel
- *             - Modifications by Richard Purdie (rpurdie@rpsys.net)
- *             - made compatible with kernel 2.5.6 onwards by changing
- *             udsl_usb_send_data_context->urb to a pointer and adding code
- *             to alloc and free it
- *             - remove_wait_queue() added to udsl_atm_processqueue_thread()
- *
- *  1.5:       - fixed memory leak when atmsar_decode_aal5 returned NULL.
- *             (reported by stephen.robinson@zen.co.uk)
- *
- *  1.4:       - changed the spin_lock() under interrupt to spin_lock_irqsave()
- *             - unlink all active send urbs of a vcc that is being closed.
- *
- *  1.3.1:     - added the version number
- *
- *  1.3:       - Added multiple send urb support
- *             - fixed memory leak and vcc->tx_inuse starvation bug
- *               when not enough memory left in vcc.
- *
- *  1.2:       - Fixed race condition in udsl_usb_send_data()
- *  1.1:       - Turned off packet debugging
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <asm/uaccess.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <linux/crc32.h>
-#include <linux/init.h>
-#include <linux/firmware.h>
-
-#include "usb_atm.h"
-
-#ifdef VERBOSE_DEBUG
-static int udsl_print_packet(const unsigned char *data, int len);
-#define PACKETDEBUG(arg...)    udsl_print_packet (arg)
-#define vdbg(arg...)           dbg (arg)
-#else
-#define PACKETDEBUG(arg...)
-#define vdbg(arg...)
-#endif
-
-#define DRIVER_AUTHOR  "Johan Verrept, Duncan Sands <duncan.sands@free.fr>"
-#define DRIVER_VERSION "1.8"
-#define DRIVER_DESC    "Generic USB ATM/DSL I/O, version " DRIVER_VERSION
-
-static unsigned int num_rcv_urbs = UDSL_DEFAULT_RCV_URBS;
-static unsigned int num_snd_urbs = UDSL_DEFAULT_SND_URBS;
-static unsigned int num_rcv_bufs = UDSL_DEFAULT_RCV_BUFS;
-static unsigned int num_snd_bufs = UDSL_DEFAULT_SND_BUFS;
-static unsigned int rcv_buf_size = UDSL_DEFAULT_RCV_BUF_SIZE;
-static unsigned int snd_buf_size = UDSL_DEFAULT_SND_BUF_SIZE;
-
-module_param(num_rcv_urbs, uint, 0444);
-MODULE_PARM_DESC(num_rcv_urbs,
-                "Number of urbs used for reception (range: 0-"
-                __MODULE_STRING(UDSL_MAX_RCV_URBS) ", default: "
-                __MODULE_STRING(UDSL_DEFAULT_RCV_URBS) ")");
-
-module_param(num_snd_urbs, uint, 0444);
-MODULE_PARM_DESC(num_snd_urbs,
-                "Number of urbs used for transmission (range: 0-"
-                __MODULE_STRING(UDSL_MAX_SND_URBS) ", default: "
-                __MODULE_STRING(UDSL_DEFAULT_SND_URBS) ")");
-
-module_param(num_rcv_bufs, uint, 0444);
-MODULE_PARM_DESC(num_rcv_bufs,
-                "Number of buffers used for reception (range: 0-"
-                __MODULE_STRING(UDSL_MAX_RCV_BUFS) ", default: "
-                __MODULE_STRING(UDSL_DEFAULT_RCV_BUFS) ")");
-
-module_param(num_snd_bufs, uint, 0444);
-MODULE_PARM_DESC(num_snd_bufs,
-                "Number of buffers used for transmission (range: 0-"
-                __MODULE_STRING(UDSL_MAX_SND_BUFS) ", default: "
-                __MODULE_STRING(UDSL_DEFAULT_SND_BUFS) ")");
-
-module_param(rcv_buf_size, uint, 0444);
-MODULE_PARM_DESC(rcv_buf_size,
-                "Size of the buffers used for reception (range: 0-"
-                __MODULE_STRING(UDSL_MAX_RCV_BUF_SIZE) ", default: "
-                __MODULE_STRING(UDSL_DEFAULT_RCV_BUF_SIZE) ")");
-
-module_param(snd_buf_size, uint, 0444);
-MODULE_PARM_DESC(snd_buf_size,
-                "Size of the buffers used for transmission (range: 0-"
-                __MODULE_STRING(UDSL_MAX_SND_BUF_SIZE) ", default: "
-                __MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")");
-
-/* ATM */
-
-static void udsl_atm_dev_close(struct atm_dev *dev);
-static int udsl_atm_open(struct atm_vcc *vcc);
-static void udsl_atm_close(struct atm_vcc *vcc);
-static int udsl_atm_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg);
-static int udsl_atm_send(struct atm_vcc *vcc, struct sk_buff *skb);
-static int udsl_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page);
-
-static struct atmdev_ops udsl_atm_devops = {
-       .dev_close      = udsl_atm_dev_close,
-       .open           = udsl_atm_open,
-       .close          = udsl_atm_close,
-       .ioctl          = udsl_atm_ioctl,
-       .send           = udsl_atm_send,
-       .proc_read      = udsl_atm_proc_read,
-       .owner          = THIS_MODULE,
-};
-
-/***********
-**  misc  **
-***********/
-
-static inline void udsl_pop(struct atm_vcc *vcc, struct sk_buff *skb)
-{
-       if (vcc->pop)
-               vcc->pop(vcc, skb);
-       else
-               dev_kfree_skb(skb);
-}
-
-/*************
-**  decode  **
-*************/
-
-static inline struct udsl_vcc_data *udsl_find_vcc(struct udsl_instance_data *instance,
-                                                 short vpi, int vci)
-{
-       struct udsl_vcc_data *vcc;
-
-       list_for_each_entry(vcc, &instance->vcc_list, list)
-               if ((vcc->vci == vci) && (vcc->vpi == vpi))
-                       return vcc;
-       return NULL;
-}
-
-static void udsl_extract_cells(struct udsl_instance_data *instance,
-                              unsigned char *source, unsigned int howmany)
-{
-       struct udsl_vcc_data *cached_vcc = NULL;
-       struct atm_vcc *vcc;
-       struct sk_buff *sarb;
-       struct udsl_vcc_data *vcc_data;
-       int cached_vci = 0;
-       unsigned int i;
-       int pti;
-       int vci;
-       short cached_vpi = 0;
-       short vpi;
-
-       for (i = 0; i < howmany;
-            i++, source += ATM_CELL_SIZE + instance->rcv_padding) {
-               vpi = ((source[0] & 0x0f) << 4) | (source[1] >> 4);
-               vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
-               pti = (source[3] & 0x2) != 0;
-
-               vdbg("udsl_extract_cells: vpi %hd, vci %d, pti %d", vpi, vci, pti);
-
-               if (cached_vcc && (vci == cached_vci) && (vpi == cached_vpi))
-                       vcc_data = cached_vcc;
-               else if ((vcc_data = udsl_find_vcc(instance, vpi, vci))) {
-                       cached_vcc = vcc_data;
-                       cached_vpi = vpi;
-                       cached_vci = vci;
-               } else {
-                       dbg("udsl_extract_cells: unknown vpi/vci (%hd/%d)!", vpi, vci);
-                       continue;
-               }
-
-               vcc = vcc_data->vcc;
-               sarb = vcc_data->sarb;
-
-               if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) {
-                       dbg("udsl_extract_cells: buffer overrun (sarb->len %u, vcc: 0x%p)!", sarb->len, vcc);
-                       /* discard cells already received */
-                       skb_trim(sarb, 0);
-               }
-
-               memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
-               __skb_put(sarb, ATM_CELL_PAYLOAD);
-
-               if (pti) {
-                       struct sk_buff *skb;
-                       unsigned int length;
-                       unsigned int pdu_length;
-
-                       length = (source[ATM_CELL_SIZE - 6] << 8) + source[ATM_CELL_SIZE - 5];
-
-                       /* guard against overflow */
-                       if (length > ATM_MAX_AAL5_PDU) {
-                               dbg("udsl_extract_cells: bogus length %u (vcc: 0x%p)!", length, vcc);
-                               atomic_inc(&vcc->stats->rx_err);
-                               goto out;
-                       }
-
-                       pdu_length = UDSL_NUM_CELLS(length) * ATM_CELL_PAYLOAD;
-
-                       if (sarb->len < pdu_length) {
-                               dbg("udsl_extract_cells: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!", pdu_length, sarb->len, vcc);
-                               atomic_inc(&vcc->stats->rx_err);
-                               goto out;
-                       }
-
-                       if (crc32_be(~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) {
-                               dbg("udsl_extract_cells: packet failed crc check (vcc: 0x%p)!", vcc);
-                               atomic_inc(&vcc->stats->rx_err);
-                               goto out;
-                       }
-
-                       vdbg("udsl_extract_cells: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", length, pdu_length, vcc);
-
-                       if (!(skb = dev_alloc_skb(length))) {
-                               dbg("udsl_extract_cells: no memory for skb (length: %u)!", length);
-                               atomic_inc(&vcc->stats->rx_drop);
-                               goto out;
-                       }
-
-                       vdbg("udsl_extract_cells: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", skb, skb->truesize);
-
-                       if (!atm_charge(vcc, skb->truesize)) {
-                               dbg("udsl_extract_cells: failed atm_charge (skb->truesize: %u)!", skb->truesize);
-                               dev_kfree_skb(skb);
-                               goto out;       /* atm_charge increments rx_drop */
-                       }
-
-                       memcpy(skb->data, sarb->tail - pdu_length, length);
-                       __skb_put(skb, length);
-
-                       vdbg("udsl_extract_cells: sending skb 0x%p, skb->len %u, skb->truesize %u", skb, skb->len, skb->truesize);
-
-                       PACKETDEBUG(skb->data, skb->len);
-
-                       vcc->push(vcc, skb);
-
-                       atomic_inc(&vcc->stats->rx);
-               out:
-                       skb_trim(sarb, 0);
-               }
-       }
-}
-
-/*************
-**  encode  **
-*************/
-
-static inline void udsl_fill_cell_header(unsigned char *target, struct atm_vcc *vcc)
-{
-       target[0] = vcc->vpi >> 4;
-       target[1] = (vcc->vpi << 4) | (vcc->vci >> 12);
-       target[2] = vcc->vci >> 4;
-       target[3] = vcc->vci << 4;
-       target[4] = 0xec;
-}
-
-static const unsigned char zeros[ATM_CELL_PAYLOAD];
-
-static void udsl_groom_skb(struct atm_vcc *vcc, struct sk_buff *skb)
-{
-       struct udsl_control *ctrl = UDSL_SKB(skb);
-       unsigned int zero_padding;
-       u32 crc;
-
-       ctrl->atm_data.vcc = vcc;
-
-       ctrl->num_cells = UDSL_NUM_CELLS(skb->len);
-       ctrl->num_entire = skb->len / ATM_CELL_PAYLOAD;
-
-       zero_padding = ctrl->num_cells * ATM_CELL_PAYLOAD - skb->len - ATM_AAL5_TRAILER;
-
-       if (ctrl->num_entire + 1 < ctrl->num_cells)
-               ctrl->pdu_padding = zero_padding - (ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
-       else
-               ctrl->pdu_padding = zero_padding;
-
-       ctrl->aal5_trailer[0] = 0;      /* UU = 0 */
-       ctrl->aal5_trailer[1] = 0;      /* CPI = 0 */
-       ctrl->aal5_trailer[2] = skb->len >> 8;
-       ctrl->aal5_trailer[3] = skb->len;
-
-       crc = crc32_be(~0, skb->data, skb->len);
-       crc = crc32_be(crc, zeros, zero_padding);
-       crc = crc32_be(crc, ctrl->aal5_trailer, 4);
-       crc = ~crc;
-
-       ctrl->aal5_trailer[4] = crc >> 24;
-       ctrl->aal5_trailer[5] = crc >> 16;
-       ctrl->aal5_trailer[6] = crc >> 8;
-       ctrl->aal5_trailer[7] = crc;
-}
-
-static unsigned int udsl_write_cells(struct udsl_instance_data *instance,
-                                    unsigned int howmany, struct sk_buff *skb,
-                                    unsigned char **target_p)
-{
-       struct udsl_control *ctrl = UDSL_SKB(skb);
-       unsigned char *target = *target_p;
-       unsigned int nc, ne, i;
-
-       vdbg("udsl_write_cells: howmany=%u, skb->len=%d, num_cells=%u, num_entire=%u, pdu_padding=%u", howmany, skb->len, ctrl->num_cells, ctrl->num_entire, ctrl->pdu_padding);
-
-       nc = ctrl->num_cells;
-       ne = min(howmany, ctrl->num_entire);
-
-       for (i = 0; i < ne; i++) {
-               udsl_fill_cell_header(target, ctrl->atm_data.vcc);
-               target += ATM_CELL_HEADER;
-               memcpy(target, skb->data, ATM_CELL_PAYLOAD);
-               target += ATM_CELL_PAYLOAD;
-               if (instance->snd_padding) {
-                       memset(target, 0, instance->snd_padding);
-                       target += instance->snd_padding;
-               }
-               __skb_pull(skb, ATM_CELL_PAYLOAD);
-       }
-
-       ctrl->num_entire -= ne;
-
-       if (!(ctrl->num_cells -= ne) || !(howmany -= ne))
-               goto out;
-
-       udsl_fill_cell_header(target, ctrl->atm_data.vcc);
-       target += ATM_CELL_HEADER;
-       memcpy(target, skb->data, skb->len);
-       target += skb->len;
-       __skb_pull(skb, skb->len);
-       memset(target, 0, ctrl->pdu_padding);
-       target += ctrl->pdu_padding;
-
-       if (--ctrl->num_cells) {
-               if (!--howmany) {
-                       ctrl->pdu_padding = ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
-                       goto out;
-               }
-
-               if (instance->snd_padding) {
-                       memset(target, 0, instance->snd_padding);
-                       target += instance->snd_padding;
-               }
-               udsl_fill_cell_header(target, ctrl->atm_data.vcc);
-               target += ATM_CELL_HEADER;
-               memset(target, 0, ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
-               target += ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
-
-               --ctrl->num_cells;
-               UDSL_ASSERT(!ctrl->num_cells);
-       }
-
-       memcpy(target, ctrl->aal5_trailer, ATM_AAL5_TRAILER);
-       target += ATM_AAL5_TRAILER;
-       /* set pti bit in last cell */
-       *(target + 3 - ATM_CELL_SIZE) |= 0x2;
-       if (instance->snd_padding) {
-               memset(target, 0, instance->snd_padding);
-               target += instance->snd_padding;
-       }
- out:
-       *target_p = target;
-       return nc - ctrl->num_cells;
-}
-
-/**************
-**  receive  **
-**************/
-
-static void udsl_complete_receive(struct urb *urb, struct pt_regs *regs)
-{
-       struct udsl_receive_buffer *buf;
-       struct udsl_instance_data *instance;
-       struct udsl_receiver *rcv;
-       unsigned long flags;
-
-       if (!urb || !(rcv = urb->context)) {
-               dbg("udsl_complete_receive: bad urb!");
-               return;
-       }
-
-       instance = rcv->instance;
-       buf = rcv->buffer;
-
-       buf->filled_cells = urb->actual_length / (ATM_CELL_SIZE + instance->rcv_padding);
-
-       vdbg("udsl_complete_receive: urb 0x%p, status %d, actual_length %d, filled_cells %u, rcv 0x%p, buf 0x%p", urb, urb->status, urb->actual_length, buf->filled_cells, rcv, buf);
-
-       UDSL_ASSERT(buf->filled_cells <= rcv_buf_size);
-
-       /* may not be in_interrupt() */
-       spin_lock_irqsave(&instance->receive_lock, flags);
-       list_add(&rcv->list, &instance->spare_receivers);
-       list_add_tail(&buf->list, &instance->filled_receive_buffers);
-       if (likely(!urb->status))
-               tasklet_schedule(&instance->receive_tasklet);
-       spin_unlock_irqrestore(&instance->receive_lock, flags);
-}
-
-static void udsl_process_receive(unsigned long data)
-{
-       struct udsl_receive_buffer *buf;
-       struct udsl_instance_data *instance = (struct udsl_instance_data *)data;
-       struct udsl_receiver *rcv;
-       int err;
-
- made_progress:
-       while (!list_empty(&instance->spare_receive_buffers)) {
-               spin_lock_irq(&instance->receive_lock);
-               if (list_empty(&instance->spare_receivers)) {
-                       spin_unlock_irq(&instance->receive_lock);
-                       break;
-               }
-               rcv = list_entry(instance->spare_receivers.next,
-                                struct udsl_receiver, list);
-               list_del(&rcv->list);
-               spin_unlock_irq(&instance->receive_lock);
-
-               buf = list_entry(instance->spare_receive_buffers.next,
-                                struct udsl_receive_buffer, list);
-               list_del(&buf->list);
-
-               rcv->buffer = buf;
-
-               usb_fill_bulk_urb(rcv->urb, instance->usb_dev,
-                                 usb_rcvbulkpipe(instance->usb_dev, instance->data_endpoint),
-                                 buf->base,
-                                 rcv_buf_size * (ATM_CELL_SIZE + instance->rcv_padding),
-                                 udsl_complete_receive, rcv);
-
-               vdbg("udsl_process_receive: sending urb 0x%p, rcv 0x%p, buf 0x%p",
-                    rcv->urb, rcv, buf);
-
-               if ((err = usb_submit_urb(rcv->urb, GFP_ATOMIC)) < 0) {
-                       dbg("udsl_process_receive: urb submission failed (%d)!", err);
-                       list_add(&buf->list, &instance->spare_receive_buffers);
-                       spin_lock_irq(&instance->receive_lock);
-                       list_add(&rcv->list, &instance->spare_receivers);
-                       spin_unlock_irq(&instance->receive_lock);
-                       break;
-               }
-       }
-
-       spin_lock_irq(&instance->receive_lock);
-       if (list_empty(&instance->filled_receive_buffers)) {
-               spin_unlock_irq(&instance->receive_lock);
-               return;         /* done - no more buffers */
-       }
-       buf = list_entry(instance->filled_receive_buffers.next,
-                        struct udsl_receive_buffer, list);
-       list_del(&buf->list);
-       spin_unlock_irq(&instance->receive_lock);
-
-       vdbg("udsl_process_receive: processing buf 0x%p", buf);
-       udsl_extract_cells(instance, buf->base, buf->filled_cells);
-       list_add(&buf->list, &instance->spare_receive_buffers);
-       goto made_progress;
-}
-
-/***********
-**  send  **
-***********/
-
-static void udsl_complete_send(struct urb *urb, struct pt_regs *regs)
-{
-       struct udsl_instance_data *instance;
-       struct udsl_sender *snd;
-       unsigned long flags;
-
-       if (!urb || !(snd = urb->context) || !(instance = snd->instance)) {
-               dbg("udsl_complete_send: bad urb!");
-               return;
-       }
-
-       vdbg("udsl_complete_send: urb 0x%p, status %d, snd 0x%p, buf 0x%p", urb,
-            urb->status, snd, snd->buffer);
-
-       /* may not be in_interrupt() */
-       spin_lock_irqsave(&instance->send_lock, flags);
-       list_add(&snd->list, &instance->spare_senders);
-       list_add(&snd->buffer->list, &instance->spare_send_buffers);
-       tasklet_schedule(&instance->send_tasklet);
-       spin_unlock_irqrestore(&instance->send_lock, flags);
-}
-
-static void udsl_process_send(unsigned long data)
-{
-       struct udsl_send_buffer *buf;
-       struct udsl_instance_data *instance = (struct udsl_instance_data *)data;
-       struct sk_buff *skb;
-       struct udsl_sender *snd;
-       int err;
-       unsigned int num_written;
-
- made_progress:
-       spin_lock_irq(&instance->send_lock);
-       while (!list_empty(&instance->spare_senders)) {
-               if (!list_empty(&instance->filled_send_buffers)) {
-                       buf = list_entry(instance->filled_send_buffers.next,
-                                        struct udsl_send_buffer, list);
-                       list_del(&buf->list);
-               } else if ((buf = instance->current_buffer)) {
-                       instance->current_buffer = NULL;
-               } else          /* all buffers empty */
-                       break;
-
-               snd = list_entry(instance->spare_senders.next,
-                                struct udsl_sender, list);
-               list_del(&snd->list);
-               spin_unlock_irq(&instance->send_lock);
-
-               snd->buffer = buf;
-               usb_fill_bulk_urb(snd->urb, instance->usb_dev,
-                                 usb_sndbulkpipe(instance->usb_dev, instance->data_endpoint),
-                                 buf->base,
-                                 (snd_buf_size - buf->free_cells) * (ATM_CELL_SIZE + instance->snd_padding),
-                                 udsl_complete_send, snd);
-
-               vdbg("udsl_process_send: submitting urb 0x%p (%d cells), snd 0x%p, buf 0x%p",
-                    snd->urb, snd_buf_size - buf->free_cells, snd, buf);
-
-               if ((err = usb_submit_urb(snd->urb, GFP_ATOMIC)) < 0) {
-                       dbg("udsl_process_send: urb submission failed (%d)!", err);
-                       spin_lock_irq(&instance->send_lock);
-                       list_add(&snd->list, &instance->spare_senders);
-                       spin_unlock_irq(&instance->send_lock);
-                       list_add(&buf->list, &instance->filled_send_buffers);
-                       return; /* bail out */
-               }
-
-               spin_lock_irq(&instance->send_lock);
-       }                       /* while */
-       spin_unlock_irq(&instance->send_lock);
-
-       if (!instance->current_skb)
-               instance->current_skb = skb_dequeue(&instance->sndqueue);
-       if (!instance->current_skb)
-               return;         /* done - no more skbs */
-
-       skb = instance->current_skb;
-
-       if (!(buf = instance->current_buffer)) {
-               spin_lock_irq(&instance->send_lock);
-               if (list_empty(&instance->spare_send_buffers)) {
-                       instance->current_buffer = NULL;
-                       spin_unlock_irq(&instance->send_lock);
-                       return; /* done - no more buffers */
-               }
-               buf = list_entry(instance->spare_send_buffers.next,
-                              struct udsl_send_buffer, list);
-               list_del(&buf->list);
-               spin_unlock_irq(&instance->send_lock);
-
-               buf->free_start = buf->base;
-               buf->free_cells = snd_buf_size;
-
-               instance->current_buffer = buf;
-       }
-
-       num_written = udsl_write_cells(instance, buf->free_cells, skb, &buf->free_start);
-
-       vdbg("udsl_process_send: wrote %u cells from skb 0x%p to buffer 0x%p",
-            num_written, skb, buf);
-
-       if (!(buf->free_cells -= num_written)) {
-               list_add_tail(&buf->list, &instance->filled_send_buffers);
-               instance->current_buffer = NULL;
-       }
-
-       vdbg("udsl_process_send: buffer contains %d cells, %d left",
-            snd_buf_size - buf->free_cells, buf->free_cells);
-
-       if (!UDSL_SKB(skb)->num_cells) {
-               struct atm_vcc *vcc = UDSL_SKB(skb)->atm_data.vcc;
-
-               udsl_pop(vcc, skb);
-               instance->current_skb = NULL;
-
-               atomic_inc(&vcc->stats->tx);
-       }
-
-       goto made_progress;
-}
-
-static void udsl_cancel_send(struct udsl_instance_data *instance,
-                            struct atm_vcc *vcc)
-{
-       struct sk_buff *skb, *n;
-
-       dbg("udsl_cancel_send entered");
-       spin_lock_irq(&instance->sndqueue.lock);
-       for (skb = instance->sndqueue.next, n = skb->next;
-            skb != (struct sk_buff *)&instance->sndqueue;
-            skb = n, n = skb->next)
-               if (UDSL_SKB(skb)->atm_data.vcc == vcc) {
-                       dbg("udsl_cancel_send: popping skb 0x%p", skb);
-                       __skb_unlink(skb, &instance->sndqueue);
-                       udsl_pop(vcc, skb);
-               }
-       spin_unlock_irq(&instance->sndqueue.lock);
-
-       tasklet_disable(&instance->send_tasklet);
-       if ((skb = instance->current_skb) && (UDSL_SKB(skb)->atm_data.vcc == vcc)) {
-               dbg("udsl_cancel_send: popping current skb (0x%p)", skb);
-               instance->current_skb = NULL;
-               udsl_pop(vcc, skb);
-       }
-       tasklet_enable(&instance->send_tasklet);
-       dbg("udsl_cancel_send done");
-}
-
-static int udsl_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
-{
-       struct udsl_instance_data *instance = vcc->dev->dev_data;
-       int err;
-
-       vdbg("udsl_atm_send called (skb 0x%p, len %u)", skb, skb->len);
-
-       if (!instance) {
-               dbg("udsl_atm_send: NULL data!");
-               err = -ENODEV;
-               goto fail;
-       }
-
-       if (vcc->qos.aal != ATM_AAL5) {
-               dbg("udsl_atm_send: unsupported ATM type %d!", vcc->qos.aal);
-               err = -EINVAL;
-               goto fail;
-       }
-
-       if (skb->len > ATM_MAX_AAL5_PDU) {
-               dbg("udsl_atm_send: packet too long (%d vs %d)!", skb->len,
-                   ATM_MAX_AAL5_PDU);
-               err = -EINVAL;
-               goto fail;
-       }
-
-       PACKETDEBUG(skb->data, skb->len);
-
-       udsl_groom_skb(vcc, skb);
-       skb_queue_tail(&instance->sndqueue, skb);
-       tasklet_schedule(&instance->send_tasklet);
-
-       return 0;
-
- fail:
-       udsl_pop(vcc, skb);
-       return err;
-}
-
-/********************
-**  bean counting  **
-********************/
-
-static void udsl_destroy_instance(struct kref *kref)
-{
-       struct udsl_instance_data *instance =
-           container_of(kref, struct udsl_instance_data, refcount);
-
-       tasklet_kill(&instance->receive_tasklet);
-       tasklet_kill(&instance->send_tasklet);
-       usb_put_dev(instance->usb_dev);
-       kfree(instance);
-}
-
-void udsl_get_instance(struct udsl_instance_data *instance)
-{
-       kref_get(&instance->refcount);
-}
-
-void udsl_put_instance(struct udsl_instance_data *instance)
-{
-       kref_put(&instance->refcount, udsl_destroy_instance);
-}
-
-/**********
-**  ATM  **
-**********/
-
-static void udsl_atm_dev_close(struct atm_dev *dev)
-{
-       struct udsl_instance_data *instance = dev->dev_data;
-
-       dev->dev_data = NULL;
-       udsl_put_instance(instance);
-}
-
-static int udsl_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page)
-{
-       struct udsl_instance_data *instance = atm_dev->dev_data;
-       int left = *pos;
-
-       if (!instance) {
-               dbg("udsl_atm_proc_read: NULL instance!");
-               return -ENODEV;
-       }
-
-       if (!left--)
-               return sprintf(page, "%s\n", instance->description);
-
-       if (!left--)
-               return sprintf(page, "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
-                              atm_dev->esi[0], atm_dev->esi[1],
-                              atm_dev->esi[2], atm_dev->esi[3],
-                              atm_dev->esi[4], atm_dev->esi[5]);
-
-       if (!left--)
-               return sprintf(page,
-                              "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n",
-                              atomic_read(&atm_dev->stats.aal5.tx),
-                              atomic_read(&atm_dev->stats.aal5.tx_err),
-                              atomic_read(&atm_dev->stats.aal5.rx),
-                              atomic_read(&atm_dev->stats.aal5.rx_err),
-                              atomic_read(&atm_dev->stats.aal5.rx_drop));
-
-       if (!left--) {
-               switch (atm_dev->signal) {
-               case ATM_PHY_SIG_FOUND:
-                       sprintf(page, "Line up");
-                       break;
-               case ATM_PHY_SIG_LOST:
-                       sprintf(page, "Line down");
-                       break;
-               default:
-                       sprintf(page, "Line state unknown");
-                       break;
-               }
-
-               if (instance->usb_dev->state == USB_STATE_NOTATTACHED)
-                       strcat(page, ", disconnected\n");
-               else {
-                       if (instance->status == UDSL_LOADED_FIRMWARE)
-                               strcat(page, ", firmware loaded\n");
-                       else if (instance->status == UDSL_LOADING_FIRMWARE)
-                               strcat(page, ", firmware loading\n");
-                       else
-                               strcat(page, ", no firmware\n");
-               }
-
-               return strlen(page);
-       }
-
-       return 0;
-}
-
-static int udsl_atm_open(struct atm_vcc *vcc)
-{
-       struct udsl_instance_data *instance = vcc->dev->dev_data;
-       struct udsl_vcc_data *new;
-       unsigned int max_pdu;
-       int vci = vcc->vci;
-       short vpi = vcc->vpi;
-       int err;
-
-       dbg("udsl_atm_open: vpi %hd, vci %d", vpi, vci);
-
-       if (!instance) {
-               dbg("udsl_atm_open: NULL data!");
-               return -ENODEV;
-       }
-
-       /* only support AAL5 */
-       if ((vcc->qos.aal != ATM_AAL5) || (vcc->qos.rxtp.max_sdu < 0)
-           || (vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU)) {
-               dbg("udsl_atm_open: unsupported ATM type %d!", vcc->qos.aal);
-               return -EINVAL;
-       }
-
-       if (instance->firmware_wait &&
-           (err = instance->firmware_wait(instance)) < 0) {
-               dbg("udsl_atm_open: firmware not loaded (%d)!", err);
-               return err;
-       }
-
-       down(&instance->serialize);     /* vs self, udsl_atm_close */
-
-       if (udsl_find_vcc(instance, vpi, vci)) {
-               dbg("udsl_atm_open: %hd/%d already in use!", vpi, vci);
-               up(&instance->serialize);
-               return -EADDRINUSE;
-       }
-
-       if (!(new = kmalloc(sizeof(struct udsl_vcc_data), GFP_KERNEL))) {
-               dbg("udsl_atm_open: no memory for vcc_data!");
-               up(&instance->serialize);
-               return -ENOMEM;
-       }
-
-       memset(new, 0, sizeof(struct udsl_vcc_data));
-       new->vcc = vcc;
-       new->vpi = vpi;
-       new->vci = vci;
-
-       /* udsl_extract_cells requires at least one cell */
-       max_pdu = max(1, UDSL_NUM_CELLS(vcc->qos.rxtp.max_sdu)) * ATM_CELL_PAYLOAD;
-       if (!(new->sarb = alloc_skb(max_pdu, GFP_KERNEL))) {
-               dbg("udsl_atm_open: no memory for SAR buffer!");
-               kfree(new);
-               up(&instance->serialize);
-               return -ENOMEM;
-       }
-
-       vcc->dev_data = new;
-
-       tasklet_disable(&instance->receive_tasklet);
-       list_add(&new->list, &instance->vcc_list);
-       tasklet_enable(&instance->receive_tasklet);
-
-       set_bit(ATM_VF_ADDR, &vcc->flags);
-       set_bit(ATM_VF_PARTIAL, &vcc->flags);
-       set_bit(ATM_VF_READY, &vcc->flags);
-
-       up(&instance->serialize);
-
-       tasklet_schedule(&instance->receive_tasklet);
-
-       dbg("udsl_atm_open: allocated vcc data 0x%p (max_pdu: %u)", new, max_pdu);
-
-       return 0;
-}
-
-static void udsl_atm_close(struct atm_vcc *vcc)
-{
-       struct udsl_instance_data *instance = vcc->dev->dev_data;
-       struct udsl_vcc_data *vcc_data = vcc->dev_data;
-
-       dbg("udsl_atm_close called");
-
-       if (!instance || !vcc_data) {
-               dbg("udsl_atm_close: NULL data!");
-               return;
-       }
-
-       dbg("udsl_atm_close: deallocating vcc 0x%p with vpi %d vci %d",
-           vcc_data, vcc_data->vpi, vcc_data->vci);
-
-       udsl_cancel_send(instance, vcc);
-
-       down(&instance->serialize);     /* vs self, udsl_atm_open */
-
-       tasklet_disable(&instance->receive_tasklet);
-       list_del(&vcc_data->list);
-       tasklet_enable(&instance->receive_tasklet);
-
-       kfree_skb(vcc_data->sarb);
-       vcc_data->sarb = NULL;
-
-       kfree(vcc_data);
-       vcc->dev_data = NULL;
-
-       vcc->vpi = ATM_VPI_UNSPEC;
-       vcc->vci = ATM_VCI_UNSPEC;
-       clear_bit(ATM_VF_READY, &vcc->flags);
-       clear_bit(ATM_VF_PARTIAL, &vcc->flags);
-       clear_bit(ATM_VF_ADDR, &vcc->flags);
-
-       up(&instance->serialize);
-
-       dbg("udsl_atm_close successful");
-}
-
-static int udsl_atm_ioctl(struct atm_dev *dev, unsigned int cmd,
-                         void __user * arg)
-{
-       switch (cmd) {
-       case ATM_QUERYLOOP:
-               return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0;
-       default:
-               return -ENOIOCTLCMD;
-       }
-}
-
-/**********
-**  USB  **
-**********/
-
-int udsl_instance_setup(struct usb_device *dev,
-                       struct udsl_instance_data *instance)
-{
-       char *buf;
-       int i, length;
-
-       kref_init(&instance->refcount); /* one for USB */
-       udsl_get_instance(instance);    /* one for ATM */
-
-       init_MUTEX(&instance->serialize);
-
-       instance->usb_dev = dev;
-
-       INIT_LIST_HEAD(&instance->vcc_list);
-
-       instance->status = UDSL_NO_FIRMWARE;
-       init_waitqueue_head(&instance->firmware_waiters);
-
-       spin_lock_init(&instance->receive_lock);
-       INIT_LIST_HEAD(&instance->spare_receivers);
-       INIT_LIST_HEAD(&instance->filled_receive_buffers);
-
-       tasklet_init(&instance->receive_tasklet, udsl_process_receive, (unsigned long)instance);
-       INIT_LIST_HEAD(&instance->spare_receive_buffers);
-
-       skb_queue_head_init(&instance->sndqueue);
-
-       spin_lock_init(&instance->send_lock);
-       INIT_LIST_HEAD(&instance->spare_senders);
-       INIT_LIST_HEAD(&instance->spare_send_buffers);
-
-       tasklet_init(&instance->send_tasklet, udsl_process_send,
-                    (unsigned long)instance);
-       INIT_LIST_HEAD(&instance->filled_send_buffers);
-
-       /* receive init */
-       for (i = 0; i < num_rcv_urbs; i++) {
-               struct udsl_receiver *rcv = &(instance->receivers[i]);
-
-               if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
-                       dbg("udsl_usb_probe: no memory for receive urb %d!", i);
-                       goto fail;
-               }
-
-               rcv->instance = instance;
-
-               list_add(&rcv->list, &instance->spare_receivers);
-       }
-
-       for (i = 0; i < num_rcv_bufs; i++) {
-               struct udsl_receive_buffer *buf =
-                   &(instance->receive_buffers[i]);
-
-               buf->base = kmalloc(rcv_buf_size * (ATM_CELL_SIZE + instance->rcv_padding),
-                                   GFP_KERNEL);
-               if (!buf->base) {
-                       dbg("udsl_usb_probe: no memory for receive buffer %d!", i);
-                       goto fail;
-               }
-
-               list_add(&buf->list, &instance->spare_receive_buffers);
-       }
-
-       /* send init */
-       for (i = 0; i < num_snd_urbs; i++) {
-               struct udsl_sender *snd = &(instance->senders[i]);
-
-               if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) {
-                       dbg("udsl_usb_probe: no memory for send urb %d!", i);
-                       goto fail;
-               }
-
-               snd->instance = instance;
-
-               list_add(&snd->list, &instance->spare_senders);
-       }
-
-       for (i = 0; i < num_snd_bufs; i++) {
-               struct udsl_send_buffer *buf = &(instance->send_buffers[i]);
-
-               buf->base = kmalloc(snd_buf_size * (ATM_CELL_SIZE + instance->snd_padding),
-                                   GFP_KERNEL);
-               if (!buf->base) {
-                       dbg("udsl_usb_probe: no memory for send buffer %d!", i);
-                       goto fail;
-               }
-
-               list_add(&buf->list, &instance->spare_send_buffers);
-       }
-
-       /* ATM init */
-       instance->atm_dev = atm_dev_register(instance->driver_name,
-                                            &udsl_atm_devops, -1, NULL);
-       if (!instance->atm_dev) {
-               dbg("udsl_usb_probe: failed to register ATM device!");
-               goto fail;
-       }
-
-       instance->atm_dev->ci_range.vpi_bits = ATM_CI_MAX;
-       instance->atm_dev->ci_range.vci_bits = ATM_CI_MAX;
-       instance->atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
-
-       /* temp init ATM device, set to 128kbit */
-       instance->atm_dev->link_rate = 128 * 1000 / 424;
-
-       /* device description */
-       buf = instance->description;
-       length = sizeof(instance->description);
-
-       if ((i = usb_string(dev, dev->descriptor.iProduct, buf, length)) < 0)
-               goto finish;
-
-       buf += i;
-       length -= i;
-
-       i = scnprintf(buf, length, " (");
-       buf += i;
-       length -= i;
-
-       if (length <= 0 || (i = usb_make_path(dev, buf, length)) < 0)
-               goto finish;
-
-       buf += i;
-       length -= i;
-
-       snprintf(buf, length, ")");
-
- finish:
-       /* ready for ATM callbacks */
-       wmb();
-       instance->atm_dev->dev_data = instance;
-
-       usb_get_dev(dev);
-
-       return 0;
-
- fail:
-       for (i = 0; i < num_snd_bufs; i++)
-               kfree(instance->send_buffers[i].base);
-
-       for (i = 0; i < num_snd_urbs; i++)
-               usb_free_urb(instance->senders[i].urb);
-
-       for (i = 0; i < num_rcv_bufs; i++)
-               kfree(instance->receive_buffers[i].base);
-
-       for (i = 0; i < num_rcv_urbs; i++)
-               usb_free_urb(instance->receivers[i].urb);
-
-       return -ENOMEM;
-}
-
-void udsl_instance_disconnect(struct udsl_instance_data *instance)
-{
-       int i;
-
-       dbg("udsl_instance_disconnect entered");
-
-       if (!instance) {
-               dbg("udsl_instance_disconnect: NULL instance!");
-               return;
-       }
-
-       /* receive finalize */
-       tasklet_disable(&instance->receive_tasklet);
-
-       for (i = 0; i < num_rcv_urbs; i++)
-               usb_kill_urb(instance->receivers[i].urb);
-
-       /* no need to take the spinlock */
-       INIT_LIST_HEAD(&instance->filled_receive_buffers);
-       INIT_LIST_HEAD(&instance->spare_receive_buffers);
-
-       tasklet_enable(&instance->receive_tasklet);
-
-       for (i = 0; i < num_rcv_urbs; i++)
-               usb_free_urb(instance->receivers[i].urb);
-
-       for (i = 0; i < num_rcv_bufs; i++)
-               kfree(instance->receive_buffers[i].base);
-
-       /* send finalize */
-       tasklet_disable(&instance->send_tasklet);
-
-       for (i = 0; i < num_snd_urbs; i++)
-               usb_kill_urb(instance->senders[i].urb);
-
-       /* no need to take the spinlock */
-       INIT_LIST_HEAD(&instance->spare_senders);
-       INIT_LIST_HEAD(&instance->spare_send_buffers);
-       instance->current_buffer = NULL;
-
-       tasklet_enable(&instance->send_tasklet);
-
-       for (i = 0; i < num_snd_urbs; i++)
-               usb_free_urb(instance->senders[i].urb);
-
-       for (i = 0; i < num_snd_bufs; i++)
-               kfree(instance->send_buffers[i].base);
-
-       /* ATM finalize */
-       shutdown_atm_dev(instance->atm_dev);
-}
-
-EXPORT_SYMBOL_GPL(udsl_get_instance);
-EXPORT_SYMBOL_GPL(udsl_put_instance);
-EXPORT_SYMBOL_GPL(udsl_instance_setup);
-EXPORT_SYMBOL_GPL(udsl_instance_disconnect);
-
-/***********
-**  init  **
-***********/
-
-static int __init udsl_usb_init(void)
-{
-       dbg("udsl_usb_init: driver version " DRIVER_VERSION);
-
-       if (sizeof(struct udsl_control) > sizeof(((struct sk_buff *) 0)->cb)) {
-               printk(KERN_ERR __FILE__ ": unusable with this kernel!\n");
-               return -EIO;
-       }
-
-       if ((num_rcv_urbs > UDSL_MAX_RCV_URBS)
-           || (num_snd_urbs > UDSL_MAX_SND_URBS)
-           || (num_rcv_bufs > UDSL_MAX_RCV_BUFS)
-           || (num_snd_bufs > UDSL_MAX_SND_BUFS)
-           || (rcv_buf_size > UDSL_MAX_RCV_BUF_SIZE)
-           || (snd_buf_size > UDSL_MAX_SND_BUF_SIZE))
-               return -EINVAL;
-
-       return 0;
-}
-
-static void __exit udsl_usb_exit(void)
-{
-}
-
-module_init(udsl_usb_init);
-module_exit(udsl_usb_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
-
-/************
-**  debug  **
-************/
-
-#ifdef VERBOSE_DEBUG
-static int udsl_print_packet(const unsigned char *data, int len)
-{
-       unsigned char buffer[256];
-       int i = 0, j = 0;
-
-       for (i = 0; i < len;) {
-               buffer[0] = '\0';
-               sprintf(buffer, "%.3d :", i);
-               for (j = 0; (j < 16) && (i < len); j++, i++) {
-                       sprintf(buffer, "%s %2.2x", buffer, data[i]);
-               }
-               dbg("%s", buffer);
-       }
-       return i;
-}
-#endif
diff --git a/drivers/usb/atm/usb_atm.h b/drivers/usb/atm/usb_atm.h
deleted file mode 100644 (file)
index cf8c532..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/******************************************************************************
- *  usb_atm.h - Generic USB xDSL driver core
- *
- *  Copyright (C) 2001, Alcatel
- *  Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
- *  Copyright (C) 2004, David Woodhouse
- *
- *  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/config.h>
-#include <linux/list.h>
-#include <linux/kref.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <asm/semaphore.h>
-
-/*
-#define DEBUG
-#define VERBOSE_DEBUG
-*/
-
-#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
-#      define DEBUG
-#endif
-
-#include <linux/usb.h>
-
-#ifdef DEBUG
-#define UDSL_ASSERT(x) BUG_ON(!(x))
-#else
-#define UDSL_ASSERT(x) do { if (!(x)) warn("failed assertion '" #x "' at line %d", __LINE__); } while(0)
-#endif
-
-#define UDSL_MAX_RCV_URBS              4
-#define UDSL_MAX_SND_URBS              4
-#define UDSL_MAX_RCV_BUFS              8
-#define UDSL_MAX_SND_BUFS              8
-#define UDSL_MAX_RCV_BUF_SIZE          1024    /* ATM cells */
-#define UDSL_MAX_SND_BUF_SIZE          1024    /* ATM cells */
-#define UDSL_DEFAULT_RCV_URBS          2
-#define UDSL_DEFAULT_SND_URBS          2
-#define UDSL_DEFAULT_RCV_BUFS          4
-#define UDSL_DEFAULT_SND_BUFS          4
-#define UDSL_DEFAULT_RCV_BUF_SIZE      64      /* ATM cells */
-#define UDSL_DEFAULT_SND_BUF_SIZE      64      /* ATM cells */
-
-#define ATM_CELL_HEADER                        (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
-#define UDSL_NUM_CELLS(x)              (((x) + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD)
-
-/* receive */
-
-struct udsl_receive_buffer {
-       struct list_head list;
-       unsigned char *base;
-       unsigned int filled_cells;
-};
-
-struct udsl_receiver {
-       struct list_head list;
-       struct udsl_receive_buffer *buffer;
-       struct urb *urb;
-       struct udsl_instance_data *instance;
-};
-
-struct udsl_vcc_data {
-       /* vpi/vci lookup */
-       struct list_head list;
-       short vpi;
-       int vci;
-       struct atm_vcc *vcc;
-
-       /* raw cell reassembly */
-       struct sk_buff *sarb;
-};
-
-/* send */
-
-struct udsl_send_buffer {
-       struct list_head list;
-       unsigned char *base;
-       unsigned char *free_start;
-       unsigned int free_cells;
-};
-
-struct udsl_sender {
-       struct list_head list;
-       struct udsl_send_buffer *buffer;
-       struct urb *urb;
-       struct udsl_instance_data *instance;
-};
-
-struct udsl_control {
-       struct atm_skb_data atm_data;
-       unsigned int num_cells;
-       unsigned int num_entire;
-       unsigned int pdu_padding;
-       unsigned char aal5_trailer[ATM_AAL5_TRAILER];
-};
-
-#define UDSL_SKB(x)            ((struct udsl_control *)(x)->cb)
-
-/* main driver data */
-
-enum udsl_status {
-       UDSL_NO_FIRMWARE,
-       UDSL_LOADING_FIRMWARE,
-       UDSL_LOADED_FIRMWARE
-};
-
-struct udsl_instance_data {
-       struct kref refcount;
-       struct semaphore serialize;
-
-       /* USB device part */
-       struct usb_device *usb_dev;
-       char description[64];
-       int data_endpoint;
-       int snd_padding;
-       int rcv_padding;
-       const char *driver_name;
-
-       /* ATM device part */
-       struct atm_dev *atm_dev;
-       struct list_head vcc_list;
-
-       /* firmware */
-       int (*firmware_wait) (struct udsl_instance_data *);
-       enum udsl_status status;
-       wait_queue_head_t firmware_waiters;
-
-       /* receive */
-       struct udsl_receiver receivers[UDSL_MAX_RCV_URBS];
-       struct udsl_receive_buffer receive_buffers[UDSL_MAX_RCV_BUFS];
-
-       spinlock_t receive_lock;
-       struct list_head spare_receivers;
-       struct list_head filled_receive_buffers;
-
-       struct tasklet_struct receive_tasklet;
-       struct list_head spare_receive_buffers;
-
-       /* send */
-       struct udsl_sender senders[UDSL_MAX_SND_URBS];
-       struct udsl_send_buffer send_buffers[UDSL_MAX_SND_BUFS];
-
-       struct sk_buff_head sndqueue;
-
-       spinlock_t send_lock;
-       struct list_head spare_senders;
-       struct list_head spare_send_buffers;
-
-       struct tasklet_struct send_tasklet;
-       struct sk_buff *current_skb;                    /* being emptied */
-       struct udsl_send_buffer *current_buffer;        /* being filled */
-       struct list_head filled_send_buffers;
-};
-
-extern int udsl_instance_setup(struct usb_device *dev,
-                              struct udsl_instance_data *instance);
-extern void udsl_instance_disconnect(struct udsl_instance_data *instance);
-extern void udsl_get_instance(struct udsl_instance_data *instance);
-extern void udsl_put_instance(struct udsl_instance_data *instance);
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
new file mode 100644 (file)
index 0000000..bb1db19
--- /dev/null
@@ -0,0 +1,1230 @@
+/******************************************************************************
+ *  usbatm.c - Generic USB xDSL driver core
+ *
+ *  Copyright (C) 2001, Alcatel
+ *  Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
+ *  Copyright (C) 2004, David Woodhouse, Roman Kagan
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/*
+ *  Written by Johan Verrept, Duncan Sands (duncan.sands@free.fr) and David Woodhouse
+ *
+ *  1.7+:      - See the check-in logs
+ *
+ *  1.6:       - No longer opens a connection if the firmware is not loaded
+ *             - Added support for the speedtouch 330
+ *             - Removed the limit on the number of devices
+ *             - Module now autoloads on device plugin
+ *             - Merged relevant parts of sarlib
+ *             - Replaced the kernel thread with a tasklet
+ *             - New packet transmission code
+ *             - Changed proc file contents
+ *             - Fixed all known SMP races
+ *             - Many fixes and cleanups
+ *             - Various fixes by Oliver Neukum (oliver@neukum.name)
+ *
+ *  1.5A:      - Version for inclusion in 2.5 series kernel
+ *             - Modifications by Richard Purdie (rpurdie@rpsys.net)
+ *             - made compatible with kernel 2.5.6 onwards by changing
+ *             usbatm_usb_send_data_context->urb to a pointer and adding code
+ *             to alloc and free it
+ *             - remove_wait_queue() added to usbatm_atm_processqueue_thread()
+ *
+ *  1.5:       - fixed memory leak when atmsar_decode_aal5 returned NULL.
+ *             (reported by stephen.robinson@zen.co.uk)
+ *
+ *  1.4:       - changed the spin_lock() under interrupt to spin_lock_irqsave()
+ *             - unlink all active send urbs of a vcc that is being closed.
+ *
+ *  1.3.1:     - added the version number
+ *
+ *  1.3:       - Added multiple send urb support
+ *             - fixed memory leak and vcc->tx_inuse starvation bug
+ *               when not enough memory left in vcc.
+ *
+ *  1.2:       - Fixed race condition in usbatm_usb_send_data()
+ *  1.1:       - Turned off packet debugging
+ *
+ */
+
+#include "usbatm.h"
+
+#include <asm/uaccess.h>
+#include <linux/crc32.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/stat.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+
+#ifdef VERBOSE_DEBUG
+static int usbatm_print_packet(const unsigned char *data, int len);
+#define PACKETDEBUG(arg...)    usbatm_print_packet (arg)
+#define vdbg(arg...)           dbg (arg)
+#else
+#define PACKETDEBUG(arg...)
+#define vdbg(arg...)
+#endif
+
+#define DRIVER_AUTHOR  "Johan Verrept, Duncan Sands <duncan.sands@free.fr>"
+#define DRIVER_VERSION "1.9"
+#define DRIVER_DESC    "Generic USB ATM/DSL I/O, version " DRIVER_VERSION
+
+static const char usbatm_driver_name[] = "usbatm";
+
+#define UDSL_MAX_RCV_URBS              16
+#define UDSL_MAX_SND_URBS              16
+#define UDSL_MAX_RCV_BUF_SIZE          1024    /* ATM cells */
+#define UDSL_MAX_SND_BUF_SIZE          1024    /* ATM cells */
+#define UDSL_DEFAULT_RCV_URBS          4
+#define UDSL_DEFAULT_SND_URBS          4
+#define UDSL_DEFAULT_RCV_BUF_SIZE      64      /* ATM cells */
+#define UDSL_DEFAULT_SND_BUF_SIZE      64      /* ATM cells */
+
+#define ATM_CELL_HEADER                        (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
+
+#define THROTTLE_MSECS                 100     /* delay to recover processing after urb submission fails */
+
+static unsigned int num_rcv_urbs = UDSL_DEFAULT_RCV_URBS;
+static unsigned int num_snd_urbs = UDSL_DEFAULT_SND_URBS;
+static unsigned int rcv_buf_size = UDSL_DEFAULT_RCV_BUF_SIZE;
+static unsigned int snd_buf_size = UDSL_DEFAULT_SND_BUF_SIZE;
+
+module_param(num_rcv_urbs, uint, S_IRUGO);
+MODULE_PARM_DESC(num_rcv_urbs,
+                "Number of urbs used for reception (range: 0-"
+                __MODULE_STRING(UDSL_MAX_RCV_URBS) ", default: "
+                __MODULE_STRING(UDSL_DEFAULT_RCV_URBS) ")");
+
+module_param(num_snd_urbs, uint, S_IRUGO);
+MODULE_PARM_DESC(num_snd_urbs,
+                "Number of urbs used for transmission (range: 0-"
+                __MODULE_STRING(UDSL_MAX_SND_URBS) ", default: "
+                __MODULE_STRING(UDSL_DEFAULT_SND_URBS) ")");
+
+module_param(rcv_buf_size, uint, S_IRUGO);
+MODULE_PARM_DESC(rcv_buf_size,
+                "Size of the buffers used for reception in ATM cells (range: 1-"
+                __MODULE_STRING(UDSL_MAX_RCV_BUF_SIZE) ", default: "
+                __MODULE_STRING(UDSL_DEFAULT_RCV_BUF_SIZE) ")");
+
+module_param(snd_buf_size, uint, S_IRUGO);
+MODULE_PARM_DESC(snd_buf_size,
+                "Size of the buffers used for transmission in ATM cells (range: 1-"
+                __MODULE_STRING(UDSL_MAX_SND_BUF_SIZE) ", default: "
+                __MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")");
+
+
+/* receive */
+
+struct usbatm_vcc_data {
+       /* vpi/vci lookup */
+       struct list_head list;
+       short vpi;
+       int vci;
+       struct atm_vcc *vcc;
+
+       /* raw cell reassembly */
+       struct sk_buff *sarb;
+};
+
+
+/* send */
+
+struct usbatm_control {
+       struct atm_skb_data atm;
+       u32 len;
+       u32 crc;
+};
+
+#define UDSL_SKB(x)            ((struct usbatm_control *)(x)->cb)
+
+
+/* ATM */
+
+static void usbatm_atm_dev_close(struct atm_dev *dev);
+static int usbatm_atm_open(struct atm_vcc *vcc);
+static void usbatm_atm_close(struct atm_vcc *vcc);
+static int usbatm_atm_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg);
+static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb);
+static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page);
+
+static struct atmdev_ops usbatm_atm_devops = {
+       .dev_close      = usbatm_atm_dev_close,
+       .open           = usbatm_atm_open,
+       .close          = usbatm_atm_close,
+       .ioctl          = usbatm_atm_ioctl,
+       .send           = usbatm_atm_send,
+       .proc_read      = usbatm_atm_proc_read,
+       .owner          = THIS_MODULE,
+};
+
+
+/***********
+**  misc  **
+***********/
+
+static inline unsigned int usbatm_pdu_length(unsigned int length)
+{
+       length += ATM_CELL_PAYLOAD - 1 + ATM_AAL5_TRAILER;
+       return length - length % ATM_CELL_PAYLOAD;
+}
+
+static inline void usbatm_pop(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+       if (vcc->pop)
+               vcc->pop(vcc, skb);
+       else
+               dev_kfree_skb(skb);
+}
+
+
+/***********
+**  urbs  **
+************/
+
+static inline struct urb *usbatm_pop_urb(struct usbatm_channel *channel)
+{
+       struct urb *urb;
+
+       spin_lock_irq(&channel->lock);
+       if (list_empty(&channel->list)) {
+               spin_unlock_irq(&channel->lock);
+               return NULL;
+       }
+
+       urb = list_entry(channel->list.next, struct urb, urb_list);
+       list_del(&urb->urb_list);
+       spin_unlock_irq(&channel->lock);
+
+       return urb;
+}
+
+static inline int usbatm_submit_urb(struct urb *urb)
+{
+       struct usbatm_channel *channel = urb->context;
+       int ret;
+
+       vdbg("%s: submitting urb 0x%p, size %u",
+            __func__, urb, urb->transfer_buffer_length);
+
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+       if (ret) {
+               atm_dbg(channel->usbatm, "%s: urb 0x%p submission failed (%d)!\n",
+                       __func__, urb, ret);
+
+               /* consider all errors transient and return the buffer back to the queue */
+               urb->status = -EAGAIN;
+               spin_lock_irq(&channel->lock);
+
+               /* must add to the front when sending; doesn't matter when receiving */
+               list_add(&urb->urb_list, &channel->list);
+
+               spin_unlock_irq(&channel->lock);
+
+               /* make sure the channel doesn't stall */
+               mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
+       }
+
+       return ret;
+}
+
+static void usbatm_complete(struct urb *urb, struct pt_regs *regs)
+{
+       struct usbatm_channel *channel = urb->context;
+       unsigned long flags;
+
+       vdbg("%s: urb 0x%p, status %d, actual_length %d",
+            __func__, urb, urb->status, urb->actual_length);
+
+       /* usually in_interrupt(), but not always */
+       spin_lock_irqsave(&channel->lock, flags);
+
+       /* must add to the back when receiving; doesn't matter when sending */
+       list_add_tail(&urb->urb_list, &channel->list);
+
+       spin_unlock_irqrestore(&channel->lock, flags);
+
+       if (unlikely(urb->status))
+               /* throttle processing in case of an error */
+               mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
+       else
+               tasklet_schedule(&channel->tasklet);
+}
+
+
+/*************
+**  decode  **
+*************/
+
+static inline struct usbatm_vcc_data *usbatm_find_vcc(struct usbatm_data *instance,
+                                                 short vpi, int vci)
+{
+       struct usbatm_vcc_data *vcc;
+
+       list_for_each_entry(vcc, &instance->vcc_list, list)
+               if ((vcc->vci == vci) && (vcc->vpi == vpi))
+                       return vcc;
+       return NULL;
+}
+
+static void usbatm_extract_cells(struct usbatm_data *instance,
+                              unsigned char *source, unsigned int avail_data)
+{
+       struct usbatm_vcc_data *cached_vcc = NULL;
+       struct atm_vcc *vcc;
+       struct sk_buff *sarb;
+       unsigned int stride = instance->rx_channel.stride;
+       int vci, cached_vci = 0;
+       short vpi, cached_vpi = 0;
+       u8 pti;
+
+       for (; avail_data >= stride; avail_data -= stride, source += stride) {
+               vpi = ((source[0] & 0x0f) << 4)  | (source[1] >> 4);
+               vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
+               pti = ((source[3] & 0xe) >> 1);
+
+               vdbg("%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti);
+
+               if ((vci != cached_vci) || (vpi != cached_vpi)) {
+                       cached_vpi = vpi;
+                       cached_vci = vci;
+
+                       cached_vcc = usbatm_find_vcc(instance, vpi, vci);
+
+                       if (!cached_vcc)
+                               atm_dbg(instance, "%s: unknown vpi/vci (%hd/%d)!\n", __func__, vpi, vci);
+               }
+
+               if (!cached_vcc)
+                       continue;
+
+               vcc = cached_vcc->vcc;
+
+               /* OAM F5 end-to-end */
+               if (pti == ATM_PTI_E2EF5) {
+                       atm_warn(instance, "%s: OAM not supported (vpi %d, vci %d)!\n", __func__, vpi, vci);
+                       atomic_inc(&vcc->stats->rx_err);
+                       continue;
+               }
+
+               sarb = cached_vcc->sarb;
+
+               if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) {
+                       atm_dbg(instance, "%s: buffer overrun (sarb->len %u, vcc: 0x%p)!\n",
+                                       __func__, sarb->len, vcc);
+                       /* discard cells already received */
+                       skb_trim(sarb, 0);
+                       UDSL_ASSERT(sarb->tail + ATM_CELL_PAYLOAD <= sarb->end);
+               }
+
+               memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
+               __skb_put(sarb, ATM_CELL_PAYLOAD);
+
+               if (pti & 1) {
+                       struct sk_buff *skb;
+                       unsigned int length;
+                       unsigned int pdu_length;
+
+                       length = (source[ATM_CELL_SIZE - 6] << 8) + source[ATM_CELL_SIZE - 5];
+
+                       /* guard against overflow */
+                       if (length > ATM_MAX_AAL5_PDU) {
+                               atm_dbg(instance, "%s: bogus length %u (vcc: 0x%p)!\n",
+                                               __func__, length, vcc);
+                               atomic_inc(&vcc->stats->rx_err);
+                               goto out;
+                       }
+
+                       pdu_length = usbatm_pdu_length(length);
+
+                       if (sarb->len < pdu_length) {
+                               atm_dbg(instance, "%s: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!\n",
+                                               __func__, pdu_length, sarb->len, vcc);
+                               atomic_inc(&vcc->stats->rx_err);
+                               goto out;
+                       }
+
+                       if (crc32_be(~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) {
+                               atm_dbg(instance, "%s: packet failed crc check (vcc: 0x%p)!\n",
+                                               __func__, vcc);
+                               atomic_inc(&vcc->stats->rx_err);
+                               goto out;
+                       }
+
+                       vdbg("%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", __func__, length, pdu_length, vcc);
+
+                       if (!(skb = dev_alloc_skb(length))) {
+                               atm_dbg(instance, "%s: no memory for skb (length: %u)!\n", __func__, length);
+                               atomic_inc(&vcc->stats->rx_drop);
+                               goto out;
+                       }
+
+                       vdbg("%s: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", __func__, skb, skb->truesize);
+
+                       if (!atm_charge(vcc, skb->truesize)) {
+                               atm_dbg(instance, "%s: failed atm_charge (skb->truesize: %u)!\n", __func__, skb->truesize);
+                               dev_kfree_skb(skb);
+                               goto out;       /* atm_charge increments rx_drop */
+                       }
+
+                       memcpy(skb->data, sarb->tail - pdu_length, length);
+                       __skb_put(skb, length);
+
+                       vdbg("%s: sending skb 0x%p, skb->len %u, skb->truesize %u",
+                            __func__, skb, skb->len, skb->truesize);
+
+                       PACKETDEBUG(skb->data, skb->len);
+
+                       vcc->push(vcc, skb);
+
+                       atomic_inc(&vcc->stats->rx);
+               out:
+                       skb_trim(sarb, 0);
+               }
+       }
+}
+
+
+/*************
+**  encode  **
+*************/
+
+static unsigned int usbatm_write_cells(struct usbatm_data *instance,
+                                      struct sk_buff *skb,
+                                      u8 *target, unsigned int avail_space)
+{
+       struct usbatm_control *ctrl = UDSL_SKB(skb);
+       struct atm_vcc *vcc = ctrl->atm.vcc;
+       unsigned int num_written;
+       unsigned int stride = instance->tx_channel.stride;
+
+       vdbg("%s: skb->len=%d, avail_space=%u", __func__, skb->len, avail_space);
+       UDSL_ASSERT(!(avail_space % stride));
+
+       for (num_written = 0; num_written < avail_space && ctrl->len;
+            num_written += stride, target += stride) {
+               unsigned int data_len = min_t(unsigned int, skb->len, ATM_CELL_PAYLOAD);
+               unsigned int left = ATM_CELL_PAYLOAD - data_len;
+               u8 *ptr = target;
+
+               ptr[0] = vcc->vpi >> 4;
+               ptr[1] = (vcc->vpi << 4) | (vcc->vci >> 12);
+               ptr[2] = vcc->vci >> 4;
+               ptr[3] = vcc->vci << 4;
+               ptr[4] = 0xec;
+               ptr += ATM_CELL_HEADER;
+
+               memcpy(ptr, skb->data, data_len);
+               ptr += data_len;
+               __skb_pull(skb, data_len);
+
+               if(!left)
+                       continue;
+
+               memset(ptr, 0, left);
+
+               if (left >= ATM_AAL5_TRAILER) { /* trailer will go in this cell */
+                       u8 *trailer = target + ATM_CELL_SIZE - ATM_AAL5_TRAILER;
+                       /* trailer[0] = 0;              UU = 0 */
+                       /* trailer[1] = 0;              CPI = 0 */
+                       trailer[2] = ctrl->len >> 8;
+                       trailer[3] = ctrl->len;
+
+                       ctrl->crc = ~ crc32_be(ctrl->crc, ptr, left - 4);
+
+                       trailer[4] = ctrl->crc >> 24;
+                       trailer[5] = ctrl->crc >> 16;
+                       trailer[6] = ctrl->crc >> 8;
+                       trailer[7] = ctrl->crc;
+
+                       target[3] |= 0x2;       /* adjust PTI */
+
+                       ctrl->len = 0;          /* tag this skb finished */
+               }
+               else
+                       ctrl->crc = crc32_be(ctrl->crc, ptr, left);
+       }
+
+       return num_written;
+}
+
+
+/**************
+**  receive  **
+**************/
+
+static void usbatm_rx_process(unsigned long data)
+{
+       struct usbatm_data *instance = (struct usbatm_data *)data;
+       struct urb *urb;
+
+       while ((urb = usbatm_pop_urb(&instance->rx_channel))) {
+               vdbg("%s: processing urb 0x%p", __func__, urb);
+
+               if (usb_pipeisoc(urb->pipe)) {
+                       int i;
+                       for (i = 0; i < urb->number_of_packets; i++)
+                               if (!urb->iso_frame_desc[i].status)
+                                       usbatm_extract_cells(instance,
+                                                            (u8 *)urb->transfer_buffer + urb->iso_frame_desc[i].offset,
+                                                            urb->iso_frame_desc[i].actual_length);
+               }
+               else
+                       if (!urb->status)
+                               usbatm_extract_cells(instance, urb->transfer_buffer, urb->actual_length);
+
+               if (usbatm_submit_urb(urb))
+                       return;
+       }
+}
+
+
+/***********
+**  send  **
+***********/
+
+static void usbatm_tx_process(unsigned long data)
+{
+       struct usbatm_data *instance = (struct usbatm_data *)data;
+       struct sk_buff *skb = instance->current_skb;
+       struct urb *urb = NULL;
+       const unsigned int buf_size = instance->tx_channel.buf_size;
+       unsigned int num_written = 0;
+       u8 *buffer = NULL;
+
+       if (!skb)
+               skb = skb_dequeue(&instance->sndqueue);
+
+       while (skb) {
+               if (!urb) {
+                       urb = usbatm_pop_urb(&instance->tx_channel);
+                       if (!urb)
+                               break;          /* no more senders */
+                       buffer = urb->transfer_buffer;
+                       num_written = (urb->status == -EAGAIN) ?
+                               urb->transfer_buffer_length : 0;
+               }
+
+               num_written += usbatm_write_cells(instance, skb,
+                                                 buffer + num_written,
+                                                 buf_size - num_written);
+
+               vdbg("%s: wrote %u bytes from skb 0x%p to urb 0x%p",
+                    __func__, num_written, skb, urb);
+
+               if (!UDSL_SKB(skb)->len) {
+                       struct atm_vcc *vcc = UDSL_SKB(skb)->atm.vcc;
+
+                       usbatm_pop(vcc, skb);
+                       atomic_inc(&vcc->stats->tx);
+
+                       skb = skb_dequeue(&instance->sndqueue);
+               }
+
+               if (num_written == buf_size || (!skb && num_written)) {
+                       urb->transfer_buffer_length = num_written;
+
+                       if (usbatm_submit_urb(urb))
+                               break;
+                       urb = NULL;
+               }
+       }
+
+       instance->current_skb = skb;
+}
+
+static void usbatm_cancel_send(struct usbatm_data *instance,
+                              struct atm_vcc *vcc)
+{
+       struct sk_buff *skb, *n;
+
+       atm_dbg(instance, "%s entered\n", __func__);
+       spin_lock_irq(&instance->sndqueue.lock);
+       for (skb = instance->sndqueue.next, n = skb->next;
+            skb != (struct sk_buff *)&instance->sndqueue;
+            skb = n, n = skb->next)
+               if (UDSL_SKB(skb)->atm.vcc == vcc) {
+                       atm_dbg(instance, "%s: popping skb 0x%p\n", __func__, skb);
+                       __skb_unlink(skb, &instance->sndqueue);
+                       usbatm_pop(vcc, skb);
+               }
+       spin_unlock_irq(&instance->sndqueue.lock);
+
+       tasklet_disable(&instance->tx_channel.tasklet);
+       if ((skb = instance->current_skb) && (UDSL_SKB(skb)->atm.vcc == vcc)) {
+               atm_dbg(instance, "%s: popping current skb (0x%p)\n", __func__, skb);
+               instance->current_skb = NULL;
+               usbatm_pop(vcc, skb);
+       }
+       tasklet_enable(&instance->tx_channel.tasklet);
+       atm_dbg(instance, "%s done\n", __func__);
+}
+
+static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+       struct usbatm_data *instance = vcc->dev->dev_data;
+       struct usbatm_control *ctrl = UDSL_SKB(skb);
+       int err;
+
+       vdbg("%s called (skb 0x%p, len %u)", __func__, skb, skb->len);
+
+       if (!instance) {
+               dbg("%s: NULL data!", __func__);
+               err = -ENODEV;
+               goto fail;
+       }
+
+       if (vcc->qos.aal != ATM_AAL5) {
+               atm_dbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
+               err = -EINVAL;
+               goto fail;
+       }
+
+       if (skb->len > ATM_MAX_AAL5_PDU) {
+               atm_dbg(instance, "%s: packet too long (%d vs %d)!\n",
+                               __func__, skb->len, ATM_MAX_AAL5_PDU);
+               err = -EINVAL;
+               goto fail;
+       }
+
+       PACKETDEBUG(skb->data, skb->len);
+
+       /* initialize the control block */
+       ctrl->atm.vcc = vcc;
+       ctrl->len = skb->len;
+       ctrl->crc = crc32_be(~0, skb->data, skb->len);
+
+       skb_queue_tail(&instance->sndqueue, skb);
+       tasklet_schedule(&instance->tx_channel.tasklet);
+
+       return 0;
+
+ fail:
+       usbatm_pop(vcc, skb);
+       return err;
+}
+
+
+/********************
+**  bean counting  **
+********************/
+
+static void usbatm_destroy_instance(struct kref *kref)
+{
+       struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount);
+
+       dbg("%s", __func__);
+
+       tasklet_kill(&instance->rx_channel.tasklet);
+       tasklet_kill(&instance->tx_channel.tasklet);
+       usb_put_dev(instance->usb_dev);
+       kfree(instance);
+}
+
+void usbatm_get_instance(struct usbatm_data *instance)
+{
+       dbg("%s", __func__);
+
+       kref_get(&instance->refcount);
+}
+
+void usbatm_put_instance(struct usbatm_data *instance)
+{
+       dbg("%s", __func__);
+
+       kref_put(&instance->refcount, usbatm_destroy_instance);
+}
+
+
+/**********
+**  ATM  **
+**********/
+
+static void usbatm_atm_dev_close(struct atm_dev *dev)
+{
+       struct usbatm_data *instance = dev->dev_data;
+
+       dbg("%s", __func__);
+
+       if (!instance)
+               return;
+
+       dev->dev_data = NULL;
+       usbatm_put_instance(instance);  /* taken in usbatm_atm_init */
+}
+
+static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page)
+{
+       struct usbatm_data *instance = atm_dev->dev_data;
+       int left = *pos;
+
+       if (!instance) {
+               dbg("%s: NULL instance!", __func__);
+               return -ENODEV;
+       }
+
+       if (!left--)
+               return sprintf(page, "%s\n", instance->description);
+
+       if (!left--)
+               return sprintf(page, "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
+                              atm_dev->esi[0], atm_dev->esi[1],
+                              atm_dev->esi[2], atm_dev->esi[3],
+                              atm_dev->esi[4], atm_dev->esi[5]);
+
+       if (!left--)
+               return sprintf(page,
+                              "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n",
+                              atomic_read(&atm_dev->stats.aal5.tx),
+                              atomic_read(&atm_dev->stats.aal5.tx_err),
+                              atomic_read(&atm_dev->stats.aal5.rx),
+                              atomic_read(&atm_dev->stats.aal5.rx_err),
+                              atomic_read(&atm_dev->stats.aal5.rx_drop));
+
+       if (!left--)
+               switch (atm_dev->signal) {
+               case ATM_PHY_SIG_FOUND:
+                       return sprintf(page, "Line up\n");
+               case ATM_PHY_SIG_LOST:
+                       return sprintf(page, "Line down\n");
+               default:
+                       return sprintf(page, "Line state unknown\n");
+               }
+
+       return 0;
+}
+
+static int usbatm_atm_open(struct atm_vcc *vcc)
+{
+       struct usbatm_data *instance = vcc->dev->dev_data;
+       struct usbatm_vcc_data *new = NULL;
+       int ret;
+       int vci = vcc->vci;
+       short vpi = vcc->vpi;
+
+       if (!instance) {
+               dbg("%s: NULL data!", __func__);
+               return -ENODEV;
+       }
+
+       atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci);
+
+       /* only support AAL5 */
+       if ((vcc->qos.aal != ATM_AAL5) || (vcc->qos.rxtp.max_sdu < 0)
+           || (vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU)) {
+               atm_dbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
+               return -EINVAL;
+       }
+
+       down(&instance->serialize);     /* vs self, usbatm_atm_close */
+
+       if (usbatm_find_vcc(instance, vpi, vci)) {
+               atm_dbg(instance, "%s: %hd/%d already in use!\n", __func__, vpi, vci);
+               ret = -EADDRINUSE;
+               goto fail;
+       }
+
+       if (!(new = kmalloc(sizeof(struct usbatm_vcc_data), GFP_KERNEL))) {
+               atm_dbg(instance, "%s: no memory for vcc_data!\n", __func__);
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       memset(new, 0, sizeof(struct usbatm_vcc_data));
+       new->vcc = vcc;
+       new->vpi = vpi;
+       new->vci = vci;
+
+       new->sarb = alloc_skb(usbatm_pdu_length(vcc->qos.rxtp.max_sdu), GFP_KERNEL);
+       if (!new->sarb) {
+               atm_dbg(instance, "%s: no memory for SAR buffer!\n", __func__);
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       vcc->dev_data = new;
+
+       tasklet_disable(&instance->rx_channel.tasklet);
+       list_add(&new->list, &instance->vcc_list);
+       tasklet_enable(&instance->rx_channel.tasklet);
+
+       set_bit(ATM_VF_ADDR, &vcc->flags);
+       set_bit(ATM_VF_PARTIAL, &vcc->flags);
+       set_bit(ATM_VF_READY, &vcc->flags);
+
+       up(&instance->serialize);
+
+       atm_dbg(instance, "%s: allocated vcc data 0x%p\n", __func__, new);
+
+       return 0;
+
+fail:
+       kfree(new);
+       up(&instance->serialize);
+       return ret;
+}
+
+static void usbatm_atm_close(struct atm_vcc *vcc)
+{
+       struct usbatm_data *instance = vcc->dev->dev_data;
+       struct usbatm_vcc_data *vcc_data = vcc->dev_data;
+
+       if (!instance || !vcc_data) {
+               dbg("%s: NULL data!", __func__);
+               return;
+       }
+
+       atm_dbg(instance, "%s entered\n", __func__);
+
+       atm_dbg(instance, "%s: deallocating vcc 0x%p with vpi %d vci %d\n",
+               __func__, vcc_data, vcc_data->vpi, vcc_data->vci);
+
+       usbatm_cancel_send(instance, vcc);
+
+       down(&instance->serialize);     /* vs self, usbatm_atm_open */
+
+       tasklet_disable(&instance->rx_channel.tasklet);
+       list_del(&vcc_data->list);
+       tasklet_enable(&instance->rx_channel.tasklet);
+
+       kfree_skb(vcc_data->sarb);
+       vcc_data->sarb = NULL;
+
+       kfree(vcc_data);
+       vcc->dev_data = NULL;
+
+       vcc->vpi = ATM_VPI_UNSPEC;
+       vcc->vci = ATM_VCI_UNSPEC;
+       clear_bit(ATM_VF_READY, &vcc->flags);
+       clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+       clear_bit(ATM_VF_ADDR, &vcc->flags);
+
+       up(&instance->serialize);
+
+       atm_dbg(instance, "%s successful\n", __func__);
+}
+
+static int usbatm_atm_ioctl(struct atm_dev *dev, unsigned int cmd,
+                         void __user * arg)
+{
+       switch (cmd) {
+       case ATM_QUERYLOOP:
+               return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0;
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+static int usbatm_atm_init(struct usbatm_data *instance)
+{
+       struct atm_dev *atm_dev;
+       int ret, i;
+
+       /* ATM init */
+       atm_dev = atm_dev_register(instance->driver_name, &usbatm_atm_devops, -1, NULL);
+       if (!atm_dev) {
+               usb_dbg(instance, "%s: failed to register ATM device!\n", __func__);
+               return -1;
+       }
+
+       instance->atm_dev = atm_dev;
+
+       atm_dev->ci_range.vpi_bits = ATM_CI_MAX;
+       atm_dev->ci_range.vci_bits = ATM_CI_MAX;
+       atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+
+       /* temp init ATM device, set to 128kbit */
+       atm_dev->link_rate = 128 * 1000 / 424;
+
+       if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) {
+               atm_dbg(instance, "%s: atm_start failed: %d!\n", __func__, ret);
+               goto fail;
+       }
+
+       /* ready for ATM callbacks */
+       usbatm_get_instance(instance);  /* dropped in usbatm_atm_dev_close */
+       mb();
+       atm_dev->dev_data = instance;
+
+       /* submit all rx URBs */
+       for (i = 0; i < num_rcv_urbs; i++)
+               usbatm_submit_urb(instance->urbs[i]);
+
+       return 0;
+
+ fail:
+       instance->atm_dev = NULL;
+       shutdown_atm_dev(atm_dev); /* usbatm_atm_dev_close will eventually be called */
+       return ret;
+}
+
+
+/**********
+**  USB  **
+**********/
+
+static int usbatm_do_heavy_init(void *arg)
+{
+       struct usbatm_data *instance = arg;
+       int ret;
+
+       daemonize(instance->driver->driver_name);
+       allow_signal(SIGTERM);
+
+       complete(&instance->thread_started);
+
+       ret = instance->driver->heavy_init(instance, instance->usb_intf);
+
+       if (!ret)
+               ret = usbatm_atm_init(instance);
+
+       down(&instance->serialize);
+       instance->thread_pid = -1;
+       up(&instance->serialize);
+
+       complete_and_exit(&instance->thread_exited, ret);
+}
+
+static int usbatm_heavy_init(struct usbatm_data *instance)
+{
+       int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_KERNEL);
+
+       if (ret < 0) {
+               usb_dbg(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret);
+               return ret;
+       }
+
+       down(&instance->serialize);
+       instance->thread_pid = ret;
+       up(&instance->serialize);
+
+       wait_for_completion(&instance->thread_started);
+
+       return 0;
+}
+
+static void usbatm_tasklet_schedule(unsigned long data)
+{
+       tasklet_schedule((struct tasklet_struct *) data);
+}
+
+static inline void usbatm_init_channel(struct usbatm_channel *channel)
+{
+       spin_lock_init(&channel->lock);
+       INIT_LIST_HEAD(&channel->list);
+       channel->delay.function = usbatm_tasklet_schedule;
+       channel->delay.data = (unsigned long) &channel->tasklet;
+       init_timer(&channel->delay);
+}
+
+int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
+                    struct usbatm_driver *driver)
+{
+       struct device *dev = &intf->dev;
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
+       struct usbatm_data *instance;
+       char *buf;
+       int error = -ENOMEM;
+       int i, length;
+       int need_heavy;
+
+       dev_dbg(dev, "%s: trying driver %s with vendor=0x%x, product=0x%x, ifnum %d\n",
+                       __func__, driver->driver_name,
+                       le16_to_cpu(usb_dev->descriptor.idVendor),
+                       le16_to_cpu(usb_dev->descriptor.idProduct),
+                       intf->altsetting->desc.bInterfaceNumber);
+
+       /* instance init */
+       instance = kcalloc(1, sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL);
+       if (!instance) {
+               dev_dbg(dev, "%s: no memory for instance data!\n", __func__);
+               return -ENOMEM;
+       }
+
+       /* public fields */
+
+       instance->driver = driver;
+       snprintf(instance->driver_name, sizeof(instance->driver_name), driver->driver_name);
+
+       instance->usb_dev = usb_dev;
+       instance->usb_intf = intf;
+
+       buf = instance->description;
+       length = sizeof(instance->description);
+
+       if ((i = usb_string(usb_dev, usb_dev->descriptor.iProduct, buf, length)) < 0)
+               goto bind;
+
+       buf += i;
+       length -= i;
+
+       i = scnprintf(buf, length, " (");
+       buf += i;
+       length -= i;
+
+       if (length <= 0 || (i = usb_make_path(usb_dev, buf, length)) < 0)
+               goto bind;
+
+       buf += i;
+       length -= i;
+
+       snprintf(buf, length, ")");
+
+ bind:
+       need_heavy = 1;
+       if (driver->bind && (error = driver->bind(instance, intf, id, &need_heavy)) < 0) {
+                       dev_dbg(dev, "%s: bind failed: %d!\n", __func__, error);
+                       goto fail_free;
+       }
+
+       /* private fields */
+
+       kref_init(&instance->refcount);         /* dropped in usbatm_usb_disconnect */
+       init_MUTEX(&instance->serialize);
+
+       instance->thread_pid = -1;
+       init_completion(&instance->thread_started);
+       init_completion(&instance->thread_exited);
+
+       INIT_LIST_HEAD(&instance->vcc_list);
+
+       usbatm_init_channel(&instance->rx_channel);
+       usbatm_init_channel(&instance->tx_channel);
+       tasklet_init(&instance->rx_channel.tasklet, usbatm_rx_process, (unsigned long)instance);
+       tasklet_init(&instance->tx_channel.tasklet, usbatm_tx_process, (unsigned long)instance);
+       instance->rx_channel.endpoint = usb_rcvbulkpipe(usb_dev, driver->in);
+       instance->tx_channel.endpoint = usb_sndbulkpipe(usb_dev, driver->out);
+       instance->rx_channel.stride = ATM_CELL_SIZE + driver->rx_padding;
+       instance->tx_channel.stride = ATM_CELL_SIZE + driver->tx_padding;
+       instance->rx_channel.buf_size = rcv_buf_size * instance->rx_channel.stride;
+       instance->tx_channel.buf_size = snd_buf_size * instance->tx_channel.stride;
+       instance->rx_channel.usbatm = instance->tx_channel.usbatm = instance;
+
+       skb_queue_head_init(&instance->sndqueue);
+
+       for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
+               struct urb *urb;
+               u8 *buffer;
+               unsigned int iso_packets = 0, iso_size = 0;
+               struct usbatm_channel *channel = i < num_rcv_urbs ?
+                       &instance->rx_channel : &instance->tx_channel;
+
+               if (usb_pipeisoc(channel->endpoint)) {
+                       /* don't expect iso out endpoints */
+                       iso_size = usb_maxpacket(instance->usb_dev, channel->endpoint, 0);
+                       iso_size -= iso_size % channel->stride; /* alignment */
+                       BUG_ON(!iso_size);
+                       iso_packets = (channel->buf_size - 1) / iso_size + 1;
+               }
+
+               urb = usb_alloc_urb(iso_packets, GFP_KERNEL);
+               if (!urb) {
+                       dev_dbg(dev, "%s: no memory for urb %d!\n", __func__, i);
+                       goto fail_unbind;
+               }
+
+               instance->urbs[i] = urb;
+
+               buffer = kmalloc(channel->buf_size, GFP_KERNEL);
+               if (!buffer) {
+                       dev_dbg(dev, "%s: no memory for buffer %d!\n", __func__, i);
+                       goto fail_unbind;
+               }
+               memset(buffer, 0, channel->buf_size);
+
+               usb_fill_bulk_urb(urb, instance->usb_dev, channel->endpoint,
+                                 buffer, channel->buf_size, usbatm_complete, channel);
+               if (iso_packets) {
+                       int j;
+                       urb->interval = 1;
+                       urb->transfer_flags = URB_ISO_ASAP;
+                       urb->number_of_packets = iso_packets;
+                       for (j = 0; j < iso_packets; j++) {
+                               urb->iso_frame_desc[j].offset = iso_size * j;
+                               urb->iso_frame_desc[j].length = min_t(int, iso_size,
+                                                                     channel->buf_size - urb->iso_frame_desc[j].offset);
+                       }
+               }
+
+               /* put all tx URBs on the list of spares */
+               if (i >= num_rcv_urbs)
+                       list_add_tail(&urb->urb_list, &channel->list);
+
+               vdbg("%s: alloced buffer 0x%p buf size %u urb 0x%p",
+                    __func__, urb->transfer_buffer, urb->transfer_buffer_length, urb);
+       }
+
+       if (need_heavy && driver->heavy_init) {
+               error = usbatm_heavy_init(instance);
+       } else {
+               complete(&instance->thread_exited);     /* pretend that heavy_init was run */
+               error = usbatm_atm_init(instance);
+       }
+
+       if (error < 0)
+               goto fail_unbind;
+
+       usb_get_dev(usb_dev);
+       usb_set_intfdata(intf, instance);
+
+       return 0;
+
+ fail_unbind:
+       if (instance->driver->unbind)
+               instance->driver->unbind(instance, intf);
+ fail_free:
+       for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
+               if (instance->urbs[i])
+                       kfree(instance->urbs[i]->transfer_buffer);
+               usb_free_urb(instance->urbs[i]);
+       }
+
+       kfree (instance);
+
+       return error;
+}
+EXPORT_SYMBOL_GPL(usbatm_usb_probe);
+
+void usbatm_usb_disconnect(struct usb_interface *intf)
+{
+       struct device *dev = &intf->dev;
+       struct usbatm_data *instance = usb_get_intfdata(intf);
+       int i;
+
+       dev_dbg(dev, "%s entered\n", __func__);
+
+       if (!instance) {
+               dev_dbg(dev, "%s: NULL instance!\n", __func__);
+               return;
+       }
+
+       usb_set_intfdata(intf, NULL);
+
+       down(&instance->serialize);
+       if (instance->thread_pid >= 0)
+               kill_proc(instance->thread_pid, SIGTERM, 1);
+       up(&instance->serialize);
+
+       wait_for_completion(&instance->thread_exited);
+
+       tasklet_disable(&instance->rx_channel.tasklet);
+       tasklet_disable(&instance->tx_channel.tasklet);
+
+       for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++)
+               usb_kill_urb(instance->urbs[i]);
+
+       del_timer_sync(&instance->rx_channel.delay);
+       del_timer_sync(&instance->tx_channel.delay);
+
+       if (instance->atm_dev && instance->driver->atm_stop)
+               instance->driver->atm_stop(instance, instance->atm_dev);
+
+       if (instance->driver->unbind)
+               instance->driver->unbind(instance, intf);
+
+       instance->driver_data = NULL;
+
+       /* turn usbatm_[rt]x_process into noop */
+       /* no need to take the spinlock */
+       INIT_LIST_HEAD(&instance->rx_channel.list);
+       INIT_LIST_HEAD(&instance->tx_channel.list);
+
+       tasklet_enable(&instance->rx_channel.tasklet);
+       tasklet_enable(&instance->tx_channel.tasklet);
+
+       for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
+               kfree(instance->urbs[i]->transfer_buffer);
+               usb_free_urb(instance->urbs[i]);
+       }
+
+       /* ATM finalize */
+       if (instance->atm_dev)
+               shutdown_atm_dev(instance->atm_dev);
+
+       usbatm_put_instance(instance);  /* taken in usbatm_usb_probe */
+}
+EXPORT_SYMBOL_GPL(usbatm_usb_disconnect);
+
+
+/***********
+**  init  **
+***********/
+
+static int __init usbatm_usb_init(void)
+{
+       dbg("%s: driver version %s", __func__, DRIVER_VERSION);
+
+       if (sizeof(struct usbatm_control) > sizeof(((struct sk_buff *) 0)->cb)) {
+               printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name);
+               return -EIO;
+       }
+
+       if ((num_rcv_urbs > UDSL_MAX_RCV_URBS)
+           || (num_snd_urbs > UDSL_MAX_SND_URBS)
+           || (rcv_buf_size < 1)
+           || (rcv_buf_size > UDSL_MAX_RCV_BUF_SIZE)
+           || (snd_buf_size < 1)
+           || (snd_buf_size > UDSL_MAX_SND_BUF_SIZE))
+               return -EINVAL;
+
+       return 0;
+}
+module_init(usbatm_usb_init);
+
+static void __exit usbatm_usb_exit(void)
+{
+       dbg("%s", __func__);
+}
+module_exit(usbatm_usb_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+/************
+**  debug  **
+************/
+
+#ifdef VERBOSE_DEBUG
+static int usbatm_print_packet(const unsigned char *data, int len)
+{
+       unsigned char buffer[256];
+       int i = 0, j = 0;
+
+       for (i = 0; i < len;) {
+               buffer[0] = '\0';
+               sprintf(buffer, "%.3d :", i);
+               for (j = 0; (j < 16) && (i < len); j++, i++) {
+                       sprintf(buffer, "%s %2.2x", buffer, data[i]);
+               }
+               dbg("%s", buffer);
+       }
+       return i;
+}
+#endif
diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h
new file mode 100644 (file)
index 0000000..9366464
--- /dev/null
@@ -0,0 +1,184 @@
+/******************************************************************************
+ *  usbatm.h - Generic USB xDSL driver core
+ *
+ *  Copyright (C) 2001, Alcatel
+ *  Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
+ *  Copyright (C) 2004, David Woodhouse
+ *
+ *  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        _USBATM_H_
+#define        _USBATM_H_
+
+#include <linux/config.h>
+
+/*
+#define DEBUG
+#define VERBOSE_DEBUG
+*/
+
+#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
+#      define DEBUG
+#endif
+
+#include <asm/semaphore.h>
+#include <linux/atm.h>
+#include <linux/atmdev.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/stringify.h>
+#include <linux/usb.h>
+
+#ifdef DEBUG
+#define UDSL_ASSERT(x) BUG_ON(!(x))
+#else
+#define UDSL_ASSERT(x) do { if (!(x)) warn("failed assertion '%s' at line %d", __stringify(x), __LINE__); } while(0)
+#endif
+
+#define usb_err(instance, format, arg...)      \
+       dev_err(&(instance)->usb_intf->dev , format , ## arg)
+#define usb_info(instance, format, arg...)     \
+       dev_info(&(instance)->usb_intf->dev , format , ## arg)
+#define usb_warn(instance, format, arg...)     \
+       dev_warn(&(instance)->usb_intf->dev , format , ## arg)
+#define usb_dbg(instance, format, arg...)      \
+       dev_dbg(&(instance)->usb_intf->dev , format , ## arg)
+
+/* FIXME: move to dev_* once ATM is driver model aware */
+#define atm_printk(level, instance, format, arg...)    \
+       printk(level "ATM dev %d: " format ,            \
+       (instance)->atm_dev->number , ## arg)
+
+#define atm_err(instance, format, arg...)      \
+       atm_printk(KERN_ERR, instance , format , ## arg)
+#define atm_info(instance, format, arg...)     \
+       atm_printk(KERN_INFO, instance , format , ## arg)
+#define atm_warn(instance, format, arg...)     \
+       atm_printk(KERN_WARNING, instance , format , ## arg)
+#ifdef DEBUG
+#define atm_dbg(instance, format, arg...)      \
+       atm_printk(KERN_DEBUG, instance , format , ## arg)
+#else
+#define atm_dbg(instance, format, arg...)      \
+       do {} while (0)
+#endif
+
+
+/* mini driver */
+
+struct usbatm_data;
+
+/*
+*  Assuming all methods exist and succeed, they are called in this order:
+*
+*      bind, heavy_init, atm_start, ..., atm_stop, unbind
+*/
+
+struct usbatm_driver {
+       struct module *owner;
+
+       const char *driver_name;
+
+       /*
+       *  init device ... can sleep, or cause probe() failure.  Drivers with a heavy_init
+       *  method can avoid having it called by setting need_heavy_init to zero.
+       */
+        int (*bind) (struct usbatm_data *, struct usb_interface *,
+                    const struct usb_device_id *id, int *need_heavy_init);
+
+       /* additional device initialization that is too slow to be done in probe() */
+        int (*heavy_init) (struct usbatm_data *, struct usb_interface *);
+
+       /* cleanup device ... can sleep, but can't fail */
+        void (*unbind) (struct usbatm_data *, struct usb_interface *);
+
+       /* init ATM device ... can sleep, or cause ATM initialization failure */
+       int (*atm_start) (struct usbatm_data *, struct atm_dev *);
+
+       /* cleanup ATM device ... can sleep, but can't fail */
+       void (*atm_stop) (struct usbatm_data *, struct atm_dev *);
+
+        int in;                /* rx endpoint */
+        int out;       /* tx endpoint */
+
+       unsigned rx_padding;
+       unsigned tx_padding;
+};
+
+extern int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
+               struct usbatm_driver *driver);
+extern void usbatm_usb_disconnect(struct usb_interface *intf);
+
+
+struct usbatm_channel {
+       int endpoint;                   /* usb pipe */
+       unsigned int stride;            /* ATM cell size + padding */
+       unsigned int buf_size;          /* urb buffer size */
+       spinlock_t lock;
+       struct list_head list;
+       struct tasklet_struct tasklet;
+       struct timer_list delay;
+       struct usbatm_data *usbatm;
+};
+
+/* main driver data */
+
+struct usbatm_data {
+       /******************
+       *  public fields  *
+        ******************/
+
+       /* mini driver */
+       struct usbatm_driver *driver;
+       void *driver_data;
+       char driver_name[16];
+
+       /* USB device */
+       struct usb_device *usb_dev;
+       struct usb_interface *usb_intf;
+       char description[64];
+
+       /* ATM device */
+       struct atm_dev *atm_dev;
+
+       /********************************
+       *  private fields - do not use  *
+        ********************************/
+
+       struct kref refcount;
+       struct semaphore serialize;
+
+       /* heavy init */
+       int thread_pid;
+       struct completion thread_started;
+       struct completion thread_exited;
+
+       /* ATM device */
+       struct list_head vcc_list;
+
+       struct usbatm_channel rx_channel;
+       struct usbatm_channel tx_channel;
+
+       struct sk_buff_head sndqueue;
+       struct sk_buff *current_skb;                    /* being emptied */
+
+       struct urb *urbs[0];
+};
+
+#endif /* _USBATM_H_ */
diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c
new file mode 100644 (file)
index 0000000..7fe7fb4
--- /dev/null
@@ -0,0 +1,196 @@
+/******************************************************************************
+ *  xusbatm.c -        dumb usbatm-based driver for modems initialized in userspace
+ *
+ *  Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with
+ *  this program; if not, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/module.h>
+#include <linux/netdevice.h>           /* FIXME: required by linux/etherdevice.h */
+#include <linux/etherdevice.h>         /* for random_ether_addr() */
+
+#include "usbatm.h"
+
+
+#define XUSBATM_DRIVERS_MAX    8
+
+#define XUSBATM_PARM(name, type, parmtype, desc) \
+       static type name[XUSBATM_DRIVERS_MAX]; \
+       static int num_##name; \
+       module_param_array(name, parmtype, &num_##name, 0444); \
+       MODULE_PARM_DESC(name, desc)
+
+XUSBATM_PARM(vendor, unsigned short, ushort, "USB device vendor");
+XUSBATM_PARM(product, unsigned short, ushort, "USB device product");
+
+XUSBATM_PARM(rx_endpoint, unsigned char, byte, "rx endpoint number");
+XUSBATM_PARM(tx_endpoint, unsigned char, byte, "tx endpoint number");
+XUSBATM_PARM(rx_padding, unsigned char, byte, "rx padding (default 0)");
+XUSBATM_PARM(tx_padding, unsigned char, byte, "tx padding (default 0)");
+
+static const char xusbatm_driver_name[] = "xusbatm";
+
+static struct usbatm_driver xusbatm_drivers[XUSBATM_DRIVERS_MAX];
+static struct usb_device_id xusbatm_usb_ids[XUSBATM_DRIVERS_MAX + 1];
+static struct usb_driver xusbatm_usb_driver;
+
+static int usb_intf_has_ep(const struct usb_interface *intf, u8 ep)
+{
+       int i, j;
+
+       for (i = 0; i < intf->num_altsetting; i++) {
+               struct usb_host_interface *alt = intf->altsetting;
+               for (j = 0; j < alt->desc.bNumEndpoints; j++)
+                       if ((alt->endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) == ep)
+                               return 1;
+       }
+       return 0;
+}
+
+static int xusbatm_bind(struct usbatm_data *usbatm_instance,
+                       struct usb_interface *intf, const struct usb_device_id *id,
+                       int *need_heavy_init)
+{
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
+       int drv_ix = id - xusbatm_usb_ids;
+       int rx_ep_present = usb_intf_has_ep(intf, rx_endpoint[drv_ix]);
+       int tx_ep_present = usb_intf_has_ep(intf, tx_endpoint[drv_ix]);
+       u8 searched_ep = rx_ep_present ? tx_endpoint[drv_ix] : rx_endpoint[drv_ix];
+       int i, ret;
+
+       usb_dbg(usbatm_instance, "%s: binding driver %d: vendor %#x product %#x"
+               " rx: ep %#x padd %d tx: ep %#x padd %d\n",
+               __func__, drv_ix, vendor[drv_ix], product[drv_ix],
+               rx_endpoint[drv_ix], rx_padding[drv_ix],
+               tx_endpoint[drv_ix], tx_padding[drv_ix]);
+
+       if (!rx_ep_present && !tx_ep_present) {
+               usb_dbg(usbatm_instance, "%s: intf #%d has neither rx (%#x) nor tx (%#x) endpoint\n",
+                       __func__, intf->altsetting->desc.bInterfaceNumber,
+                       rx_endpoint[drv_ix], tx_endpoint[drv_ix]);
+               return -ENODEV;
+       }
+
+       if (rx_ep_present && tx_ep_present)
+               return 0;
+
+       for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) {
+               struct usb_interface *cur_if = usb_dev->actconfig->interface[i];
+
+               if (cur_if != intf && usb_intf_has_ep(cur_if, searched_ep)) {
+                       ret = usb_driver_claim_interface(&xusbatm_usb_driver,
+                                                        cur_if, usbatm_instance);
+                       if (!ret)
+                               usb_err(usbatm_instance, "%s: failed to claim interface #%d (%d)\n",
+                                       __func__, cur_if->altsetting->desc.bInterfaceNumber, ret);
+                       return ret;
+               }
+       }
+
+       usb_err(usbatm_instance, "%s: no interface has endpoint %#x\n",
+               __func__, searched_ep);
+       return -ENODEV;
+}
+
+static void xusbatm_unbind(struct usbatm_data *usbatm_instance,
+                          struct usb_interface *intf)
+{
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
+       int i;
+       usb_dbg(usbatm_instance, "%s entered\n", __func__);
+
+       for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) {
+               struct usb_interface *cur_if = usb_dev->actconfig->interface[i];
+               usb_set_intfdata(cur_if, NULL);
+               usb_driver_release_interface(&xusbatm_usb_driver, cur_if);
+       }
+}
+
+static int xusbatm_atm_start(struct usbatm_data *usbatm_instance,
+                            struct atm_dev *atm_dev)
+{
+       atm_dbg(usbatm_instance, "%s entered\n", __func__);
+
+       /* use random MAC as we've no way to get it from the device */
+       random_ether_addr(atm_dev->esi);
+
+       return 0;
+}
+
+
+static int xusbatm_usb_probe(struct usb_interface *intf,
+                            const struct usb_device_id *id)
+{
+       return usbatm_usb_probe(intf, id,
+                               xusbatm_drivers + (id - xusbatm_usb_ids));
+}
+
+static struct usb_driver xusbatm_usb_driver = {
+       .owner          = THIS_MODULE,
+       .name           = xusbatm_driver_name,
+       .probe          = xusbatm_usb_probe,
+       .disconnect     = usbatm_usb_disconnect,
+       .id_table       = xusbatm_usb_ids
+};
+
+static int __init xusbatm_init(void)
+{
+       int i;
+
+       dbg("xusbatm_init");
+
+       if (!num_vendor ||
+           num_vendor != num_product ||
+           num_vendor != num_rx_endpoint ||
+           num_vendor != num_tx_endpoint) {
+               warn("malformed module parameters");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < num_vendor; i++) {
+               xusbatm_usb_ids[i].match_flags  = USB_DEVICE_ID_MATCH_DEVICE;
+               xusbatm_usb_ids[i].idVendor     = vendor[i];
+               xusbatm_usb_ids[i].idProduct    = product[i];
+
+
+               xusbatm_drivers[i].owner        = THIS_MODULE;
+               xusbatm_drivers[i].driver_name  = xusbatm_driver_name;
+               xusbatm_drivers[i].bind         = xusbatm_bind;
+               xusbatm_drivers[i].unbind       = xusbatm_unbind;
+               xusbatm_drivers[i].atm_start    = xusbatm_atm_start;
+               xusbatm_drivers[i].in           = rx_endpoint[i];
+               xusbatm_drivers[i].out          = tx_endpoint[i];
+               xusbatm_drivers[i].rx_padding   = rx_padding[i];
+               xusbatm_drivers[i].tx_padding   = tx_padding[i];
+       }
+
+       return usb_register(&xusbatm_usb_driver);
+}
+module_init(xusbatm_init);
+
+static void __exit xusbatm_exit(void)
+{
+       dbg("xusbatm_exit entered");
+
+       usb_deregister(&xusbatm_usb_driver);
+}
+module_exit(xusbatm_exit);
+
+MODULE_AUTHOR("Roman Kagan, Duncan Sands");
+MODULE_DESCRIPTION("Driver for USB ADSL modems initialized in userspace");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
index 6d1f9b6aecff7d68bb57b2a2b5a2274e4f3e624c..69e859e0f51d42d479436516d675b5182da0e3a7 100644 (file)
@@ -105,6 +105,111 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int
 #define acm_send_break(acm, ms) \
        acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
 
+/*
+ * Write buffer management.
+ * All of these assume proper locks taken by the caller.
+ */
+
+static int acm_wb_alloc(struct acm *acm)
+{
+       int i, wbn;
+       struct acm_wb *wb;
+
+       wbn = acm->write_current;
+       i = 0;
+       for (;;) {
+               wb = &acm->wb[wbn];
+               if (!wb->use) {
+                       wb->use = 1;
+                       return wbn;
+               }
+               wbn = (wbn + 1) % ACM_NWB;
+               if (++i >= ACM_NWB)
+                       return -1;
+       }
+}
+
+static void acm_wb_free(struct acm *acm, int wbn)
+{
+       acm->wb[wbn].use = 0;
+}
+
+static int acm_wb_is_avail(struct acm *acm)
+{
+       int i, n;
+
+       n = 0;
+       for (i = 0; i < ACM_NWB; i++) {
+               if (!acm->wb[i].use)
+                       n++;
+       }
+       return n;
+}
+
+static inline int acm_wb_is_used(struct acm *acm, int wbn)
+{
+       return acm->wb[wbn].use;
+}
+
+/*
+ * Finish write.
+ */
+static void acm_write_done(struct acm *acm)
+{
+       unsigned long flags;
+       int wbn;
+
+       spin_lock_irqsave(&acm->write_lock, flags);
+       acm->write_ready = 1;
+       wbn = acm->write_current;
+       acm_wb_free(acm, wbn);
+       acm->write_current = (wbn + 1) % ACM_NWB;
+       spin_unlock_irqrestore(&acm->write_lock, flags);
+}
+
+/*
+ * Poke write.
+ */
+static int acm_write_start(struct acm *acm)
+{
+       unsigned long flags;
+       int wbn;
+       struct acm_wb *wb;
+       int rc;
+
+       spin_lock_irqsave(&acm->write_lock, flags);
+       if (!acm->dev) {
+               spin_unlock_irqrestore(&acm->write_lock, flags);
+               return -ENODEV;
+       }
+
+       if (!acm->write_ready) {
+               spin_unlock_irqrestore(&acm->write_lock, flags);
+               return 0;       /* A white lie */
+       }
+
+       wbn = acm->write_current;
+       if (!acm_wb_is_used(acm, wbn)) {
+               spin_unlock_irqrestore(&acm->write_lock, flags);
+               return 0;
+       }
+       wb = &acm->wb[wbn];
+
+       acm->write_ready = 0;
+       spin_unlock_irqrestore(&acm->write_lock, flags);
+
+       acm->writeurb->transfer_buffer = wb->buf;
+       acm->writeurb->transfer_dma = wb->dmah;
+       acm->writeurb->transfer_buffer_length = wb->len;
+       acm->writeurb->dev = acm->dev;
+
+       if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) {
+               dbg("usb_submit_urb(write bulk) failed: %d", rc);
+               acm_write_done(acm);
+       }
+       return rc;
+}
+
 /*
  * Interrupt handlers for various ACM device responses
  */
@@ -237,17 +342,13 @@ static void acm_rx_tasklet(unsigned long _acm)
 static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
 {
        struct acm *acm = (struct acm *)urb->context;
-       dbg("Entering acm_write_bulk with status %d\n", urb->status);
-
-       if (!ACM_READY(acm))
-               goto out;
 
-       if (urb->status)
-               dbg("nonzero write bulk status received: %d", urb->status);
+       dbg("Entering acm_write_bulk with status %d\n", urb->status);
 
-       schedule_work(&acm->work);
-out:
-       acm->ready_for_write = 1;
+       acm_write_done(acm);
+       acm_write_start(acm);
+       if (ACM_READY(acm))
+               schedule_work(&acm->work);
 }
 
 static void acm_softint(void *private)
@@ -351,32 +452,33 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
 {
        struct acm *acm = tty->driver_data;
        int stat;
+       unsigned long flags;
+       int wbn;
+       struct acm_wb *wb;
+
        dbg("Entering acm_tty_write to write %d bytes,\n", count);
 
        if (!ACM_READY(acm))
                return -EINVAL;
-       if (!acm->ready_for_write)
-               return 0;
        if (!count)
                return 0;
 
-       count = (count > acm->writesize) ? acm->writesize : count;
+       spin_lock_irqsave(&acm->write_lock, flags);
+       if ((wbn = acm_wb_alloc(acm)) < 0) {
+               spin_unlock_irqrestore(&acm->write_lock, flags);
+               acm_write_start(acm);
+               return 0;
+       }
+       wb = &acm->wb[wbn];
 
+       count = (count > acm->writesize) ? acm->writesize : count;
        dbg("Get %d bytes...", count);
-       memcpy(acm->write_buffer, buf, count);
-       dbg("  Successfully copied.\n");
+       memcpy(wb->buf, buf, count);
+       wb->len = count;
+       spin_unlock_irqrestore(&acm->write_lock, flags);
 
-       acm->writeurb->transfer_buffer_length = count;
-       acm->writeurb->dev = acm->dev;
-
-       acm->ready_for_write = 0;
-       stat = usb_submit_urb(acm->writeurb, GFP_ATOMIC);
-       if (stat < 0) {
-               dbg("usb_submit_urb(write bulk) failed");
-               acm->ready_for_write = 1;
+       if ((stat = acm_write_start(acm)) < 0)
                return stat;
-       }
-
        return count;
 }
 
@@ -385,7 +487,11 @@ static int acm_tty_write_room(struct tty_struct *tty)
        struct acm *acm = tty->driver_data;
        if (!ACM_READY(acm))
                return -EINVAL;
-       return !acm->ready_for_write ? 0 : acm->writesize;
+       /*
+        * Do not let the line discipline to know that we have a reserve,
+        * or it might get too enthusiastic.
+        */
+       return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0;
 }
 
 static int acm_tty_chars_in_buffer(struct tty_struct *tty)
@@ -393,7 +499,10 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty)
        struct acm *acm = tty->driver_data;
        if (!ACM_READY(acm))
                return -EINVAL;
-       return !acm->ready_for_write ? acm->writeurb->transfer_buffer_length : 0;
+       /*
+        * This is inaccurate (overcounts), but it works.
+        */
+       return (ACM_NWB - acm_wb_is_avail(acm)) * acm->writesize;
 }
 
 static void acm_tty_throttle(struct tty_struct *tty)
@@ -526,6 +635,39 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_
  * USB probe and disconnect routines.
  */
 
+/* Little helper: write buffers free */
+static void acm_write_buffers_free(struct acm *acm)
+{
+       int i;
+       struct acm_wb *wb;
+
+       for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
+               usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
+       }
+}
+
+/* Little helper: write buffers allocate */
+static int acm_write_buffers_alloc(struct acm *acm)
+{
+       int i;
+       struct acm_wb *wb;
+
+       for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
+               wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
+                   &wb->dmah);
+               if (!wb->buf) {
+                       while (i != 0) {
+                               --i;
+                               --wb;
+                               usb_buffer_free(acm->dev, acm->writesize,
+                                   wb->buf, wb->dmah);
+                       }
+                       return -ENOMEM;
+               }
+       }
+       return 0;
+}
+
 static int acm_probe (struct usb_interface *intf,
                      const struct usb_device_id *id)
 {
@@ -700,7 +842,8 @@ skip_normal_probe:
        acm->bh.data = (unsigned long) acm;
        INIT_WORK(&acm->work, acm_softint, acm);
        spin_lock_init(&acm->throttle_lock);
-       acm->ready_for_write = 1;
+       spin_lock_init(&acm->write_lock);
+       acm->write_ready = 1;
 
        buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
        if (!buf) {
@@ -716,12 +859,10 @@ skip_normal_probe:
        }
        acm->read_buffer = buf;
 
-       buf = usb_buffer_alloc(usb_dev, acm->writesize, GFP_KERNEL, &acm->write_dma);
-       if (!buf) {
+       if (acm_write_buffers_alloc(acm) < 0) {
                dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
                goto alloc_fail4;
        }
-       acm->write_buffer = buf;        
 
        acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
        if (!acm->ctrlurb) {
@@ -750,9 +891,9 @@ skip_normal_probe:
        acm->readurb->transfer_dma = acm->read_dma;
 
        usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
-                         acm->write_buffer, acm->writesize, acm_write_bulk, acm);
+                         NULL, acm->writesize, acm_write_bulk, acm);
        acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
-       acm->writeurb->transfer_dma = acm->write_dma;
+       /* acm->writeurb->transfer_dma = 0; */
 
        dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
 
@@ -775,7 +916,7 @@ alloc_fail7:
 alloc_fail6:
        usb_free_urb(acm->ctrlurb);
 alloc_fail5:
-       usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma);
+       acm_write_buffers_free(acm);
 alloc_fail4:
        usb_buffer_free(usb_dev, readsize, acm->read_buffer, acm->read_dma);
 alloc_fail3:
@@ -806,7 +947,7 @@ static void acm_disconnect(struct usb_interface *intf)
 
        flush_scheduled_work(); /* wait for acm_softint */
 
-       usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma);
+       acm_write_buffers_free(acm);
        usb_buffer_free(usb_dev, acm->readsize, acm->read_buffer, acm->read_dma);
        usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
 
index 9009114e311bebc1c50fc7e5946ac428dbf08862..963a5dfd209670a8d93dcc1825d24eb600af6da8 100644 (file)
  * Internal driver structures.
  */
 
+/*
+ * The only reason to have several buffers is to accomodate assumptions
+ * in line disciplines. They ask for empty space amount, receive our URB size,
+ * and proceed to issue several 1-character writes, assuming they will fit.
+ * The very first write takes a complete URB. Fortunately, this only happens
+ * when processing onlcr, so we only need 2 buffers.
+ */
+#define ACM_NWB  2
+struct acm_wb {
+       unsigned char *buf;
+       dma_addr_t dmah;
+       int len;
+       int use;
+};
+
 struct acm {
        struct usb_device *dev;                         /* the corresponding usb device */
        struct usb_interface *control;                  /* control interface */
        struct usb_interface *data;                     /* data interface */
        struct tty_struct *tty;                         /* the corresponding tty */
        struct urb *ctrlurb, *readurb, *writeurb;       /* urbs */
-       u8 *ctrl_buffer, *read_buffer, *write_buffer;   /* buffers of urbs */
-       dma_addr_t ctrl_dma, read_dma, write_dma;       /* dma handles of buffers */
+       u8 *ctrl_buffer, *read_buffer;                  /* buffers of urbs */
+       dma_addr_t ctrl_dma, read_dma;                  /* dma handles of buffers */
+       struct acm_wb wb[ACM_NWB];
+       int write_current;                              /* current write buffer */
+       int write_used;                                 /* number of non-empty write buffers */
+       int write_ready;                                /* write urb is not running */
+       spinlock_t write_lock;
        struct usb_cdc_line_coding line;                /* bits, stop, parity */
        struct work_struct work;                        /* work queue entry for line discipline waking up */
        struct tasklet_struct bh;                       /* rx processing */
@@ -71,7 +91,6 @@ struct acm {
        unsigned int minor;                             /* acm minor number */
        unsigned char throttle;                         /* throttled by tty layer */
        unsigned char clocal;                           /* termios CLOCAL */
-       unsigned char ready_for_write;                  /* write urb can be used */
        unsigned char resubmit_to_unthrottle;           /* throtteling has disabled the read urb */
        unsigned int ctrl_caps;                         /* control capabilities from the class specific header */
 };
index bba22e97ea0f0efefdde0d958d3b035c269f6f17..7ce43fb8118a3b79e969711606390bdaafee96e5 100644 (file)
@@ -379,6 +379,8 @@ static int usblp_open(struct inode *inode, struct file *file)
        usblp->writeurb->transfer_buffer_length = 0;
        usblp->wcomplete = 1; /* we begin writeable */
        usblp->rcomplete = 0;
+       usblp->writeurb->status = 0;
+       usblp->readurb->status = 0;
 
        if (usblp->bidir) {
                usblp->readcount = 0;
@@ -751,6 +753,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
                                schedule();
                        } else {
                                set_current_state(TASK_RUNNING);
+                               down(&usblp->sem);
                                break;
                        }
                        down (&usblp->sem);
index 6bfab4bcaa9e945a5f919a93ce1cb0f75da08775..787c27a63c5135731c71f75fed5429501b97aa78 100644 (file)
@@ -784,16 +784,16 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
                for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
                        if (usb_interface_claimed(actconfig->interface[i])) {
                                dev_warn (&ps->dev->dev,
-                                       "usbfs: interface %d claimed "
+                                       "usbfs: interface %d claimed by %s "
                                        "while '%s' sets config #%d\n",
                                        actconfig->interface[i]
                                                ->cur_altsetting
                                                ->desc.bInterfaceNumber,
+                                       actconfig->interface[i]
+                                               ->dev.driver->name,
                                        current->comm, u);
-#if 0  /* FIXME:  enable in 2.6.10 or so */
                                status = -EBUSY;
                                break;
-#endif
                        }
                }
        }
index 0da23732e8076572d275edf87ede9fac8656733a..83e732a0d64a5bd318dd9034a3728519b6bc1b06 100644 (file)
@@ -519,119 +519,120 @@ error:
 /*-------------------------------------------------------------------------*/
 
 /*
- * Root Hub interrupt transfers are synthesized with a timer.
- * Completions are called in_interrupt() but not in_irq().
+ * Root Hub interrupt transfers are polled using a timer if the
+ * driver requests it; otherwise the driver is responsible for
+ * calling usb_hcd_poll_rh_status() when an event occurs.
  *
- * Note: some root hubs (including common UHCI based designs) can't
- * correctly issue port change IRQs.  They're the ones that _need_ a
- * timer; most other root hubs don't.  Some systems could save a
- * lot of battery power by eliminating these root hub timer IRQs.
+ * Completions are called in_interrupt(), but they may or may not
+ * be in_irq().
  */
+void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
+{
+       struct urb      *urb;
+       int             length;
+       unsigned long   flags;
+       char            buffer[4];      /* Any root hubs with > 31 ports? */
 
-static void rh_report_status (unsigned long ptr);
+       if (!hcd->uses_new_polling && !hcd->status_urb)
+               return;
 
-static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) 
-{
-       int     len = 1 + (urb->dev->maxchild / 8);
+       length = hcd->driver->hub_status_data(hcd, buffer);
+       if (length > 0) {
 
-       /* rh_timer protected by hcd_data_lock */
-       if (hcd->rh_timer.data || urb->transfer_buffer_length < len) {
-               dev_dbg (hcd->self.controller,
-                               "not queuing rh status urb, stat %d\n",
-                               urb->status);
-               return -EINVAL;
+               /* try to complete the status urb */
+               local_irq_save (flags);
+               spin_lock(&hcd_root_hub_lock);
+               urb = hcd->status_urb;
+               if (urb) {
+                       spin_lock(&urb->lock);
+                       if (urb->status == -EINPROGRESS) {
+                               hcd->poll_pending = 0;
+                               hcd->status_urb = NULL;
+                               urb->status = 0;
+                               urb->hcpriv = NULL;
+                               urb->actual_length = length;
+                               memcpy(urb->transfer_buffer, buffer, length);
+                       } else          /* urb has been unlinked */
+                               length = 0;
+                       spin_unlock(&urb->lock);
+               } else
+                       length = 0;
+               spin_unlock(&hcd_root_hub_lock);
+
+               /* local irqs are always blocked in completions */
+               if (length > 0)
+                       usb_hcd_giveback_urb (hcd, urb, NULL);
+               else
+                       hcd->poll_pending = 1;
+               local_irq_restore (flags);
        }
 
-       init_timer (&hcd->rh_timer);
-       hcd->rh_timer.function = rh_report_status;
-       hcd->rh_timer.data = (unsigned long) urb;
-       /* USB 2.0 spec says 256msec; this is close enough */
-       hcd->rh_timer.expires = jiffies + HZ/4;
-       add_timer (&hcd->rh_timer);
-       urb->hcpriv = hcd;      /* nonzero to indicate it's queued */
-       return 0;
+       /* The USB 2.0 spec says 256 ms.  This is close enough and won't
+        * exceed that limit if HZ is 100. */
+       if (hcd->uses_new_polling ? hcd->poll_rh :
+                       (length == 0 && hcd->status_urb != NULL))
+               mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250));
 }
+EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status);
 
 /* timer callback */
+static void rh_timer_func (unsigned long _hcd)
+{
+       usb_hcd_poll_rh_status((struct usb_hcd *) _hcd);
+}
 
-static void rh_report_status (unsigned long ptr)
+/*-------------------------------------------------------------------------*/
+
+static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
 {
-       struct urb      *urb;
-       struct usb_hcd  *hcd;
-       int             length = 0;
+       int             retval;
        unsigned long   flags;
+       int             len = 1 + (urb->dev->maxchild / 8);
 
-       urb = (struct urb *) ptr;
-       local_irq_save (flags);
-       spin_lock (&urb->lock);
+       spin_lock_irqsave (&hcd_root_hub_lock, flags);
+       if (urb->status != -EINPROGRESS)        /* already unlinked */
+               retval = urb->status;
+       else if (hcd->status_urb || urb->transfer_buffer_length < len) {
+               dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
+               retval = -EINVAL;
+       } else {
+               hcd->status_urb = urb;
+               urb->hcpriv = hcd;      /* indicate it's queued */
 
-       /* do nothing if the urb's been unlinked */
-       if (!urb->dev
-                       || urb->status != -EINPROGRESS
-                       || (hcd = urb->dev->bus->hcpriv) == NULL) {
-               spin_unlock (&urb->lock);
-               local_irq_restore (flags);
-               return;
-       }
+               if (!hcd->uses_new_polling)
+                       mod_timer (&hcd->rh_timer, jiffies +
+                                       msecs_to_jiffies(250));
 
-       /* complete the status urb, or retrigger the timer */
-       spin_lock (&hcd_data_lock);
-       if (urb->dev->state == USB_STATE_CONFIGURED) {
-               length = hcd->driver->hub_status_data (
-                                       hcd, urb->transfer_buffer);
-               if (length > 0) {
-                       hcd->rh_timer.data = 0;
-                       urb->actual_length = length;
-                       urb->status = 0;
-                       urb->hcpriv = NULL;
-               } else
-                       mod_timer (&hcd->rh_timer, jiffies + HZ/4);
+               /* If a status change has already occurred, report it ASAP */
+               else if (hcd->poll_pending)
+                       mod_timer (&hcd->rh_timer, jiffies);
+               retval = 0;
        }
-       spin_unlock (&hcd_data_lock);
-       spin_unlock (&urb->lock);
-
-       /* local irqs are always blocked in completions */
-       if (length > 0)
-               usb_hcd_giveback_urb (hcd, urb, NULL);
-       local_irq_restore (flags);
+       spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
+       return retval;
 }
 
-/*-------------------------------------------------------------------------*/
-
 static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
 {
-       if (usb_pipeint (urb->pipe)) {
-               int             retval;
-               unsigned long   flags;
-
-               spin_lock_irqsave (&hcd_data_lock, flags);
-               retval = rh_status_urb (hcd, urb);
-               spin_unlock_irqrestore (&hcd_data_lock, flags);
-               return retval;
-       }
+       if (usb_pipeint (urb->pipe))
+               return rh_queue_status (hcd, urb);
        if (usb_pipecontrol (urb->pipe))
                return rh_call_control (hcd, urb);
-       else
-               return -EINVAL;
+       return -EINVAL;
 }
 
 /*-------------------------------------------------------------------------*/
 
+/* Asynchronous unlinks of root-hub control URBs are legal, but they
+ * don't do anything.  Status URB unlinks must be made in process context
+ * with interrupts enabled.
+ */
 static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
 {
-       unsigned long   flags;
+       if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
+               if (in_interrupt())
+                       return 0;               /* nothing to do */
 
-       /* note:  always a synchronous unlink */
-       if ((unsigned long) urb == hcd->rh_timer.data) {
-               del_timer_sync (&hcd->rh_timer);
-               hcd->rh_timer.data = 0;
-
-               local_irq_save (flags);
-               urb->hcpriv = NULL;
-               usb_hcd_giveback_urb (hcd, urb, NULL);
-               local_irq_restore (flags);
-
-       } else if (usb_pipeendpoint(urb->pipe) == 0) {
                spin_lock_irq(&urb->lock);      /* from usb_kill_urb */
                ++urb->reject;
                spin_unlock_irq(&urb->lock);
@@ -642,8 +643,22 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
                spin_lock_irq(&urb->lock);
                --urb->reject;
                spin_unlock_irq(&urb->lock);
-       } else
-               return -EINVAL;
+
+       } else {                                /* Status URB */
+               if (!hcd->uses_new_polling)
+                       del_timer_sync (&hcd->rh_timer);
+               local_irq_disable ();
+               spin_lock (&hcd_root_hub_lock);
+               if (urb == hcd->status_urb) {
+                       hcd->status_urb = NULL;
+                       urb->hcpriv = NULL;
+               } else
+                       urb = NULL;             /* wasn't fully queued */
+               spin_unlock (&hcd_root_hub_lock);
+               if (urb)
+                       usb_hcd_giveback_urb (hcd, urb, NULL);
+               local_irq_enable ();
+       }
 
        return 0;
 }
@@ -817,30 +832,22 @@ static void usb_deregister_bus (struct usb_bus *bus)
 }
 
 /**
- * usb_hcd_register_root_hub - called by HCD to register its root hub 
+ * register_root_hub - called by usb_add_hcd() to register a root hub
  * @usb_dev: the usb root hub device to be registered.
  * @hcd: host controller for this root hub
  *
- * The USB host controller calls this function to register the root hub
- * properly with the USB subsystem.  It sets up the device properly in
- * the device tree and stores the root_hub pointer in the bus structure,
- * then calls usb_new_device() to register the usb device.  It also
- * assigns the root hub's USB address (always 1).
+ * This function registers the root hub with the USB subsystem.  It sets up
+ * the device properly in the device tree and stores the root_hub pointer
+ * in the bus structure, then calls usb_new_device() to register the usb
+ * device.  It also assigns the root hub's USB address (always 1).
  */
-int usb_hcd_register_root_hub (struct usb_device *usb_dev, struct usb_hcd *hcd)
+static int register_root_hub (struct usb_device *usb_dev,
+               struct usb_hcd *hcd)
 {
        struct device *parent_dev = hcd->self.controller;
        const int devnum = 1;
        int retval;
 
-       /* hcd->driver->start() reported can_wakeup, probably with
-        * assistance from board's boot firmware.
-        * NOTE:  normal devices won't enable wakeup by default.
-        */
-       if (hcd->can_wakeup)
-               dev_dbg (parent_dev, "supports USB remote wakeup\n");
-       hcd->remote_wakeup = hcd->can_wakeup;
-
        usb_dev->devnum = devnum;
        usb_dev->bus->devnum_next = devnum + 1;
        memset (&usb_dev->bus->devmap.devicemap, 0,
@@ -883,7 +890,16 @@ int usb_hcd_register_root_hub (struct usb_device *usb_dev, struct usb_hcd *hcd)
 
        return retval;
 }
-EXPORT_SYMBOL_GPL(usb_hcd_register_root_hub);
+
+void usb_enable_root_hub_irq (struct usb_bus *bus)
+{
+       struct usb_hcd *hcd;
+
+       hcd = container_of (bus, struct usb_hcd, self);
+       if (hcd->driver->hub_irq_enable && !hcd->poll_rh &&
+                       hcd->state != HC_STATE_HALT)
+               hcd->driver->hub_irq_enable (hcd);
+}
 
 
 /*-------------------------------------------------------------------------*/
@@ -1348,7 +1364,8 @@ hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep)
 
        hcd = udev->bus->hcpriv;
 
-       WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT);
+       WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT &&
+                       udev->state != USB_STATE_NOTATTACHED);
 
        local_irq_disable ();
 
@@ -1612,6 +1629,8 @@ void usb_hc_died (struct usb_hcd *hcd)
 
        spin_lock_irqsave (&hcd_root_hub_lock, flags);
        if (hcd->rh_registered) {
+               hcd->poll_rh = 0;
+               del_timer(&hcd->rh_timer);
 
                /* make khubd clean up old urbs and devices */
                usb_set_device_state (hcd->self.root_hub,
@@ -1665,6 +1684,8 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
        hcd->self.bus_name = bus_name;
 
        init_timer(&hcd->rh_timer);
+       hcd->rh_timer.function = rh_timer_func;
+       hcd->rh_timer.data = (unsigned long) hcd;
 
        hcd->driver = driver;
        hcd->product_desc = (driver->product_desc) ? driver->product_desc :
@@ -1694,7 +1715,8 @@ EXPORT_SYMBOL (usb_put_hcd);
 int usb_add_hcd(struct usb_hcd *hcd,
                unsigned int irqnum, unsigned long irqflags)
 {
-       int     retval;
+       int retval;
+       struct usb_device *rhdev;
 
        dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
 
@@ -1710,7 +1732,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
        }
 
        if ((retval = usb_register_bus(&hcd->self)) < 0)
-               goto err1;
+               goto err_register_bus;
 
        if (hcd->driver->irq) {
                char    buf[8], *bufp = buf;
@@ -1727,7 +1749,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
                                hcd->irq_descr, hcd)) != 0) {
                        dev_err(hcd->self.controller,
                                        "request interrupt %s failed\n", bufp);
-                       goto err2;
+                       goto err_request_irq;
                }
                hcd->irq = irqnum;
                dev_info(hcd->self.controller, "irq %s, %s 0x%08llx\n", bufp,
@@ -1743,19 +1765,55 @@ int usb_add_hcd(struct usb_hcd *hcd,
                                        (unsigned long long)hcd->rsrc_start);
        }
 
+       /* Allocate the root hub before calling hcd->driver->start(),
+        * but don't register it until afterward so that the hardware
+        * is running.
+        */
+       if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
+               dev_err(hcd->self.controller, "unable to allocate root hub\n");
+               retval = -ENOMEM;
+               goto err_allocate_root_hub;
+       }
+       rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
+                       USB_SPEED_FULL;
+
+       /* Although in principle hcd->driver->start() might need to use rhdev,
+        * none of the current drivers do.
+        */
        if ((retval = hcd->driver->start(hcd)) < 0) {
                dev_err(hcd->self.controller, "startup error %d\n", retval);
-               goto err3;
+               goto err_hcd_driver_start;
        }
 
+       /* hcd->driver->start() reported can_wakeup, probably with
+        * assistance from board's boot firmware.
+        * NOTE:  normal devices won't enable wakeup by default.
+        */
+       if (hcd->can_wakeup)
+               dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
+       hcd->remote_wakeup = hcd->can_wakeup;
+
+       if ((retval = register_root_hub(rhdev, hcd)) != 0)
+               goto err_register_root_hub;
+
+       if (hcd->uses_new_polling && hcd->poll_rh)
+               usb_hcd_poll_rh_status(hcd);
        return retval;
 
- err3:
+ err_register_root_hub:
+       hcd->driver->stop(hcd);
+
+ err_hcd_driver_start:
+       usb_put_dev(rhdev);
+
+ err_allocate_root_hub:
        if (hcd->irq >= 0)
                free_irq(irqnum, hcd);
- err2:
+
+ err_request_irq:
        usb_deregister_bus(&hcd->self);
- err1:
+
+ err_register_bus:
        hcd_buffer_destroy(hcd);
        return retval;
 } 
@@ -1782,6 +1840,9 @@ void usb_remove_hcd(struct usb_hcd *hcd)
        spin_unlock_irq (&hcd_root_hub_lock);
        usb_disconnect(&hcd->self.root_hub);
 
+       hcd->poll_rh = 0;
+       del_timer_sync(&hcd->rh_timer);
+
        hcd->driver->stop(hcd);
        hcd->state = HC_STATE_HALT;
 
index 325a51656c3f2e4848626e3338b66176c8ac5c70..8dc13cde2f73eea8d0801cbb6b6a9e3bcdb4f13d 100644 (file)
@@ -65,7 +65,8 @@ struct usb_hcd {      /* usb_bus.hcpriv points to this */
        const char              *product_desc;  /* product/vendor string */
        char                    irq_descr[24];  /* driver + bus # */
 
-       struct timer_list       rh_timer;       /* drives root hub */
+       struct timer_list       rh_timer;       /* drives root-hub polling */
+       struct urb              *status_urb;    /* the current status urb */
 
        /*
         * hardware info/state
@@ -76,10 +77,17 @@ struct usb_hcd {    /* usb_bus.hcpriv points to this */
        unsigned                remote_wakeup:1;/* sw should use wakeup? */
        unsigned                rh_registered:1;/* is root hub registered? */
 
+       /* The next flag is a stopgap, to be removed when all the HCDs
+        * support the new root-hub polling mechanism. */
+       unsigned                uses_new_polling:1;
+       unsigned                poll_rh:1;      /* poll for rh status? */
+       unsigned                poll_pending:1; /* status has changed? */
+
        int                     irq;            /* irq allocated */
        void __iomem            *regs;          /* device memory/io */
        u64                     rsrc_start;     /* memory/io resource start */
        u64                     rsrc_len;       /* memory/io resource length */
+       unsigned                power_budget;   /* in mA, 0 = no limit */
 
 #define HCD_BUFFER_POOLS       4
        struct dma_pool         *pool [HCD_BUFFER_POOLS];
@@ -207,6 +215,8 @@ struct hc_driver {
        int             (*hub_suspend)(struct usb_hcd *);
        int             (*hub_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 */
 };
 
 extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);
@@ -243,7 +253,9 @@ void hcd_buffer_free (struct usb_bus *bus, size_t size,
 
 /* generic bus glue, needed for host controllers that don't use PCI */
 extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);
+
 extern void usb_hc_died (struct usb_hcd *hcd);
+extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
 
 /* -------------------------------------------------------------------------- */
 
@@ -341,9 +353,6 @@ extern long usb_calc_bus_time (int speed, int is_input,
 
 extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
 
-extern int usb_hcd_register_root_hub (struct usb_device *usb_dev,
-               struct usb_hcd *hcd);
-
 extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
 
 extern void usb_set_device_state(struct usb_device *udev,
@@ -360,6 +369,8 @@ extern wait_queue_head_t usb_kill_urb_queue;
 extern struct usb_bus *usb_bus_get (struct usb_bus *bus);
 extern void usb_bus_put (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,
        struct usb_interface *interface);
 
index d2d648ee864009cc028d2ce539ffede88f9bf17f..32ff32181852baefc713c1b1e7a79382e3525a86 100644 (file)
@@ -643,15 +643,21 @@ static int hub_configure(struct usb_hub *hub,
                message = "can't get hub status";
                goto fail;
        }
-       cpu_to_le16s(&hubstatus);
-       if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
+       le16_to_cpus(&hubstatus);
+       if (hdev == hdev->bus->root_hub) {
+               struct usb_hcd *hcd =
+                               container_of(hdev->bus, struct usb_hcd, self);
+
+               hub->power_budget = min(500u, hcd->power_budget) / 2;
+       } else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
                dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
                        hub->descriptor->bHubContrCurrent);
                hub->power_budget = (501 - hub->descriptor->bHubContrCurrent)
                                        / 2;
+       }
+       if (hub->power_budget)
                dev_dbg(hub_dev, "%dmA bus power budget for children\n",
                        hub->power_budget * 2);
-       }
 
 
        ret = hub_hub_status(hub, &hubstatus, &hubchange);
@@ -1727,7 +1733,7 @@ static int finish_port_resume(struct usb_device *udev)
                        struct usb_driver       *driver;
 
                        intf = udev->actconfig->interface[i];
-                       if (intf->dev.power.power_state == PMSG_SUSPEND)
+                       if (intf->dev.power.power_state == PMSG_ON)
                                continue;
                        if (!intf->dev.driver) {
                                /* FIXME maybe force to alt 0 */
@@ -2787,6 +2793,11 @@ static void hub_events(void)
 
                hub->activating = 0;
 
+               /* If this is a root hub, tell the HCD it's okay to
+                * re-enable port-change interrupts now. */
+               if (!hdev->parent)
+                       usb_enable_root_hub_irq(hdev->bus);
+
 loop:
                usb_unlock_device(hdev);
                usb_put_intf(intf);
@@ -2808,7 +2819,7 @@ static int hub_thread(void *__unused)
        do {
                hub_events();
                wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); 
-               try_to_freeze(PF_FREEZE);
+               try_to_freeze();
        } while (!signal_pending(current));
 
        pr_debug ("%s: khubd exiting\n", usbcore_name);
index d114b847d56f84e9ba0b1fb1b754283e02618eed..53bf5649621ef366485c4346e754cfc9f60ab893 100644 (file)
@@ -224,15 +224,4 @@ struct usb_hub {
        struct work_struct      leds;
 };
 
-/* use this for low-powered root hubs */
-static inline void
-hub_set_power_budget (struct usb_device *hubdev, unsigned mA)
-{
-       struct usb_hub  *hub;
-
-       hub = (struct usb_hub *)
-               usb_get_intfdata (hubdev->actconfig->interface[0]);
-       hub->power_budget = min(mA,(unsigned)500)/2;
-}
-
 #endif /* __LINUX_HUB_H */
index 3b24f9f2c2341808206de28609385e6cb88aaf6a..ff075a53c8d66787461b634925c317d8e2ea648a 100644 (file)
@@ -53,6 +53,9 @@ config USB_GADGET_DEBUG_FILES
           driver on a new board.   Enable these files by choosing "Y"
           here.  If in doubt, or to conserve kernel memory, say "N".
 
+config USB_GADGET_SELECTED
+       boolean
+
 #
 # USB Peripheral Controller Support
 #
@@ -85,6 +88,7 @@ config USB_NET2280
        tristate
        depends on USB_GADGET_NET2280
        default USB_GADGET
+       select USB_GADGET_SELECTED
 
 config USB_GADGET_PXA2XX
        boolean "PXA 25x or IXP 4xx"
@@ -105,6 +109,7 @@ config USB_PXA2XX
        tristate
        depends on USB_GADGET_PXA2XX
        default USB_GADGET
+       select USB_GADGET_SELECTED
 
 # if there's only one gadget driver, using only two bulk endpoints,
 # don't waste memory for the other endpoints
@@ -134,6 +139,7 @@ config USB_GOKU
        tristate
        depends on USB_GADGET_GOKU
        default USB_GADGET
+       select USB_GADGET_SELECTED
 
 
 config USB_GADGET_LH7A40X
@@ -146,6 +152,7 @@ config USB_LH7A40X
        tristate
        depends on USB_GADGET_LH7A40X
        default USB_GADGET
+       select USB_GADGET_SELECTED
 
 
 config USB_GADGET_OMAP
@@ -167,6 +174,7 @@ config USB_OMAP
        tristate
        depends on USB_GADGET_OMAP
        default USB_GADGET
+       select USB_GADGET_SELECTED
 
 config USB_OTG
        boolean "OTG Support"
@@ -207,6 +215,7 @@ config USB_DUMMY_HCD
        tristate
        depends on USB_GADGET_DUMMY_HCD
        default USB_GADGET
+       select USB_GADGET_SELECTED
 
 # NOTE:  Please keep dummy_hcd LAST so that "real hardware" appears
 # first and will be selected by default.
@@ -226,7 +235,7 @@ config USB_GADGET_DUALSPEED
 #
 choice
        tristate "USB Gadget Drivers"
-       depends on USB_GADGET
+       depends on USB_GADGET && USB_GADGET_SELECTED
        default USB_ETH
        help
          A Linux "Gadget Driver" talks to the USB Peripheral Controller
index c039d2fbe7ab950ea092e6a853869fc32c760162..4d692670f2887be5124199ce0fe8f26643c142b9 100644 (file)
@@ -65,7 +65,7 @@
 
 
 #define DRIVER_DESC    "USB Host+Gadget Emulator"
-#define DRIVER_VERSION "17 Dec 2004"
+#define DRIVER_VERSION "02 May 2005"
 
 static const char      driver_name [] = "dummy_hcd";
 static const char      driver_desc [] = "USB Host+Gadget Emulator";
@@ -141,6 +141,8 @@ static const char *const ep_name [] = {
 };
 #define DUMMY_ENDPOINTS        (sizeof(ep_name)/sizeof(char *))
 
+/*-------------------------------------------------------------------------*/
+
 #define FIFO_SIZE              64
 
 struct urbp {
@@ -148,6 +150,13 @@ struct urbp {
        struct list_head        urbp_list;
 };
 
+
+enum dummy_rh_state {
+       DUMMY_RH_RESET,
+       DUMMY_RH_SUSPENDED,
+       DUMMY_RH_RUNNING
+};
+
 struct dummy {
        spinlock_t                      lock;
 
@@ -161,12 +170,18 @@ struct dummy {
        struct dummy_request            fifo_req;
        u8                              fifo_buf [FIFO_SIZE];
        u16                             devstatus;
+       unsigned                        udc_suspended:1;
+       unsigned                        pullup:1;
+       unsigned                        active:1;
+       unsigned                        old_active:1;
 
        /*
         * MASTER/HOST side support
         */
+       enum dummy_rh_state             rh_state;
        struct timer_list               timer;
        u32                             port_status;
+       u32                             old_status;
        unsigned                        resuming:1;
        unsigned long                   re_timeout;
 
@@ -189,6 +204,11 @@ static inline struct device *dummy_dev (struct dummy *dum)
        return dummy_to_hcd(dum)->self.controller;
 }
 
+static inline struct device *udc_dev (struct dummy *dum)
+{
+       return dum->gadget.dev.parent;
+}
+
 static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
 {
        return container_of (ep->gadget, struct dummy, gadget);
@@ -208,16 +228,98 @@ static struct dummy                       *the_controller;
 
 /*-------------------------------------------------------------------------*/
 
-/*
- * This "hardware" may look a bit odd in diagnostics since it's got both
- * host and device sides; and it binds different drivers to each side.
- */
-static struct platform_device          the_pdev;
+/* SLAVE/GADGET SIDE UTILITY ROUTINES */
 
-static struct device_driver dummy_driver = {
-       .name           = (char *) driver_name,
-       .bus            = &platform_bus_type,
-};
+/* called with spinlock held */
+static void nuke (struct dummy *dum, struct dummy_ep *ep)
+{
+       while (!list_empty (&ep->queue)) {
+               struct dummy_request    *req;
+
+               req = list_entry (ep->queue.next, struct dummy_request, queue);
+               list_del_init (&req->queue);
+               req->req.status = -ESHUTDOWN;
+
+               spin_unlock (&dum->lock);
+               req->req.complete (&ep->ep, &req->req);
+               spin_lock (&dum->lock);
+       }
+}
+
+/* caller must hold lock */
+static void
+stop_activity (struct dummy *dum)
+{
+       struct dummy_ep *ep;
+
+       /* prevent any more requests */
+       dum->address = 0;
+
+       /* The timer is left running so that outstanding URBs can fail */
+
+       /* nuke any pending requests first, so driver i/o is quiesced */
+       list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
+               nuke (dum, ep);
+
+       /* driver now does any non-usb quiescing necessary */
+}
+
+/* caller must hold lock */
+static void
+set_link_state (struct dummy *dum)
+{
+       dum->active = 0;
+       if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
+               dum->port_status = 0;
+
+       /* UDC suspend must cause a disconnect */
+       else if (!dum->pullup || dum->udc_suspended) {
+               dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
+                                       USB_PORT_STAT_ENABLE |
+                                       USB_PORT_STAT_LOW_SPEED |
+                                       USB_PORT_STAT_HIGH_SPEED |
+                                       USB_PORT_STAT_SUSPEND);
+               if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
+                       dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
+       } else {
+               dum->port_status |= USB_PORT_STAT_CONNECTION;
+               if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
+                       dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
+               if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0)
+                       dum->port_status &= ~USB_PORT_STAT_SUSPEND;
+               else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
+                               dum->rh_state != DUMMY_RH_SUSPENDED)
+                       dum->active = 1;
+       }
+
+       if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
+               dum->resuming = 0;
+
+       if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
+                       (dum->port_status & USB_PORT_STAT_RESET) != 0) {
+               if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
+                               (dum->old_status & USB_PORT_STAT_RESET) == 0 &&
+                               dum->driver) {
+                       stop_activity (dum);
+                       spin_unlock (&dum->lock);
+                       dum->driver->disconnect (&dum->gadget);
+                       spin_lock (&dum->lock);
+               }
+       } else if (dum->active != dum->old_active) {
+               if (dum->old_active && dum->driver->suspend) {
+                       spin_unlock (&dum->lock);
+                       dum->driver->suspend (&dum->gadget);
+                       spin_lock (&dum->lock);
+               } else if (!dum->old_active && dum->driver->resume) {
+                       spin_unlock (&dum->lock);
+                       dum->driver->resume (&dum->gadget);
+                       spin_lock (&dum->lock);
+               }
+       }
+
+       dum->old_status = dum->port_status;
+       dum->old_active = dum->active;
+}
 
 /*-------------------------------------------------------------------------*/
 
@@ -324,7 +426,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
        _ep->maxpacket = max;
        ep->desc = desc;
 
-       dev_dbg (dummy_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
+       dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
                _ep->name,
                desc->bEndpointAddress & 0x0f,
                (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
@@ -345,22 +447,6 @@ done:
        return retval;
 }
 
-/* called with spinlock held */
-static void nuke (struct dummy *dum, struct dummy_ep *ep)
-{
-       while (!list_empty (&ep->queue)) {
-               struct dummy_request    *req;
-
-               req = list_entry (ep->queue.next, struct dummy_request, queue);
-               list_del_init (&req->queue);
-               req->req.status = -ESHUTDOWN;
-
-               spin_unlock (&dum->lock);
-               req->req.complete (&ep->ep, &req->req);
-               spin_lock (&dum->lock);
-       }
-}
-
 static int dummy_disable (struct usb_ep *_ep)
 {
        struct dummy_ep         *ep;
@@ -379,7 +465,7 @@ static int dummy_disable (struct usb_ep *_ep)
        nuke (dum, ep);
        spin_unlock_irqrestore (&dum->lock, flags);
 
-       dev_dbg (dummy_dev(dum), "disabled %s\n", _ep->name);
+       dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name);
        return retval;
 }
 
@@ -474,7 +560,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags)
                return -ESHUTDOWN;
 
 #if 0
-       dev_dbg (dummy_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
+       dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
                        ep, _req, _ep->name, _req->length, _req->buf);
 #endif
 
@@ -537,7 +623,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
        spin_unlock_irqrestore (&dum->lock, flags);
 
        if (retval == 0) {
-               dev_dbg (dummy_dev(dum),
+               dev_dbg (udc_dev(dum),
                                "dequeued req %p from %s, len %d buf %p\n",
                                req, _ep->name, _req->length, _req->buf);
                _req->complete (_ep, _req);
@@ -601,13 +687,21 @@ static int dummy_wakeup (struct usb_gadget *_gadget)
        struct dummy    *dum;
 
        dum = gadget_to_dummy (_gadget);
-       if ((dum->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) == 0
-                       || !(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)))
+       if (!(dum->devstatus &  ( (1 << USB_DEVICE_B_HNP_ENABLE)
+                               | (1 << USB_DEVICE_REMOTE_WAKEUP))))
                return -EINVAL;
+       if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0)
+               return -ENOLINK;
+       if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
+                        dum->rh_state != DUMMY_RH_SUSPENDED)
+               return -EIO;
+
+       /* FIXME: What if the root hub is suspended but the port isn't? */
 
        /* hub notices our request, issues downstream resume, etc */
        dum->resuming = 1;
-       dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
+       dum->re_timeout = jiffies + msecs_to_jiffies(20);
+       mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout);
        return 0;
 }
 
@@ -623,10 +717,26 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
        return 0;
 }
 
+static int dummy_pullup (struct usb_gadget *_gadget, int value)
+{
+       struct dummy    *dum;
+       unsigned long   flags;
+
+       dum = gadget_to_dummy (_gadget);
+       spin_lock_irqsave (&dum->lock, flags);
+       dum->pullup = (value != 0);
+       set_link_state (dum);
+       spin_unlock_irqrestore (&dum->lock, flags);
+
+       usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+       return 0;
+}
+
 static const struct usb_gadget_ops dummy_ops = {
        .get_frame      = dummy_g_get_frame,
        .wakeup         = dummy_wakeup,
        .set_selfpowered = dummy_set_selfpowered,
+       .pullup         = dummy_pullup,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -641,7 +751,7 @@ show_function (struct device *dev, struct device_attribute *attr, char *buf)
                return 0;
        return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);
 }
-DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
+static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
 
 /*-------------------------------------------------------------------------*/
 
@@ -659,38 +769,6 @@ DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
  * for each driver that registers:  just add to a big root hub.
  */
 
-static void
-dummy_udc_release (struct device *dev)
-{
-}
-
-static void
-dummy_pdev_release (struct device *dev)
-{
-}
-
-static int
-dummy_register_udc (struct dummy *dum)
-{
-       int             rc;
-
-       strcpy (dum->gadget.dev.bus_id, "udc");
-       dum->gadget.dev.parent = dummy_dev(dum);
-       dum->gadget.dev.release = dummy_udc_release;
-
-       rc = device_register (&dum->gadget.dev);
-       if (rc == 0)
-               device_create_file (&dum->gadget.dev, &dev_attr_function);
-       return rc;
-}
-
-static void
-dummy_unregister_udc (struct dummy *dum)
-{
-       device_remove_file (&dum->gadget.dev, &dev_attr_function);
-       device_unregister (&dum->gadget.dev);
-}
-
 int
 usb_gadget_register_driver (struct usb_gadget_driver *driver)
 {
@@ -709,12 +787,8 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
         * SLAVE side init ... the layer above hardware, which
         * can't enumerate without help from the driver we're binding.
         */
-       dum->gadget.name = gadget_name;
-       dum->gadget.ops = &dummy_ops;
-       dum->gadget.is_dualspeed = 1;
 
        dum->devstatus = 0;
-       dum->resuming = 0;
 
        INIT_LIST_HEAD (&dum->gadget.ep_list);
        for (i = 0; i < DUMMY_ENDPOINTS; i++) {
@@ -740,7 +814,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
 
        dum->driver = driver;
        dum->gadget.dev.driver = &driver->driver;
-       dev_dbg (dummy_dev(dum), "binding gadget driver '%s'\n",
+       dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
                        driver->driver.name);
        if ((retval = driver->bind (&dum->gadget)) != 0) {
                dum->driver = NULL;
@@ -748,42 +822,21 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
                return retval;
        }
 
-       // FIXME: Check these calls for errors and re-order
        driver->driver.bus = dum->gadget.dev.parent->bus;
        driver_register (&driver->driver);
-
        device_bind_driver (&dum->gadget.dev);
 
        /* khubd will enumerate this in a while */
-       dum->port_status |= USB_PORT_STAT_CONNECTION
-               | (1 << USB_PORT_FEAT_C_CONNECTION);
+       spin_lock_irq (&dum->lock);
+       dum->pullup = 1;
+       set_link_state (dum);
+       spin_unlock_irq (&dum->lock);
+
+       usb_hcd_poll_rh_status (dummy_to_hcd (dum));
        return 0;
 }
 EXPORT_SYMBOL (usb_gadget_register_driver);
 
-/* caller must hold lock */
-static void
-stop_activity (struct dummy *dum, struct usb_gadget_driver *driver)
-{
-       struct dummy_ep *ep;
-
-       /* prevent any more requests */
-       dum->address = 0;
-
-       /* The timer is left running so that outstanding URBs can fail */
-
-       /* nuke any pending requests first, so driver i/o is quiesced */
-       list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
-               nuke (dum, ep);
-
-       /* driver now does any non-usb quiescing necessary */
-       if (driver) {
-               spin_unlock (&dum->lock);
-               driver->disconnect (&dum->gadget);
-               spin_lock (&dum->lock);
-       }
-}
-
 int
 usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 {
@@ -795,35 +848,138 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
        if (!driver || driver != dum->driver)
                return -EINVAL;
 
-       dev_dbg (dummy_dev(dum), "unregister gadget driver '%s'\n",
+       dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
                        driver->driver.name);
 
        spin_lock_irqsave (&dum->lock, flags);
-       stop_activity (dum, driver);
-       dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE |
-                       USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED);
-       dum->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
+       dum->pullup = 0;
+       set_link_state (dum);
        spin_unlock_irqrestore (&dum->lock, flags);
 
        driver->unbind (&dum->gadget);
        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);
+       spin_unlock_irqrestore (&dum->lock, flags);
+
+       usb_hcd_poll_rh_status (dummy_to_hcd (dum));
        return 0;
 }
 EXPORT_SYMBOL (usb_gadget_unregister_driver);
 
 #undef is_enabled
 
+/* just declare this in any driver that really need it */
+extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
+
 int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode)
 {
        return -ENOSYS;
 }
 EXPORT_SYMBOL (net2280_set_fifo_mode);
 
+
+/* The gadget structure is stored inside the hcd structure and will be
+ * released along with it. */
+static void
+dummy_gadget_release (struct device *dev)
+{
+#if 0          /* usb_bus_put isn't EXPORTed! */
+       struct dummy    *dum = gadget_dev_to_dummy (dev);
+
+       usb_bus_put (&dummy_to_hcd (dum)->self);
+#endif
+}
+
+static int dummy_udc_probe (struct device *dev)
+{
+       struct dummy    *dum = the_controller;
+       int             rc;
+
+       dum->gadget.name = gadget_name;
+       dum->gadget.ops = &dummy_ops;
+       dum->gadget.is_dualspeed = 1;
+
+       /* maybe claim OTG support, though we won't complete HNP */
+       dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
+
+       strcpy (dum->gadget.dev.bus_id, "gadget");
+       dum->gadget.dev.parent = dev;
+       dum->gadget.dev.release = dummy_gadget_release;
+       rc = device_register (&dum->gadget.dev);
+       if (rc < 0)
+               return rc;
+
+#if 0          /* usb_bus_get isn't EXPORTed! */
+       usb_bus_get (&dummy_to_hcd (dum)->self);
+#endif
+
+       dev_set_drvdata (dev, dum);
+       device_create_file (&dum->gadget.dev, &dev_attr_function);
+       return rc;
+}
+
+static int dummy_udc_remove (struct device *dev)
+{
+       struct dummy    *dum = dev_get_drvdata (dev);
+
+       dev_set_drvdata (dev, NULL);
+       device_remove_file (&dum->gadget.dev, &dev_attr_function);
+       device_unregister (&dum->gadget.dev);
+       return 0;
+}
+
+static int dummy_udc_suspend (struct device *dev, pm_message_t state,
+               u32 level)
+{
+       struct dummy    *dum = dev_get_drvdata(dev);
+
+       if (level != SUSPEND_DISABLE)
+               return 0;
+
+       dev_dbg (dev, "%s\n", __FUNCTION__);
+       spin_lock_irq (&dum->lock);
+       dum->udc_suspended = 1;
+       set_link_state (dum);
+       spin_unlock_irq (&dum->lock);
+
+       dev->power.power_state = state;
+       usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+       return 0;
+}
+
+static int dummy_udc_resume (struct device *dev, u32 level)
+{
+       struct dummy    *dum = dev_get_drvdata(dev);
+
+       if (level != RESUME_ENABLE)
+               return 0;
+
+       dev_dbg (dev, "%s\n", __FUNCTION__);
+       spin_lock_irq (&dum->lock);
+       dum->udc_suspended = 0;
+       set_link_state (dum);
+       spin_unlock_irq (&dum->lock);
+
+       dev->power.power_state = PMSG_ON;
+       usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+       return 0;
+}
+
+static struct device_driver dummy_udc_driver = {
+       .name           = (char *) gadget_name,
+       .bus            = &platform_bus_type,
+       .probe          = dummy_udc_probe,
+       .remove         = dummy_udc_remove,
+       .suspend        = dummy_udc_suspend,
+       .resume         = dummy_udc_resume,
+};
+
 /*-------------------------------------------------------------------------*/
 
 /* MASTER/HOST SIDE DRIVER
@@ -880,7 +1036,16 @@ static int dummy_urb_enqueue (
 
 static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
 {
-       /* giveback happens automatically in timer callback */
+       struct dummy    *dum;
+       unsigned long   flags;
+
+       /* giveback happens automatically in timer callback,
+        * so make sure the callback happens */
+       dum = hcd_to_dummy (hcd);
+       spin_lock_irqsave (&dum->lock, flags);
+       if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
+               mod_timer (&dum->timer, jiffies);
+       spin_unlock_irqrestore (&dum->lock, flags);
        return 0;
 }
 
@@ -1025,7 +1190,6 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
 
                /* high bandwidth mode */
                tmp = le16_to_cpu(ep->desc->wMaxPacketSize);
-               tmp = le16_to_cpu (tmp);
                tmp = (tmp >> 11) & 0x03;
                tmp *= 8 /* applies to entire frame */;
                limit += limit * tmp;
@@ -1123,7 +1287,8 @@ restart:
                if (urb->status != -EINPROGRESS) {
                        /* likely it was just unlinked */
                        goto return_urb;
-               }
+               } else if (dum->rh_state != DUMMY_RH_RUNNING)
+                       continue;
                type = usb_pipetype (urb->pipe);
 
                /* used up this frame's non-periodic bandwidth?
@@ -1168,12 +1333,14 @@ restart:
                        struct usb_ctrlrequest          setup;
                        int                             value = 1;
                        struct dummy_ep                 *ep2;
+                       unsigned                        w_index;
+                       unsigned                        w_value;
 
                        setup = *(struct usb_ctrlrequest*) urb->setup_packet;
-                       le16_to_cpus (&setup.wIndex);
-                       le16_to_cpus (&setup.wValue);
-                       le16_to_cpus (&setup.wLength);
-                       if (setup.wLength != urb->transfer_buffer_length) {
+                       w_index = le16_to_cpu(setup.wIndex);
+                       w_value = le16_to_cpu(setup.wValue);
+                       if (le16_to_cpu(setup.wLength) !=
+                                       urb->transfer_buffer_length) {
                                maybe_set_status (urb, -EOVERFLOW);
                                goto return_urb;
                        }
@@ -1182,7 +1349,7 @@ restart:
                        list_for_each_entry (req, &ep->queue, queue) {
                                list_del_init (&req->queue);
                                req->req.status = -EOVERFLOW;
-                               dev_dbg (dummy_dev(dum), "stale req = %p\n",
+                               dev_dbg (udc_dev(dum), "stale req = %p\n",
                                                req);
 
                                spin_unlock (&dum->lock);
@@ -1203,31 +1370,40 @@ restart:
                        case USB_REQ_SET_ADDRESS:
                                if (setup.bRequestType != Dev_Request)
                                        break;
-                               dum->address = setup.wValue;
+                               dum->address = w_value;
                                maybe_set_status (urb, 0);
-                               dev_dbg (dummy_dev(dum), "set_address = %d\n",
-                                               setup.wValue);
+                               dev_dbg (udc_dev(dum), "set_address = %d\n",
+                                               w_value);
                                value = 0;
                                break;
                        case USB_REQ_SET_FEATURE:
                                if (setup.bRequestType == Dev_Request) {
                                        value = 0;
-                                       switch (setup.wValue) {
+                                       switch (w_value) {
                                        case USB_DEVICE_REMOTE_WAKEUP:
                                                break;
+                                       case USB_DEVICE_B_HNP_ENABLE:
+                                               dum->gadget.b_hnp_enable = 1;
+                                               break;
+                                       case USB_DEVICE_A_HNP_SUPPORT:
+                                               dum->gadget.a_hnp_support = 1;
+                                               break;
+                                       case USB_DEVICE_A_ALT_HNP_SUPPORT:
+                                               dum->gadget.a_alt_hnp_support
+                                                       = 1;
+                                               break;
                                        default:
                                                value = -EOPNOTSUPP;
                                        }
                                        if (value == 0) {
                                                dum->devstatus |=
-                                                       (1 << setup.wValue);
+                                                       (1 << w_value);
                                                maybe_set_status (urb, 0);
                                        }
 
                                } else if (setup.bRequestType == Ep_Request) {
                                        // endpoint halt
-                                       ep2 = find_endpoint (dum,
-                                                       setup.wIndex);
+                                       ep2 = find_endpoint (dum, w_index);
                                        if (!ep2) {
                                                value = -EOPNOTSUPP;
                                                break;
@@ -1239,7 +1415,7 @@ restart:
                                break;
                        case USB_REQ_CLEAR_FEATURE:
                                if (setup.bRequestType == Dev_Request) {
-                                       switch (setup.wValue) {
+                                       switch (w_value) {
                                        case USB_DEVICE_REMOTE_WAKEUP:
                                                dum->devstatus &= ~(1 <<
                                                        USB_DEVICE_REMOTE_WAKEUP);
@@ -1252,8 +1428,7 @@ restart:
                                        }
                                } else if (setup.bRequestType == Ep_Request) {
                                        // endpoint halt
-                                       ep2 = find_endpoint (dum,
-                                                       setup.wIndex);
+                                       ep2 = find_endpoint (dum, w_index);
                                        if (!ep2) {
                                                value = -EOPNOTSUPP;
                                                break;
@@ -1279,7 +1454,7 @@ restart:
                                        if (urb->transfer_buffer_length > 0) {
                                                if (setup.bRequestType ==
                                                                Ep_InRequest) {
-       ep2 = find_endpoint (dum, setup.wIndex);
+       ep2 = find_endpoint (dum, w_index);
        if (!ep2) {
                value = -EOPNOTSUPP;
                break;
@@ -1321,7 +1496,7 @@ restart:
 
                        if (value < 0) {
                                if (value != -EOPNOTSUPP)
-                                       dev_dbg (dummy_dev(dum),
+                                       dev_dbg (udc_dev(dum),
                                                "setup --> %d\n",
                                                value);
                                maybe_set_status (urb, -EPIPE);
@@ -1377,12 +1552,12 @@ return_urb:
                goto restart;
        }
 
-       /* want a 1 msec delay here */
-       if (!list_empty (&dum->urbp_list))
-               mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
-       else {
+       if (list_empty (&dum->urbp_list)) {
                usb_put_dev (dum->udev);
                dum->udev = NULL;
+       } else if (dum->rh_state == DUMMY_RH_RUNNING) {
+               /* want a 1 msec delay here */
+               mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
        }
 
        spin_unlock_irqrestore (&dum->lock, flags);
@@ -1391,29 +1566,39 @@ return_urb:
 /*-------------------------------------------------------------------------*/
 
 #define PORT_C_MASK \
-        ((1 << USB_PORT_FEAT_C_CONNECTION) \
-       | (1 << USB_PORT_FEAT_C_ENABLE) \
-       | (1 << USB_PORT_FEAT_C_SUSPEND) \
-       | (1 << USB_PORT_FEAT_C_OVER_CURRENT) \
-       | (1 << USB_PORT_FEAT_C_RESET))
+       ((USB_PORT_STAT_C_CONNECTION \
+       | USB_PORT_STAT_C_ENABLE \
+       | USB_PORT_STAT_C_SUSPEND \
+       | USB_PORT_STAT_C_OVERCURRENT \
+       | USB_PORT_STAT_C_RESET) << 16)
 
 static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
 {
        struct dummy            *dum;
        unsigned long           flags;
-       int                     retval;
+       int                     retval = 0;
 
        dum = hcd_to_dummy (hcd);
 
        spin_lock_irqsave (&dum->lock, flags);
-       if (!(dum->port_status & PORT_C_MASK))
-               retval = 0;
-       else {
+       if (hcd->state != HC_STATE_RUNNING)
+               goto done;
+
+       if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
+               dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
+               dum->port_status &= ~USB_PORT_STAT_SUSPEND;
+               set_link_state (dum);
+       }
+
+       if ((dum->port_status & PORT_C_MASK) != 0) {
                *buf = (1 << 1);
                dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",
-                       dum->port_status);
+                               dum->port_status);
                retval = 1;
+               if (dum->rh_state == DUMMY_RH_SUSPENDED)
+                       usb_hcd_resume_root_hub (hcd);
        }
+done:
        spin_unlock_irqrestore (&dum->lock, flags);
        return retval;
 }
@@ -1424,7 +1609,8 @@ hub_descriptor (struct usb_hub_descriptor *desc)
        memset (desc, 0, sizeof *desc);
        desc->bDescriptorType = 0x29;
        desc->bDescLength = 9;
-       desc->wHubCharacteristics = __constant_cpu_to_le16 (0x0001);
+       desc->wHubCharacteristics = (__force __u16)
+                       (__constant_cpu_to_le16 (0x0001));
        desc->bNbrPorts = 1;
        desc->bitmap [0] = 0xff;
        desc->bitmap [1] = 0xff;
@@ -1442,6 +1628,9 @@ static int dummy_hub_control (
        int             retval = 0;
        unsigned long   flags;
 
+       if (hcd->state != HC_STATE_RUNNING)
+               return -ETIMEDOUT;
+
        dum = hcd_to_dummy (hcd);
        spin_lock_irqsave (&dum->lock, flags);
        switch (typeReq) {
@@ -1450,27 +1639,27 @@ static int dummy_hub_control (
        case ClearPortFeature:
                switch (wValue) {
                case USB_PORT_FEAT_SUSPEND:
-                       if (dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) {
+                       if (dum->port_status & USB_PORT_STAT_SUSPEND) {
                                /* 20msec resume signaling */
                                dum->resuming = 1;
                                dum->re_timeout = jiffies +
-                                                       msecs_to_jiffies(20);
+                                               msecs_to_jiffies(20);
                        }
                        break;
                case USB_PORT_FEAT_POWER:
-                       dum->port_status = 0;
-                       dum->resuming = 0;
-                       stop_activity(dum, dum->driver);
-                       break;
+                       if (dum->port_status & USB_PORT_STAT_POWER)
+                               dev_dbg (dummy_dev(dum), "power-off\n");
+                       /* FALLS THROUGH */
                default:
                        dum->port_status &= ~(1 << wValue);
+                       set_link_state (dum);
                }
                break;
        case GetHubDescriptor:
                hub_descriptor ((struct usb_hub_descriptor *) buf);
                break;
        case GetHubStatus:
-               *(u32 *) buf = __constant_cpu_to_le32 (0);
+               *(__le32 *) buf = __constant_cpu_to_le32 (0);
                break;
        case GetPortStatus:
                if (wIndex != 1)
@@ -1479,23 +1668,16 @@ static int dummy_hub_control (
                /* whoever resets or resumes must GetPortStatus to
                 * complete it!!
                 */
-               if (dum->resuming && time_after (jiffies, dum->re_timeout)) {
-                       dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
-                       dum->port_status &= ~(1 << USB_PORT_FEAT_SUSPEND);
-                       dum->resuming = 0;
-                       dum->re_timeout = 0;
-                       if (dum->driver && dum->driver->resume) {
-                               spin_unlock (&dum->lock);
-                               dum->driver->resume (&dum->gadget);
-                               spin_lock (&dum->lock);
-                       }
+               if (dum->resuming &&
+                               time_after_eq (jiffies, dum->re_timeout)) {
+                       dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
+                       dum->port_status &= ~USB_PORT_STAT_SUSPEND;
                }
-               if ((dum->port_status & (1 << USB_PORT_FEAT_RESET)) != 0
-                               && time_after (jiffies, dum->re_timeout)) {
-                       dum->port_status |= (1 << USB_PORT_FEAT_C_RESET);
-                       dum->port_status &= ~(1 << USB_PORT_FEAT_RESET);
-                       dum->re_timeout = 0;
-                       if (dum->driver) {
+               if ((dum->port_status & USB_PORT_STAT_RESET) != 0 &&
+                               time_after_eq (jiffies, dum->re_timeout)) {
+                       dum->port_status |= (USB_PORT_STAT_C_RESET << 16);
+                       dum->port_status &= ~USB_PORT_STAT_RESET;
+                       if (dum->pullup) {
                                dum->port_status |= USB_PORT_STAT_ENABLE;
                                /* give it the best speed we agree on */
                                dum->gadget.speed = dum->driver->speed;
@@ -1516,8 +1698,9 @@ static int dummy_hub_control (
                                }
                        }
                }
-               ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status);
-               ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
+               set_link_state (dum);
+               ((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
+               ((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
                break;
        case SetHubFeature:
                retval = -EPIPE;
@@ -1525,36 +1708,37 @@ static int dummy_hub_control (
        case SetPortFeature:
                switch (wValue) {
                case USB_PORT_FEAT_SUSPEND:
-                       if ((dum->port_status & (1 << USB_PORT_FEAT_SUSPEND))
-                                       == 0) {
-                               dum->port_status |=
-                                               (1 << USB_PORT_FEAT_SUSPEND);
-                               if (dum->driver && dum->driver->suspend) {
-                                       spin_unlock (&dum->lock);
-                                       dum->driver->suspend (&dum->gadget);
-                                       spin_lock (&dum->lock);
-                               }
+                       if (dum->active) {
+                               dum->port_status |= USB_PORT_STAT_SUSPEND;
+
+                               /* HNP would happen here; for now we
+                                * assume b_bus_req is always true.
+                                */
+                               set_link_state (dum);
+                               if (((1 << USB_DEVICE_B_HNP_ENABLE)
+                                               & dum->devstatus) != 0)
+                                       dev_dbg (dummy_dev(dum),
+                                                       "no HNP yet!\n");
                        }
                        break;
+               case USB_PORT_FEAT_POWER:
+                       dum->port_status |= USB_PORT_STAT_POWER;
+                       set_link_state (dum);
+                       break;
                case USB_PORT_FEAT_RESET:
-                       /* if it's already running, disconnect first */
-                       if (dum->port_status & USB_PORT_STAT_ENABLE) {
-                               dum->port_status &= ~(USB_PORT_STAT_ENABLE
-                                               | USB_PORT_STAT_LOW_SPEED
-                                               | USB_PORT_STAT_HIGH_SPEED);
-                               if (dum->driver) {
-                                       dev_dbg (dummy_dev(dum),
-                                                       "disconnect\n");
-                                       stop_activity (dum, dum->driver);
-                               }
-
-                               /* FIXME test that code path! */
-                       }
+                       /* if it's already enabled, disable */
+                       dum->port_status &= ~(USB_PORT_STAT_ENABLE
+                                       | USB_PORT_STAT_LOW_SPEED
+                                       | USB_PORT_STAT_HIGH_SPEED);
+                       dum->devstatus = 0;
                        /* 50msec reset signaling */
                        dum->re_timeout = jiffies + msecs_to_jiffies(50);
-                       /* FALLTHROUGH */
+                       /* FALLTHROUGH */
                default:
-                       dum->port_status |= (1 << wValue);
+                       if ((dum->port_status & USB_PORT_STAT_POWER) != 0) {
+                               dum->port_status |= (1 << wValue);
+                               set_link_state (dum);
+                       }
                }
                break;
 
@@ -1567,9 +1751,35 @@ static int dummy_hub_control (
                retval = -EPIPE;
        }
        spin_unlock_irqrestore (&dum->lock, flags);
+
+       if ((dum->port_status & PORT_C_MASK) != 0)
+               usb_hcd_poll_rh_status (hcd);
        return retval;
 }
 
+static int dummy_hub_suspend (struct usb_hcd *hcd)
+{
+       struct dummy *dum = hcd_to_dummy (hcd);
+
+       spin_lock_irq (&dum->lock);
+       dum->rh_state = DUMMY_RH_SUSPENDED;
+       set_link_state (dum);
+       spin_unlock_irq (&dum->lock);
+       return 0;
+}
+
+static int dummy_hub_resume (struct usb_hcd *hcd)
+{
+       struct dummy *dum = hcd_to_dummy (hcd);
+
+       spin_lock_irq (&dum->lock);
+       dum->rh_state = DUMMY_RH_RUNNING;
+       set_link_state (dum);
+       if (!list_empty(&dum->urbp_list))
+               mod_timer (&dum->timer, jiffies);
+       spin_unlock_irq (&dum->lock);
+       return 0;
+}
 
 /*-------------------------------------------------------------------------*/
 
@@ -1625,8 +1835,6 @@ static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
 static int dummy_start (struct usb_hcd *hcd)
 {
        struct dummy            *dum;
-       struct usb_device       *root;
-       int                     retval;
 
        dum = hcd_to_dummy (hcd);
 
@@ -1639,38 +1847,22 @@ static int dummy_start (struct usb_hcd *hcd)
        init_timer (&dum->timer);
        dum->timer.function = dummy_timer;
        dum->timer.data = (unsigned long) dum;
+       dum->rh_state = DUMMY_RH_RUNNING;
 
        INIT_LIST_HEAD (&dum->urbp_list);
 
-       root = usb_alloc_dev (NULL, &hcd->self, 0);
-       if (!root)
-               return -ENOMEM;
-
-       /* root hub enters addressed state... */
-       hcd->state = HC_STATE_RUNNING;
-       root->speed = USB_SPEED_HIGH;
-
-       /* ...then configured, so khubd sees us. */
-       if ((retval = usb_hcd_register_root_hub (root, hcd)) != 0) {
-               goto err1;
-       }
-
        /* only show a low-power port: just 8mA */
-       hub_set_power_budget (root, 8);
+       hcd->power_budget = 8;
+       hcd->state = HC_STATE_RUNNING;
+       hcd->uses_new_polling = 1;
 
-       if ((retval = dummy_register_udc (dum)) != 0)
-               goto err2;
+#ifdef CONFIG_USB_OTG
+       hcd->self.otg_port = 1;
+#endif
 
        /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
        device_create_file (dummy_dev(dum), &dev_attr_urbs);
        return 0;
-
- err2:
-       usb_disconnect (&hcd->self.root_hub);
- err1:
-       usb_put_dev (root);
-       hcd->state = HC_STATE_QUIESCING;
-       return retval;
 }
 
 static void dummy_stop (struct usb_hcd *hcd)
@@ -1680,10 +1872,7 @@ static void dummy_stop (struct usb_hcd *hcd)
        dum = hcd_to_dummy (hcd);
 
        device_remove_file (dummy_dev(dum), &dev_attr_urbs);
-
        usb_gadget_unregister_driver (dum->driver);
-       dummy_unregister_udc (dum);
-
        dev_info (dummy_dev(dum), "stopped\n");
 }
 
@@ -1711,9 +1900,11 @@ static const struct hc_driver dummy_hcd = {
 
        .hub_status_data =      dummy_hub_status,
        .hub_control =          dummy_hub_control,
+       .hub_suspend =          dummy_hub_suspend,
+       .hub_resume =           dummy_hub_resume,
 };
 
-static int dummy_probe (struct device *dev)
+static int dummy_hcd_probe (struct device *dev)
 {
        struct usb_hcd          *hcd;
        int                     retval;
@@ -1733,7 +1924,7 @@ static int dummy_probe (struct device *dev)
        return retval;
 }
 
-static void dummy_remove (struct device *dev)
+static int dummy_hcd_remove (struct device *dev)
 {
        struct usb_hcd          *hcd;
 
@@ -1741,53 +1932,127 @@ static void dummy_remove (struct device *dev)
        usb_remove_hcd (hcd);
        usb_put_hcd (hcd);
        the_controller = NULL;
+       return 0;
 }
 
-/*-------------------------------------------------------------------------*/
-
-static int dummy_pdev_detect (void)
+static int dummy_hcd_suspend (struct device *dev, pm_message_t state,
+               u32 level)
 {
-       int                     retval;
+       struct usb_hcd          *hcd;
 
-       retval = driver_register (&dummy_driver);
-       if (retval < 0)
-               return retval;
+       if (level != SUSPEND_DISABLE)
+               return 0;
+
+       dev_dbg (dev, "%s\n", __FUNCTION__);
+       hcd = dev_get_drvdata (dev);
 
-       the_pdev.name = "hc";
-       the_pdev.dev.driver = &dummy_driver;
-       the_pdev.dev.release = dummy_pdev_release;
+#ifndef CONFIG_USB_SUSPEND
+       /* Otherwise this would never happen */
+       usb_lock_device (hcd->self.root_hub);
+       dummy_hub_suspend (hcd);
+       usb_unlock_device (hcd->self.root_hub);
+#endif
 
-       retval = platform_device_register (&the_pdev);
-       if (retval < 0)
-               driver_unregister (&dummy_driver);
-       return retval;
+       hcd->state = HC_STATE_SUSPENDED;
+       return 0;
 }
 
-static void dummy_pdev_remove (void)
+static int dummy_hcd_resume (struct device *dev, u32 level)
 {
-       platform_device_unregister (&the_pdev);
-       driver_unregister (&dummy_driver);
+       struct usb_hcd          *hcd;
+
+       if (level != RESUME_ENABLE)
+               return 0;
+
+       dev_dbg (dev, "%s\n", __FUNCTION__);
+       hcd = dev_get_drvdata (dev);
+       hcd->state = HC_STATE_RUNNING;
+
+#ifndef CONFIG_USB_SUSPEND
+       /* Otherwise this would never happen */
+       usb_lock_device (hcd->self.root_hub);
+       dummy_hub_resume (hcd);
+       usb_unlock_device (hcd->self.root_hub);
+#endif
+
+       usb_hcd_poll_rh_status (hcd);
+       return 0;
 }
 
+static struct device_driver dummy_hcd_driver = {
+       .name           = (char *) driver_name,
+       .bus            = &platform_bus_type,
+       .probe          = dummy_hcd_probe,
+       .remove         = dummy_hcd_remove,
+       .suspend        = dummy_hcd_suspend,
+       .resume         = dummy_hcd_resume,
+};
+
 /*-------------------------------------------------------------------------*/
 
+/* These don't need to do anything because the pdev structures are
+ * statically allocated. */
+static void
+dummy_udc_release (struct device *dev) {}
+
+static void
+dummy_hcd_release (struct device *dev) {}
+
+static struct platform_device          the_udc_pdev = {
+       .name           = (char *) gadget_name,
+       .id             = -1,
+       .dev            = {
+               .release        = dummy_udc_release,
+       },
+};
+
+static struct platform_device          the_hcd_pdev = {
+       .name           = (char *) driver_name,
+       .id             = -1,
+       .dev            = {
+               .release        = dummy_hcd_release,
+       },
+};
+
 static int __init init (void)
 {
        int     retval;
 
        if (usb_disabled ())
                return -ENODEV;
-       if ((retval = dummy_pdev_detect ()) != 0)
+
+       retval = driver_register (&dummy_hcd_driver);
+       if (retval < 0)
                return retval;
-       if ((retval = dummy_probe (&the_pdev.dev)) != 0)
-               dummy_pdev_remove ();
+
+       retval = driver_register (&dummy_udc_driver);
+       if (retval < 0)
+               goto err_register_udc_driver;
+
+       retval = platform_device_register (&the_hcd_pdev);
+       if (retval < 0)
+               goto err_register_hcd;
+
+       retval = platform_device_register (&the_udc_pdev);
+       if (retval < 0)
+               goto err_register_udc;
+       return retval;
+
+err_register_udc:
+       platform_device_unregister (&the_hcd_pdev);
+err_register_hcd:
+       driver_unregister (&dummy_udc_driver);
+err_register_udc_driver:
+       driver_unregister (&dummy_hcd_driver);
        return retval;
 }
 module_init (init);
 
 static void __exit cleanup (void)
 {
-       dummy_remove (&the_pdev.dev);
-       dummy_pdev_remove ();
+       platform_device_unregister (&the_udc_pdev);
+       platform_device_unregister (&the_hcd_pdev);
+       driver_unregister (&dummy_udc_driver);
+       driver_unregister (&dummy_hcd_driver);
 }
 module_exit (cleanup);
index 3f783cbdc7c3e18345af9f36308e90ade3a81bc1..5bb53ae889690077efff872aac0f85051ebe629c 100644 (file)
  */
 
 #define DRIVER_DESC            "Ethernet Gadget"
-#define DRIVER_VERSION         "Equinox 2004"
+#define DRIVER_VERSION         "May Day 2005"
 
 static const char shortname [] = "ether";
 static const char driver_desc [] = DRIVER_DESC;
 
 #define RX_EXTRA       20              /* guard against rx overflows */
 
-#ifdef CONFIG_USB_ETH_RNDIS
 #include "rndis.h"
-#else
-#define rndis_init() 0
-#define rndis_exit() do{}while(0)
+
+#ifndef        CONFIG_USB_ETH_RNDIS
+#define rndis_uninit(x)                do{}while(0)
+#define rndis_deregister(c)    do{}while(0)
+#define rndis_exit()           do{}while(0)
 #endif
 
 /* CDC and RNDIS support the same host-chosen outgoing packet filters. */
@@ -140,9 +141,6 @@ struct eth_dev {
  * It also ASSUMES a self-powered device, without remote wakeup,
  * although remote wakeup support would make sense.
  */
-static const char *EP_IN_NAME;
-static const char *EP_OUT_NAME;
-static const char *EP_STATUS_NAME;
 
 /*-------------------------------------------------------------------------*/
 
@@ -312,6 +310,7 @@ static inline int rndis_active(struct eth_dev *dev)
 #define        FS_BPS          (19 *  64 * 1 * 1000 * 8)
 
 #ifdef CONFIG_USB_GADGET_DUALSPEED
+#define        DEVSPEED        USB_SPEED_HIGH
 
 static unsigned qmult = 5;
 module_param (qmult, uint, S_IRUGO|S_IWUSR);
@@ -330,6 +329,8 @@ static inline int BITRATE(struct usb_gadget *g)
 }
 
 #else  /* full speed (low speed doesn't do bulk) */
+#define        DEVSPEED        USB_SPEED_FULL
+
 #define qlen(gadget) DEFAULT_QLEN
 
 static inline int BITRATE(struct usb_gadget *g)
@@ -395,7 +396,8 @@ static inline int BITRATE(struct usb_gadget *g)
 #define STRING_SUBSET                  8
 #define STRING_RNDIS                   9
 
-#define USB_BUFSIZ     256             /* holds our biggest descriptor */
+/* holds our biggest descriptor (or RNDIS response) */
+#define USB_BUFSIZ     256
 
 /*
  * This device advertises one configuration, eth_config, unless RNDIS
@@ -538,7 +540,7 @@ static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
        .bDataInterface =       0x01,
 };
 
-static struct usb_cdc_acm_descriptor acm_descriptor = {
+static const struct usb_cdc_acm_descriptor acm_descriptor = {
        .bLength =              sizeof acm_descriptor,
        .bDescriptorType =      USB_DT_CS_INTERFACE,
        .bDescriptorSubType =   USB_CDC_ACM_TYPE,
@@ -846,7 +848,7 @@ static const struct usb_descriptor_header *hs_rndis_function [] = {
 #else
 
 /* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) fs
+#define ep_desc(g,hs,fs) (((void)(g)), (fs))
 
 static inline void __init hs_subset_descriptors(void)
 {
@@ -946,10 +948,31 @@ config_buf (enum usb_device_speed speed,
 static void eth_start (struct eth_dev *dev, int gfp_flags);
 static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags);
 
-#ifdef DEV_CONFIG_CDC
-static inline int ether_alt_ep_setup (struct eth_dev *dev, struct usb_ep *ep)
+static int
+set_ether_config (struct eth_dev *dev, int gfp_flags)
 {
-       const struct usb_endpoint_descriptor    *d;
+       int                                     result = 0;
+       struct usb_gadget                       *gadget = dev->gadget;
+
+       /* status endpoint used for RNDIS and (optionally) CDC */
+       if (!subset_active(dev) && dev->status_ep) {
+               dev->status = ep_desc (gadget, &hs_status_desc,
+                                               &fs_status_desc);
+               dev->status_ep->driver_data = dev;
+
+               result = usb_ep_enable (dev->status_ep, dev->status);
+               if (result != 0) {
+                       DEBUG (dev, "enable %s --> %d\n", 
+                               dev->status_ep->name, result);
+                       goto done;
+               }
+       }
+
+       dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
+       dev->in_ep->driver_data = dev;
+
+       dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
+       dev->out_ep->driver_data = dev;
 
        /* With CDC,  the host isn't allowed to use these two data
         * endpoints in the default altsetting for the interface.
@@ -959,135 +982,33 @@ static inline int ether_alt_ep_setup (struct eth_dev *dev, struct usb_ep *ep)
         * a side effect of setting a packet filter.  Deactivation is
         * from REMOTE_NDIS_HALT_MSG, reset from REMOTE_NDIS_RESET_MSG.
         */
-
-       /* one endpoint writes data back IN to the host */
-       if (strcmp (ep->name, EP_IN_NAME) == 0) {
-               d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
-               ep->driver_data = dev;
-               dev->in = d;
-
-       /* one endpoint just reads OUT packets */
-       } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
-               d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
-               ep->driver_data = dev;
-               dev->out = d;
-
-       /* optional status/notification endpoint */
-       } else if (EP_STATUS_NAME &&
-                       strcmp (ep->name, EP_STATUS_NAME) == 0) {
-               int                     result;
-
-               d = ep_desc (dev->gadget, &hs_status_desc, &fs_status_desc);
-               result = usb_ep_enable (ep, d);
-               if (result < 0)
-                       return result;
-
-               ep->driver_data = dev;
-               dev->status = d;
-       }
-       return 0;
-}
-#endif
-
-#if    defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
-static inline int ether_ep_setup (struct eth_dev *dev, struct usb_ep *ep)
-{
-       int                                     result;
-       const struct usb_endpoint_descriptor    *d;
-
-       /* CDC subset is simpler:  if the device is there,
-        * it's live with rx and tx endpoints.
-        *
-        * Do this as a shortcut for RNDIS too.
-        */
-
-       /* one endpoint writes data back IN to the host */
-       if (strcmp (ep->name, EP_IN_NAME) == 0) {
-               d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
-               result = usb_ep_enable (ep, d);
-               if (result < 0)
-                       return result;
-
-               ep->driver_data = dev;
-               dev->in = d;
-
-       /* one endpoint just reads OUT packets */
-       } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
-               d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
-               result = usb_ep_enable (ep, d);
-               if (result < 0)
-                       return result;
-
-               ep->driver_data = dev;
-               dev->out = d;
-       }
-
-       return 0;
-}
-#endif
-
-static int
-set_ether_config (struct eth_dev *dev, int gfp_flags)
-{
-       int                     result = 0;
-       struct usb_ep           *ep;
-       struct usb_gadget       *gadget = dev->gadget;
-
-       gadget_for_each_ep (ep, gadget) {
-#ifdef DEV_CONFIG_CDC
-               if (!dev->rndis && dev->cdc) {
-                       result = ether_alt_ep_setup (dev, ep);
-                       if (result == 0)
-                               continue;
+       if (!cdc_active(dev)) {
+               result = usb_ep_enable (dev->in_ep, dev->in);
+               if (result != 0) {
+                       DEBUG(dev, "enable %s --> %d\n", 
+                               dev->in_ep->name, result);
+                       goto done;
                }
-#endif
-
-#ifdef CONFIG_USB_ETH_RNDIS
-               if (dev->rndis && strcmp (ep->name, EP_STATUS_NAME) == 0) {
-                       const struct usb_endpoint_descriptor    *d;
-                       d = ep_desc (gadget, &hs_status_desc, &fs_status_desc);
-                       result = usb_ep_enable (ep, d);
-                       if (result == 0) {
-                               ep->driver_data = dev;
-                               dev->status = d;
-                               continue;
-                       }
-               } else
-#endif
 
-               {
-#if    defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
-                       result = ether_ep_setup (dev, ep);
-                       if (result == 0)
-                               continue;
-#endif
+               result = usb_ep_enable (dev->out_ep, dev->out);
+               if (result != 0) {
+                       DEBUG (dev, "enable %s --> %d\n", 
+                               dev->in_ep->name, result);
+                       goto done;
                }
-
-               /* stop on error */
-               ERROR (dev, "can't enable %s, result %d\n", ep->name, result);
-               break;
        }
-       if (!result && (!dev->in_ep || !dev->out_ep))
-               result = -ENODEV;
 
+done:
        if (result == 0)
                result = alloc_requests (dev, qlen (gadget), gfp_flags);
 
        /* on error, disable any endpoints  */
        if (result < 0) {
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-               if (dev->status)
+               if (!subset_active(dev))
                        (void) usb_ep_disable (dev->status_ep);
-#endif
                dev->status = NULL;
-#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
-               if (dev->rndis || !dev->cdc) {
-                       if (dev->in)
-                               (void) usb_ep_disable (dev->in_ep);
-                       if (dev->out)
-                               (void) usb_ep_disable (dev->out_ep);
-               }
-#endif
+               (void) usb_ep_disable (dev->in_ep);
+               (void) usb_ep_disable (dev->out_ep);
                dev->in = NULL;
                dev->out = NULL;
        } else
@@ -1095,8 +1016,7 @@ set_ether_config (struct eth_dev *dev, int gfp_flags)
        /* activate non-CDC configs right away
         * this isn't strictly according to the RNDIS spec
         */
-#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
-       if (dev->rndis || !dev->cdc) {
+       if (!cdc_active (dev)) {
                netif_carrier_on (dev->net);
                if (netif_running (dev->net)) {
                        spin_unlock (&dev->lock);
@@ -1104,7 +1024,6 @@ set_ether_config (struct eth_dev *dev, int gfp_flags)
                        spin_lock (&dev->lock);
                }
        }
-#endif
 
        if (result == 0)
                DEBUG (dev, "qlen %d\n", qlen (gadget));
@@ -1124,6 +1043,7 @@ static void eth_reset_config (struct eth_dev *dev)
 
        netif_stop_queue (dev->net);
        netif_carrier_off (dev->net);
+       rndis_uninit(dev->rndis_config);
 
        /* disable endpoints, forcing (synchronous) completion of
         * pending i/o.  then free the requests.
@@ -1150,6 +1070,8 @@ static void eth_reset_config (struct eth_dev *dev)
        if (dev->status) {
                usb_ep_disable (dev->status_ep);
        }
+       dev->rndis = 0;
+       dev->cdc_filter = 0;
        dev->config = 0;
 }
 
@@ -1162,9 +1084,6 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
        int                     result = 0;
        struct usb_gadget       *gadget = dev->gadget;
 
-       if (number == dev->config)
-               return 0;
-
        if (gadget_is_sa1100 (gadget)
                        && dev->config
                        && atomic_read (&dev->tx_qlen) != 0) {
@@ -1174,12 +1093,8 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
        }
        eth_reset_config (dev);
 
-       /* default:  pass all packets, no multicast filtering */
-       dev->cdc_filter = DEFAULT_FILTER;
-
        switch (number) {
        case DEV_CONFIG_VALUE:
-               dev->rndis = 0;
                result = set_ether_config (dev, gfp_flags);
                break;
 #ifdef CONFIG_USB_ETH_RNDIS
@@ -1218,9 +1133,9 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
                dev->config = number;
                INFO (dev, "%s speed config #%d: %d mA, %s, using %s\n",
                                speed, number, power, driver_desc,
-                               dev->rndis
+                               rndis_active(dev)
                                        ? "RNDIS"
-                                       : (dev->cdc
+                                       : (cdc_active(dev)
                                                ? "CDC Ethernet"
                                                : "CDC Ethernet Subset"));
        }
@@ -1231,6 +1146,13 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
 
 #ifdef DEV_CONFIG_CDC
 
+/* The interrupt endpoint is used in CDC networking models (Ethernet, ATM)
+ * only to notify the host about link status changes (which we support) or
+ * report completion of some encapsulated command (as used in RNDIS).  Since
+ * we want this CDC Ethernet code to be vendor-neutral, we don't use that
+ * command mechanism; and only one status request is ever queued.
+ */
+
 static void eth_status_complete (struct usb_ep *ep, struct usb_request *req)
 {
        struct usb_cdc_notification     *event = req->buf;
@@ -1259,7 +1181,7 @@ static void eth_status_complete (struct usb_ep *ep, struct usb_request *req)
        } else if (value != -ECONNRESET)
                DEBUG (dev, "event %02x --> %d\n",
                        event->bNotificationType, value);
-       event->bmRequestType = 0xff;
+       req->context = NULL;
 }
 
 static void issue_start_status (struct eth_dev *dev)
@@ -1276,6 +1198,8 @@ static void issue_start_status (struct eth_dev *dev)
         * a "cancel the whole queue" primitive since any
         * unlink-one primitive has way too many error modes.
         * here, we "know" toggle is already clear...
+        *
+        * FIXME iff req->context != null just dequeue it
         */
        usb_ep_disable (dev->status_ep);
        usb_ep_enable (dev->status_ep, dev->status);
@@ -1292,6 +1216,8 @@ static void issue_start_status (struct eth_dev *dev)
 
        req->length = sizeof *event;
        req->complete = eth_status_complete;
+       req->context = dev;
+
        value = usb_ep_queue (dev->status_ep, req, GFP_ATOMIC);
        if (value < 0)
                DEBUG (dev, "status buf queue --> %d\n", value);
@@ -1351,9 +1277,9 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
        struct eth_dev          *dev = get_gadget_data (gadget);
        struct usb_request      *req = dev->req;
        int                     value = -EOPNOTSUPP;
-       u16                     wIndex = (__force u16) ctrl->wIndex;
-       u16                     wValue = (__force u16) ctrl->wValue;
-       u16                     wLength = (__force u16) ctrl->wLength;
+       u16                     wIndex = le16_to_cpu(ctrl->wIndex);
+       u16                     wValue = le16_to_cpu(ctrl->wValue);
+       u16                     wLength = le16_to_cpu(ctrl->wLength);
 
        /* descriptors just go into the pre-allocated ep0 buffer,
         * while config change events may enable network traffic.
@@ -1424,7 +1350,7 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                                || !dev->config
                                || wIndex > 1)
                        break;
-               if (!dev->cdc && wIndex != 0)
+               if (!cdc_active(dev) && wIndex != 0)
                        break;
                spin_lock (&dev->lock);
 
@@ -1456,9 +1382,11 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 
                        /* CDC requires the data transfers not be done from
                         * the default interface setting ... also, setting
-                        * the non-default interface clears filters etc.
+                        * the non-default interface resets filters etc.
                         */
                        if (wValue == 1) {
+                               if (!cdc_active (dev))
+                                       break;
                                usb_ep_enable (dev->in_ep, dev->in);
                                usb_ep_enable (dev->out_ep, dev->out);
                                dev->cdc_filter = DEFAULT_FILTER;
@@ -1492,11 +1420,11 @@ done_set_intf:
                                || !dev->config
                                || wIndex > 1)
                        break;
-               if (!(dev->cdc || dev->rndis) && wIndex != 0)
+               if (!(cdc_active(dev) || rndis_active(dev)) && wIndex != 0)
                        break;
 
                /* for CDC, iff carrier is on, data interface is active. */
-               if (dev->rndis || wIndex != 1)
+               if (rndis_active(dev) || wIndex != 1)
                        *(u8 *)req->buf = 0;
                else
                        *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0;
@@ -1509,8 +1437,7 @@ done_set_intf:
                 * wValue = packet filter bitmap
                 */
                if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
-                               || !dev->cdc
-                               || dev->rndis
+                               || !cdc_active(dev)
                                || wLength != 0
                                || wIndex > 1)
                        break;
@@ -1534,7 +1461,7 @@ done_set_intf:
         */
        case USB_CDC_SEND_ENCAPSULATED_COMMAND:
                if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
-                               || !dev->rndis
+                               || !rndis_active(dev)
                                || wLength > USB_BUFSIZ
                                || wValue
                                || rndis_control_intf.bInterfaceNumber
@@ -1549,7 +1476,7 @@ done_set_intf:
        case USB_CDC_GET_ENCAPSULATED_RESPONSE:
                if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)
                                        == ctrl->bRequestType
-                               && dev->rndis
+                               && rndis_active(dev)
                                // && wLength >= 0x0400
                                && !wValue
                                && rndis_control_intf.bInterfaceNumber
@@ -1688,10 +1615,8 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags)
         */
        size = (sizeof (struct ethhdr) + dev->net->mtu + RX_EXTRA);
        size += dev->out_ep->maxpacket - 1;
-#ifdef CONFIG_USB_ETH_RNDIS
-       if (dev->rndis)
+       if (rndis_active(dev))
                size += sizeof (struct rndis_packet_msg_type);
-#endif 
        size -= size % dev->out_ep->maxpacket;
 
        if ((skb = alloc_skb (size + NET_IP_ALIGN, gfp_flags)) == 0) {
@@ -1735,11 +1660,9 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req)
        /* normal completion */
        case 0:
                skb_put (skb, req->actual);
-#ifdef CONFIG_USB_ETH_RNDIS
                /* we know MaxPacketsPerTransfer == 1 here */
-               if (dev->rndis)
+               if (rndis_active(dev))
                        status = rndis_rm_hdr (skb);
-#endif
                if (status < 0
                                || ETH_HLEN > skb->len
                                || skb->len > ETH_FRAME_LEN) {
@@ -1859,8 +1782,6 @@ static void rx_fill (struct eth_dev *dev, int gfp_flags)
        struct usb_request      *req;
        unsigned long           flags;
 
-       clear_bit (WORK_RX_MEMORY, &dev->todo);
-
        /* fill unused rxq slots with some skb */
        spin_lock_irqsave (&dev->lock, flags);
        while (!list_empty (&dev->rx_reqs)) {
@@ -1883,11 +1804,9 @@ static void eth_work (void *_dev)
 {
        struct eth_dev          *dev = _dev;
 
-       if (test_bit (WORK_RX_MEMORY, &dev->todo)) {
+       if (test_and_clear_bit (WORK_RX_MEMORY, &dev->todo)) {
                if (netif_running (dev->net))
                        rx_fill (dev, GFP_KERNEL);
-               else
-                       clear_bit (WORK_RX_MEMORY, &dev->todo);
        }
 
        if (dev->todo)
@@ -1971,8 +1890,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
         * or the hardware can't use skb buffers.
         * or there's not enough space for any RNDIS headers we need
         */
-#ifdef CONFIG_USB_ETH_RNDIS
-       if (dev->rndis) {
+       if (rndis_active(dev)) {
                struct sk_buff  *skb_rndis;
 
                skb_rndis = skb_realloc_headroom (skb,
@@ -1985,7 +1903,6 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
                rndis_add_hdr (skb);
                length = skb->len;
        }
-#endif
        req->buf = skb->data;
        req->context = skb;
        req->complete = tx_complete;
@@ -2018,9 +1935,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
        }
 
        if (retval) {
-#ifdef CONFIG_USB_ETH_RNDIS
 drop:
-#endif
                dev->stats.tx_dropped++;
                dev_kfree_skb_any (skb);
                spin_lock_irqsave (&dev->lock, flags);
@@ -2036,27 +1951,31 @@ drop:
 
 #ifdef CONFIG_USB_ETH_RNDIS
 
-static void rndis_send_media_state (struct eth_dev *dev, int connect)
-{
-       if (!dev)
-               return;
-       
-       if (connect) {
-               if (rndis_signal_connect (dev->rndis_config))
-                       return;
-       } else {
-               if (rndis_signal_disconnect (dev->rndis_config))
-                       return;
-       }
-}
+/* The interrupt endpoint is used in RNDIS to notify the host when messages
+ * other than data packets are available ... notably the REMOTE_NDIS_*_CMPLT
+ * messages, but also REMOTE_NDIS_INDICATE_STATUS_MSG and potentially even
+ * REMOTE_NDIS_KEEPALIVE_MSG.
+ *
+ * The RNDIS control queue is processed by GET_ENCAPSULATED_RESPONSE, and
+ * normally just one notification will be queued.
+ */
+
+static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, unsigned);
+static void eth_req_free (struct usb_ep *ep, struct usb_request *req);
 
 static void
 rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
 {
+       struct eth_dev          *dev = ep->driver_data;
+
        if (req->status || req->actual != req->length)
-               DEBUG ((struct eth_dev *) ep->driver_data,
+               DEBUG (dev,
                        "rndis control ack complete --> %d, %d/%d\n",
                        req->status, req->actual, req->length);
+       req->context = NULL;
+
+       if (req != dev->stat_req)
+               eth_req_free(ep, req);
 }
 
 static int rndis_control_ack (struct net_device *net)
@@ -2071,11 +1990,19 @@ static int rndis_control_ack (struct net_device *net)
                return -ENODEV;
        }
 
+       /* in case queue length > 1 */
+       if (resp->context) {
+               resp = eth_req_alloc (dev->status_ep, 8, GFP_ATOMIC);
+               if (!resp)
+                       return -ENOMEM;
+       }
+
        /* Send RNDIS RESPONSE_AVAILABLE notification;
         * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too
         */
        resp->length = 8;
        resp->complete = rndis_control_ack_complete;
+       resp->context = dev;
        
        *((__le32 *) resp->buf) = __constant_cpu_to_le32 (1);
        *((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0);
@@ -2089,6 +2016,10 @@ static int rndis_control_ack (struct net_device *net)
        return 0;
 }
 
+#else
+
+#define        rndis_control_ack       NULL
+
 #endif /* RNDIS */
 
 static void eth_start (struct eth_dev *dev, int gfp_flags)
@@ -2101,14 +2032,12 @@ static void eth_start (struct eth_dev *dev, int gfp_flags)
        /* and open the tx floodgates */ 
        atomic_set (&dev->tx_qlen, 0);
        netif_wake_queue (dev->net);
-#ifdef CONFIG_USB_ETH_RNDIS
-       if (dev->rndis) {
+       if (rndis_active(dev)) {
                rndis_set_param_medium (dev->rndis_config,
                                        NDIS_MEDIUM_802_3,
                                        BITRATE(dev->gadget)/100);
-               rndis_send_media_state (dev, 1);
+               (void) rndis_signal_connect (dev->rndis_config);
        }
-#endif 
 }
 
 static int eth_open (struct net_device *net)
@@ -2149,28 +2078,27 @@ static int eth_stop (struct net_device *net)
                }
        }
        
-#ifdef CONFIG_USB_ETH_RNDIS
-       if (dev->rndis) {
+       if (rndis_active(dev)) {
                rndis_set_param_medium (dev->rndis_config,
                                        NDIS_MEDIUM_802_3, 0);
-               rndis_send_media_state (dev, 0);
+               (void) rndis_signal_disconnect (dev->rndis_config);
        }
-#endif
 
        return 0;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static struct usb_request *eth_req_alloc (struct usb_ep *ep, unsigned size)
+static struct usb_request *
+eth_req_alloc (struct usb_ep *ep, unsigned size, unsigned gfp_flags)
 {
        struct usb_request      *req;
 
-       req = usb_ep_alloc_request (ep, GFP_KERNEL);
+       req = usb_ep_alloc_request (ep, gfp_flags);
        if (!req)
                return NULL;
 
-       req->buf = kmalloc (size, GFP_KERNEL);
+       req->buf = kmalloc (size, gfp_flags);
        if (!req->buf) {
                usb_ep_free_request (ep, req);
                req = NULL;
@@ -2192,10 +2120,8 @@ eth_unbind (struct usb_gadget *gadget)
        struct eth_dev          *dev = get_gadget_data (gadget);
 
        DEBUG (dev, "unbind\n");
-#ifdef CONFIG_USB_ETH_RNDIS
        rndis_deregister (dev->rndis_config);
        rndis_exit ();
-#endif
 
        /* we've already been disconnected ... no i/o is active */
        if (dev->req) {
@@ -2368,13 +2294,11 @@ autoconf_fail:
                        gadget->name);
                return -ENODEV;
        }
-       EP_IN_NAME = in_ep->name;
        in_ep->driver_data = in_ep;     /* claim */
        
        out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
        if (!out_ep)
                goto autoconf_fail;
-       EP_OUT_NAME = out_ep->name;
        out_ep->driver_data = out_ep;   /* claim */
 
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
@@ -2384,7 +2308,6 @@ autoconf_fail:
        if (cdc || rndis) {
                status_ep = usb_ep_autoconfig (gadget, &fs_status_desc);
                if (status_ep) {
-                       EP_STATUS_NAME = status_ep->name;
                        status_ep->driver_data = status_ep;     /* claim */
                } else if (rndis) {
                        dev_err (&gadget->dev,
@@ -2426,7 +2349,7 @@ autoconf_fail:
        hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
        hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-       if (EP_STATUS_NAME)
+       if (status_ep)
                hs_status_desc.bEndpointAddress =
                                fs_status_desc.bEndpointAddress;
 #endif
@@ -2499,20 +2422,23 @@ autoconf_fail:
        SET_ETHTOOL_OPS(net, &ops);
 
        /* preallocate control message data and buffer */
-       dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ);
+       dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ, GFP_KERNEL);
        if (!dev->req)
                goto fail;
        dev->req->complete = eth_setup_complete;
 
        /* ... and maybe likewise for status transfer */
+#ifdef DEV_CONFIG_CDC
        if (dev->status_ep) {
                dev->stat_req = eth_req_alloc (dev->status_ep,
-                                       STATUS_BYTECOUNT);
+                                       STATUS_BYTECOUNT, GFP_KERNEL);
                if (!dev->stat_req) {
                        eth_req_free (gadget->ep0, dev->req);
                        goto fail;
                }
+               dev->stat_req->context = NULL;
        }
+#endif
 
        /* finish hookup to lower layer ... */
        dev->gadget = gadget;
@@ -2526,16 +2452,16 @@ autoconf_fail:
        netif_stop_queue (dev->net);
        netif_carrier_off (dev->net);
 
-       // SET_NETDEV_DEV (dev->net, &gadget->dev);
+       SET_NETDEV_DEV (dev->net, &gadget->dev);
        status = register_netdev (dev->net);
        if (status < 0)
                goto fail1;
 
        INFO (dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
        INFO (dev, "using %s, OUT %s IN %s%s%s\n", gadget->name,
-               EP_OUT_NAME, EP_IN_NAME,
-               EP_STATUS_NAME ? " STATUS " : "",
-               EP_STATUS_NAME ? EP_STATUS_NAME : ""
+               out_ep->name, in_ep->name,
+               status_ep ? " STATUS " : "",
+               status_ep ? status_ep->name : ""
                );
        INFO (dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
                net->dev_addr [0], net->dev_addr [1],
@@ -2548,7 +2474,6 @@ autoconf_fail:
                        dev->host_mac [2], dev->host_mac [3],
                        dev->host_mac [4], dev->host_mac [5]);
 
-#ifdef CONFIG_USB_ETH_RNDIS
        if (rndis) {
                u32     vendorID = 0;
 
@@ -2565,7 +2490,7 @@ fail0:
                /* these set up a lot of the OIDs that RNDIS needs */
                rndis_set_host_mac (dev->rndis_config, dev->host_mac);
                if (rndis_set_param_dev (dev->rndis_config, dev->net,
-                                        &dev->stats))
+                                        &dev->stats, &dev->cdc_filter))
                        goto fail0;
                if (rndis_set_param_vendor (dev->rndis_config, vendorID,
                                            manufacturer))
@@ -2576,7 +2501,6 @@ fail0:
                        goto fail0;
                INFO (dev, "RNDIS ready\n");
        }
-#endif 
 
        return status;
 
@@ -2610,11 +2534,8 @@ eth_resume (struct usb_gadget *gadget)
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver eth_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       .speed          = USB_SPEED_HIGH,
-#else
-       .speed          = USB_SPEED_FULL,
-#endif
+       .speed          = DEVSPEED,
+
        .function       = (char *) driver_desc,
        .bind           = eth_bind,
        .unbind         = eth_unbind,
index 037a7f163822d6c74c4a671d0a904b5e02a577e8..4f57085619b4fa26ea922e9c358f361210e4fc03 100644 (file)
  *     removable               Default false, boolean for removable media
  *     luns=N                  Default N = number of filenames, number of
  *                                     LUNs to support
+ *     stall                   Default determined according to the type of
+ *                                     USB device controller (usually true),
+ *                                     boolean to permit the driver to halt
+ *                                     bulk endpoints
  *     transport=XXX           Default BBB, transport name (CB, CBI, or BBB)
  *     protocol=YYY            Default SCSI, protocol name (RBC, 8020 or
  *                                     ATAPI, QIC, UFI, 8070, or SCSI;
  *     buflen=N                Default N=16384, buffer size used (will be
  *                                     rounded down to a multiple of
  *                                     PAGE_CACHE_SIZE)
- *     stall                   Default determined according to the type of
- *                                     USB device controller (usually true),
- *                                     boolean to permit the driver to halt
- *                                     bulk endpoints
  *
  * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro",
- * "removable", and "luns" options are available; default values are used
- * for everything else.
+ * "removable", "luns", and "stall" options are available; default values
+ * are used for everything else.
  *
  * The pathnames of the backing files and the ro settings are available in
  * the attribute files "file" and "ro" in the lun<n> subdirectory of the
@@ -342,14 +342,15 @@ static struct {
        int             num_ros;
        unsigned int    nluns;
 
+       int             removable;
+       int             can_stall;
+
        char            *transport_parm;
        char            *protocol_parm;
-       int             removable;
        unsigned short  vendor;
        unsigned short  product;
        unsigned short  release;
        unsigned int    buflen;
-       int             can_stall;
 
        int             transport_type;
        char            *transport_name;
@@ -360,11 +361,11 @@ static struct {
        .transport_parm         = "BBB",
        .protocol_parm          = "SCSI",
        .removable              = 0,
+       .can_stall              = 1,
        .vendor                 = DRIVER_VENDOR_ID,
        .product                = DRIVER_PRODUCT_ID,
        .release                = 0xffff,       // Use controller chip type
        .buflen                 = 16384,
-       .can_stall              = 1,
        };
 
 
@@ -380,6 +381,9 @@ MODULE_PARM_DESC(luns, "number of LUNs");
 module_param_named(removable, mod_data.removable, bool, S_IRUGO);
 MODULE_PARM_DESC(removable, "true to simulate removable media");
 
+module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
+MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
+
 
 /* In the non-TEST version, only the module parameters listed above
  * are available. */
@@ -404,9 +408,6 @@ MODULE_PARM_DESC(release, "USB release number");
 module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
 MODULE_PARM_DESC(buflen, "I/O buffer size");
 
-module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
-MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
-
 #endif /* CONFIG_USB_FILE_STORAGE_TEST */
 
 
@@ -818,7 +819,7 @@ static void inline put_be32(u8 *buf, u32 val)
        buf[0] = val >> 24;
        buf[1] = val >> 16;
        buf[2] = val >> 8;
-       buf[3] = val;
+       buf[3] = val & 0xff;
 }
 
 
@@ -1276,8 +1277,8 @@ static int class_setup_req(struct fsg_dev *fsg,
 {
        struct usb_request      *req = fsg->ep0req;
        int                     value = -EOPNOTSUPP;
-       u16                     w_index = ctrl->wIndex;
-       u16                     w_length = ctrl->wLength;
+       u16                     w_index = le16_to_cpu(ctrl->wIndex);
+       u16                     w_length = le16_to_cpu(ctrl->wLength);
 
        if (!fsg->config)
                return value;
@@ -1312,7 +1313,7 @@ static int class_setup_req(struct fsg_dev *fsg,
                        }
                        VDBG(fsg, "get max LUN\n");
                        *(u8 *) req->buf = fsg->nluns - 1;
-                       value = min(w_length, (u16) 1);
+                       value = 1;
                        break;
                }
        }
@@ -1344,7 +1345,7 @@ static int class_setup_req(struct fsg_dev *fsg,
                        "unknown class-specific control req "
                        "%02x.%02x v%04x i%04x l%u\n",
                        ctrl->bRequestType, ctrl->bRequest,
-                       ctrl->wValue, w_index, w_length);
+                       le16_to_cpu(ctrl->wValue), w_index, w_length);
        return value;
 }
 
@@ -1358,9 +1359,8 @@ static int standard_setup_req(struct fsg_dev *fsg,
 {
        struct usb_request      *req = fsg->ep0req;
        int                     value = -EOPNOTSUPP;
-       u16                     w_index = ctrl->wIndex;
-       u16                     w_value = ctrl->wValue;
-       u16                     w_length = ctrl->wLength;
+       u16                     w_index = le16_to_cpu(ctrl->wIndex);
+       u16                     w_value = le16_to_cpu(ctrl->wValue);
 
        /* Usually this just stores reply data in the pre-allocated ep0 buffer,
         * but config change events will also reconfigure hardware. */
@@ -1374,7 +1374,7 @@ static int standard_setup_req(struct fsg_dev *fsg,
 
                case USB_DT_DEVICE:
                        VDBG(fsg, "get device descriptor\n");
-                       value = min(w_length, (u16) sizeof device_desc);
+                       value = sizeof device_desc;
                        memcpy(req->buf, &device_desc, value);
                        break;
 #ifdef CONFIG_USB_GADGET_DUALSPEED
@@ -1382,7 +1382,7 @@ static int standard_setup_req(struct fsg_dev *fsg,
                        VDBG(fsg, "get device qualifier\n");
                        if (!fsg->gadget->is_dualspeed)
                                break;
-                       value = min(w_length, (u16) sizeof dev_qualifier);
+                       value = sizeof dev_qualifier;
                        memcpy(req->buf, &dev_qualifier, value);
                        break;
 
@@ -1401,8 +1401,6 @@ static int standard_setup_req(struct fsg_dev *fsg,
                                        req->buf,
                                        w_value >> 8,
                                        w_value & 0xff);
-                       if (value >= 0)
-                               value = min(w_length, (u16) value);
                        break;
 
                case USB_DT_STRING:
@@ -1411,8 +1409,6 @@ static int standard_setup_req(struct fsg_dev *fsg,
                        /* wIndex == language code */
                        value = usb_gadget_get_string(&stringtab,
                                        w_value & 0xff, req->buf);
-                       if (value >= 0)
-                               value = min(w_length, (u16) value);
                        break;
                }
                break;
@@ -1438,7 +1434,7 @@ static int standard_setup_req(struct fsg_dev *fsg,
                        break;
                VDBG(fsg, "get configuration\n");
                *(u8 *) req->buf = fsg->config;
-               value = min(w_length, (u16) 1);
+               value = 1;
                break;
 
        case USB_REQ_SET_INTERFACE:
@@ -1466,14 +1462,14 @@ static int standard_setup_req(struct fsg_dev *fsg,
                }
                VDBG(fsg, "get interface\n");
                *(u8 *) req->buf = 0;
-               value = min(w_length, (u16) 1);
+               value = 1;
                break;
 
        default:
                VDBG(fsg,
                        "unknown control req %02x.%02x v%04x i%04x l%u\n",
                        ctrl->bRequestType, ctrl->bRequest,
-                       w_value, w_index, w_length);
+                       w_value, w_index, le16_to_cpu(ctrl->wLength));
        }
 
        return value;
@@ -1485,6 +1481,7 @@ static int fsg_setup(struct usb_gadget *gadget,
 {
        struct fsg_dev          *fsg = get_gadget_data(gadget);
        int                     rc;
+       int                     w_length = le16_to_cpu(ctrl->wLength);
 
        ++fsg->ep0_req_tag;             // Record arrival of a new request
        fsg->ep0req->context = NULL;
@@ -1498,9 +1495,9 @@ static int fsg_setup(struct usb_gadget *gadget,
 
        /* Respond with data/status or defer until later? */
        if (rc >= 0 && rc != DELAYED_STATUS) {
+               rc = min(rc, w_length);
                fsg->ep0req->length = rc;
-               fsg->ep0req->zero = (rc < ctrl->wLength &&
-                               (rc % gadget->ep0->maxpacket) == 0);
+               fsg->ep0req->zero = rc < w_length;
                fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
                                "ep0-in" : "ep0-out");
                rc = ep0_queue(fsg);
@@ -1554,8 +1551,7 @@ static int sleep_thread(struct fsg_dev *fsg)
        rc = wait_event_interruptible(fsg->thread_wqh,
                        fsg->thread_wakeup_needed);
        fsg->thread_wakeup_needed = 0;
-       if (current->flags & PF_FREEZE)
-               refrigerator(PF_FREEZE);
+       try_to_freeze();
        return (rc ? -EINTR : 0);
 }
 
@@ -2661,7 +2657,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
                }
        }
 
-       /* Check that the LUN values are oonsistent */
+       /* Check that the LUN values are consistent */
        if (transport_is_bbb()) {
                if (fsg->lun != lun)
                        DBG(fsg, "using LUN %d from CBW, "
index 005db7cca2920452dabf48d032e66e6388ffe956..ed773a9111de6be447ea2f43c372122d5a68c828 100644 (file)
@@ -70,7 +70,7 @@ MODULE_LICENSE("GPL");
  * seem to behave quite as expected.  Used by default.
  *
  * OUT dma documents design problems handling the common "short packet"
- * transfer termination policy; it couldn't enabled by default, even
+ * transfer termination policy; it couldn't be enabled by default, even
  * if the OUT-dma abort problems had a resolution.
  */
 static unsigned use_dma = 1;
@@ -313,7 +313,7 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req)
 #if    defined(CONFIG_X86)
 #define USE_KMALLOC
 
-#elif  defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO)
+#elif  defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT)
 #define USE_KMALLOC
 
 #elif  defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
@@ -1524,9 +1524,12 @@ static void ep0_setup(struct goku_udc *dev)
        /* read SETUP packet and enter DATA stage */
        ctrl.bRequestType = readl(&regs->bRequestType);
        ctrl.bRequest = readl(&regs->bRequest);
-       ctrl.wValue  = (readl(&regs->wValueH)  << 8) | readl(&regs->wValueL);
-       ctrl.wIndex  = (readl(&regs->wIndexH)  << 8) | readl(&regs->wIndexL);
-       ctrl.wLength = (readl(&regs->wLengthH) << 8) | readl(&regs->wLengthL);
+       ctrl.wValue  = cpu_to_le16((readl(&regs->wValueH)  << 8)
+                                       | readl(&regs->wValueL));
+       ctrl.wIndex  = cpu_to_le16((readl(&regs->wIndexH)  << 8)
+                                       | readl(&regs->wIndexL));
+       ctrl.wLength = cpu_to_le16((readl(&regs->wLengthH) << 8)
+                                       | readl(&regs->wLengthL));
        writel(0, &regs->SetupRecv);
 
        nuke(&dev->ep[0], 0);
@@ -1548,18 +1551,20 @@ static void ep0_setup(struct goku_udc *dev)
                case USB_REQ_CLEAR_FEATURE:
                        switch (ctrl.bRequestType) {
                        case USB_RECIP_ENDPOINT:
-                               tmp = ctrl.wIndex & 0x0f;
+                               tmp = le16_to_cpu(ctrl.wIndex) & 0x0f;
                                /* active endpoint */
                                if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0))
                                        goto stall;
-                               if (ctrl.wIndex & USB_DIR_IN) {
+                               if (ctrl.wIndex & __constant_cpu_to_le16(
+                                               USB_DIR_IN)) {
                                        if (!dev->ep[tmp].is_in)
                                                goto stall;
                                } else {
                                        if (dev->ep[tmp].is_in)
                                                goto stall;
                                }
-                               if (ctrl.wValue != USB_ENDPOINT_HALT)
+                               if (ctrl.wValue != __constant_cpu_to_le16(
+                                               USB_ENDPOINT_HALT))
                                        goto stall;
                                if (tmp)
                                        goku_clear_halt(&dev->ep[tmp]);
@@ -1571,7 +1576,7 @@ succeed:
                                return;
                        case USB_RECIP_DEVICE:
                                /* device remote wakeup: always clear */
-                               if (ctrl.wValue != 1)
+                               if (ctrl.wValue != __constant_cpu_to_le16(1))
                                        goto stall;
                                VDBG(dev, "clear dev remote wakeup\n");
                                goto succeed;
@@ -1589,14 +1594,15 @@ succeed:
 #ifdef USB_TRACE
        VDBG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
                ctrl.bRequestType, ctrl.bRequest,
-               ctrl.wValue, ctrl.wIndex, ctrl.wLength);
+               le16_to_cpu(ctrl.wValue), le16_to_cpu(ctrl.wIndex),
+               le16_to_cpu(ctrl.wLength));
 #endif
 
        /* hw wants to know when we're configured (or not) */
        dev->req_config = (ctrl.bRequest == USB_REQ_SET_CONFIGURATION
                                && ctrl.bRequestType == USB_RECIP_DEVICE);
        if (unlikely(dev->req_config))
-               dev->configured = (ctrl.wValue != 0);
+               dev->configured = (ctrl.wValue != __constant_cpu_to_le16(0));
 
        /* delegate everything to the gadget driver.
         * it may respond after this irq handler returns.
index 1e5e6ddef787443564071325af3d6e1945c4d50e..020815397a49ddf59743ecb1d4d0ce9443856adc 100644 (file)
@@ -417,8 +417,8 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
                goto free1;
 
        value = ep_io (data, kbuf, len);
-       VDEBUG (data->dev, "%s read %d OUT, status %d\n",
-               data->name, len, value);
+       VDEBUG (data->dev, "%s read %zu OUT, status %d\n",
+               data->name, len, (int) value);
        if (value >= 0 && copy_to_user (buf, kbuf, value))
                value = -EFAULT;
 
@@ -465,8 +465,8 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        }
 
        value = ep_io (data, kbuf, len);
-       VDEBUG (data->dev, "%s write %d IN, status %d\n",
-               data->name, len, value);
+       VDEBUG (data->dev, "%s write %zu IN, status %d\n",
+               data->name, len, (int) value);
 free1:
        up (&data->lock);
        kfree (kbuf);
@@ -1318,8 +1318,8 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
        struct usb_request              *req = dev->req;
        int                             value = -EOPNOTSUPP;
        struct usb_gadgetfs_event       *event;
-       u16                             w_value = ctrl->wValue;
-       u16                             w_length = ctrl->wLength;
+       u16                             w_value = le16_to_cpu(ctrl->wValue);
+       u16                             w_length = le16_to_cpu(ctrl->wLength);
 
        spin_lock (&dev->lock);
        dev->setup_abort = 0;
index c553bbf68cab5cd5c92e95fe0f7326b375a809d5..09e3ee4eeae1741e5313e2a1f6d50f8e972066ae 100644 (file)
@@ -47,17 +47,17 @@ struct NDIS_PM_WAKE_UP_CAPABILITIES {
 #define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE   0x00000004
 
 struct NDIS_PNP_CAPABILITIES {
-       u32                                     Flags;
+       __le32                                  Flags;
        struct NDIS_PM_WAKE_UP_CAPABILITIES     WakeUpCapabilities;
 };
 
 struct NDIS_PM_PACKET_PATTERN {
-       u32     Priority;
-       u32     Reserved;
-       u32     MaskSize;
-       u32     PatternOffset;
-       u32     PatternSize;
-       u32     PatternFlags;
+       __le32  Priority;
+       __le32  Reserved;
+       __le32  MaskSize;
+       __le32  PatternOffset;
+       __le32  PatternSize;
+       __le32  PatternFlags;
 };
 
 
index e47e398daeb5b64f1c1bb286b875c0c71f0484c3..13a3dbc9949bdb6fd93fb6d903e954d170cec863 100644 (file)
@@ -448,7 +448,7 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
 #elif  defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
 #define USE_KMALLOC
 
-#elif  defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO)
+#elif  defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT)
 #define USE_KMALLOC
 
 /* FIXME there are other cases, including an x86-64 one ...  */
@@ -1113,7 +1113,7 @@ static void restart_dma (struct net2280_ep *ep)
                if (ep->in_fifo_validate)
                        dmactl |= (1 << DMA_FIFO_VALIDATE);
                list_for_each_entry (entry, &ep->queue, queue) {
-                       u32             dmacount;
+                       __le32          dmacount;
 
                        if (entry == req)
                                continue;
@@ -1238,7 +1238,7 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req)
                                &ep->dma->dmadesc);
                        if (req->td->dmacount & dma_done_ie)
                                writel (readl (&ep->dma->dmacount)
-                                               | dma_done_ie,
+                                               | le32_to_cpu(dma_done_ie),
                                        &ep->dma->dmacount);
                } else {
                        struct net2280_request  *prev;
@@ -1779,6 +1779,9 @@ static void set_fifo_mode (struct net2280 *dev, int mode)
        list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list);
 }
 
+/* just declare this in any driver that really need it */
+extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
+
 /**
  * net2280_set_fifo_mode - change allocation of fifo buffers
  * @gadget: access to the net2280 device that will be updated
@@ -2382,9 +2385,9 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                cpu_to_le32s (&u.raw [0]);
                cpu_to_le32s (&u.raw [1]);
 
-               le16_to_cpus (&u.r.wValue);
-               le16_to_cpus (&u.r.wIndex);
-               le16_to_cpus (&u.r.wLength);
+#define        w_value         le16_to_cpup (&u.r.wValue)
+#define        w_index         le16_to_cpup (&u.r.wIndex)
+#define        w_length        le16_to_cpup (&u.r.wLength)
 
                /* ack the irq */
                writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0);
@@ -2413,25 +2416,25 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                switch (u.r.bRequest) {
                case USB_REQ_GET_STATUS: {
                        struct net2280_ep       *e;
-                       u16                     status;
+                       __le32                  status;
 
                        /* hw handles device and interface status */
                        if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))
                                goto delegate;
-                       if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0
-                                       || u.r.wLength > 2)
+                       if ((e = get_ep_by_addr (dev, w_index)) == 0
+                                       || w_length > 2)
                                goto do_stall;
 
                        if (readl (&e->regs->ep_rsp)
                                        & (1 << SET_ENDPOINT_HALT))
-                               status = __constant_cpu_to_le16 (1);
+                               status = __constant_cpu_to_le32 (1);
                        else
-                               status = __constant_cpu_to_le16 (0);
+                               status = __constant_cpu_to_le32 (0);
 
                        /* don't bother with a request object! */
                        writel (0, &dev->epregs [0].ep_irqenb);
-                       set_fifo_bytecount (ep, u.r.wLength);
-                       writel (status, &dev->epregs [0].ep_data);
+                       set_fifo_bytecount (ep, w_length);
+                       writel ((__force u32)status, &dev->epregs [0].ep_data);
                        allow_status (ep);
                        VDEBUG (dev, "%s stat %02x\n", ep->ep.name, status);
                        goto next_endpoints;
@@ -2443,10 +2446,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                        /* hw handles device features */
                        if (u.r.bRequestType != USB_RECIP_ENDPOINT)
                                goto delegate;
-                       if (u.r.wValue != USB_ENDPOINT_HALT
-                                       || u.r.wLength != 0)
+                       if (w_value != USB_ENDPOINT_HALT
+                                       || w_length != 0)
                                goto do_stall;
-                       if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)
+                       if ((e = get_ep_by_addr (dev, w_index)) == 0)
                                goto do_stall;
                        clear_halt (e);
                        allow_status (ep);
@@ -2460,10 +2463,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                        /* hw handles device features */
                        if (u.r.bRequestType != USB_RECIP_ENDPOINT)
                                goto delegate;
-                       if (u.r.wValue != USB_ENDPOINT_HALT
-                                       || u.r.wLength != 0)
+                       if (w_value != USB_ENDPOINT_HALT
+                                       || w_length != 0)
                                goto do_stall;
-                       if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)
+                       if ((e = get_ep_by_addr (dev, w_index)) == 0)
                                goto do_stall;
                        set_halt (e);
                        allow_status (ep);
@@ -2473,10 +2476,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                        break;
                default:
 delegate:
-                       VDEBUG (dev, "setup %02x.%02x v%04x i%04x "
+                       VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x"
                                "ep_cfg %08x\n",
                                u.r.bRequestType, u.r.bRequest,
-                               u.r.wValue, u.r.wIndex,
+                               w_value, w_index, w_length,
                                readl (&ep->regs->ep_cfg));
                        spin_unlock (&dev->lock);
                        tmp = dev->driver->setup (&dev->gadget, &u.r);
@@ -2497,6 +2500,10 @@ do_stall:
                 */
        }
 
+#undef w_value
+#undef w_index
+#undef w_length
+
 next_endpoints:
        /* endpoint data irq ? */
        scratch = stat & 0x7f;
@@ -2653,7 +2660,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
                                restart_dma (ep);
                        else if (ep->is_in && use_dma_chaining) {
                                struct net2280_request  *req;
-                               u32                     dmacount;
+                               __le32                  dmacount;
 
                                /* the descriptor at the head of the chain
                                 * may still have VALID_BIT clear; that's
index 98cbcbc16cc19da3429aca42ef966612bf667723..a2b812af6e669ab69a384912e18626cbd07190e4 100644 (file)
@@ -52,7 +52,6 @@
 #include <asm/mach-types.h>
 
 #include <asm/arch/dma.h>
-#include <asm/arch/mux.h>
 #include <asm/arch/usb.h>
 
 #include "omap_udc.h"
@@ -167,7 +166,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
        maxp = le16_to_cpu (desc->wMaxPacketSize);
        if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
                                && maxp != ep->maxpacket)
-                       || desc->wMaxPacketSize > ep->maxpacket
+                       || le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket
                        || !desc->wMaxPacketSize) {
                DBG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);
                return -ERANGE;
@@ -214,7 +213,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
        ep->has_dma = 0;
        ep->lch = -1;
        use_ep(ep, UDC_EP_SEL);
-       UDC_CTRL_REG = UDC_RESET_EP;
+       UDC_CTRL_REG = udc->clr_halt;
        ep->ackwait = 0;
        deselect_ep();
 
@@ -253,7 +252,7 @@ static int omap_ep_disable(struct usb_ep *_ep)
        }
 
        spin_lock_irqsave(&ep->udc->lock, flags);
-       ep->desc = 0;
+       ep->desc = NULL;
        nuke (ep, -ESHUTDOWN);
        ep->ep.maxpacket = ep->maxpacket;
        ep->has_dma = 0;
@@ -388,8 +387,8 @@ done(struct omap_ep *ep, struct omap_req *req, int status)
 
 /*-------------------------------------------------------------------------*/
 
-#define        FIFO_FULL       (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL)
-#define        FIFO_UNWRITABLE (UDC_EP_HALTED | FIFO_FULL)
+#define UDC_FIFO_FULL          (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL)
+#define UDC_FIFO_UNWRITABLE    (UDC_EP_HALTED | UDC_FIFO_FULL)
 
 #define FIFO_EMPTY     (UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY)
 #define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY)
@@ -433,7 +432,7 @@ static int write_fifo(struct omap_ep *ep, struct omap_req *req)
 
        /* PIO-IN isn't double buffered except for iso */
        ep_stat = UDC_STAT_FLG_REG;
-       if (ep_stat & FIFO_UNWRITABLE)
+       if (ep_stat & UDC_FIFO_UNWRITABLE)
                return 0;
 
        count = ep->ep.maxpacket;
@@ -504,7 +503,7 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
                if (ep_stat & UDC_EP_HALTED)
                        break;
 
-               if (ep_stat & FIFO_FULL)
+               if (ep_stat & UDC_FIFO_FULL)
                        avail = ep->ep.maxpacket;
                else  {
                        avail = UDC_RXFSTAT_REG;
@@ -538,6 +537,32 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
 
 /*-------------------------------------------------------------------------*/
 
+static inline dma_addr_t dma_csac(unsigned lch)
+{
+       dma_addr_t      csac;
+
+       /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
+        * read before the DMA controller finished disabling the channel.
+        */
+       csac = omap_readw(OMAP_DMA_CSAC(lch));
+       if (csac == 0)
+               csac = omap_readw(OMAP_DMA_CSAC(lch));
+       return csac;
+}
+
+static inline dma_addr_t dma_cdac(unsigned lch)
+{
+       dma_addr_t      cdac;
+
+       /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
+        * read before the DMA controller finished disabling the channel.
+        */
+       cdac = omap_readw(OMAP_DMA_CDAC(lch));
+       if (cdac == 0)
+               cdac = omap_readw(OMAP_DMA_CDAC(lch));
+       return cdac;
+}
+
 static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
 {
        dma_addr_t      end;
@@ -548,7 +573,7 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
        if (cpu_is_omap15xx())
                return 0;
 
-       end = omap_readw(OMAP_DMA_CSAC(ep->lch));
+       end = dma_csac(ep->lch);
        if (end == ep->dma_counter)
                return 0;
 
@@ -559,14 +584,14 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
 }
 
 #define DMA_DEST_LAST(x) (cpu_is_omap15xx() \
-               ? OMAP_DMA_CSAC(x) /* really: CPC */ \
-               : OMAP_DMA_CDAC(x))
+               ? omap_readw(OMAP_DMA_CSAC(x)) /* really: CPC */ \
+               : dma_cdac(x))
 
 static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
 {
        dma_addr_t      end;
 
-       end = omap_readw(DMA_DEST_LAST(ep->lch));
+       end = DMA_DEST_LAST(ep->lch);
        if (end == ep->dma_counter)
                return 0;
 
@@ -593,7 +618,7 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
                                : OMAP_DMA_SYNC_ELEMENT;
 
        /* measure length in either bytes or packets */
-       if ((cpu_is_omap16xx() && length <= (UDC_TXN_TSC + 1))
+       if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC)
                        || (cpu_is_omap15xx() && length < ep->maxpacket)) {
                txdma_ctrl = UDC_TXN_EOT | length;
                omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
@@ -602,15 +627,15 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
                length = min(length / ep->maxpacket,
                                (unsigned) UDC_TXN_TSC + 1);
                txdma_ctrl = length;
-               omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
-                               ep->ep.maxpacket, length, sync_mode);
+               omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
+                               ep->ep.maxpacket >> 1, length, sync_mode);
                length *= ep->maxpacket;
        }
        omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
                OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
 
        omap_start_dma(ep->lch);
-       ep->dma_counter = omap_readw(OMAP_DMA_CSAC(ep->lch));
+       ep->dma_counter = dma_csac(ep->lch);
        UDC_DMA_IRQ_EN_REG |= UDC_TX_DONE_IE(ep->dma_channel);
        UDC_TXDMA_REG(ep->dma_channel) = UDC_TXN_START | txdma_ctrl;
        req->dma_bytes = length;
@@ -650,12 +675,12 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
        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_S8,
-                       ep->ep.maxpacket, packets,
+       omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
+                       ep->ep.maxpacket >> 1, packets,
                        OMAP_DMA_SYNC_ELEMENT);
        omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
                OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
-       ep->dma_counter = omap_readw(DMA_DEST_LAST(ep->lch));
+       ep->dma_counter = DMA_DEST_LAST(ep->lch);
 
        UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1);
        UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel);
@@ -763,7 +788,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
                reg = UDC_TXDMA_CFG_REG;
        else
                reg = UDC_RXDMA_CFG_REG;
-       reg |= 1 << 12;         /* "pulse" activated */
+       reg |= UDC_DMA_REQ;             /* "pulse" activated */
 
        ep->dma_channel = 0;
        ep->lch = -1;
@@ -787,6 +812,11 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
                        ep->ep.name, dma_error, ep, &ep->lch);
                if (status == 0) {
                        UDC_TXDMA_CFG_REG = reg;
+                       /* EMIFF */
+                       omap_set_dma_src_burst_mode(ep->lch,
+                                               OMAP_DMA_DATA_BURST_4);
+                       omap_set_dma_src_data_pack(ep->lch, 1);
+                       /* TIPB */
                        omap_set_dma_dest_params(ep->lch,
                                OMAP_DMA_PORT_TIPB,
                                OMAP_DMA_AMODE_CONSTANT,
@@ -797,10 +827,15 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
                        ep->ep.name, dma_error, ep, &ep->lch);
                if (status == 0) {
                        UDC_RXDMA_CFG_REG = reg;
+                       /* TIPB */
                        omap_set_dma_src_params(ep->lch,
                                OMAP_DMA_PORT_TIPB,
                                OMAP_DMA_AMODE_CONSTANT,
                                (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG));
+                       /* EMIFF */
+                       omap_set_dma_dest_burst_mode(ep->lch,
+                                               OMAP_DMA_DATA_BURST_4);
+                       omap_set_dma_dest_data_pack(ep->lch, 1);
                }
        }
        if (status)
@@ -856,7 +891,7 @@ static void dma_channel_release(struct omap_ep *ep)
        if (!list_empty(&ep->queue))
                req = container_of(ep->queue.next, struct omap_req, queue);
        else
-               req = 0;
+               req = NULL;
 
        active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0;
 
@@ -865,9 +900,13 @@ static void dma_channel_release(struct omap_ep *ep)
                        (ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r',
                        ep->dma_channel - 1, req);
 
+       /* NOTE: re-setting RX_REQ/TX_REQ because of a chip bug (before
+        * OMAP 1710 ES2.0) where reading the DMA_CFG can clear them.
+        */
+
        /* wait till current packet DMA finishes, and fifo empties */
        if (ep->bEndpointAddress & USB_DIR_IN) {
-               UDC_TXDMA_CFG_REG &= ~mask;
+               UDC_TXDMA_CFG_REG = (UDC_TXDMA_CFG_REG & ~mask) | UDC_DMA_REQ;
 
                if (req) {
                        finish_in_dma(ep, req, -ECONNRESET);
@@ -880,7 +919,7 @@ static void dma_channel_release(struct omap_ep *ep)
                while (UDC_TXDMA_CFG_REG & mask)
                        udelay(10);
        } else {
-               UDC_RXDMA_CFG_REG &= ~mask;
+               UDC_RXDMA_CFG_REG = (UDC_RXDMA_CFG_REG & ~mask) | UDC_DMA_REQ;
 
                /* dma empties the fifo */
                while (UDC_RXDMA_CFG_REG & mask)
@@ -997,18 +1036,19 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
                                        UDC_IRQ_EN_REG = irq_en;
                                }
 
-                               /* STATUS is reverse direction */
-                               UDC_EP_NUM_REG = is_in
-                                               ? UDC_EP_SEL
-                                               : (UDC_EP_SEL|UDC_EP_DIR);
+                               /* STATUS for zero length DATA stages is
+                                * always an IN ... even for IN transfers,
+                                * a wierd case which seem to stall OMAP.
+                                */
+                               UDC_EP_NUM_REG = (UDC_EP_SEL|UDC_EP_DIR);
                                UDC_CTRL_REG = UDC_CLR_EP;
                                UDC_CTRL_REG = UDC_SET_FIFO_EN;
-                               UDC_EP_NUM_REG = udc->ep0_in ? 0 : UDC_EP_DIR;
+                               UDC_EP_NUM_REG = UDC_EP_DIR;
 
                                /* cleanup */
                                udc->ep0_pending = 0;
                                done(ep, req, 0);
-                               req = 0;
+                               req = NULL;
 
                        /* non-empty DATA stage */
                        } else if (is_in) {
@@ -1029,7 +1069,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
                        (is_in ? next_in_dma : next_out_dma)(ep, req);
                else if (req) {
                        if ((is_in ? write_fifo : read_fifo)(ep, req) == 1)
-                               req = 0;
+                               req = NULL;
                        deselect_ep();
                        if (!is_in) {
                                UDC_CTRL_REG = UDC_SET_FIFO_EN;
@@ -1041,7 +1081,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
 
 irq_wait:
        /* irq handler advances the queue */
-       if (req != 0)
+       if (req != NULL)
                list_add_tail(&req->queue, &ep->queue);
        spin_unlock_irqrestore(&udc->lock, flags);
 
@@ -1140,7 +1180,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value)
                                dma_channel_claim(ep, channel);
                } else {
                        use_ep(ep, 0);
-                       UDC_CTRL_REG = UDC_RESET_EP;
+                       UDC_CTRL_REG = ep->udc->clr_halt;
                        ep->ackwait = 0;
                        if (!(ep->bEndpointAddress & USB_DIR_IN)) {
                                UDC_CTRL_REG = UDC_SET_FIFO_EN;
@@ -1238,6 +1278,8 @@ static int can_pullup(struct omap_udc *udc)
 
 static void pullup_enable(struct omap_udc *udc)
 {
+       udc->gadget.dev.parent->power.power_state = PMSG_ON;
+       udc->gadget.dev.power.power_state = PMSG_ON;
        UDC_SYSCON1_REG |= UDC_PULLUP_EN;
 #ifndef CONFIG_USB_OTG
        if (!cpu_is_omap15xx())
@@ -1382,7 +1424,7 @@ static void update_otg(struct omap_udc *udc)
 static void ep0_irq(struct omap_udc *udc, u16 irq_src)
 {
        struct omap_ep  *ep0 = &udc->ep[0];
-       struct omap_req *req = 0;
+       struct omap_req *req = NULL;
 
        ep0->irqs++;
 
@@ -1438,7 +1480,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
                                if (req)
                                        done(ep0, req, 0);
                        }
-                       req = 0;
+                       req = NULL;
                } else if (stat & UDC_STALL) {
                        UDC_CTRL_REG = UDC_CLR_HALT;
                        UDC_EP_NUM_REG = UDC_EP_DIR;
@@ -1511,9 +1553,10 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
                        u.word[3] = UDC_DATA_REG;
                        UDC_EP_NUM_REG = 0;
                } while (UDC_IRQ_SRC_REG & UDC_SETUP);
-               le16_to_cpus (&u.r.wValue);
-               le16_to_cpus (&u.r.wIndex);
-               le16_to_cpus (&u.r.wLength);
+
+#define        w_value         le16_to_cpup (&u.r.wValue)
+#define        w_index         le16_to_cpup (&u.r.wIndex)
+#define        w_length        le16_to_cpup (&u.r.wLength)
 
                /* Delegate almost all control requests to the gadget driver,
                 * except for a handful of ch9 status/feature requests that
@@ -1529,11 +1572,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
                        /* udc needs to know when ep != 0 is valid */
                        if (u.r.bRequestType != USB_RECIP_DEVICE)
                                goto delegate;
-                       if (u.r.wLength != 0)
+                       if (w_length != 0)
                                goto do_stall;
                        udc->ep0_set_config = 1;
-                       udc->ep0_reset_config = (u.r.wValue == 0);
-                       VDBG("set config %d\n", u.r.wValue);
+                       udc->ep0_reset_config = (w_value == 0);
+                       VDBG("set config %d\n", w_value);
 
                        /* update udc NOW since gadget driver may start
                         * queueing requests immediately; clear config
@@ -1549,23 +1592,28 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
                        /* clear endpoint halt */
                        if (u.r.bRequestType != USB_RECIP_ENDPOINT)
                                goto delegate;
-                       if (u.r.wValue != USB_ENDPOINT_HALT
-                                       || u.r.wLength != 0)
+                       if (w_value != USB_ENDPOINT_HALT
+                                       || w_length != 0)
                                goto do_stall;
-                       ep = &udc->ep[u.r.wIndex & 0xf];
+                       ep = &udc->ep[w_index & 0xf];
                        if (ep != ep0) {
-                               if (u.r.wIndex & USB_DIR_IN)
+                               if (w_index & USB_DIR_IN)
                                        ep += 16;
                                if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
                                                || !ep->desc)
                                        goto do_stall;
                                use_ep(ep, 0);
-                               UDC_CTRL_REG = UDC_RESET_EP;
+                               UDC_CTRL_REG = udc->clr_halt;
                                ep->ackwait = 0;
                                if (!(ep->bEndpointAddress & USB_DIR_IN)) {
                                        UDC_CTRL_REG = UDC_SET_FIFO_EN;
                                        ep->ackwait = 1 + ep->double_buf;
                                }
+                               /* NOTE:  assumes the host behaves sanely,
+                                * only clearing real halts.  Else we may
+                                * need to kill pending transfers and then
+                                * restart the queue... very messy for DMA!
+                                */
                        }
                        VDBG("%s halt cleared by host\n", ep->name);
                        goto ep0out_status_stage;
@@ -1573,11 +1621,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
                        /* set endpoint halt */
                        if (u.r.bRequestType != USB_RECIP_ENDPOINT)
                                goto delegate;
-                       if (u.r.wValue != USB_ENDPOINT_HALT
-                                       || u.r.wLength != 0)
+                       if (w_value != USB_ENDPOINT_HALT
+                                       || w_length != 0)
                                goto do_stall;
-                       ep = &udc->ep[u.r.wIndex & 0xf];
-                       if (u.r.wIndex & USB_DIR_IN)
+                       ep = &udc->ep[w_index & 0xf];
+                       if (w_index & USB_DIR_IN)
                                ep += 16;
                        if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
                                        || ep == ep0 || !ep->desc)
@@ -1615,13 +1663,13 @@ ep0out_status_stage:
                        UDC_CTRL_REG = UDC_SET_FIFO_EN;
                        UDC_EP_NUM_REG = UDC_EP_DIR;
                        status = 0;
-                       VDBG("GET_STATUS, interface %d\n", u.r.wIndex);
+                       VDBG("GET_STATUS, interface %d\n", w_index);
                        /* next, status stage */
                        break;
                default:
 delegate:
                        /* activate the ep0out fifo right away */
-                       if (!udc->ep0_in && u.r.wLength) {
+                       if (!udc->ep0_in && w_length) {
                                UDC_EP_NUM_REG = 0;
                                UDC_CTRL_REG = UDC_SET_FIFO_EN;
                        }
@@ -1632,7 +1680,11 @@ delegate:
                         */
                        VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n",
                                u.r.bRequestType, u.r.bRequest,
-                               u.r.wValue, u.r.wIndex, u.r.wLength);
+                               w_value, w_index, w_length);
+
+#undef w_value
+#undef w_index
+#undef w_length
 
                        /* The gadget driver may return an error here,
                         * causing an immediate protocol stall.
@@ -2013,7 +2065,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
        udc->softconnect = 1;
 
        /* hook up the driver */
-       driver->driver.bus = 0;
+       driver->driver.bus = NULL;
        udc->driver = driver;
        udc->gadget.dev.driver = &driver->driver;
        spin_unlock_irqrestore(&udc->lock, flags);
@@ -2021,8 +2073,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
        status = driver->bind (&udc->gadget);
        if (status) {
                DBG("bind to %s --> %d\n", driver->driver.name, status);
-               udc->gadget.dev.driver = 0;
-               udc->driver = 0;
+               udc->gadget.dev.driver = NULL;
+               udc->driver = NULL;
                goto done;
        }
        DBG("bound to driver %s\n", driver->driver.name);
@@ -2035,8 +2087,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
                if (status < 0) {
                        ERR("can't bind to transceiver\n");
                        driver->unbind (&udc->gadget);
-                       udc->gadget.dev.driver = 0;
-                       udc->driver = 0;
+                       udc->gadget.dev.driver = NULL;
+                       udc->driver = NULL;
                        goto done;
                }
        } else {
@@ -2071,7 +2123,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
                omap_vbus_session(&udc->gadget, 0);
 
        if (udc->transceiver)
-               (void) otg_set_peripheral(udc->transceiver, 0);
+               (void) otg_set_peripheral(udc->transceiver, NULL);
        else
                pullup_disable(udc);
 
@@ -2080,9 +2132,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
        spin_unlock_irqrestore(&udc->lock, flags);
 
        driver->unbind(&udc->gadget);
-       udc->gadget.dev.driver = 0;
-       udc->driver = 0;
-
+       udc->gadget.dev.driver = NULL;
+       udc->driver = NULL;
 
        DBG("unregistered driver '%s'\n", driver->driver.name);
        return status;
@@ -2178,14 +2229,14 @@ static int proc_otg_show(struct seq_file *s)
 
        tmp = OTG_REV_REG;
        trans = USB_TRANSCEIVER_CTRL_REG;
-       seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %03x\n",
+       seq_printf(s, "\nOTG rev %d.%d, transceiver_ctrl %05x\n",
                tmp >> 4, tmp & 0xf, trans);
        tmp = OTG_SYSCON_1_REG;
        seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s,"
                        FOURBITS "\n", tmp,
                trx_mode(USB2_TRX_MODE(tmp), trans & CONF_USB2_UNI_R),
                trx_mode(USB1_TRX_MODE(tmp), trans & CONF_USB1_UNI_R),
-               (USB0_TRX_MODE(tmp) == 0)
+               (USB0_TRX_MODE(tmp) == 0 && !cpu_is_omap1710())
                        ? "internal"
                        : trx_mode(USB0_TRX_MODE(tmp), 1),
                (tmp & OTG_IDLE_EN) ? " !otg" : "",
@@ -2235,6 +2286,7 @@ static int proc_otg_show(struct seq_file *s)
        seq_printf(s, "otg_outctrl %04x" "\n", tmp);
        tmp = OTG_TEST_REG;
        seq_printf(s, "otg_test    %04x" "\n", tmp);
+       return 0;
 }
 
 static int proc_udc_show(struct seq_file *s, void *_)
@@ -2378,7 +2430,7 @@ static int proc_udc_show(struct seq_file *s, void *_)
 
 static int proc_udc_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, proc_udc_show, 0);
+       return single_open(file, proc_udc_show, NULL);
 }
 
 static struct file_operations proc_ops = {
@@ -2399,7 +2451,7 @@ static void create_proc_file(void)
 
 static void remove_proc_file(void)
 {
-       remove_proc_entry(proc_filename, 0);
+       remove_proc_entry(proc_filename, NULL);
 }
 
 #else
@@ -2414,6 +2466,10 @@ static inline void remove_proc_file(void) {}
 /* Before this controller can enumerate, we need to pick an endpoint
  * configuration, or "fifo_mode"  That involves allocating 2KB of packet
  * buffer space among the endpoints we'll be operating.
+ *
+ * NOTE: as of OMAP 1710 ES2.0, writing a new endpoint config when
+ * UDC_SYSCON_1_REG.CFG_LOCK is set can now work.  We won't use that
+ * capability yet though.
  */
 static unsigned __init
 omap_ep_setup(char *name, u8 addr, u8 type,
@@ -2505,7 +2561,7 @@ static void omap_udc_release(struct device *dev)
 {
        complete(udc->done);
        kfree (udc);
-       udc = 0;
+       udc = NULL;
 }
 
 static int __init
@@ -2577,23 +2633,33 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
        case 1:
                OMAP_BULK_EP("ep1in",  USB_DIR_IN  | 1);
                OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2);
+               OMAP_INT_EP("ep9in",   USB_DIR_IN  | 9, 16);
+
                OMAP_BULK_EP("ep3in",  USB_DIR_IN  | 3);
                OMAP_BULK_EP("ep4out", USB_DIR_OUT | 4);
+               OMAP_INT_EP("ep10in",  USB_DIR_IN  | 10, 16);
 
                OMAP_BULK_EP("ep5in",  USB_DIR_IN  | 5);
                OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5);
+               OMAP_INT_EP("ep11in",  USB_DIR_IN  | 11, 16);
+
                OMAP_BULK_EP("ep6in",  USB_DIR_IN  | 6);
                OMAP_BULK_EP("ep6out", USB_DIR_OUT | 6);
+               OMAP_INT_EP("ep12in",  USB_DIR_IN  | 12, 16);
 
                OMAP_BULK_EP("ep7in",  USB_DIR_IN  | 7);
                OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7);
+               OMAP_INT_EP("ep13in",  USB_DIR_IN  | 13, 16);
+               OMAP_INT_EP("ep13out", USB_DIR_OUT | 13, 16);
+
                OMAP_BULK_EP("ep8in",  USB_DIR_IN  | 8);
                OMAP_BULK_EP("ep8out", USB_DIR_OUT | 8);
+               OMAP_INT_EP("ep14in",  USB_DIR_IN  | 14, 16);
+               OMAP_INT_EP("ep14out", USB_DIR_OUT | 14, 16);
+
+               OMAP_BULK_EP("ep15in",  USB_DIR_IN  | 15);
+               OMAP_BULK_EP("ep15out", USB_DIR_OUT | 15);
 
-               OMAP_INT_EP("ep9in",   USB_DIR_IN  | 9, 16);
-               OMAP_INT_EP("ep10out", USB_DIR_IN  | 10, 16);
-               OMAP_INT_EP("ep11in",  USB_DIR_IN  | 9, 16);
-               OMAP_INT_EP("ep12out", USB_DIR_IN  | 10, 16);
                break;
 
 #ifdef USE_ISO
@@ -2640,8 +2706,8 @@ static int __init omap_udc_probe(struct device *dev)
        struct platform_device  *odev = to_platform_device(dev);
        int                     status = -ENODEV;
        int                     hmc;
-       struct otg_transceiver  *xceiv = 0;
-       const char              *type = 0;
+       struct otg_transceiver  *xceiv = NULL;
+       const char              *type = NULL;
        struct omap_usb_config  *config = dev->platform_data;
 
        /* NOTE:  "knows" the order of the resources! */
@@ -2676,54 +2742,78 @@ static int __init omap_udc_probe(struct device *dev)
                        FUNC_MUX_CTRL_0_REG = tmp;
                }
        } else {
+               /* The transceiver may package some GPIO logic or handle
+                * loopback and/or transceiverless setup; if we find one,
+                * use it.  Except for OTG, we don't _need_ to talk to one;
+                * but not having one probably means no VBUS detection.
+                */
+               xceiv = otg_get_transceiver();
+               if (xceiv)
+                       type = xceiv->label;
+               else if (config->otg) {
+                       DBG("OTG requires external transceiver!\n");
+                       goto cleanup0;
+               }
+
                hmc = HMC_1610;
                switch (hmc) {
+               case 0:                 /* POWERUP DEFAULT == 0 */
+               case 4:
+               case 12:
+               case 20:
+                       if (!cpu_is_omap1710()) {
+                               type = "integrated";
+                               break;
+                       }
+                       /* FALL THROUGH */
                case 3:
                case 11:
                case 16:
                case 19:
                case 25:
-                       xceiv = otg_get_transceiver();
                        if (!xceiv) {
                                DBG("external transceiver not registered!\n");
-                               if (config->otg)
-                                       goto cleanup0;
-                               type = "(unknown external)";
-                       } else
-                               type = xceiv->label;
-                       break;
-               case 0:                 /* POWERUP DEFAULT == 0 */
-               case 4:
-               case 12:
-               case 20:
-                       type = "INTEGRATED";
+                               type = "unknown";
+                       }
                        break;
                case 21:                        /* internal loopback */
-                       type = "(loopback)";
+                       type = "loopback";
                        break;
                case 14:                        /* transceiverless */
-                       type = "(none)";
+                       if (cpu_is_omap1710())
+                               goto bad_on_1710;
+                       /* FALL THROUGH */
+               case 13:
+               case 15:
+                       type = "no";
                        break;
 
                default:
+bad_on_1710:
                        ERR("unrecognized UDC HMC mode %d\n", hmc);
-                       return -ENODEV;
+                       goto cleanup0;
                }
        }
-       INFO("hmc mode %d, transceiver %s\n", hmc, type);
+       INFO("hmc mode %d, %s transceiver\n", hmc, type);
 
        /* a "gadget" abstracts/virtualizes the controller */
        status = omap_udc_setup(odev, xceiv);
        if (status) {
                goto cleanup0;
        }
-       xceiv = 0;
+       xceiv = NULL;
        // "udc" is now valid
        pullup_disable(udc);
 #if    defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
        udc->gadget.is_otg = (config->otg != 0);
 #endif
 
+       /* starting with omap1710 es2.0, clear toggle is a separate bit */
+       if (UDC_REV_REG >= 0x61)
+               udc->clr_halt = UDC_RESET_EP | UDC_CLRDATA_TOGGLE;
+       else
+               udc->clr_halt = UDC_RESET_EP;
+
        /* USB general purpose IRQ:  ep0, state changes, dma, etc */
        status = request_irq(odev->resource[1].start, omap_udc_irq,
                        SA_SAMPLE_RANDOM, driver_name, udc);
@@ -2765,7 +2855,7 @@ cleanup2:
 
 cleanup1:
        kfree (udc);
-       udc = 0;
+       udc = NULL;
 
 cleanup0:
        if (xceiv)
@@ -2788,7 +2878,7 @@ static int __exit omap_udc_remove(struct device *dev)
        pullup_disable(udc);
        if (udc->transceiver) {
                put_device(udc->transceiver->dev);
-               udc->transceiver = 0;
+               udc->transceiver = NULL;
        }
        UDC_SYSCON1_REG = 0;
 
@@ -2809,13 +2899,32 @@ static int __exit omap_udc_remove(struct device *dev)
        return 0;
 }
 
-static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level)
+/* suspend/resume/wakeup from sysfs (echo > power/state) or when the
+ * system is forced into deep sleep
+ *
+ * REVISIT we should probably reject suspend requests when there's a host
+ * session active, rather than disconnecting, at least on boards that can
+ * report VBUS irqs (UDC_DEVSTAT_REG.UDC_ATT).  And in any case, we need to
+ * make host resumes and VBUS detection trigger OMAP wakeup events; that
+ * may involve talking to an external transceiver (e.g. isp1301).
+ */
+static int omap_udc_suspend(struct device *dev, pm_message_t message, u32 level)
 {
-       if (level != 0)
+       u32     devstat;
+
+       if (level != SUSPEND_POWER_DOWN)
                return 0;
+       devstat = UDC_DEVSTAT_REG;
+
+       /* we're requesting 48 MHz clock if the pullup is enabled
+        * (== we're attached to the host) and we're not suspended,
+        * which would prevent entry to deep sleep...
+        */
+       if ((devstat & UDC_ATT) != 0 && (devstat & UDC_SUS) == 0) {
+               WARN("session active; suspend requires disconnect\n");
+               omap_pullup(&udc->gadget, 0);
+       }
 
-       DBG("suspend, state %d\n", state);
-       omap_pullup(&udc->gadget, 0);
        udc->gadget.dev.power.power_state = PMSG_SUSPEND;
        udc->gadget.dev.parent->power.power_state = PMSG_SUSPEND;
        return 0;
@@ -2823,7 +2932,7 @@ static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level)
 
 static int omap_udc_resume(struct device *dev, u32 level)
 {
-       if (level != 0)
+       if (level != RESUME_POWER_ON)
                return 0;
 
        DBG("resume + wakeup/SRP\n");
index c9e68541622c9e86c12372fd03b25b3766c3f432..652ee462734470345eed415a474c096fbe4a7909 100644 (file)
@@ -20,6 +20,7 @@
 #define        UDC_CTRL_REG                    UDC_REG(0x0C)   /* Endpoint control */
 #      define  UDC_CLR_HALT            (1 << 7)
 #      define  UDC_SET_HALT            (1 << 6)
+#      define  UDC_CLRDATA_TOGGLE      (1 << 3)
 #      define  UDC_SET_FIFO_EN         (1 << 2)
 #      define  UDC_CLR_EP              (1 << 1)
 #      define  UDC_RESET_EP            (1 << 0)
 
 /* DMA configuration registers:  up to three channels in each direction.  */
 #define        UDC_RXDMA_CFG_REG               UDC_REG(0x40)   /* 3 eps for RX DMA */
+#      define  UDC_DMA_REQ             (1 << 12)
 #define        UDC_TXDMA_CFG_REG               UDC_REG(0x44)   /* 3 eps for TX DMA */
 #define        UDC_DATA_DMA_REG                UDC_REG(0x48)   /* rx/tx fifo addr */
 
@@ -162,6 +164,7 @@ struct omap_udc {
        spinlock_t                      lock;
        struct omap_ep                  ep[32];
        u16                             devstat;
+       u16                             clr_halt;
        struct otg_transceiver          *transceiver;
        struct list_head                iso;
        unsigned                        softconnect:1;
@@ -171,7 +174,6 @@ struct omap_udc {
        unsigned                        ep0_set_config:1;
        unsigned                        ep0_reset_config:1;
        unsigned                        ep0_setup:1;
-
        struct completion               *done;
 };
 
index b8b4524ed7468cda98e8d19a66a39adc84a9578b..6a0b957af335abfd3d038f4246bfdc63eb08d722 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * linux/drivers/usb/gadget/pxa2xx_udc.c
- * Intel PXA2xx and IXP4xx on-chip full speed USB device controllers
+ * Intel PXA25x and IXP4xx on-chip full speed USB device controllers
  *
  * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker)
  * Copyright (C) 2003 Robert Schwebel, Pengutronix
@@ -63,7 +63,7 @@
 
 
 /*
- * This driver handles the USB Device Controller (UDC) in Intel's PXA 2xx
+ * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x
  * series processors.  The UDC for the IXP 4xx series is very similar.
  * There are fifteen endpoints, in addition to ep0.
  *
@@ -79,8 +79,8 @@
  * pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
  */
 
-#define        DRIVER_VERSION  "14-Dec-2003"
-#define        DRIVER_DESC     "PXA 2xx USB Device Controller driver"
+#define        DRIVER_VERSION  "4-May-2005"
+#define        DRIVER_DESC     "PXA 25x USB Device Controller driver"
 
 
 static const char driver_name [] = "pxa2xx_udc";
@@ -290,6 +290,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
 static int pxa2xx_ep_disable (struct usb_ep *_ep)
 {
        struct pxa2xx_ep        *ep;
+       unsigned long           flags;
 
        ep = container_of (_ep, struct pxa2xx_ep, ep);
        if (!_ep || !ep->desc) {
@@ -297,6 +298,8 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
                        _ep ? ep->ep.name : NULL);
                return -EINVAL;
        }
+       local_irq_save(flags);
+
        nuke (ep, -ESHUTDOWN);
 
 #ifdef USE_DMA
@@ -313,6 +316,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
        ep->desc = NULL;
        ep->stopped = 1;
 
+       local_irq_restore(flags);
        DBG(DBG_VERBOSE, "%s disabled\n", _ep->name);
        return 0;
 }
@@ -971,10 +975,10 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
                        kick_dma(ep, req);
 #endif
                /* can the FIFO can satisfy the request immediately? */
-               } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0
-                               && (*ep->reg_udccs & UDCCS_BI_TFS) != 0
-                               && write_fifo(ep, req)) {
-                       req = NULL;
+               } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
+                       if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0
+                                       && write_fifo(ep, req))
+                               req = NULL;
                } else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0
                                && read_fifo(ep, req)) {
                        req = NULL;
@@ -1290,7 +1294,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
                "%s version: %s\nGadget driver: %s\nHost %s\n\n",
                driver_name, DRIVER_VERSION SIZE_STR DMASTR,
                dev->driver ? dev->driver->driver.name : "(none)",
-               is_usb_connected() ? "full speed" : "disconnected");
+               is_vbus_present() ? "full speed" : "disconnected");
        size -= t;
        next += t;
 
@@ -1339,7 +1343,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
                next += t;
        }
 
-       if (!is_usb_connected() || !dev->driver)
+       if (!is_vbus_present() || !dev->driver)
                goto done;
 
        t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
@@ -1454,7 +1458,7 @@ static void udc_disable(struct pxa2xx_udc *dev)
        UFNRH = UFNRH_SIM;
 
        /* if hardware supports it, disconnect from usb */
-       make_usb_disappear();
+       pullup_off();
 
        udc_clear_mask_UDCCR(UDCCR_UDE);
 
@@ -1567,7 +1571,7 @@ static void udc_enable (struct pxa2xx_udc *dev)
        UICR0 &= ~UICR0_IM0;
 
        /* if hardware supports it, pullup D+ and wait for reset */
-       let_usb_appear();
+       pullup_on();
 }
 
 
@@ -2052,10 +2056,10 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r)
                if (unlikely(udccr & UDCCR_SUSIR)) {
                        udc_ack_int_UDCCR(UDCCR_SUSIR);
                        handled = 1;
-                       DBG(DBG_VERBOSE, "USB suspend%s\n", is_usb_connected()
+                       DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present()
                                ? "" : "+disconnect");
 
-                       if (!is_usb_connected())
+                       if (!is_vbus_present())
                                stop_activity(dev, dev->driver);
                        else if (dev->gadget.speed != USB_SPEED_UNKNOWN
                                        && dev->driver
@@ -2073,7 +2077,7 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r)
                        if (dev->gadget.speed != USB_SPEED_UNKNOWN
                                        && dev->driver
                                        && dev->driver->resume
-                                       && is_usb_connected())
+                                       && is_vbus_present())
                                dev->driver->resume(&dev->gadget);
                }
 
@@ -2509,7 +2513,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev)
        udc_disable(dev);
        udc_reinit(dev);
 
-       dev->vbus = is_usb_connected();
+       dev->vbus = is_vbus_present();
 
        /* irq setup after old hardware state is cleaned up */
        retval = request_irq(IRQ_USB, pxa2xx_udc_irq,
@@ -2555,6 +2559,12 @@ lubbock_fail0:
 
        return 0;
 }
+
+static void pxa2xx_udc_shutdown(struct device *_dev)
+{
+       pullup_off();
+}
+
 static int __exit pxa2xx_udc_remove(struct device *_dev)
 {
        struct pxa2xx_udc *dev = dev_get_drvdata(_dev);
@@ -2624,6 +2634,7 @@ static struct device_driver udc_driver = {
        .name           = "pxa2xx-udc",
        .bus            = &platform_bus_type,
        .probe          = pxa2xx_udc_probe,
+       .shutdown       = pxa2xx_udc_shutdown,
        .remove         = __exit_p(pxa2xx_udc_remove),
        .suspend        = pxa2xx_udc_suspend,
        .resume         = pxa2xx_udc_resume,
index 1f3a7d999da7e31dfbcac893897b2cec06aa4cc0..d0bc396a85d50041e030289ae4c0ab99396f525b 100644 (file)
@@ -177,23 +177,23 @@ struct pxa2xx_udc {
 
 static struct pxa2xx_udc *the_controller;
 
-/* one GPIO should be used to detect host disconnect */
-static inline int is_usb_connected(void)
+/* one GPIO should be used to detect VBUS from the host */
+static inline int is_vbus_present(void)
 {
        if (!the_controller->mach->udc_is_connected)
                return 1;
        return the_controller->mach->udc_is_connected();
 }
 
-/* one GPIO should force the host to see this device (or not) */
-static inline void make_usb_disappear(void)
+/* one GPIO should control a D+ pullup, so host sees this device (or not) */
+static inline void pullup_off(void)
 {
        if (!the_controller->mach->udc_command)
                return;
        the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
 }
 
-static inline void let_usb_appear(void)
+static inline void pullup_on(void)
 {
        if (!the_controller->mach->udc_command)
                return;
index 7457268d5f282b9e9d1d6217857db70e0ecaefc9..06b6eba925b59e5542378eca866387fe4ba9c15e 100644 (file)
@@ -41,6 +41,7 @@
 
 
 #undef RNDIS_PM
+#undef RNDIS_WAKEUP
 #undef VERBOSE
 
 #include "rndis.h"
@@ -60,7 +61,7 @@
        } while (0)
 static int rndis_debug = 0;
 
-module_param (rndis_debug, bool, 0);
+module_param (rndis_debug, int, 0);
 MODULE_PARM_DESC (rndis_debug, "enable debugging");
 
 #else
@@ -78,22 +79,103 @@ static rndis_params rndis_per_dev_params [RNDIS_MAX_CONFIGS];
 static const __le32 rndis_driver_version = __constant_cpu_to_le32 (1);
 
 /* Function Prototypes */
-static int rndis_init_response (int configNr, rndis_init_msg_type *buf);
-static int rndis_query_response (int configNr, rndis_query_msg_type *buf);
-static int rndis_set_response (int configNr, rndis_set_msg_type *buf);
-static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf);
-static int rndis_keepalive_response (int configNr, 
-                                    rndis_keepalive_msg_type *buf);
-
 static rndis_resp_t *rndis_add_response (int configNr, u32 length);
 
 
+/* supported OIDs */
+static const u32 oid_supported_list [] = 
+{
+       /* the general stuff */
+       OID_GEN_SUPPORTED_LIST,
+       OID_GEN_HARDWARE_STATUS,
+       OID_GEN_MEDIA_SUPPORTED,
+       OID_GEN_MEDIA_IN_USE,
+       OID_GEN_MAXIMUM_FRAME_SIZE,
+       OID_GEN_LINK_SPEED,
+       OID_GEN_TRANSMIT_BLOCK_SIZE,
+       OID_GEN_RECEIVE_BLOCK_SIZE,
+       OID_GEN_VENDOR_ID,
+       OID_GEN_VENDOR_DESCRIPTION,
+       OID_GEN_VENDOR_DRIVER_VERSION,
+       OID_GEN_CURRENT_PACKET_FILTER,
+       OID_GEN_MAXIMUM_TOTAL_SIZE,
+       OID_GEN_MEDIA_CONNECT_STATUS,
+       OID_GEN_PHYSICAL_MEDIUM,
+#if 0
+       OID_GEN_RNDIS_CONFIG_PARAMETER,
+#endif
+       
+       /* the statistical stuff */
+       OID_GEN_XMIT_OK,
+       OID_GEN_RCV_OK,
+       OID_GEN_XMIT_ERROR,
+       OID_GEN_RCV_ERROR,
+       OID_GEN_RCV_NO_BUFFER,
+#ifdef RNDIS_OPTIONAL_STATS
+       OID_GEN_DIRECTED_BYTES_XMIT,
+       OID_GEN_DIRECTED_FRAMES_XMIT,
+       OID_GEN_MULTICAST_BYTES_XMIT,
+       OID_GEN_MULTICAST_FRAMES_XMIT,
+       OID_GEN_BROADCAST_BYTES_XMIT,
+       OID_GEN_BROADCAST_FRAMES_XMIT,
+       OID_GEN_DIRECTED_BYTES_RCV,
+       OID_GEN_DIRECTED_FRAMES_RCV,
+       OID_GEN_MULTICAST_BYTES_RCV,
+       OID_GEN_MULTICAST_FRAMES_RCV,
+       OID_GEN_BROADCAST_BYTES_RCV,
+       OID_GEN_BROADCAST_FRAMES_RCV,
+       OID_GEN_RCV_CRC_ERROR,
+       OID_GEN_TRANSMIT_QUEUE_LENGTH,
+#endif /* RNDIS_OPTIONAL_STATS */
+
+       /* mandatory 802.3 */
+       /* the general stuff */
+       OID_802_3_PERMANENT_ADDRESS,
+       OID_802_3_CURRENT_ADDRESS,
+       OID_802_3_MULTICAST_LIST,
+       OID_802_3_MAC_OPTIONS,
+       OID_802_3_MAXIMUM_LIST_SIZE,
+       
+       /* the statistical stuff */
+       OID_802_3_RCV_ERROR_ALIGNMENT,
+       OID_802_3_XMIT_ONE_COLLISION,
+       OID_802_3_XMIT_MORE_COLLISIONS,
+#ifdef RNDIS_OPTIONAL_STATS
+       OID_802_3_XMIT_DEFERRED,
+       OID_802_3_XMIT_MAX_COLLISIONS,
+       OID_802_3_RCV_OVERRUN,
+       OID_802_3_XMIT_UNDERRUN,
+       OID_802_3_XMIT_HEARTBEAT_FAILURE,
+       OID_802_3_XMIT_TIMES_CRS_LOST,
+       OID_802_3_XMIT_LATE_COLLISIONS,
+#endif /* RNDIS_OPTIONAL_STATS */
+
+#ifdef RNDIS_PM
+       /* PM and wakeup are mandatory for USB: */
+
+       /* power management */
+       OID_PNP_CAPABILITIES,
+       OID_PNP_QUERY_POWER,
+       OID_PNP_SET_POWER,
+
+#ifdef RNDIS_WAKEUP
+       /* wake up host */
+       OID_PNP_ENABLE_WAKE_UP,
+       OID_PNP_ADD_WAKE_UP_PATTERN,
+       OID_PNP_REMOVE_WAKE_UP_PATTERN,
+#endif /* RNDIS_WAKEUP */
+#endif /* RNDIS_PM */
+};
+
+
 /* NDIS Functions */
-static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
+static int
+gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
+               rndis_resp_t *r)
 {
        int                     retval = -ENOTSUPP;
-       u32                     length = 0;
-       __le32                  *tmp;
+       u32                     length = 4;     /* usually */
+       __le32                  *outbuf;
        int                     i, count;
        rndis_query_cmplt_type  *resp;
 
@@ -101,7 +183,22 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
        resp = (rndis_query_cmplt_type *) r->buf;
 
        if (!resp) return -ENOMEM;
-       
+
+       if (buf_len && rndis_debug > 1) {
+               DEBUG("query OID %08x value, len %d:\n", OID, buf_len);
+               for (i = 0; i < buf_len; i += 16) {
+                       DEBUG ("%03d: %08x %08x %08x %08x\n", i,
+                               le32_to_cpup((__le32 *)&buf[i]),
+                               le32_to_cpup((__le32 *)&buf[i + 4]),
+                               le32_to_cpup((__le32 *)&buf[i + 8]),
+                               le32_to_cpup((__le32 *)&buf[i + 12]));
+               }
+       }
+
+       /* response goes here, right after the header */
+       outbuf = (__le32 *) &resp[1];
+       resp->InformationBufferOffset = __constant_cpu_to_le32 (16);
+
        switch (OID) {
 
        /* general oids (table 4-1) */
@@ -111,42 +208,36 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
                DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
                length = sizeof (oid_supported_list);
                count  = length / sizeof (u32);
-               tmp = (__le32 *) ((u8 *)resp + 24);
                for (i = 0; i < count; i++)
-                       tmp[i] = cpu_to_le32 (oid_supported_list[i]);
+                       outbuf[i] = cpu_to_le32 (oid_supported_list[i]);
                retval = 0;
                break;
                
        /* mandatory */
        case OID_GEN_HARDWARE_STATUS:
                DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
-               length = 4;
                /* Bogus question! 
                 * Hardware must be ready to receive high level protocols.
                 * BTW: 
                 * reddite ergo quae sunt Caesaris Caesari
                 * et quae sunt Dei Deo!
                 */
-               *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+               *outbuf = __constant_cpu_to_le32 (0);
                retval = 0;
                break;
                
        /* mandatory */
        case OID_GEN_MEDIA_SUPPORTED:
                DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
-               length = 4;
-               *((__le32 *) resp + 6) = cpu_to_le32 (
-                                       rndis_per_dev_params [configNr].medium);
+               *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
                retval = 0;
                break;
                
        /* mandatory */
        case OID_GEN_MEDIA_IN_USE:
                DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
-               length = 4;
                /* one medium, one transport... (maybe you do it better) */
-               *((__le32 *) resp + 6) = cpu_to_le32 (
-                                       rndis_per_dev_params [configNr].medium);
+               *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
                retval = 0;
                break;
                
@@ -154,25 +245,21 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
        case OID_GEN_MAXIMUM_FRAME_SIZE:
                DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].dev) {
-                       length = 4;
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
+                       *outbuf = cpu_to_le32 (
                                rndis_per_dev_params [configNr].dev->mtu);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
        /* mandatory */
        case OID_GEN_LINK_SPEED:
-//             DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
-               length = 4;
+               if (rndis_debug > 1)
+                       DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].media_state
-                       == NDIS_MEDIA_STATE_DISCONNECTED)
-                   *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+                               == NDIS_MEDIA_STATE_DISCONNECTED)
+                       *outbuf = __constant_cpu_to_le32 (0);
                else
-                   *((__le32 *) resp + 6) = cpu_to_le32 (
+                       *outbuf = cpu_to_le32 (
                                rndis_per_dev_params [configNr].speed);
                retval = 0;
                break;
@@ -181,8 +268,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
        case OID_GEN_TRANSMIT_BLOCK_SIZE:
                DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].dev) {
-                       length = 4;
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
+                       *outbuf = cpu_to_le32 (
                                rndis_per_dev_params [configNr].dev->mtu);
                        retval = 0;
                }
@@ -192,8 +278,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
        case OID_GEN_RECEIVE_BLOCK_SIZE:
                DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].dev) {
-                       length = 4;
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
+                       *outbuf = cpu_to_le32 (
                                rndis_per_dev_params [configNr].dev->mtu);
                        retval = 0;
                }
@@ -202,8 +287,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
        /* mandatory */
        case OID_GEN_VENDOR_ID:
                DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
-               length = 4;
-               *((__le32 *) resp + 6) = cpu_to_le32 (
+               *outbuf = cpu_to_le32 (
                        rndis_per_dev_params [configNr].vendorID);
                retval = 0;
                break;
@@ -212,51 +296,44 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
        case OID_GEN_VENDOR_DESCRIPTION:
                DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
                length = strlen (rndis_per_dev_params [configNr].vendorDescr);
-               memcpy ((u8 *) resp + 24, 
+               memcpy (outbuf,
                        rndis_per_dev_params [configNr].vendorDescr, length);
                retval = 0;
                break;
 
        case OID_GEN_VENDOR_DRIVER_VERSION:
                DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
-               length = 4;
                /* Created as LE */
-               *((__le32 *) resp + 6) = rndis_driver_version;
+               *outbuf = rndis_driver_version;
                retval = 0;
                break;
 
        /* mandatory */
        case OID_GEN_CURRENT_PACKET_FILTER:
                DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
-               length = 4;
-               *((__le32 *) resp + 6) = cpu_to_le32 (
-                                       rndis_per_dev_params[configNr].filter);
+               *outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter);
                retval = 0;
                break;
 
        /* mandatory */
        case OID_GEN_MAXIMUM_TOTAL_SIZE:
                DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
-               length = 4;
-               *((__le32 *) resp + 6) = __constant_cpu_to_le32(
-                                       RNDIS_MAX_TOTAL_SIZE);
+               *outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
                retval = 0;
                break;
 
        /* mandatory */
        case OID_GEN_MEDIA_CONNECT_STATUS:
-               DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
-               length = 4;
-               *((__le32 *) resp + 6) = cpu_to_le32 (
-                                       rndis_per_dev_params [configNr]
+               if (rndis_debug > 1)
+                       DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
+               *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
                                                .media_state);
                retval = 0;
                break;
 
        case OID_GEN_PHYSICAL_MEDIUM:
                DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
-               length = 4;
-               *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+               *outbuf = __constant_cpu_to_le32 (0);
                retval = 0;
                break;
 
@@ -266,8 +343,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
         */
        case OID_GEN_MAC_OPTIONS:               /* from WinME */
                DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
-               length = 4;
-               *((__le32 *) resp + 6) = __constant_cpu_to_le32(
+               *outbuf = __constant_cpu_to_le32(
                          NDIS_MAC_OPTION_RECEIVE_SERIALIZED
                        | NDIS_MAC_OPTION_FULL_DUPLEX);
                retval = 0;
@@ -277,62 +353,49 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
 
        /* mandatory */
        case OID_GEN_XMIT_OK:
-               DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
+               if (rndis_debug > 1)
+                       DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
-                       length = 4;
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
+                       *outbuf = cpu_to_le32 (
                            rndis_per_dev_params [configNr].stats->tx_packets - 
                            rndis_per_dev_params [configNr].stats->tx_errors -
                            rndis_per_dev_params [configNr].stats->tx_dropped);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
 
        /* mandatory */
        case OID_GEN_RCV_OK:
-               DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
+               if (rndis_debug > 1)
+                       DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
-                       length = 4;
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
+                       *outbuf = cpu_to_le32 (
                            rndis_per_dev_params [configNr].stats->rx_packets - 
                            rndis_per_dev_params [configNr].stats->rx_errors -
                            rndis_per_dev_params [configNr].stats->rx_dropped);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
        /* mandatory */
        case OID_GEN_XMIT_ERROR:
-               DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
+               if (rndis_debug > 1)
+                       DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
-                       length = 4;
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
-                               rndis_per_dev_params [configNr]
+                       *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
                                        .stats->tx_errors);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
        /* mandatory */
        case OID_GEN_RCV_ERROR:
-               DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
+               if (rndis_debug > 1)
+                       DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
-                               rndis_per_dev_params [configNr]
+                       *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
                                        .stats->rx_errors);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
@@ -340,13 +403,9 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
        case OID_GEN_RCV_NO_BUFFER:
                DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
-                               rndis_per_dev_params [configNr]
+                       *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
                                        .stats->rx_dropped);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
 
@@ -359,8 +418,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
                 * divided by weight of Alpha Centauri
                 */
                if (rndis_per_dev_params [configNr].stats) {
-                       length = 4;
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
+                       *outbuf = cpu_to_le32 (
                                (rndis_per_dev_params [configNr]
                                        .stats->tx_packets - 
                                 rndis_per_dev_params [configNr]
@@ -369,9 +427,6 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
                                         .stats->tx_dropped)
                                * 123);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
@@ -379,8 +434,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
                DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
                /* dito */
                if (rndis_per_dev_params [configNr].stats) {
-                       length = 4;
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
+                       *outbuf = cpu_to_le32 (
                                (rndis_per_dev_params [configNr]
                                        .stats->tx_packets - 
                                 rndis_per_dev_params [configNr]
@@ -389,144 +443,105 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
                                         .stats->tx_dropped)
                                / 123);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
        case OID_GEN_MULTICAST_BYTES_XMIT:
                DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
-                               rndis_per_dev_params [configNr]
+                       *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
                                        .stats->multicast*1234);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
        case OID_GEN_MULTICAST_FRAMES_XMIT:
                DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
-                               rndis_per_dev_params [configNr]
+                       *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
                                        .stats->multicast);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
        case OID_GEN_BROADCAST_BYTES_XMIT:
                DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
-                               rndis_per_dev_params [configNr]
+                       *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
                                        .stats->tx_packets/42*255);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
        case OID_GEN_BROADCAST_FRAMES_XMIT:
                DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
-                               rndis_per_dev_params [configNr]
+                       *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
                                        .stats->tx_packets/42);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
        case OID_GEN_DIRECTED_BYTES_RCV:
                DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
-               *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+               *outbuf = __constant_cpu_to_le32 (0);
                retval = 0;
                break;
                
        case OID_GEN_DIRECTED_FRAMES_RCV:
                DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
-               *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+               *outbuf = __constant_cpu_to_le32 (0);
                retval = 0;
                break;
                
        case OID_GEN_MULTICAST_BYTES_RCV:
                DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
-                               rndis_per_dev_params [configNr]
+                       *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
                                        .stats->multicast * 1111);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
        case OID_GEN_MULTICAST_FRAMES_RCV:
                DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
-                               rndis_per_dev_params [configNr]
+                       *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
                                        .stats->multicast);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
        case OID_GEN_BROADCAST_BYTES_RCV:
                DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
-                               rndis_per_dev_params [configNr]
+                       *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
                                        .stats->rx_packets/42*255);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
        case OID_GEN_BROADCAST_FRAMES_RCV:
                DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
-                               rndis_per_dev_params [configNr]
+                       *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
                                        .stats->rx_packets/42);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
        case OID_GEN_RCV_CRC_ERROR:
                DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
-                               rndis_per_dev_params [configNr]
+                       *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
                                        .stats->rx_crc_errors);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
        case OID_GEN_TRANSMIT_QUEUE_LENGTH:
                DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
-               *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+               *outbuf = __constant_cpu_to_le32 (0);
                retval = 0;
                break;
 #endif /* RNDIS_OPTIONAL_STATS */
@@ -538,13 +553,10 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
                DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].dev) {
                        length = ETH_ALEN;
-                       memcpy ((u8 *) resp + 24,
+                       memcpy (outbuf,
                                rndis_per_dev_params [configNr].host_mac,
                                length);
                        retval = 0;
-               } else {
-                       *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-                       retval = 0;
                }
                break;
                
@@ -553,7 +565,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
                DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].dev) {
                        length = ETH_ALEN;
-                       memcpy ((u8 *) resp + 24,
+                       memcpy (outbuf,
                                rndis_per_dev_params [configNr].host_mac,
                                length);
                        retval = 0;
@@ -563,18 +575,16 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
        /* mandatory */
        case OID_802_3_MULTICAST_LIST:
                DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
-               length = 4;
                /* Multicast base address only */
-               *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0xE0000000);
+               *outbuf = __constant_cpu_to_le32 (0xE0000000);
                retval = 0;
                break;
                
        /* mandatory */
        case OID_802_3_MAXIMUM_LIST_SIZE:
                DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
-                length = 4;
                /* Multicast base address only */
-               *((__le32 *) resp + 6) = __constant_cpu_to_le32 (1);
+               *outbuf = __constant_cpu_to_le32 (1);
                retval = 0;
                break;
                
@@ -587,11 +597,8 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
        /* mandatory */
        case OID_802_3_RCV_ERROR_ALIGNMENT:
                DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
-               if (rndis_per_dev_params [configNr].stats)
-               {
-                       length = 4;
-                       *((__le32 *) resp + 6) = cpu_to_le32 (
-                               rndis_per_dev_params [configNr]
+               if (rndis_per_dev_params [configNr].stats) {
+                       *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
                                        .stats->rx_frame_errors);
                        retval = 0;
                }
@@ -600,16 +607,14 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
        /* mandatory */
        case OID_802_3_XMIT_ONE_COLLISION:
                DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
-               length = 4;
-               *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+               *outbuf = __constant_cpu_to_le32 (0);
                retval = 0;
                break;
                
        /* mandatory */
        case OID_802_3_XMIT_MORE_COLLISIONS:
                DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
-               length = 4;
-               *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+               *outbuf = __constant_cpu_to_le32 (0);
                retval = 0;
                break;
                
@@ -655,27 +660,18 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
        case OID_PNP_CAPABILITIES:
                DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
 
-               /* just PM, and remote wakeup on link status change
-                * (not magic packet or pattern match)
-                */
+               /* for now, no wakeup capabilities */
                length = sizeof (struct NDIS_PNP_CAPABILITIES);
-               memset (resp, 0, length);
-               {
-                       struct NDIS_PNP_CAPABILITIES *caps = (void *) resp;
-
-                       caps->Flags = NDIS_DEVICE_WAKE_UP_ENABLE;
-                       caps->WakeUpCapabilities.MinLinkChangeWakeUp 
-                                = NdisDeviceStateD3;
-
-                       /* FIXME then use usb_gadget_wakeup(), and
-                        * set USB_CONFIG_ATT_WAKEUP in config desc
-                        */
-               }
+               memset(outbuf, 0, length);
                retval = 0;
                break;
        case OID_PNP_QUERY_POWER:
-               DEBUG("%s: OID_PNP_QUERY_POWER\n", __FUNCTION__);
-               /* sure, handle any power state that maps to USB suspend */
+               DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
+                               le32_to_cpup((__le32 *) buf) - 1);
+               /* only suspend is a real power state, and
+                * it can't be entered by OID_PNP_SET_POWER...
+                */
+               length = 0;
                retval = 0;
                break;
 #endif
@@ -684,11 +680,12 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
                printk (KERN_WARNING "%s: query unknown OID 0x%08X\n", 
                         __FUNCTION__, OID);
        }
+       if (retval < 0)
+               length = 0;
        
-       resp->InformationBufferOffset = __constant_cpu_to_le32 (16);
        resp->InformationBufferLength = cpu_to_le32 (length);
-       resp->MessageLength = cpu_to_le32 (24 + length);
-       r->length = 24 + length;
+       r->length = length + sizeof *resp;
+       resp->MessageLength = cpu_to_le32 (r->length);
        return retval;
 }
 
@@ -705,45 +702,40 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
        if (!resp)
                return -ENOMEM;
 
-       DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
-       for (i = 0; i < buf_len; i += 16) {
-               DEBUG ("%03d: "
-                       " %02x %02x %02x %02x"
-                       " %02x %02x %02x %02x"
-                       " %02x %02x %02x %02x"
-                       " %02x %02x %02x %02x"
-                       "\n",
-                       i,
-                       buf[i], buf [i+1],
-                               buf[i+2], buf[i+3],
-                       buf[i+4], buf [i+5],
-                               buf[i+6], buf[i+7],
-                       buf[i+8], buf [i+9],
-                               buf[i+10], buf[i+11],
-                       buf[i+12], buf [i+13],
-                               buf[i+14], buf[i+15]);
+       if (buf_len && rndis_debug > 1) {
+               DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
+               for (i = 0; i < buf_len; i += 16) {
+                       DEBUG ("%03d: %08x %08x %08x %08x\n", i,
+                               le32_to_cpup((__le32 *)&buf[i]),
+                               le32_to_cpup((__le32 *)&buf[i + 4]),
+                               le32_to_cpup((__le32 *)&buf[i + 8]),
+                               le32_to_cpup((__le32 *)&buf[i + 12]));
+               }
        }
 
+       params = &rndis_per_dev_params [configNr];
        switch (OID) {
        case OID_GEN_CURRENT_PACKET_FILTER:
-               params = &rndis_per_dev_params [configNr];
-               retval = 0;
 
-               /* FIXME use these NDIS_PACKET_TYPE_* bitflags to
-                * set the cdc_filter; it's not RNDIS-specific
+               /* these NDIS_PACKET_TYPE_* bitflags are shared with
+                * cdc_filter; it's not RNDIS-specific
                 * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
                 *      PROMISCUOUS, DIRECTED,
                 *      MULTICAST, ALL_MULTICAST, BROADCAST
                 */
-               params->filter = le32_to_cpup((__le32 *)buf);
+               *params->filter = (u16) le32_to_cpup((__le32 *)buf);
                DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
-                       __FUNCTION__, params->filter);
+                       __FUNCTION__, *params->filter);
 
                /* this call has a significant side effect:  it's
                 * what makes the packet flow start and stop, like
                 * activating the CDC Ethernet altsetting.
                 */
-               if (params->filter) {
+#ifdef RNDIS_PM
+update_linkstate:
+#endif
+               retval = 0;
+               if (*params->filter) {
                        params->state = RNDIS_DATA_INITIALIZED;
                        netif_carrier_on(params->dev);
                        if (netif_running(params->dev))
@@ -776,21 +768,34 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
 
 #ifdef RNDIS_PM
        case OID_PNP_SET_POWER:
-               DEBUG ("OID_PNP_SET_POWER\n");
-               /* sure, handle any power state that maps to USB suspend */
-               retval = 0;
-               break;
-
-       case OID_PNP_ENABLE_WAKE_UP:
-               /* always-connected ... */
-               DEBUG ("OID_PNP_ENABLE_WAKE_UP\n");
-               retval = 0;
+               /* The only real power state is USB suspend, and RNDIS requests
+                * can't enter it; this one isn't really about power.  After
+                * resuming, Windows forces a reset, and then SET_POWER D0.
+                * FIXME ... then things go batty; Windows wedges itself.
+                */
+               i = le32_to_cpup((__force __le32 *)buf);
+               DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
+               switch (i) {
+               case NdisDeviceStateD0:
+                       *params->filter = params->saved_filter;
+                       goto update_linkstate;
+               case NdisDeviceStateD3:
+               case NdisDeviceStateD2:
+               case NdisDeviceStateD1:
+                       params->saved_filter = *params->filter;
+                       retval = 0;
+                       break;
+               }
                break;
 
-       // no PM resume patterns supported (specified where?)
-       // so OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN always fails
+#ifdef RNDIS_WAKEUP
+       // no wakeup support advertised, so wakeup OIDs always fail:
+       //  - OID_PNP_ENABLE_WAKE_UP
+       //  - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN
 #endif
 
+#endif /* RNDIS_PM */
+
        default:
                printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n", 
                         __FUNCTION__, OID, buf_len);
@@ -811,13 +816,10 @@ static int rndis_init_response (int configNr, rndis_init_msg_type *buf)
        if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
        
        r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type));
-       
-       if (!r) return -ENOMEM;
-       
+       if (!r)
+               return -ENOMEM;
        resp = (rndis_init_cmplt_type *) r->buf;
        
-       if (!resp) return -ENOMEM;
-       
        resp->MessageType = __constant_cpu_to_le32 (
                        REMOTE_NDIS_INITIALIZE_CMPLT);
        resp->MessageLength = __constant_cpu_to_le32 (52);
@@ -857,20 +859,22 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
         * oid_supported_list is the largest answer 
         */
        r = rndis_add_response (configNr, sizeof (oid_supported_list));
-       
-       if (!r) return -ENOMEM;
+       if (!r)
+               return -ENOMEM;
        resp = (rndis_query_cmplt_type *) r->buf;
        
-       if (!resp) return -ENOMEM;
-       
        resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT);
-       resp->MessageLength = __constant_cpu_to_le32 (24);
        resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
-       
-       if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID), r)) {
+       
+       if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID),
+                       le32_to_cpu(buf->InformationBufferOffset)
+                                       + 8 + (u8 *) buf,
+                       le32_to_cpu(buf->InformationBufferLength),
+                       r)) {
                /* OID not supported */
                resp->Status = __constant_cpu_to_le32 (
                                RNDIS_STATUS_NOT_SUPPORTED);
+               resp->MessageLength = __constant_cpu_to_le32 (sizeof *resp);
                resp->InformationBufferLength = __constant_cpu_to_le32 (0);
                resp->InformationBufferOffset = __constant_cpu_to_le32 (0);
        } else
@@ -889,10 +893,9 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
        rndis_resp_t            *r;
        
        r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type));
-       
-       if (!r) return -ENOMEM;
+       if (!r)
+               return -ENOMEM;
        resp = (rndis_set_cmplt_type *) r->buf;
-       if (!resp) return -ENOMEM;
 
        BufLength = le32_to_cpu (buf->InformationBufferLength);
        BufOffset = le32_to_cpu (buf->InformationBufferOffset);
@@ -930,10 +933,9 @@ static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf)
        rndis_resp_t            *r;
        
        r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type));
-       
-       if (!r) return -ENOMEM;
+       if (!r)
+               return -ENOMEM;
        resp = (rndis_reset_cmplt_type *) r->buf;
-       if (!resp) return -ENOMEM;
        
        resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT);
        resp->MessageLength = __constant_cpu_to_le32 (16);
@@ -957,8 +959,9 @@ static int rndis_keepalive_response (int configNr,
        /* host "should" check only in RNDIS_DATA_INITIALIZED state */
 
        r = rndis_add_response (configNr, sizeof (rndis_keepalive_cmplt_type));
+       if (!r)
+               return -ENOMEM;
        resp = (rndis_keepalive_cmplt_type *) r->buf;
-       if (!resp) return -ENOMEM;
                
        resp->MessageType = __constant_cpu_to_le32 (
                        REMOTE_NDIS_KEEPALIVE_CMPLT);
@@ -987,10 +990,9 @@ static int rndis_indicate_status_msg (int configNr, u32 status)
        
        r = rndis_add_response (configNr, 
                                sizeof (rndis_indicate_status_msg_type));
-       if (!r) return -ENOMEM;
-       
+       if (!r)
+               return -ENOMEM;
        resp = (rndis_indicate_status_msg_type *) r->buf;
-       if (!resp) return -ENOMEM;
        
        resp->MessageType = __constant_cpu_to_le32 (
                        REMOTE_NDIS_INDICATE_STATUS_MSG);
@@ -1021,6 +1023,21 @@ int rndis_signal_disconnect (int configNr)
                                          RNDIS_STATUS_MEDIA_DISCONNECT);
 }
 
+void rndis_uninit (int configNr)
+{
+       u8 *buf;
+       u32 length;
+
+       if (configNr >= RNDIS_MAX_CONFIGS)
+               return;
+       rndis_per_dev_params [configNr].used = 0;
+       rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED;
+
+       /* drain the response queue */
+       while ((buf = rndis_get_next_response(configNr, &length)))
+               rndis_free_response(configNr, buf);
+}
+
 void rndis_set_host_mac (int configNr, const u8 *addr)
 {
        rndis_per_dev_params [configNr].host_mac = addr;
@@ -1046,9 +1063,13 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
                return -ENOTSUPP;
        params = &rndis_per_dev_params [configNr];
        
+       /* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
+        * rx/tx statistics and link status, in addition to KEEPALIVE traffic
+        * and normal HC level polling to see if there's any IN traffic.
+        */
+
        /* For USB: responses may take up to 10 seconds */
-       switch (MsgType)
-       {
+       switch (MsgType) {
        case REMOTE_NDIS_INITIALIZE_MSG:
                DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", 
                        __FUNCTION__ );
@@ -1082,10 +1103,9 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
 
        case REMOTE_NDIS_KEEPALIVE_MSG:
                /* For USB: host does this every 5 seconds */
-#ifdef VERBOSE
-               DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", 
-                       __FUNCTION__ );
-#endif
+               if (rndis_debug > 1)
+                       DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", 
+                               __FUNCTION__ );
                return rndis_keepalive_response (configNr,
                                                 (rndis_keepalive_msg_type *) 
                                                 buf);
@@ -1152,7 +1172,8 @@ void rndis_deregister (int configNr)
 }
 
 int rndis_set_param_dev (u8 configNr, struct net_device *dev, 
-                        struct net_device_stats *stats)
+                        struct net_device_stats *stats,
+                        u16 *cdc_filter)
 {
        DEBUG("%s:\n", __FUNCTION__ );
        if (!dev || !stats) return -1;
@@ -1160,6 +1181,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev,
        
        rndis_per_dev_params [configNr].dev = dev;
        rndis_per_dev_params [configNr].stats = stats;
+       rndis_per_dev_params [configNr].filter = cdc_filter;
        
        return 0;
 }
@@ -1178,7 +1200,7 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
 
 int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed)
 {
-       DEBUG("%s:\n", __FUNCTION__ );
+       DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed);
        if (configNr >= RNDIS_MAX_CONFIGS) return -1;
        
        rndis_per_dev_params [configNr].medium = medium;
@@ -1242,6 +1264,7 @@ static rndis_resp_t *rndis_add_response (int configNr, u32 length)
 {
        rndis_resp_t    *r;
        
+       /* NOTE:  this gets copied into ether.c USB_BUFSIZ bytes ... */
        r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC);
        if (!r) return NULL;
        
index 2b5b55df3cfd3042bfc189c12e6cbbc8fea54a4b..95b4c63261000b15d8c0a0dff21aa48ab720232f 100644 (file)
 #define OID_PNP_ENABLE_WAKE_UP                 0xFD010106
 
 
-/* supported OIDs */
-static const u32 oid_supported_list [] = 
-{
-       /* the general stuff */
-       OID_GEN_SUPPORTED_LIST,
-       OID_GEN_HARDWARE_STATUS,
-       OID_GEN_MEDIA_SUPPORTED,
-       OID_GEN_MEDIA_IN_USE,
-       OID_GEN_MAXIMUM_FRAME_SIZE,
-       OID_GEN_LINK_SPEED,
-       OID_GEN_TRANSMIT_BLOCK_SIZE,
-       OID_GEN_RECEIVE_BLOCK_SIZE,
-       OID_GEN_VENDOR_ID,
-       OID_GEN_VENDOR_DESCRIPTION,
-       OID_GEN_VENDOR_DRIVER_VERSION,
-       OID_GEN_CURRENT_PACKET_FILTER,
-       OID_GEN_MAXIMUM_TOTAL_SIZE,
-       OID_GEN_MEDIA_CONNECT_STATUS,
-       OID_GEN_PHYSICAL_MEDIUM,
-#if 0
-       OID_GEN_RNDIS_CONFIG_PARAMETER,
-#endif
-       
-       /* the statistical stuff */
-       OID_GEN_XMIT_OK,
-       OID_GEN_RCV_OK,
-       OID_GEN_XMIT_ERROR,
-       OID_GEN_RCV_ERROR,
-       OID_GEN_RCV_NO_BUFFER,
-#ifdef RNDIS_OPTIONAL_STATS
-       OID_GEN_DIRECTED_BYTES_XMIT,
-       OID_GEN_DIRECTED_FRAMES_XMIT,
-       OID_GEN_MULTICAST_BYTES_XMIT,
-       OID_GEN_MULTICAST_FRAMES_XMIT,
-       OID_GEN_BROADCAST_BYTES_XMIT,
-       OID_GEN_BROADCAST_FRAMES_XMIT,
-       OID_GEN_DIRECTED_BYTES_RCV,
-       OID_GEN_DIRECTED_FRAMES_RCV,
-       OID_GEN_MULTICAST_BYTES_RCV,
-       OID_GEN_MULTICAST_FRAMES_RCV,
-       OID_GEN_BROADCAST_BYTES_RCV,
-       OID_GEN_BROADCAST_FRAMES_RCV,
-       OID_GEN_RCV_CRC_ERROR,
-       OID_GEN_TRANSMIT_QUEUE_LENGTH,
-#endif /* RNDIS_OPTIONAL_STATS */
-
-       /* mandatory 802.3 */
-       /* the general stuff */
-       OID_802_3_PERMANENT_ADDRESS,
-       OID_802_3_CURRENT_ADDRESS,
-       OID_802_3_MULTICAST_LIST,
-       OID_802_3_MAC_OPTIONS,
-       OID_802_3_MAXIMUM_LIST_SIZE,
-       
-       /* the statistical stuff */
-       OID_802_3_RCV_ERROR_ALIGNMENT,
-       OID_802_3_XMIT_ONE_COLLISION,
-       OID_802_3_XMIT_MORE_COLLISIONS,
-#ifdef RNDIS_OPTIONAL_STATS
-       OID_802_3_XMIT_DEFERRED,
-       OID_802_3_XMIT_MAX_COLLISIONS,
-       OID_802_3_RCV_OVERRUN,
-       OID_802_3_XMIT_UNDERRUN,
-       OID_802_3_XMIT_HEARTBEAT_FAILURE,
-       OID_802_3_XMIT_TIMES_CRS_LOST,
-       OID_802_3_XMIT_LATE_COLLISIONS,
-#endif /* RNDIS_OPTIONAL_STATS */
-
-#ifdef RNDIS_PM
-       /* PM and wakeup are mandatory for USB: */
-
-       /* power management */
-       OID_PNP_CAPABILITIES,
-       OID_PNP_QUERY_POWER,
-       OID_PNP_SET_POWER,
-
-       /* wake up host */
-       OID_PNP_ENABLE_WAKE_UP,
-       OID_PNP_ADD_WAKE_UP_PATTERN,
-       OID_PNP_REMOVE_WAKE_UP_PATTERN,
-#endif
-};
-
-
 typedef struct rndis_init_msg_type 
 {
        __le32  MessageType;
@@ -309,15 +225,18 @@ typedef struct rndis_resp_t
 typedef struct rndis_params
 {
        u8                      confignr;
-       int                     used;
+       u8                      used;
+       u16                     saved_filter;
        enum rndis_state        state;
-       u32                     filter;
        u32                     medium;
        u32                     speed;
        u32                     media_state;
+
        const u8                *host_mac;
+       u16                     *filter;
        struct net_device       *dev;
        struct net_device_stats *stats;
+
        u32                     vendorID;
        const char              *vendorDescr;
        int                     (*ack) (struct net_device *);
@@ -329,7 +248,8 @@ int  rndis_msg_parser (u8 configNr, u8 *buf);
 int  rndis_register (int (*rndis_control_ack) (struct net_device *));
 void rndis_deregister (int configNr);
 int  rndis_set_param_dev (u8 configNr, struct net_device *dev,
-                        struct net_device_stats *stats);
+                        struct net_device_stats *stats,
+                        u16 *cdc_filter);
 int  rndis_set_param_vendor (u8 configNr, u32 vendorID, 
                            const char *vendorDescr);
 int  rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
@@ -338,6 +258,7 @@ int rndis_rm_hdr (struct sk_buff *skb);
 u8   *rndis_get_next_response (int configNr, u32 *length);
 void rndis_free_response (int configNr, u8 *buf);
 
+void rndis_uninit (int configNr);
 int  rndis_signal_connect (int configNr);
 int  rndis_signal_disconnect (int configNr);
 int  rndis_state (int configNr);
index 4d591c764e382640257e7bc569d13d58216f6a75..9e4f1c6935a54673ba19f71d24ed4aef2ed11150 100644 (file)
@@ -300,18 +300,18 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
                u8 type, unsigned int index, int is_otg);
 
 static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
-       int kmalloc_flags);
+       unsigned kmalloc_flags);
 static void gs_free_req(struct usb_ep *ep, struct usb_request *req);
 
 static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len,
-       int kmalloc_flags);
+       unsigned kmalloc_flags);
 static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req);
 
-static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags);
+static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags);
 static void gs_free_ports(struct gs_dev *dev);
 
 /* circular buffer */
-static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags);
+static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags);
 static void gs_buf_free(struct gs_buf *gb);
 static void gs_buf_clear(struct gs_buf *gb);
 static unsigned int gs_buf_data_avail(struct gs_buf *gb);
@@ -1607,9 +1607,9 @@ static int gs_setup(struct usb_gadget *gadget,
        int ret = -EOPNOTSUPP;
        struct gs_dev *dev = get_gadget_data(gadget);
        struct usb_request *req = dev->dev_ctrl_req;
-       u16 wIndex = ctrl->wIndex;
-       u16 wValue = ctrl->wValue;
-       u16 wLength = ctrl->wLength;
+       u16 wIndex = le16_to_cpu(ctrl->wIndex);
+       u16 wValue = le16_to_cpu(ctrl->wValue);
+       u16 wLength = le16_to_cpu(ctrl->wLength);
 
        switch (ctrl->bRequestType & USB_TYPE_MASK) {
        case USB_TYPE_STANDARD:
@@ -1651,9 +1651,9 @@ static int gs_setup_standard(struct usb_gadget *gadget,
        int ret = -EOPNOTSUPP;
        struct gs_dev *dev = get_gadget_data(gadget);
        struct usb_request *req = dev->dev_ctrl_req;
-       u16 wIndex = ctrl->wIndex;
-       u16 wValue = ctrl->wValue;
-       u16 wLength = ctrl->wLength;
+       u16 wIndex = le16_to_cpu(ctrl->wIndex);
+       u16 wValue = le16_to_cpu(ctrl->wValue);
+       u16 wLength = le16_to_cpu(ctrl->wLength);
 
        switch (ctrl->bRequest) {
        case USB_REQ_GET_DESCRIPTOR:
@@ -1782,9 +1782,9 @@ static int gs_setup_class(struct usb_gadget *gadget,
        struct gs_dev *dev = get_gadget_data(gadget);
        struct gs_port *port = dev->dev_port[0];        /* ACM only has one port */
        struct usb_request *req = dev->dev_ctrl_req;
-       u16 wIndex = ctrl->wIndex;
-       u16 wValue = ctrl->wValue;
-       u16 wLength = ctrl->wLength;
+       u16 wIndex = le16_to_cpu(ctrl->wIndex);
+       u16 wValue = le16_to_cpu(ctrl->wValue);
+       u16 wLength = le16_to_cpu(ctrl->wLength);
 
        switch (ctrl->bRequest) {
        case USB_CDC_REQ_SET_LINE_CODING:
@@ -2119,7 +2119,8 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
  * Allocate a usb_request and its buffer.  Returns a pointer to the
  * usb_request or NULL if there is an error.
  */
-static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, int kmalloc_flags)
+static struct usb_request *
+gs_alloc_req(struct usb_ep *ep, unsigned int len, unsigned kmalloc_flags)
 {
        struct usb_request *req;
 
@@ -2159,7 +2160,8 @@ static void gs_free_req(struct usb_ep *ep, struct usb_request *req)
  * Allocates a request and its buffer, using the given
  * endpoint, buffer len, and kmalloc flags.
  */
-static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, int kmalloc_flags)
+static struct gs_req_entry *
+gs_alloc_req_entry(struct usb_ep *ep, unsigned len, unsigned kmalloc_flags)
 {
        struct gs_req_entry     *req;
 
@@ -2200,7 +2202,7 @@ static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req)
  *
  * The device lock is normally held when calling this function.
  */
-static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags)
+static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags)
 {
        int i;
        struct gs_port *port;
@@ -2282,7 +2284,7 @@ static void gs_free_ports(struct gs_dev *dev)
  *
  * Allocate a circular buffer and all associated memory.
  */
-static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags)
+static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags)
 {
        struct gs_buf *gb;
 
index 6e49432071a1d7b1e6e506cc1efdaaaae014dc74..a6e035e24479dd7ca3c7645c8f69e3522810a752 100644 (file)
@@ -919,9 +919,9 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
        struct zero_dev         *dev = get_gadget_data (gadget);
        struct usb_request      *req = dev->req;
        int                     value = -EOPNOTSUPP;
-       u16                     w_index = ctrl->wIndex;
-       u16                     w_value = ctrl->wValue;
-       u16                     w_length = ctrl->wLength;
+       u16                     w_index = le16_to_cpu(ctrl->wIndex);
+       u16                     w_value = le16_to_cpu(ctrl->wValue);
+       u16                     w_length = le16_to_cpu(ctrl->wLength);
 
        /* usually this stores reply data in the pre-allocated ep0 buffer,
         * but config change events will reconfigure hardware.
index 19e598c9641f9661b83cefe7c996ef99d44e0fc3..ed1899d307db0b320b1038f49e66e4edca8946a8 100644 (file)
@@ -49,6 +49,19 @@ config USB_EHCI_ROOT_HUB_TT
 
          This supports the EHCI implementation from TransDimension Inc.
 
+config USB_ISP116X_HCD
+       tristate "ISP116X HCD support"
+       depends on USB
+       default N
+       ---help---
+         The ISP1160 and ISP1161 chips are USB host controllers. Enable this
+         option if your board has this chip. If unsure, say N.
+
+         This driver does not support isochronous transfers.
+
+         To compile this driver as a module, choose M here: the
+         module will be called isp116x-hcd.
+
 config USB_OHCI_HCD
        tristate "OHCI HCD support"
        depends on USB && USB_ARCH_HAS_OHCI
index 5dbd3e7a27c709a447dc9515badb98975c16f1be..350d14fc1cc9e38e066b2638314d1b376ce9d009 100644 (file)
@@ -4,6 +4,7 @@
 #
 
 obj-$(CONFIG_USB_EHCI_HCD)     += ehci-hcd.o
+obj-$(CONFIG_USB_ISP116X_HCD)  += isp116x-hcd.o
 obj-$(CONFIG_USB_OHCI_HCD)     += ohci-hcd.o
 obj-$(CONFIG_USB_UHCI_HCD)     += uhci-hcd.o
 obj-$(CONFIG_USB_SL811_HCD)    += sl811-hcd.o
index 2ff11d53567bcbfd0fdaf48de5dfc545d6d93eab..50cb01831075916c5f8e828f5e15f1ddd0df91df 100644 (file)
@@ -254,7 +254,7 @@ dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
        }
 
        return scnprintf (buf, len,
-               "%s%sport %d status %06x%s%s sig=%s %s%s%s%s%s%s%s%s%s",
+               "%s%sport %d status %06x%s%s sig=%s%s%s%s%s%s%s%s%s%s",
                label, label [0] ? " " : "", port, status,
                (status & PORT_POWER) ? " POWER" : "",
                (status & PORT_OWNER) ? " OWNER" : "",
@@ -644,9 +644,11 @@ show_registers (struct class_device *class_dev, char *buf)
        if (bus->controller->power.power_state) {
                size = scnprintf (next, size,
                        "bus %s, device %s (driver " DRIVER_VERSION ")\n"
+                       "%s\n"
                        "SUSPENDED (no register access)\n",
                        hcd->self.controller->bus->name,
-                       hcd->self.controller->bus_id);
+                       hcd->self.controller->bus_id,
+                       hcd->product_desc);
                goto done;
        }
 
@@ -654,13 +656,53 @@ show_registers (struct class_device *class_dev, char *buf)
        i = HC_VERSION(readl (&ehci->caps->hc_capbase));
        temp = scnprintf (next, size,
                "bus %s, device %s (driver " DRIVER_VERSION ")\n"
+               "%s\n"
                "EHCI %x.%02x, hcd state %d\n",
                hcd->self.controller->bus->name,
                hcd->self.controller->bus_id,
+               hcd->product_desc,
                i >> 8, i & 0x0ff, hcd->state);
        size -= temp;
        next += temp;
 
+#ifdef CONFIG_PCI
+       /* EHCI 0.96 and later may have "extended capabilities" */
+       if (hcd->self.controller->bus == &pci_bus_type) {
+               struct pci_dev  *pdev;
+               u32             offset, cap, cap2;
+               unsigned        count = 256/4;
+
+               pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
+               offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+               while (offset && count--) {
+                       pci_read_config_dword (pdev, offset, &cap);
+                       switch (cap & 0xff) {
+                       case 1:
+                               temp = scnprintf (next, size,
+                                       "ownership %08x%s%s\n", cap,
+                                       (cap & (1 << 24)) ? " linux" : "",
+                                       (cap & (1 << 16)) ? " firmware" : "");
+                               size -= temp;
+                               next += temp;
+
+                               offset += 4;
+                               pci_read_config_dword (pdev, offset, &cap2);
+                               temp = scnprintf (next, size,
+                                       "SMI sts/enable 0x%08x\n", cap2);
+                               size -= temp;
+                               next += temp;
+                               break;
+                       case 0:         /* illegal reserved capability */
+                               cap = 0;
+                               /* FALLTHROUGH */
+                       default:                /* unknown */
+                               break;
+                       }
+                       temp = (cap >> 8) & 0xff;
+               }
+       }
+#endif
+
        // FIXME interpret both types of params
        i = readl (&ehci->caps->hcs_params);
        temp = scnprintf (next, size, "structural params 0x%08x\n", i);
@@ -696,12 +738,19 @@ show_registers (struct class_device *class_dev, char *buf)
        size -= temp;
        next += temp;
 
-       for (i = 0; i < HCS_N_PORTS (ehci->hcs_params); i++) {
-               temp = dbg_port_buf (scratch, sizeof scratch, label, i + 1,
-                               readl (&ehci->regs->port_status [i]));
+       for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
+               temp = dbg_port_buf (scratch, sizeof scratch, label, i,
+                               readl (&ehci->regs->port_status [i - 1]));
                temp = scnprintf (next, size, fmt, temp, scratch);
                size -= temp;
                next += temp;
+               if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
+                       temp = scnprintf (next, size,
+                                       "    debug control %08x\n",
+                                       readl (&ehci->debug->control));
+                       size -= temp;
+                       next += temp;
+               }
        }
 
        if (ehci->reclaim) {
index bc69bd7acebe6b4849ea7797bb992348816b3c29..35248a37b7174ad807110fa74eef1382fe4c4f80 100644 (file)
@@ -304,30 +304,31 @@ static void ehci_watchdog (unsigned long param)
  */
 static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
 {
+       struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
+
+       /* always say Linux will own the hardware */
+       pci_write_config_byte(pdev, where + 3, 1);
+
+       /* maybe wait a while for BIOS to respond */
        if (cap & (1 << 16)) {
                int msec = 5000;
-               struct pci_dev *pdev =
-                               to_pci_dev(ehci_to_hcd(ehci)->self.controller);
 
-               /* request handoff to OS */
-               cap |= 1 << 24;
-               pci_write_config_dword(pdev, where, cap);
-
-               /* and wait a while for it to happen */
                do {
                        msleep(10);
                        msec -= 10;
                        pci_read_config_dword(pdev, where, &cap);
                } while ((cap & (1 << 16)) && msec);
                if (cap & (1 << 16)) {
-                       ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n",
+                       ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n",
                                where, cap);
                        // some BIOS versions seem buggy...
                        // return 1;
                        ehci_warn (ehci, "continuing after BIOS bug...\n");
-                       return 0;
-               } 
-               ehci_dbg (ehci, "BIOS handoff succeeded\n");
+                       /* disable all SMIs, and clear "BIOS owns" flag */
+                       pci_write_config_dword(pdev, where + 4, 0);
+                       pci_write_config_byte(pdev, where + 2, 0);
+               } else
+                       ehci_dbg(ehci, "BIOS handoff succeeded\n");
        }
        return 0;
 }
@@ -492,8 +493,6 @@ static int ehci_start (struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        u32                     temp;
-       struct usb_device       *udev;
-       struct usb_bus          *bus;
        int                     retval;
        u32                     hcc_params;
        u8                      sbrn = 0;
@@ -588,8 +587,8 @@ static int ehci_start (struct usb_hcd *hcd)
                writel (0, &ehci->regs->segment);
 #if 0
 // this is deeply broken on almost all architectures
-               if (!pci_set_dma_mask (to_pci_dev(hcd->self.controller), 0xffffffffffffffffULL))
-                       ehci_info (ehci, "enabled 64bit PCI DMA\n");
+               if (!dma_set_mask (hcd->self.controller, DMA_64BIT_MASK))
+                       ehci_info (ehci, "enabled 64bit DMA\n");
 #endif
        }
 
@@ -631,17 +630,6 @@ static int ehci_start (struct usb_hcd *hcd)
 
        /* set async sleep time = 10 us ... ? */
 
-       /* wire up the root hub */
-       bus = hcd_to_bus (hcd);
-       udev = first ? usb_alloc_dev (NULL, bus, 0) : bus->root_hub;
-       if (!udev) {
-done2:
-               ehci_mem_cleanup (ehci);
-               return -ENOMEM;
-       }
-       udev->speed = USB_SPEED_HIGH;
-       udev->state = first ? USB_STATE_ATTACHED : USB_STATE_CONFIGURED;
-
        /*
         * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
         * are explicitly handed to companion controller(s), so no TT is
@@ -664,24 +652,6 @@ done2:
                first ? "initialized" : "restarted",
                temp >> 8, temp & 0xff, DRIVER_VERSION);
 
-       /*
-        * From here on, khubd concurrently accesses the root
-        * hub; drivers will be talking to enumerated devices.
-        * (On restart paths, khubd already knows about the root
-        * hub and could find work as soon as we wrote FLAG_CF.)
-        *
-        * Before this point the HC was idle/ready.  After, khubd
-        * and device drivers may start it running.
-        */
-       if (first && usb_hcd_register_root_hub (udev, hcd) != 0) {
-               if (hcd->state == HC_STATE_RUNNING)
-                       ehci_quiesce (ehci);
-               ehci_reset (ehci);
-               usb_put_dev (udev); 
-               retval = -ENODEV;
-               goto done2;
-       }
-
        writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
 
        if (first)
index d7b4f7939ded4d16989478ca58fa3edc573fb728..36cc1f2218d55d203434aafb0698773291b48e4b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001-2002 by David Brownell
+ * Copyright (C) 2001-2004 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
index 7df9b9af54f60205b09a6e490db182c33ef922ec..45d89a7083b13f4bfd30b319f438c2b996948260 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001-2002 by David Brownell
+ * Copyright (C) 2001-2004 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
index 2fa1ffee5ff3bfea6428d4fb488dff8e1ab32fec..c2104cad4033ec58f2ec650c78b58b1cebd44934 100644 (file)
@@ -637,9 +637,8 @@ iso_stream_alloc (int mem_flags)
 {
        struct ehci_iso_stream *stream;
 
-       stream = kmalloc(sizeof *stream, mem_flags);
+       stream = kcalloc(1, sizeof *stream, mem_flags);
        if (likely (stream != NULL)) {
-               memset (stream, 0, sizeof(*stream));
                INIT_LIST_HEAD(&stream->td_list);
                INIT_LIST_HEAD(&stream->free_list);
                stream->next_uframe = -1;
@@ -894,7 +893,7 @@ itd_sched_init (
                trans |= length << 16;
                uframe->transaction = cpu_to_le32 (trans);
 
-               /* might need to cross a buffer page within a td */
+               /* might need to cross a buffer page within a uframe */
                uframe->bufp = (buf & ~(u64)0x0fff);
                buf += length;
                if (unlikely ((uframe->bufp != (buf & ~(u64)0x0fff))))
@@ -1194,6 +1193,7 @@ itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd)
 {
        int i;
 
+       /* it's been recently zeroed */
        itd->hw_next = EHCI_LIST_END;
        itd->hw_bufp [0] = stream->buf0;
        itd->hw_bufp [1] = stream->buf1;
@@ -1210,8 +1210,7 @@ itd_patch (
        struct ehci_itd         *itd,
        struct ehci_iso_sched   *iso_sched,
        unsigned                index,
-       u16                     uframe,
-       int                     first
+       u16                     uframe
 )
 {
        struct ehci_iso_packet  *uf = &iso_sched->packet [index];
@@ -1228,7 +1227,7 @@ itd_patch (
        itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(uf->bufp >> 32));
 
        /* iso_frame_desc[].offset must be strictly increasing */
-       if (unlikely (!first && uf->cross)) {
+       if (unlikely (uf->cross)) {
                u64     bufp = uf->bufp + 4096;
                itd->pg = ++pg;
                itd->hw_bufp [pg] |= cpu_to_le32 (bufp & ~(u32)0);
@@ -1257,7 +1256,7 @@ itd_link_urb (
        struct ehci_iso_stream  *stream
 )
 {
-       int                     packet, first = 1;
+       int                     packet;
        unsigned                next_uframe, uframe, frame;
        struct ehci_iso_sched   *iso_sched = urb->hcpriv;
        struct ehci_itd         *itd;
@@ -1290,7 +1289,6 @@ itd_link_urb (
                        list_move_tail (&itd->itd_list, &stream->td_list);
                        itd->stream = iso_stream_get (stream);
                        itd->urb = usb_get_urb (urb);
-                       first = 1;
                        itd_init (stream, itd);
                }
 
@@ -1298,8 +1296,7 @@ itd_link_urb (
                frame = next_uframe >> 3;
 
                itd->usecs [uframe] = stream->usecs;
-               itd_patch (itd, iso_sched, packet, uframe, first);
-               first = 0;
+               itd_patch (itd, iso_sched, packet, uframe);
 
                next_uframe += stream->interval;
                stream->depth += stream->interval;
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
new file mode 100644 (file)
index 0000000..ff0a168
--- /dev/null
@@ -0,0 +1,1875 @@
+/*
+ * ISP116x HCD (Host Controller Driver) for USB.
+ *
+ * Derived from the SL811 HCD, rewritten for ISP116x.
+ * Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee>
+ *
+ * Portions:
+ * Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
+ * Copyright (C) 2004 David Brownell
+ *
+ * Periodic scheduling is based on Roman's OHCI code
+ * Copyright (C) 1999 Roman Weissgaerber
+ *
+ */
+
+/*
+ * The driver basically works. A number of people have used it with a range
+ * of devices.
+ *
+ *The driver passes all usbtests 1-14.
+ *
+ * Suspending/resuming of root hub via sysfs works. Remote wakeup works too.
+ * And suspending/resuming of platform device works too. Suspend/resume
+ * via HCD operations vector is not implemented.
+ *
+ * Iso transfer support is not implemented. Adding this would include
+ * implementing recovery from the failure to service the processed ITL
+ * fifo ram in time, which will involve chip reset.
+ *
+ * TODO:
+ + More testing of suspend/resume.
+*/
+
+/*
+  ISP116x chips require certain delays between accesses to its
+  registers. The following timing options exist.
+
+  1. Configure your memory controller (the best)
+  2. Implement platform-specific delay function possibly
+  combined with configuring the memory controller; see
+  include/linux/usb-isp116x.h for more info. Some broken
+  memory controllers line LH7A400 SMC need this. Also,
+  uncomment for that to work the following
+  USE_PLATFORM_DELAY macro.
+  3. Use ndelay (easiest, poorest). For that, uncomment
+  the following USE_NDELAY macro.
+*/
+#define USE_PLATFORM_DELAY
+//#define USE_NDELAY
+
+//#define DEBUG
+//#define VERBOSE
+/* Transfer descriptors. See dump_ptd() for printout format  */
+//#define PTD_TRACE
+/* enqueuing/finishing log of urbs */
+//#define URB_TRACE
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.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/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/usb_isp116x.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+
+#ifndef DEBUG
+#      define  STUB_DEBUG_FILE
+#endif
+
+#include "../core/hcd.h"
+#include "isp116x.h"
+
+#define DRIVER_VERSION "08 Apr 2005"
+#define DRIVER_DESC    "ISP116x USB Host Controller Driver"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+static const char hcd_name[] = "isp116x-hcd";
+
+/*-----------------------------------------------------------------*/
+
+/*
+  Write len bytes to fifo, pad till 32-bit boundary
+ */
+static void write_ptddata_to_fifo(struct isp116x *isp116x, void *buf, int len)
+{
+       u8 *dp = (u8 *) buf;
+       u16 *dp2 = (u16 *) buf;
+       u16 w;
+       int quot = len % 4;
+
+       if ((unsigned long)dp2 & 1) {
+               /* not aligned */
+               for (; len > 1; len -= 2) {
+                       w = *dp++;
+                       w |= *dp++ << 8;
+                       isp116x_raw_write_data16(isp116x, w);
+               }
+               if (len)
+                       isp116x_write_data16(isp116x, (u16) * dp);
+       } else {
+               /* aligned */
+               for (; len > 1; len -= 2)
+                       isp116x_raw_write_data16(isp116x, *dp2++);
+               if (len)
+                       isp116x_write_data16(isp116x, 0xff & *((u8 *) dp2));
+       }
+       if (quot == 1 || quot == 2)
+               isp116x_raw_write_data16(isp116x, 0);
+}
+
+/*
+  Read len bytes from fifo and then read till 32-bit boundary.
+ */
+static void read_ptddata_from_fifo(struct isp116x *isp116x, void *buf, int len)
+{
+       u8 *dp = (u8 *) buf;
+       u16 *dp2 = (u16 *) buf;
+       u16 w;
+       int quot = len % 4;
+
+       if ((unsigned long)dp2 & 1) {
+               /* not aligned */
+               for (; len > 1; len -= 2) {
+                       w = isp116x_raw_read_data16(isp116x);
+                       *dp++ = w & 0xff;
+                       *dp++ = (w >> 8) & 0xff;
+               }
+               if (len)
+                       *dp = 0xff & isp116x_read_data16(isp116x);
+       } else {
+               /* aligned */
+               for (; len > 1; len -= 2)
+                       *dp2++ = isp116x_raw_read_data16(isp116x);
+               if (len)
+                       *(u8 *) dp2 = 0xff & isp116x_read_data16(isp116x);
+       }
+       if (quot == 1 || quot == 2)
+               isp116x_raw_read_data16(isp116x);
+}
+
+/*
+  Write ptd's and data for scheduled transfers into
+  the fifo ram. Fifo must be empty and ready.
+*/
+static void pack_fifo(struct isp116x *isp116x)
+{
+       struct isp116x_ep *ep;
+       struct ptd *ptd;
+       int buflen = isp116x->atl_last_dir == PTD_DIR_IN
+           ? isp116x->atl_bufshrt : isp116x->atl_buflen;
+       int ptd_count = 0;
+
+       isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
+       isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
+       isp116x_write_addr(isp116x, HCATLPORT | ISP116x_WRITE_OFFSET);
+       for (ep = isp116x->atl_active; ep; ep = ep->active) {
+               ++ptd_count;
+               ptd = &ep->ptd;
+               dump_ptd(ptd);
+               dump_ptd_out_data(ptd, ep->data);
+               isp116x_write_data16(isp116x, ptd->count);
+               isp116x_write_data16(isp116x, ptd->mps);
+               isp116x_write_data16(isp116x, ptd->len);
+               isp116x_write_data16(isp116x, ptd->faddr);
+               buflen -= sizeof(struct ptd);
+               /* Skip writing data for last IN PTD */
+               if (ep->active || (isp116x->atl_last_dir != PTD_DIR_IN)) {
+                       write_ptddata_to_fifo(isp116x, ep->data, ep->length);
+                       buflen -= ALIGN(ep->length, 4);
+               }
+       }
+       BUG_ON(buflen);
+}
+
+/*
+  Read the processed ptd's and data from fifo ram back to
+  URBs' buffers. Fifo must be full and done
+*/
+static void unpack_fifo(struct isp116x *isp116x)
+{
+       struct isp116x_ep *ep;
+       struct ptd *ptd;
+       int buflen = isp116x->atl_last_dir == PTD_DIR_IN
+           ? isp116x->atl_buflen : isp116x->atl_bufshrt;
+
+       isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
+       isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
+       isp116x_write_addr(isp116x, HCATLPORT);
+       for (ep = isp116x->atl_active; ep; ep = ep->active) {
+               ptd = &ep->ptd;
+               ptd->count = isp116x_read_data16(isp116x);
+               ptd->mps = isp116x_read_data16(isp116x);
+               ptd->len = isp116x_read_data16(isp116x);
+               ptd->faddr = isp116x_read_data16(isp116x);
+               buflen -= sizeof(struct ptd);
+               /* Skip reading data for last Setup or Out PTD */
+               if (ep->active || (isp116x->atl_last_dir == PTD_DIR_IN)) {
+                       read_ptddata_from_fifo(isp116x, ep->data, ep->length);
+                       buflen -= ALIGN(ep->length, 4);
+               }
+               dump_ptd(ptd);
+               dump_ptd_in_data(ptd, ep->data);
+       }
+       BUG_ON(buflen);
+}
+
+/*---------------------------------------------------------------*/
+
+/*
+  Set up PTD's.
+*/
+static void preproc_atl_queue(struct isp116x *isp116x)
+{
+       struct isp116x_ep *ep;
+       struct urb *urb;
+       struct ptd *ptd;
+       u16 toggle, dir, len;
+
+       for (ep = isp116x->atl_active; ep; ep = ep->active) {
+               BUG_ON(list_empty(&ep->hep->urb_list));
+               urb = container_of(ep->hep->urb_list.next,
+                                  struct urb, urb_list);
+               ptd = &ep->ptd;
+               len = ep->length;
+               spin_lock(&urb->lock);
+               ep->data = (unsigned char *)urb->transfer_buffer
+                   + urb->actual_length;
+
+               switch (ep->nextpid) {
+               case USB_PID_IN:
+                       toggle = usb_gettoggle(urb->dev, ep->epnum, 0);
+                       dir = PTD_DIR_IN;
+                       break;
+               case USB_PID_OUT:
+                       toggle = usb_gettoggle(urb->dev, ep->epnum, 1);
+                       dir = PTD_DIR_OUT;
+                       break;
+               case USB_PID_SETUP:
+                       toggle = 0;
+                       dir = PTD_DIR_SETUP;
+                       len = sizeof(struct usb_ctrlrequest);
+                       ep->data = urb->setup_packet;
+                       break;
+               case USB_PID_ACK:
+                       toggle = 1;
+                       len = 0;
+                       dir = (urb->transfer_buffer_length
+                              && usb_pipein(urb->pipe))
+                           ? PTD_DIR_OUT : PTD_DIR_IN;
+                       break;
+               default:
+                       /* To please gcc */
+                       toggle = dir = 0;
+                       ERR("%s %d: ep->nextpid %d\n", __func__, __LINE__,
+                           ep->nextpid);
+                       BUG_ON(1);
+               }
+
+               ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK | PTD_TOGGLE(toggle);
+               ptd->mps = PTD_MPS(ep->maxpacket)
+                   | PTD_SPD(urb->dev->speed == USB_SPEED_LOW)
+                   | PTD_EP(ep->epnum);
+               ptd->len = PTD_LEN(len) | PTD_DIR(dir);
+               ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe));
+               spin_unlock(&urb->lock);
+               if (!ep->active) {
+                       ptd->mps |= PTD_LAST_MSK;
+                       isp116x->atl_last_dir = dir;
+               }
+               isp116x->atl_bufshrt = sizeof(struct ptd) + isp116x->atl_buflen;
+               isp116x->atl_buflen = isp116x->atl_bufshrt + ALIGN(len, 4);
+       }
+}
+
+/*
+  Analyze transfer results, handle partial transfers and errors
+*/
+static void postproc_atl_queue(struct isp116x *isp116x)
+{
+       struct isp116x_ep *ep;
+       struct urb *urb;
+       struct usb_device *udev;
+       struct ptd *ptd;
+       int short_not_ok;
+       u8 cc;
+
+       for (ep = isp116x->atl_active; ep; ep = ep->active) {
+               BUG_ON(list_empty(&ep->hep->urb_list));
+               urb =
+                   container_of(ep->hep->urb_list.next, struct urb, urb_list);
+               udev = urb->dev;
+               ptd = &ep->ptd;
+               cc = PTD_GET_CC(ptd);
+
+               spin_lock(&urb->lock);
+               short_not_ok = 1;
+
+               /* Data underrun is special. For allowed underrun
+                  we clear the error and continue as normal. For
+                  forbidden underrun we finish the DATA stage
+                  immediately while for control transfer,
+                  we do a STATUS stage. */
+               if (cc == TD_DATAUNDERRUN) {
+                       if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) {
+                               DBG("Allowed data underrun\n");
+                               cc = TD_CC_NOERROR;
+                               short_not_ok = 0;
+                       } else {
+                               ep->error_count = 1;
+                               if (usb_pipecontrol(urb->pipe))
+                                       ep->nextpid = USB_PID_ACK;
+                               else
+                                       usb_settoggle(udev, ep->epnum,
+                                                     ep->nextpid ==
+                                                     USB_PID_OUT,
+                                                     PTD_GET_TOGGLE(ptd) ^ 1);
+                               urb->status = cc_to_error[TD_DATAUNDERRUN];
+                               spin_unlock(&urb->lock);
+                               continue;
+                       }
+               }
+               /* Keep underrun error through the STATUS stage */
+               if (urb->status == cc_to_error[TD_DATAUNDERRUN])
+                       cc = TD_DATAUNDERRUN;
+
+               if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED
+                   && (++ep->error_count >= 3 || cc == TD_CC_STALL
+                       || cc == TD_DATAOVERRUN)) {
+                       if (urb->status == -EINPROGRESS)
+                               urb->status = cc_to_error[cc];
+                       if (ep->nextpid == USB_PID_ACK)
+                               ep->nextpid = 0;
+                       spin_unlock(&urb->lock);
+                       continue;
+               }
+               /* According to usb spec, zero-length Int transfer signals
+                  finishing of the urb. Hey, does this apply only
+                  for IN endpoints? */
+               if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) {
+                       if (urb->status == -EINPROGRESS)
+                               urb->status = 0;
+                       spin_unlock(&urb->lock);
+                       continue;
+               }
+
+               /* Relax after previously failed, but later succeeded
+                  or correctly NAK'ed retransmission attempt */
+               if (ep->error_count
+                   && (cc == TD_CC_NOERROR || cc == TD_NOTACCESSED))
+                       ep->error_count = 0;
+
+               /* Take into account idiosyncracies of the isp116x chip
+                  regarding toggle bit for failed transfers */
+               if (ep->nextpid == USB_PID_OUT)
+                       usb_settoggle(udev, ep->epnum, 1, PTD_GET_TOGGLE(ptd)
+                                     ^ (ep->error_count > 0));
+               else if (ep->nextpid == USB_PID_IN)
+                       usb_settoggle(udev, ep->epnum, 0, PTD_GET_TOGGLE(ptd)
+                                     ^ (ep->error_count > 0));
+
+               switch (ep->nextpid) {
+               case USB_PID_IN:
+               case USB_PID_OUT:
+                       urb->actual_length += PTD_GET_COUNT(ptd);
+                       if (PTD_GET_ACTIVE(ptd)
+                           || (cc != TD_CC_NOERROR && cc < 0x0E))
+                               break;
+                       if (urb->transfer_buffer_length != urb->actual_length) {
+                               if (short_not_ok)
+                                       break;
+                       } else {
+                               if (urb->transfer_flags & URB_ZERO_PACKET
+                                   && ep->nextpid == USB_PID_OUT
+                                   && !(PTD_GET_COUNT(ptd) % ep->maxpacket)) {
+                                       DBG("Zero packet requested\n");
+                                       break;
+                               }
+                       }
+                       /* All data for this URB is transferred, let's finish */
+                       if (usb_pipecontrol(urb->pipe))
+                               ep->nextpid = USB_PID_ACK;
+                       else if (urb->status == -EINPROGRESS)
+                               urb->status = 0;
+                       break;
+               case USB_PID_SETUP:
+                       if (PTD_GET_ACTIVE(ptd)
+                           || (cc != TD_CC_NOERROR && cc < 0x0E))
+                               break;
+                       if (urb->transfer_buffer_length == urb->actual_length)
+                               ep->nextpid = USB_PID_ACK;
+                       else if (usb_pipeout(urb->pipe)) {
+                               usb_settoggle(udev, 0, 1, 1);
+                               ep->nextpid = USB_PID_OUT;
+                       } else {
+                               usb_settoggle(udev, 0, 0, 1);
+                               ep->nextpid = USB_PID_IN;
+                       }
+                       break;
+               case USB_PID_ACK:
+                       if (PTD_GET_ACTIVE(ptd)
+                           || (cc != TD_CC_NOERROR && cc < 0x0E))
+                               break;
+                       if (urb->status == -EINPROGRESS)
+                               urb->status = 0;
+                       ep->nextpid = 0;
+                       break;
+               default:
+                       BUG_ON(1);
+               }
+               spin_unlock(&urb->lock);
+       }
+}
+
+/*
+  Take done or failed requests out of schedule. Give back
+  processed urbs.
+*/
+static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
+                          struct urb *urb, struct pt_regs *regs)
+__releases(isp116x->lock) __acquires(isp116x->lock)
+{
+       unsigned i;
+
+       urb->hcpriv = NULL;
+       ep->error_count = 0;
+
+       if (usb_pipecontrol(urb->pipe))
+               ep->nextpid = USB_PID_SETUP;
+
+       urb_dbg(urb, "Finish");
+
+       spin_unlock(&isp116x->lock);
+       usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, regs);
+       spin_lock(&isp116x->lock);
+
+       /* take idle endpoints out of the schedule */
+       if (!list_empty(&ep->hep->urb_list))
+               return;
+
+       /* async deschedule */
+       if (!list_empty(&ep->schedule)) {
+               list_del_init(&ep->schedule);
+               return;
+       }
+
+       /* periodic deschedule */
+       DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+       for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+               struct isp116x_ep *temp;
+               struct isp116x_ep **prev = &isp116x->periodic[i];
+
+               while (*prev && ((temp = *prev) != ep))
+                       prev = &temp->next;
+               if (*prev)
+                       *prev = ep->next;
+               isp116x->load[i] -= ep->load;
+       }
+       ep->branch = PERIODIC_SIZE;
+       isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
+           ep->load / ep->period;
+
+       /* switch irq type? */
+       if (!--isp116x->periodic_count) {
+               isp116x->irqenb &= ~HCuPINT_SOF;
+               isp116x->irqenb |= HCuPINT_ATL;
+       }
+}
+
+/*
+  Scan transfer lists, schedule transfers, send data off
+  to chip.
+ */
+static void start_atl_transfers(struct isp116x *isp116x)
+{
+       struct isp116x_ep *last_ep = NULL, *ep;
+       struct urb *urb;
+       u16 load = 0;
+       int len, index, speed, byte_time;
+
+       if (atomic_read(&isp116x->atl_finishing))
+               return;
+
+       if (!HC_IS_RUNNING(isp116x_to_hcd(isp116x)->state))
+               return;
+
+       /* FIFO not empty? */
+       if (isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_FULL)
+               return;
+
+       isp116x->atl_active = NULL;
+       isp116x->atl_buflen = isp116x->atl_bufshrt = 0;
+
+       /* Schedule int transfers */
+       if (isp116x->periodic_count) {
+               isp116x->fmindex = index =
+                   (isp116x->fmindex + 1) & (PERIODIC_SIZE - 1);
+               if ((load = isp116x->load[index])) {
+                       /* Bring all int transfers for this frame
+                          into the active queue */
+                       isp116x->atl_active = last_ep =
+                           isp116x->periodic[index];
+                       while (last_ep->next)
+                               last_ep = (last_ep->active = last_ep->next);
+                       last_ep->active = NULL;
+               }
+       }
+
+       /* Schedule control/bulk transfers */
+       list_for_each_entry(ep, &isp116x->async, schedule) {
+               urb = container_of(ep->hep->urb_list.next,
+                                  struct urb, urb_list);
+               speed = urb->dev->speed;
+               byte_time = speed == USB_SPEED_LOW
+                   ? BYTE_TIME_LOWSPEED : BYTE_TIME_FULLSPEED;
+
+               if (ep->nextpid == USB_PID_SETUP) {
+                       len = sizeof(struct usb_ctrlrequest);
+               } else if (ep->nextpid == USB_PID_ACK) {
+                       len = 0;
+               } else {
+                       /* Find current free length ... */
+                       len = (MAX_LOAD_LIMIT - load) / byte_time;
+
+                       /* ... then limit it to configured max size ... */
+                       len = min(len, speed == USB_SPEED_LOW ?
+                                 MAX_TRANSFER_SIZE_LOWSPEED :
+                                 MAX_TRANSFER_SIZE_FULLSPEED);
+
+                       /* ... and finally cut to the multiple of MaxPacketSize,
+                          or to the real length if there's enough room. */
+                       if (len <
+                           (urb->transfer_buffer_length -
+                            urb->actual_length)) {
+                               len -= len % ep->maxpacket;
+                               if (!len)
+                                       continue;
+                       } else
+                               len = urb->transfer_buffer_length -
+                                   urb->actual_length;
+                       BUG_ON(len < 0);
+               }
+
+               load += len * byte_time;
+               if (load > MAX_LOAD_LIMIT)
+                       break;
+
+               ep->active = NULL;
+               ep->length = len;
+               if (last_ep)
+                       last_ep->active = ep;
+               else
+                       isp116x->atl_active = ep;
+               last_ep = ep;
+       }
+
+       /* Avoid starving of endpoints */
+       if ((&isp116x->async)->next != (&isp116x->async)->prev)
+               list_move(&isp116x->async, (&isp116x->async)->next);
+
+       if (isp116x->atl_active) {
+               preproc_atl_queue(isp116x);
+               pack_fifo(isp116x);
+       }
+}
+
+/*
+  Finish the processed transfers
+*/
+static void finish_atl_transfers(struct isp116x *isp116x, struct pt_regs *regs)
+{
+       struct isp116x_ep *ep;
+       struct urb *urb;
+
+       if (!isp116x->atl_active)
+               return;
+       /* Fifo not ready? */
+       if (!(isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_DONE))
+               return;
+
+       atomic_inc(&isp116x->atl_finishing);
+       unpack_fifo(isp116x);
+       postproc_atl_queue(isp116x);
+       for (ep = isp116x->atl_active; ep; ep = ep->active) {
+               urb =
+                   container_of(ep->hep->urb_list.next, struct urb, urb_list);
+               /* USB_PID_ACK check here avoids finishing of
+                  control transfers, for which TD_DATAUNDERRUN
+                  occured, while URB_SHORT_NOT_OK was set */
+               if (urb && urb->status != -EINPROGRESS
+                   && ep->nextpid != USB_PID_ACK)
+                       finish_request(isp116x, ep, urb, regs);
+       }
+       atomic_dec(&isp116x->atl_finishing);
+}
+
+static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
+{
+       struct isp116x *isp116x = hcd_to_isp116x(hcd);
+       u16 irqstat;
+       irqreturn_t ret = IRQ_NONE;
+
+       spin_lock(&isp116x->lock);
+       isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+       irqstat = isp116x_read_reg16(isp116x, HCuPINT);
+       isp116x_write_reg16(isp116x, HCuPINT, irqstat);
+
+       if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) {
+               ret = IRQ_HANDLED;
+               finish_atl_transfers(isp116x, regs);
+       }
+
+       if (irqstat & HCuPINT_OPR) {
+               u32 intstat = isp116x_read_reg32(isp116x, HCINTSTAT);
+               isp116x_write_reg32(isp116x, HCINTSTAT, intstat);
+               if (intstat & HCINT_UE) {
+                       ERR("Unrecoverable error\n");
+                       /* What should we do here? Reset?  */
+               }
+               if (intstat & HCINT_RHSC) {
+                       isp116x->rhstatus =
+                           isp116x_read_reg32(isp116x, HCRHSTATUS);
+                       isp116x->rhport[0] =
+                           isp116x_read_reg32(isp116x, HCRHPORT1);
+                       isp116x->rhport[1] =
+                           isp116x_read_reg32(isp116x, HCRHPORT2);
+               }
+               if (intstat & HCINT_RD) {
+                       DBG("---- remote wakeup\n");
+                       schedule_work(&isp116x->rh_resume);
+                       ret = IRQ_HANDLED;
+               }
+               irqstat &= ~HCuPINT_OPR;
+               ret = IRQ_HANDLED;
+       }
+
+       if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) {
+               start_atl_transfers(isp116x);
+       }
+
+       isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb);
+       spin_unlock(&isp116x->lock);
+       return ret;
+}
+
+/*-----------------------------------------------------------------*/
+
+/* usb 1.1 says max 90% of a frame is available for periodic transfers.
+ * this driver doesn't promise that much since it's got to handle an
+ * IRQ per packet; irq handling latencies also use up that time.
+ */
+
+/* out of 1000 us */
+#define        MAX_PERIODIC_LOAD       600
+static int balance(struct isp116x *isp116x, u16 period, u16 load)
+{
+       int i, branch = -ENOSPC;
+
+       /* search for the least loaded schedule branch of that period
+          which has enough bandwidth left unreserved. */
+       for (i = 0; i < period; i++) {
+               if (branch < 0 || isp116x->load[branch] > isp116x->load[i]) {
+                       int j;
+
+                       for (j = i; j < PERIODIC_SIZE; j += period) {
+                               if ((isp116x->load[j] + load)
+                                   > MAX_PERIODIC_LOAD)
+                                       break;
+                       }
+                       if (j < PERIODIC_SIZE)
+                               continue;
+                       branch = i;
+               }
+       }
+       return branch;
+}
+
+/* NB! ALL the code above this point runs with isp116x->lock
+   held, irqs off
+*/
+
+/*-----------------------------------------------------------------*/
+
+static int isp116x_urb_enqueue(struct usb_hcd *hcd,
+                              struct usb_host_endpoint *hep, struct urb *urb,
+                              int mem_flags)
+{
+       struct isp116x *isp116x = hcd_to_isp116x(hcd);
+       struct usb_device *udev = urb->dev;
+       unsigned int pipe = urb->pipe;
+       int is_out = !usb_pipein(pipe);
+       int type = usb_pipetype(pipe);
+       int epnum = usb_pipeendpoint(pipe);
+       struct isp116x_ep *ep = NULL;
+       unsigned long flags;
+       int i;
+       int ret = 0;
+
+       urb_dbg(urb, "Enqueue");
+
+       if (type == PIPE_ISOCHRONOUS) {
+               ERR("Isochronous transfers not supported\n");
+               urb_dbg(urb, "Refused to enqueue");
+               return -ENXIO;
+       }
+       /* avoid all allocations within spinlocks: request or endpoint */
+       if (!hep->hcpriv) {
+               ep = kcalloc(1, sizeof *ep, (__force unsigned)mem_flags);
+               if (!ep)
+                       return -ENOMEM;
+       }
+
+       spin_lock_irqsave(&isp116x->lock, flags);
+       if (!HC_IS_RUNNING(hcd->state)) {
+               ret = -ENODEV;
+               goto fail;
+       }
+
+       if (hep->hcpriv)
+               ep = hep->hcpriv;
+       else {
+               INIT_LIST_HEAD(&ep->schedule);
+               ep->udev = usb_get_dev(udev);
+               ep->epnum = epnum;
+               ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
+               usb_settoggle(udev, epnum, is_out, 0);
+
+               if (type == PIPE_CONTROL) {
+                       ep->nextpid = USB_PID_SETUP;
+               } else if (is_out) {
+                       ep->nextpid = USB_PID_OUT;
+               } else {
+                       ep->nextpid = USB_PID_IN;
+               }
+
+               if (urb->interval) {
+                       /*
+                          With INT URBs submitted, the driver works with SOF
+                          interrupt enabled and ATL interrupt disabled. After
+                          the PTDs are written to fifo ram, the chip starts
+                          fifo processing and usb transfers after the next
+                          SOF and continues until the transfers are finished
+                          (succeeded or failed) or the frame ends. Therefore,
+                          the transfers occur only in every second frame,
+                          while fifo reading/writing and data processing
+                          occur in every other second frame. */
+                       if (urb->interval < 2)
+                               urb->interval = 2;
+                       if (urb->interval > 2 * PERIODIC_SIZE)
+                               urb->interval = 2 * PERIODIC_SIZE;
+                       ep->period = urb->interval >> 1;
+                       ep->branch = PERIODIC_SIZE;
+                       ep->load = usb_calc_bus_time(udev->speed,
+                                                    !is_out,
+                                                    (type == PIPE_ISOCHRONOUS),
+                                                    usb_maxpacket(udev, pipe,
+                                                                  is_out)) /
+                           1000;
+               }
+               hep->hcpriv = ep;
+               ep->hep = hep;
+       }
+
+       /* maybe put endpoint into schedule */
+       switch (type) {
+       case PIPE_CONTROL:
+       case PIPE_BULK:
+               if (list_empty(&ep->schedule))
+                       list_add_tail(&ep->schedule, &isp116x->async);
+               break;
+       case PIPE_INTERRUPT:
+               urb->interval = ep->period;
+               ep->length = min((int)ep->maxpacket,
+                                urb->transfer_buffer_length);
+
+               /* urb submitted for already existing endpoint */
+               if (ep->branch < PERIODIC_SIZE)
+                       break;
+
+               ret = ep->branch = balance(isp116x, ep->period, ep->load);
+               if (ret < 0)
+                       goto fail;
+               ret = 0;
+
+               urb->start_frame = (isp116x->fmindex & (PERIODIC_SIZE - 1))
+                   + ep->branch;
+
+               /* sort each schedule branch by period (slow before fast)
+                  to share the faster parts of the tree without needing
+                  dummy/placeholder nodes */
+               DBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+               for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+                       struct isp116x_ep **prev = &isp116x->periodic[i];
+                       struct isp116x_ep *here = *prev;
+
+                       while (here && ep != here) {
+                               if (ep->period > here->period)
+                                       break;
+                               prev = &here->next;
+                               here = *prev;
+                       }
+                       if (ep != here) {
+                               ep->next = here;
+                               *prev = ep;
+                       }
+                       isp116x->load[i] += ep->load;
+               }
+               hcd->self.bandwidth_allocated += ep->load / ep->period;
+
+               /* switch over to SOFint */
+               if (!isp116x->periodic_count++) {
+                       isp116x->irqenb &= ~HCuPINT_ATL;
+                       isp116x->irqenb |= HCuPINT_SOF;
+                       isp116x_write_reg16(isp116x, HCuPINTENB,
+                                           isp116x->irqenb);
+               }
+       }
+
+       /* in case of unlink-during-submit */
+       spin_lock(&urb->lock);
+       if (urb->status != -EINPROGRESS) {
+               spin_unlock(&urb->lock);
+               finish_request(isp116x, ep, urb, NULL);
+               ret = 0;
+               goto fail;
+       }
+       urb->hcpriv = hep;
+       spin_unlock(&urb->lock);
+       start_atl_transfers(isp116x);
+
+      fail:
+       spin_unlock_irqrestore(&isp116x->lock, flags);
+       return ret;
+}
+
+/*
+   Dequeue URBs.
+*/
+static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+       struct isp116x *isp116x = hcd_to_isp116x(hcd);
+       struct usb_host_endpoint *hep;
+       struct isp116x_ep *ep, *ep_act;
+       unsigned long flags;
+
+       spin_lock_irqsave(&isp116x->lock, flags);
+       hep = urb->hcpriv;
+       /* URB already unlinked (or never linked)? */
+       if (!hep) {
+               spin_unlock_irqrestore(&isp116x->lock, flags);
+               return 0;
+       }
+       ep = hep->hcpriv;
+       WARN_ON(hep != ep->hep);
+
+       /* In front of queue? */
+       if (ep->hep->urb_list.next == &urb->urb_list)
+               /* active? */
+               for (ep_act = isp116x->atl_active; ep_act;
+                    ep_act = ep_act->active)
+                       if (ep_act == ep) {
+                               VDBG("dequeue, urb %p active; wait for irq\n",
+                                    urb);
+                               urb = NULL;
+                               break;
+                       }
+
+       if (urb)
+               finish_request(isp116x, ep, urb, NULL);
+
+       spin_unlock_irqrestore(&isp116x->lock, flags);
+       return 0;
+}
+
+static void isp116x_endpoint_disable(struct usb_hcd *hcd,
+                                    struct usb_host_endpoint *hep)
+{
+       int i;
+       struct isp116x_ep *ep = hep->hcpriv;;
+
+       if (!ep)
+               return;
+
+       /* assume we'd just wait for the irq */
+       for (i = 0; i < 100 && !list_empty(&hep->urb_list); i++)
+               msleep(3);
+       if (!list_empty(&hep->urb_list))
+               WARN("ep %p not empty?\n", ep);
+
+       usb_put_dev(ep->udev);
+       kfree(ep);
+       hep->hcpriv = NULL;
+}
+
+static int isp116x_get_frame(struct usb_hcd *hcd)
+{
+       struct isp116x *isp116x = hcd_to_isp116x(hcd);
+       u32 fmnum;
+       unsigned long flags;
+
+       spin_lock_irqsave(&isp116x->lock, flags);
+       fmnum = isp116x_read_reg32(isp116x, HCFMNUM);
+       spin_unlock_irqrestore(&isp116x->lock, flags);
+       return (int)fmnum;
+}
+
+/*----------------------------------------------------------------*/
+
+/*
+  Adapted from ohci-hub.c. Currently we don't support autosuspend.
+*/
+static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+       struct isp116x *isp116x = hcd_to_isp116x(hcd);
+       int ports, i, changed = 0;
+
+       if (!HC_IS_RUNNING(hcd->state))
+               return -ESHUTDOWN;
+
+       ports = isp116x->rhdesca & RH_A_NDP;
+
+       /* init status */
+       if (isp116x->rhstatus & (RH_HS_LPSC | RH_HS_OCIC))
+               buf[0] = changed = 1;
+       else
+               buf[0] = 0;
+
+       for (i = 0; i < ports; i++) {
+               u32 status = isp116x->rhport[i];
+
+               if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
+                             | RH_PS_OCIC | RH_PS_PRSC)) {
+                       changed = 1;
+                       buf[0] |= 1 << (i + 1);
+                       continue;
+               }
+       }
+       return changed;
+}
+
+static void isp116x_hub_descriptor(struct isp116x *isp116x,
+                                  struct usb_hub_descriptor *desc)
+{
+       u32 reg = isp116x->rhdesca;
+
+       desc->bDescriptorType = 0x29;
+       desc->bDescLength = 9;
+       desc->bHubContrCurrent = 0;
+       desc->bNbrPorts = (u8) (reg & 0x3);
+       /* Power switching, device type, overcurrent. */
+       desc->wHubCharacteristics =
+           (__force __u16) cpu_to_le16((u16) ((reg >> 8) & 0x1f));
+       desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff);
+       /* two bitmaps:  ports removable, and legacy PortPwrCtrlMask */
+       desc->bitmap[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1;
+       desc->bitmap[1] = ~0;
+}
+
+/* Perform reset of a given port.
+   It would be great to just start the reset and let the
+   USB core to clear the reset in due time. However,
+   root hub ports should be reset for at least 50 ms, while
+   our chip stays in reset for about 10 ms. I.e., we must
+   repeatedly reset it ourself here.
+*/
+static inline void root_port_reset(struct isp116x *isp116x, unsigned port)
+{
+       u32 tmp;
+       unsigned long flags, t;
+
+       /* Root hub reset should be 50 ms, but some devices
+          want it even longer. */
+       t = jiffies + msecs_to_jiffies(100);
+
+       while (time_before(jiffies, t)) {
+               spin_lock_irqsave(&isp116x->lock, flags);
+               /* spin until any current reset finishes */
+               for (;;) {
+                       tmp = isp116x_read_reg32(isp116x, port ?
+                                                HCRHPORT2 : HCRHPORT1);
+                       if (!(tmp & RH_PS_PRS))
+                               break;
+                       udelay(500);
+               }
+               /* Don't reset a disconnected port */
+               if (!(tmp & RH_PS_CCS)) {
+                       spin_unlock_irqrestore(&isp116x->lock, flags);
+                       break;
+               }
+               /* Reset lasts 10ms (claims datasheet) */
+               isp116x_write_reg32(isp116x, port ? HCRHPORT2 :
+                                   HCRHPORT1, (RH_PS_PRS));
+               spin_unlock_irqrestore(&isp116x->lock, flags);
+               msleep(10);
+       }
+}
+
+/* Adapted from ohci-hub.c */
+static int isp116x_hub_control(struct usb_hcd *hcd,
+                              u16 typeReq,
+                              u16 wValue, u16 wIndex, char *buf, u16 wLength)
+{
+       struct isp116x *isp116x = hcd_to_isp116x(hcd);
+       int ret = 0;
+       unsigned long flags;
+       int ports = isp116x->rhdesca & RH_A_NDP;
+       u32 tmp = 0;
+
+       switch (typeReq) {
+       case ClearHubFeature:
+               DBG("ClearHubFeature: ");
+               switch (wValue) {
+               case C_HUB_OVER_CURRENT:
+                       DBG("C_HUB_OVER_CURRENT\n");
+                       spin_lock_irqsave(&isp116x->lock, flags);
+                       isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC);
+                       spin_unlock_irqrestore(&isp116x->lock, flags);
+               case C_HUB_LOCAL_POWER:
+                       DBG("C_HUB_LOCAL_POWER\n");
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case SetHubFeature:
+               DBG("SetHubFeature: ");
+               switch (wValue) {
+               case C_HUB_OVER_CURRENT:
+               case C_HUB_LOCAL_POWER:
+                       DBG("C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n");
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case GetHubDescriptor:
+               DBG("GetHubDescriptor\n");
+               isp116x_hub_descriptor(isp116x,
+                                      (struct usb_hub_descriptor *)buf);
+               break;
+       case GetHubStatus:
+               DBG("GetHubStatus\n");
+               *(__le32 *) buf = cpu_to_le32(0);
+               break;
+       case GetPortStatus:
+               DBG("GetPortStatus\n");
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               tmp = isp116x->rhport[--wIndex];
+               *(__le32 *) buf = cpu_to_le32(tmp);
+               DBG("GetPortStatus: port[%d]  %08x\n", wIndex + 1, tmp);
+               break;
+       case ClearPortFeature:
+               DBG("ClearPortFeature: ");
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+
+               switch (wValue) {
+               case USB_PORT_FEAT_ENABLE:
+                       DBG("USB_PORT_FEAT_ENABLE\n");
+                       tmp = RH_PS_CCS;
+                       break;
+               case USB_PORT_FEAT_C_ENABLE:
+                       DBG("USB_PORT_FEAT_C_ENABLE\n");
+                       tmp = RH_PS_PESC;
+                       break;
+               case USB_PORT_FEAT_SUSPEND:
+                       DBG("USB_PORT_FEAT_SUSPEND\n");
+                       tmp = RH_PS_POCI;
+                       break;
+               case USB_PORT_FEAT_C_SUSPEND:
+                       DBG("USB_PORT_FEAT_C_SUSPEND\n");
+                       tmp = RH_PS_PSSC;
+                       break;
+               case USB_PORT_FEAT_POWER:
+                       DBG("USB_PORT_FEAT_POWER\n");
+                       tmp = RH_PS_LSDA;
+                       break;
+               case USB_PORT_FEAT_C_CONNECTION:
+                       DBG("USB_PORT_FEAT_C_CONNECTION\n");
+                       tmp = RH_PS_CSC;
+                       break;
+               case USB_PORT_FEAT_C_OVER_CURRENT:
+                       DBG("USB_PORT_FEAT_C_OVER_CURRENT\n");
+                       tmp = RH_PS_OCIC;
+                       break;
+               case USB_PORT_FEAT_C_RESET:
+                       DBG("USB_PORT_FEAT_C_RESET\n");
+                       tmp = RH_PS_PRSC;
+                       break;
+               default:
+                       goto error;
+               }
+               spin_lock_irqsave(&isp116x->lock, flags);
+               isp116x_write_reg32(isp116x, wIndex
+                                   ? HCRHPORT2 : HCRHPORT1, tmp);
+               isp116x->rhport[wIndex] =
+                   isp116x_read_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1);
+               spin_unlock_irqrestore(&isp116x->lock, flags);
+               break;
+       case SetPortFeature:
+               DBG("SetPortFeature: ");
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               switch (wValue) {
+               case USB_PORT_FEAT_SUSPEND:
+                       DBG("USB_PORT_FEAT_SUSPEND\n");
+                       spin_lock_irqsave(&isp116x->lock, flags);
+                       isp116x_write_reg32(isp116x, wIndex
+                                           ? HCRHPORT2 : HCRHPORT1, RH_PS_PSS);
+                       break;
+               case USB_PORT_FEAT_POWER:
+                       DBG("USB_PORT_FEAT_POWER\n");
+                       spin_lock_irqsave(&isp116x->lock, flags);
+                       isp116x_write_reg32(isp116x, wIndex
+                                           ? HCRHPORT2 : HCRHPORT1, RH_PS_PPS);
+                       break;
+               case USB_PORT_FEAT_RESET:
+                       DBG("USB_PORT_FEAT_RESET\n");
+                       root_port_reset(isp116x, wIndex);
+                       spin_lock_irqsave(&isp116x->lock, flags);
+                       break;
+               default:
+                       goto error;
+               }
+               isp116x->rhport[wIndex] =
+                   isp116x_read_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1);
+               spin_unlock_irqrestore(&isp116x->lock, flags);
+               break;
+
+       default:
+             error:
+               /* "protocol stall" on error */
+               DBG("PROTOCOL STALL\n");
+               ret = -EPIPE;
+       }
+       return ret;
+}
+
+#ifdef CONFIG_PM
+
+static int isp116x_hub_suspend(struct usb_hcd *hcd)
+{
+       struct isp116x *isp116x = hcd_to_isp116x(hcd);
+       unsigned long flags;
+       u32 val;
+       int ret = 0;
+
+       spin_lock_irqsave(&isp116x->lock, flags);
+
+       val = isp116x_read_reg32(isp116x, HCCONTROL);
+       switch (val & HCCONTROL_HCFS) {
+       case HCCONTROL_USB_OPER:
+               hcd->state = HC_STATE_QUIESCING;
+               val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE);
+               val |= HCCONTROL_USB_SUSPEND;
+               if (hcd->remote_wakeup)
+                       val |= HCCONTROL_RWE;
+               /* Wait for usb transfers to finish */
+               mdelay(2);
+               isp116x_write_reg32(isp116x, HCCONTROL, val);
+               hcd->state = HC_STATE_SUSPENDED;
+               /* Wait for devices to suspend */
+               mdelay(5);
+       case HCCONTROL_USB_SUSPEND:
+               break;
+       case HCCONTROL_USB_RESUME:
+               isp116x_write_reg32(isp116x, HCCONTROL,
+                                   (val & ~HCCONTROL_HCFS) |
+                                   HCCONTROL_USB_RESET);
+       case HCCONTROL_USB_RESET:
+               ret = -EBUSY;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       spin_unlock_irqrestore(&isp116x->lock, flags);
+       return ret;
+}
+
+static int isp116x_hub_resume(struct usb_hcd *hcd)
+{
+       struct isp116x *isp116x = hcd_to_isp116x(hcd);
+       u32 val;
+       int ret = -EINPROGRESS;
+
+       msleep(5);
+       spin_lock_irq(&isp116x->lock);
+
+       val = isp116x_read_reg32(isp116x, HCCONTROL);
+       switch (val & HCCONTROL_HCFS) {
+       case HCCONTROL_USB_SUSPEND:
+               val &= ~HCCONTROL_HCFS;
+               val |= HCCONTROL_USB_RESUME;
+               isp116x_write_reg32(isp116x, HCCONTROL, val);
+       case HCCONTROL_USB_RESUME:
+               break;
+       case HCCONTROL_USB_OPER:
+               /* Without setting power_state here the
+                  SUSPENDED state won't be removed from
+                  sysfs/usbN/power.state as a response to remote
+                  wakeup. Maybe in the future. */
+               hcd->self.root_hub->dev.power.power_state = PMSG_ON;
+               ret = 0;
+               break;
+       default:
+               ret = -EBUSY;
+       }
+
+       if (ret != -EINPROGRESS) {
+               spin_unlock_irq(&isp116x->lock);
+               return ret;
+       }
+
+       val = isp116x->rhdesca & RH_A_NDP;
+       while (val--) {
+               u32 stat =
+                   isp116x_read_reg32(isp116x, val ? HCRHPORT2 : HCRHPORT1);
+               /* force global, not selective, resume */
+               if (!(stat & RH_PS_PSS))
+                       continue;
+               DBG("%s: Resuming port %d\n", __func__, val);
+               isp116x_write_reg32(isp116x, RH_PS_POCI, val
+                                   ? HCRHPORT2 : HCRHPORT1);
+       }
+       spin_unlock_irq(&isp116x->lock);
+
+       hcd->state = HC_STATE_RESUMING;
+       mdelay(20);
+
+       /* Go operational */
+       spin_lock_irq(&isp116x->lock);
+       val = isp116x_read_reg32(isp116x, HCCONTROL);
+       isp116x_write_reg32(isp116x, HCCONTROL,
+                           (val & ~HCCONTROL_HCFS) | HCCONTROL_USB_OPER);
+       spin_unlock_irq(&isp116x->lock);
+       /* see analogous comment above */
+       hcd->self.root_hub->dev.power.power_state = PMSG_ON;
+       hcd->state = HC_STATE_RUNNING;
+
+       return 0;
+}
+
+static void isp116x_rh_resume(void *_hcd)
+{
+       struct usb_hcd *hcd = _hcd;
+
+       usb_resume_device(hcd->self.root_hub);
+}
+
+#else
+
+#define        isp116x_hub_suspend     NULL
+#define        isp116x_hub_resume      NULL
+
+static void isp116x_rh_resume(void *_hcd)
+{
+}
+
+#endif
+
+/*-----------------------------------------------------------------*/
+
+#ifdef STUB_DEBUG_FILE
+
+static inline void create_debug_file(struct isp116x *isp116x)
+{
+}
+
+static inline void remove_debug_file(struct isp116x *isp116x)
+{
+}
+
+#else
+
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+static void dump_irq(struct seq_file *s, char *label, u16 mask)
+{
+       seq_printf(s, "%s %04x%s%s%s%s%s%s\n", label, mask,
+                  mask & HCuPINT_CLKRDY ? " clkrdy" : "",
+                  mask & HCuPINT_SUSP ? " susp" : "",
+                  mask & HCuPINT_OPR ? " opr" : "",
+                  mask & HCuPINT_AIIEOT ? " eot" : "",
+                  mask & HCuPINT_ATL ? " atl" : "",
+                  mask & HCuPINT_SOF ? " sof" : "");
+}
+
+static void dump_int(struct seq_file *s, char *label, u32 mask)
+{
+       seq_printf(s, "%s %08x%s%s%s%s%s%s%s\n", label, mask,
+                  mask & HCINT_MIE ? " MIE" : "",
+                  mask & HCINT_RHSC ? " rhsc" : "",
+                  mask & HCINT_FNO ? " fno" : "",
+                  mask & HCINT_UE ? " ue" : "",
+                  mask & HCINT_RD ? " rd" : "",
+                  mask & HCINT_SF ? " sof" : "", mask & HCINT_SO ? " so" : "");
+}
+
+static int proc_isp116x_show(struct seq_file *s, void *unused)
+{
+       struct isp116x *isp116x = s->private;
+       struct isp116x_ep *ep;
+       struct urb *urb;
+       unsigned i;
+       char *str;
+
+       seq_printf(s, "%s\n%s version %s\n",
+                  isp116x_to_hcd(isp116x)->product_desc, hcd_name,
+                  DRIVER_VERSION);
+
+       if (HC_IS_SUSPENDED(isp116x_to_hcd(isp116x)->state)) {
+               seq_printf(s, "HCD is suspended\n");
+               return 0;
+       }
+       if (!HC_IS_RUNNING(isp116x_to_hcd(isp116x)->state)) {
+               seq_printf(s, "HCD not running\n");
+               return 0;
+       }
+
+       spin_lock_irq(&isp116x->lock);
+
+       dump_irq(s, "hc_irq_enable", isp116x_read_reg16(isp116x, HCuPINTENB));
+       dump_irq(s, "hc_irq_status", isp116x_read_reg16(isp116x, HCuPINT));
+       dump_int(s, "hc_int_enable", isp116x_read_reg32(isp116x, HCINTENB));
+       dump_int(s, "hc_int_status", isp116x_read_reg32(isp116x, HCINTSTAT));
+
+       list_for_each_entry(ep, &isp116x->async, schedule) {
+
+               switch (ep->nextpid) {
+               case USB_PID_IN:
+                       str = "in";
+                       break;
+               case USB_PID_OUT:
+                       str = "out";
+                       break;
+               case USB_PID_SETUP:
+                       str = "setup";
+                       break;
+               case USB_PID_ACK:
+                       str = "status";
+                       break;
+               default:
+                       str = "?";
+                       break;
+               };
+               seq_printf(s, "%p, ep%d%s, maxpacket %d:\n", ep,
+                          ep->epnum, str, ep->maxpacket);
+               list_for_each_entry(urb, &ep->hep->urb_list, urb_list) {
+                       seq_printf(s, "  urb%p, %d/%d\n", urb,
+                                  urb->actual_length,
+                                  urb->transfer_buffer_length);
+               }
+       }
+       if (!list_empty(&isp116x->async))
+               seq_printf(s, "\n");
+
+       seq_printf(s, "periodic size= %d\n", PERIODIC_SIZE);
+
+       for (i = 0; i < PERIODIC_SIZE; i++) {
+               ep = isp116x->periodic[i];
+               if (!ep)
+                       continue;
+               seq_printf(s, "%2d [%3d]:\n", i, isp116x->load[i]);
+
+               /* DUMB: prints shared entries multiple times */
+               do {
+                       seq_printf(s, "   %d/%p (%sdev%d ep%d%s max %d)\n",
+                                  ep->period, ep,
+                                  (ep->udev->speed ==
+                                   USB_SPEED_FULL) ? "" : "ls ",
+                                  ep->udev->devnum, ep->epnum,
+                                  (ep->epnum ==
+                                   0) ? "" : ((ep->nextpid ==
+                                               USB_PID_IN) ? "in" : "out"),
+                                  ep->maxpacket);
+                       ep = ep->next;
+               } while (ep);
+       }
+       spin_unlock_irq(&isp116x->lock);
+       seq_printf(s, "\n");
+
+       return 0;
+}
+
+static int proc_isp116x_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, proc_isp116x_show, PDE(inode)->data);
+}
+
+static struct file_operations proc_ops = {
+       .open = proc_isp116x_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+/* expect just one isp116x per system */
+static const char proc_filename[] = "driver/isp116x";
+
+static void create_debug_file(struct isp116x *isp116x)
+{
+       struct proc_dir_entry *pde;
+
+       pde = create_proc_entry(proc_filename, 0, NULL);
+       if (pde == NULL)
+               return;
+
+       pde->proc_fops = &proc_ops;
+       pde->data = isp116x;
+       isp116x->pde = pde;
+}
+
+static void remove_debug_file(struct isp116x *isp116x)
+{
+       if (isp116x->pde)
+               remove_proc_entry(proc_filename, NULL);
+}
+
+#endif
+
+/*-----------------------------------------------------------------*/
+
+/*
+  Software reset - can be called from any contect.
+*/
+static int isp116x_sw_reset(struct isp116x *isp116x)
+{
+       int retries = 15;
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&isp116x->lock, flags);
+       isp116x_write_reg16(isp116x, HCSWRES, HCSWRES_MAGIC);
+       isp116x_write_reg32(isp116x, HCCMDSTAT, HCCMDSTAT_HCR);
+       while (--retries) {
+               /* It usually resets within 1 ms */
+               mdelay(1);
+               if (!(isp116x_read_reg32(isp116x, HCCMDSTAT) & HCCMDSTAT_HCR))
+                       break;
+       }
+       if (!retries) {
+               ERR("Software reset timeout\n");
+               ret = -ETIME;
+       }
+       spin_unlock_irqrestore(&isp116x->lock, flags);
+       return ret;
+}
+
+/*
+  Reset. Tries to perform platform-specific hardware
+  reset first; falls back to software reset.
+*/
+static int isp116x_reset(struct usb_hcd *hcd)
+{
+       struct isp116x *isp116x = hcd_to_isp116x(hcd);
+       unsigned long t;
+       u16 clkrdy = 0;
+       int ret = 0, timeout = 15 /* ms */ ;
+
+       if (isp116x->board && isp116x->board->reset) {
+               /* Hardware reset */
+               isp116x->board->reset(hcd->self.controller, 1);
+               msleep(10);
+               if (isp116x->board->clock)
+                       isp116x->board->clock(hcd->self.controller, 1);
+               msleep(1);
+               isp116x->board->reset(hcd->self.controller, 0);
+       } else
+               ret = isp116x_sw_reset(isp116x);
+
+       if (ret)
+               return ret;
+
+       t = jiffies + msecs_to_jiffies(timeout);
+       while (time_before_eq(jiffies, t)) {
+               msleep(4);
+               spin_lock_irq(&isp116x->lock);
+               clkrdy = isp116x_read_reg16(isp116x, HCuPINT) & HCuPINT_CLKRDY;
+               spin_unlock_irq(&isp116x->lock);
+               if (clkrdy)
+                       break;
+       }
+       if (!clkrdy) {
+               ERR("Clock not ready after 20ms\n");
+               /* After sw_reset the clock won't report to be ready, if
+                  H_WAKEUP pin is high. */
+               if (!isp116x->board || !isp116x->board->reset)
+                       ERR("The driver does not support hardware wakeup.\n");
+                       ERR("Please make sure that the H_WAKEUP pin "
+                               "is pulled low!\n");
+               ret = -ENODEV;
+       }
+       return ret;
+}
+
+static void isp116x_stop(struct usb_hcd *hcd)
+{
+       struct isp116x *isp116x = hcd_to_isp116x(hcd);
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&isp116x->lock, flags);
+       isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+
+       /* Switch off ports' power, some devices don't come up
+          after next 'insmod' without this */
+       val = isp116x_read_reg32(isp116x, HCRHDESCA);
+       val &= ~(RH_A_NPS | RH_A_PSM);
+       isp116x_write_reg32(isp116x, HCRHDESCA, val);
+       isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS);
+       spin_unlock_irqrestore(&isp116x->lock, flags);
+
+       /* Put the chip into reset state */
+       if (isp116x->board && isp116x->board->reset)
+               isp116x->board->reset(hcd->self.controller, 0);
+       else
+               isp116x_sw_reset(isp116x);
+
+       /* Stop the clock */
+       if (isp116x->board && isp116x->board->clock)
+               isp116x->board->clock(hcd->self.controller, 0);
+}
+
+/*
+  Configure the chip. The chip must be successfully reset by now.
+*/
+static int isp116x_start(struct usb_hcd *hcd)
+{
+       struct isp116x *isp116x = hcd_to_isp116x(hcd);
+       struct isp116x_platform_data *board = isp116x->board;
+       u32 val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&isp116x->lock, flags);
+
+       /* clear interrupt status and disable all interrupt sources */
+       isp116x_write_reg16(isp116x, HCuPINT, 0xff);
+       isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+
+       val = isp116x_read_reg16(isp116x, HCCHIPID);
+       if ((val & HCCHIPID_MASK) != HCCHIPID_MAGIC) {
+               ERR("Invalid chip ID %04x\n", val);
+               spin_unlock_irqrestore(&isp116x->lock, flags);
+               return -ENODEV;
+       }
+
+       isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
+       isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);
+
+       /* ----- HW conf */
+       val = HCHWCFG_INT_ENABLE | HCHWCFG_DBWIDTH(1);
+       if (board->sel15Kres)
+               val |= HCHWCFG_15KRSEL;
+       /* Remote wakeup won't work without working clock */
+       if (board->clknotstop || board->remote_wakeup_enable)
+               val |= HCHWCFG_CLKNOTSTOP;
+       if (board->oc_enable)
+               val |= HCHWCFG_ANALOG_OC;
+       if (board->int_act_high)
+               val |= HCHWCFG_INT_POL;
+       if (board->int_edge_triggered)
+               val |= HCHWCFG_INT_TRIGGER;
+       isp116x_write_reg16(isp116x, HCHWCFG, val);
+
+       /* ----- Root hub conf */
+       val = 0;
+       /* AN10003_1.pdf recommends NPS to be always 1 */
+       if (board->no_power_switching)
+               val |= RH_A_NPS;
+       if (board->power_switching_mode)
+               val |= RH_A_PSM;
+       if (board->potpg)
+               val |= (board->potpg << 24) & RH_A_POTPGT;
+       else
+               val |= (25 << 24) & RH_A_POTPGT;
+       isp116x_write_reg32(isp116x, HCRHDESCA, val);
+       isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
+
+       val = RH_B_PPCM;
+       isp116x_write_reg32(isp116x, HCRHDESCB, val);
+       isp116x->rhdescb = isp116x_read_reg32(isp116x, HCRHDESCB);
+
+       val = 0;
+       if (board->remote_wakeup_enable) {
+               hcd->can_wakeup = 1;
+               val |= RH_HS_DRWE;
+       }
+       isp116x_write_reg32(isp116x, HCRHSTATUS, val);
+       isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);
+
+       isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf);
+
+       hcd->state = HC_STATE_RUNNING;
+
+       /* Set up interrupts */
+       isp116x->intenb = HCINT_MIE | HCINT_RHSC | HCINT_UE;
+       if (board->remote_wakeup_enable)
+               isp116x->intenb |= HCINT_RD;
+       isp116x->irqenb = HCuPINT_ATL | HCuPINT_OPR;    /* | HCuPINT_SUSP; */
+       isp116x_write_reg32(isp116x, HCINTENB, isp116x->intenb);
+       isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb);
+
+       /* Go operational */
+       val = HCCONTROL_USB_OPER;
+       /* Remote wakeup connected - NOT SUPPORTED */
+       /*  if (board->remote_wakeup_connected)
+          val |= HCCONTROL_RWC;  */
+       if (board->remote_wakeup_enable)
+               val |= HCCONTROL_RWE;
+       isp116x_write_reg32(isp116x, HCCONTROL, val);
+
+       /* Disable ports to avoid race in device enumeration */
+       isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS);
+       isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS);
+
+       isp116x_show_regs(isp116x);
+       spin_unlock_irqrestore(&isp116x->lock, flags);
+       return 0;
+}
+
+/*-----------------------------------------------------------------*/
+
+static struct hc_driver isp116x_hc_driver = {
+       .description = hcd_name,
+       .product_desc = "ISP116x Host Controller",
+       .hcd_priv_size = sizeof(struct isp116x),
+
+       .irq = isp116x_irq,
+       .flags = HCD_USB11,
+
+       .reset = isp116x_reset,
+       .start = isp116x_start,
+       .stop = isp116x_stop,
+
+       .urb_enqueue = isp116x_urb_enqueue,
+       .urb_dequeue = isp116x_urb_dequeue,
+       .endpoint_disable = isp116x_endpoint_disable,
+
+       .get_frame_number = isp116x_get_frame,
+
+       .hub_status_data = isp116x_hub_status_data,
+       .hub_control = isp116x_hub_control,
+       .hub_suspend = isp116x_hub_suspend,
+       .hub_resume = isp116x_hub_resume,
+};
+
+/*----------------------------------------------------------------*/
+
+static int __init_or_module isp116x_remove(struct device *dev)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+       struct isp116x *isp116x;
+       struct platform_device *pdev;
+       struct resource *res;
+
+       if(!hcd)
+               return 0;
+       isp116x = hcd_to_isp116x(hcd);
+       pdev = container_of(dev, struct platform_device, dev);
+       remove_debug_file(isp116x);
+       usb_remove_hcd(hcd);
+
+       iounmap(isp116x->data_reg);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       release_mem_region(res->start, 2);
+       iounmap(isp116x->addr_reg);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, 2);
+
+       usb_put_hcd(hcd);
+       return 0;
+}
+
+#define resource_len(r) (((r)->end - (r)->start) + 1)
+
+static int __init isp116x_probe(struct device *dev)
+{
+       struct usb_hcd *hcd;
+       struct isp116x *isp116x;
+       struct platform_device *pdev;
+       struct resource *addr, *data;
+       void __iomem *addr_reg;
+       void __iomem *data_reg;
+       int irq;
+       int ret = 0;
+
+       pdev = container_of(dev, struct platform_device, dev);
+       if (pdev->num_resources < 3) {
+               ret = -ENODEV;
+               goto err1;
+       }
+
+       data = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       addr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       irq = platform_get_irq(pdev, 0);
+       if (!addr || !data || irq < 0) {
+               ret = -ENODEV;
+               goto err1;
+       }
+
+       if (dev->dma_mask) {
+               DBG("DMA not supported\n");
+               ret = -EINVAL;
+               goto err1;
+       }
+
+       if (!request_mem_region(addr->start, 2, hcd_name)) {
+               ret = -EBUSY;
+               goto err1;
+       }
+       addr_reg = ioremap(addr->start, resource_len(addr));
+       if (addr_reg == NULL) {
+               ret = -ENOMEM;
+               goto err2;
+       }
+       if (!request_mem_region(data->start, 2, hcd_name)) {
+               ret = -EBUSY;
+               goto err3;
+       }
+       data_reg = ioremap(data->start, resource_len(data));
+       if (data_reg == NULL) {
+               ret = -ENOMEM;
+               goto err4;
+       }
+
+       /* allocate and initialize hcd */
+       hcd = usb_create_hcd(&isp116x_hc_driver, dev, dev->bus_id);
+       if (!hcd) {
+               ret = -ENOMEM;
+               goto err5;
+       }
+       /* this rsrc_start is bogus */
+       hcd->rsrc_start = addr->start;
+       isp116x = hcd_to_isp116x(hcd);
+       isp116x->data_reg = data_reg;
+       isp116x->addr_reg = addr_reg;
+       spin_lock_init(&isp116x->lock);
+       INIT_LIST_HEAD(&isp116x->async);
+       INIT_WORK(&isp116x->rh_resume, isp116x_rh_resume, hcd);
+       isp116x->board = dev->platform_data;
+
+       if (!isp116x->board) {
+               ERR("Platform data structure not initialized\n");
+               ret = -ENODEV;
+               goto err6;
+       }
+       if (isp116x_check_platform_delay(isp116x)) {
+               ERR("USE_PLATFORM_DELAY defined, but delay function not "
+                   "implemented.\n");
+               ERR("See comments in drivers/usb/host/isp116x-hcd.c\n");
+               ret = -ENODEV;
+               goto err6;
+       }
+
+       ret = usb_add_hcd(hcd, irq, SA_INTERRUPT);
+       if (ret != 0)
+               goto err6;
+
+       create_debug_file(isp116x);
+       return 0;
+
+      err6:
+       usb_put_hcd(hcd);
+      err5:
+       iounmap(data_reg);
+      err4:
+       release_mem_region(data->start, 2);
+      err3:
+       iounmap(addr_reg);
+      err2:
+       release_mem_region(addr->start, 2);
+      err1:
+       ERR("init error, %d\n", ret);
+       return ret;
+}
+
+#ifdef CONFIG_PM
+/*
+  Suspend of platform device
+*/
+static int isp116x_suspend(struct device *dev, pm_message_t state, u32 phase)
+{
+       int ret = 0;
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+       VDBG("%s: state %x, phase %x\n", __func__, state, phase);
+
+       if (phase != SUSPEND_DISABLE && phase != SUSPEND_POWER_DOWN)
+               return 0;
+
+       ret = usb_suspend_device(hcd->self.root_hub, state);
+       if (!ret) {
+               dev->power.power_state = state;
+               INFO("%s suspended\n", (char *)hcd_name);
+       } else
+               ERR("%s suspend failed\n", (char *)hcd_name);
+
+       return ret;
+}
+
+/*
+  Resume platform device
+*/
+static int isp116x_resume(struct device *dev, u32 phase)
+{
+       int ret = 0;
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+       VDBG("%s:  state %x, phase %x\n", __func__, dev->power.power_state,
+            phase);
+       if (phase != RESUME_POWER_ON)
+               return 0;
+
+       ret = usb_resume_device(hcd->self.root_hub);
+       if (!ret) {
+               dev->power.power_state = PMSG_ON;
+               VDBG("%s resumed\n", (char *)hcd_name);
+       }
+       return ret;
+}
+
+#else
+
+#define        isp116x_suspend    NULL
+#define        isp116x_resume     NULL
+
+#endif
+
+static struct device_driver isp116x_driver = {
+       .name = (char *)hcd_name,
+       .bus = &platform_bus_type,
+       .probe = isp116x_probe,
+       .remove = isp116x_remove,
+       .suspend = isp116x_suspend,
+       .resume = isp116x_resume,
+};
+
+/*-----------------------------------------------------------------*/
+
+static int __init isp116x_init(void)
+{
+       if (usb_disabled())
+               return -ENODEV;
+
+       INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION);
+       return driver_register(&isp116x_driver);
+}
+
+module_init(isp116x_init);
+
+static void __exit isp116x_cleanup(void)
+{
+       driver_unregister(&isp116x_driver);
+}
+
+module_exit(isp116x_cleanup);
diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h
new file mode 100644 (file)
index 0000000..5887347
--- /dev/null
@@ -0,0 +1,583 @@
+/*
+ * ISP116x register declarations and HCD data structures
+ *
+ * Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee>
+ * Portions:
+ * Copyright (C) 2004 Lothar Wassmann
+ * Copyright (C) 2004 Psion Teklogix
+ * Copyright (C) 2004 David Brownell
+ */
+
+/* us of 1ms frame */
+#define  MAX_LOAD_LIMIT                850
+
+/* Full speed: max # of bytes to transfer for a single urb
+   at a time must be < 1024 && must be multiple of 64.
+   832 allows transfering 4kiB within 5 frames. */
+#define MAX_TRANSFER_SIZE_FULLSPEED    832
+
+/* Low speed: there is no reason to schedule in very big
+   chunks; often the requested long transfers are for
+   string descriptors containing short strings. */
+#define MAX_TRANSFER_SIZE_LOWSPEED     64
+
+/* Bytetime (us), a rough indication of how much time it
+   would take to transfer a byte of useful data over USB */
+#define BYTE_TIME_FULLSPEED    1
+#define BYTE_TIME_LOWSPEED     20
+
+/* Buffer sizes */
+#define ISP116x_BUF_SIZE       4096
+#define ISP116x_ITL_BUFSIZE    0
+#define ISP116x_ATL_BUFSIZE    ((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE))
+
+#define ISP116x_WRITE_OFFSET   0x80
+
+/*------------ ISP116x registers/bits ------------*/
+#define        HCREVISION      0x00
+#define        HCCONTROL       0x01
+#define                HCCONTROL_HCFS  (3 << 6)        /* host controller
+                                                  functional state */
+#define                HCCONTROL_USB_RESET     (0 << 6)
+#define                HCCONTROL_USB_RESUME    (1 << 6)
+#define                HCCONTROL_USB_OPER      (2 << 6)
+#define                HCCONTROL_USB_SUSPEND   (3 << 6)
+#define                HCCONTROL_RWC   (1 << 9)        /* remote wakeup connected */
+#define                HCCONTROL_RWE   (1 << 10)       /* remote wakeup enable */
+#define        HCCMDSTAT       0x02
+#define                HCCMDSTAT_HCR   (1 << 0)        /* host controller reset */
+#define                HCCMDSTAT_SOC   (3 << 16)       /* scheduling overrun count */
+#define        HCINTSTAT       0x03
+#define                HCINT_SO        (1 << 0)        /* scheduling overrun */
+#define                HCINT_WDH       (1 << 1)        /* writeback of done_head */
+#define                HCINT_SF        (1 << 2)        /* start frame */
+#define                HCINT_RD        (1 << 3)        /* resume detect */
+#define                HCINT_UE        (1 << 4)        /* unrecoverable error */
+#define                HCINT_FNO       (1 << 5)        /* frame number overflow */
+#define                HCINT_RHSC      (1 << 6)        /* root hub status change */
+#define                HCINT_OC        (1 << 30)       /* ownership change */
+#define                HCINT_MIE       (1 << 31)       /* master interrupt enable */
+#define        HCINTENB        0x04
+#define        HCINTDIS        0x05
+#define        HCFMINTVL       0x0d
+#define        HCFMREM         0x0e
+#define        HCFMNUM         0x0f
+#define        HCLSTHRESH      0x11
+#define        HCRHDESCA       0x12
+#define                RH_A_NDP        (0x3 << 0)      /* # downstream ports */
+#define                RH_A_PSM        (1 << 8)        /* power switching mode */
+#define                RH_A_NPS        (1 << 9)        /* no power switching */
+#define                RH_A_DT         (1 << 10)       /* device type (mbz) */
+#define                RH_A_OCPM       (1 << 11)       /* overcurrent protection
+                                                  mode */
+#define                RH_A_NOCP       (1 << 12)       /* no overcurrent protection */
+#define                RH_A_POTPGT     (0xff << 24)    /* power on -> power good
+                                                  time */
+#define        HCRHDESCB       0x13
+#define                RH_B_DR         (0xffff << 0)   /* device removable flags */
+#define                RH_B_PPCM       (0xffff << 16)  /* port power control mask */
+#define        HCRHSTATUS      0x14
+#define                RH_HS_LPS       (1 << 0)        /* local power status */
+#define                RH_HS_OCI       (1 << 1)        /* over current indicator */
+#define                RH_HS_DRWE      (1 << 15)       /* device remote wakeup
+                                                  enable */
+#define                RH_HS_LPSC      (1 << 16)       /* local power status change */
+#define                RH_HS_OCIC      (1 << 17)       /* over current indicator
+                                                  change */
+#define                RH_HS_CRWE      (1 << 31)       /* clear remote wakeup
+                                                  enable */
+#define        HCRHPORT1       0x15
+#define                RH_PS_CCS       (1 << 0)        /* current connect status */
+#define                RH_PS_PES       (1 << 1)        /* port enable status */
+#define                RH_PS_PSS       (1 << 2)        /* port suspend status */
+#define                RH_PS_POCI      (1 << 3)        /* port over current
+                                                  indicator */
+#define                RH_PS_PRS       (1 << 4)        /* port reset status */
+#define                RH_PS_PPS       (1 << 8)        /* port power status */
+#define                RH_PS_LSDA      (1 << 9)        /* low speed device attached */
+#define                RH_PS_CSC       (1 << 16)       /* connect status change */
+#define                RH_PS_PESC      (1 << 17)       /* port enable status change */
+#define                RH_PS_PSSC      (1 << 18)       /* port suspend status
+                                                  change */
+#define                RH_PS_OCIC      (1 << 19)       /* over current indicator
+                                                  change */
+#define                RH_PS_PRSC      (1 << 20)       /* port reset status change */
+#define                HCRHPORT_CLRMASK        (0x1f << 16)
+#define        HCRHPORT2       0x16
+#define        HCHWCFG         0x20
+#define                HCHWCFG_15KRSEL         (1 << 12)
+#define                HCHWCFG_CLKNOTSTOP      (1 << 11)
+#define                HCHWCFG_ANALOG_OC       (1 << 10)
+#define                HCHWCFG_DACK_MODE       (1 << 8)
+#define                HCHWCFG_EOT_POL         (1 << 7)
+#define                HCHWCFG_DACK_POL        (1 << 6)
+#define                HCHWCFG_DREQ_POL        (1 << 5)
+#define                HCHWCFG_DBWIDTH_MASK    (0x03 << 3)
+#define                HCHWCFG_DBWIDTH(n)      (((n) << 3) & HCHWCFG_DBWIDTH_MASK)
+#define                HCHWCFG_INT_POL         (1 << 2)
+#define                HCHWCFG_INT_TRIGGER     (1 << 1)
+#define                HCHWCFG_INT_ENABLE      (1 << 0)
+#define        HCDMACFG        0x21
+#define                HCDMACFG_BURST_LEN_MASK (0x03 << 5)
+#define                HCDMACFG_BURST_LEN(n)   (((n) << 5) & HCDMACFG_BURST_LEN_MASK)
+#define                HCDMACFG_BURST_LEN_1    HCDMACFG_BURST_LEN(0)
+#define                HCDMACFG_BURST_LEN_4    HCDMACFG_BURST_LEN(1)
+#define                HCDMACFG_BURST_LEN_8    HCDMACFG_BURST_LEN(2)
+#define                HCDMACFG_DMA_ENABLE     (1 << 4)
+#define                HCDMACFG_BUF_TYPE_MASK  (0x07 << 1)
+#define                HCDMACFG_CTR_SEL        (1 << 2)
+#define                HCDMACFG_ITLATL_SEL     (1 << 1)
+#define                HCDMACFG_DMA_RW_SELECT  (1 << 0)
+#define        HCXFERCTR       0x22
+#define        HCuPINT         0x24
+#define                HCuPINT_SOF             (1 << 0)
+#define                HCuPINT_ATL             (1 << 1)
+#define                HCuPINT_AIIEOT          (1 << 2)
+#define                HCuPINT_OPR             (1 << 4)
+#define                HCuPINT_SUSP            (1 << 5)
+#define                HCuPINT_CLKRDY          (1 << 6)
+#define        HCuPINTENB      0x25
+#define        HCCHIPID        0x27
+#define                HCCHIPID_MASK           0xff00
+#define                HCCHIPID_MAGIC          0x6100
+#define        HCSCRATCH       0x28
+#define        HCSWRES         0x29
+#define                HCSWRES_MAGIC           0x00f6
+#define        HCITLBUFLEN     0x2a
+#define        HCATLBUFLEN     0x2b
+#define        HCBUFSTAT       0x2c
+#define                HCBUFSTAT_ITL0_FULL     (1 << 0)
+#define                HCBUFSTAT_ITL1_FULL     (1 << 1)
+#define                HCBUFSTAT_ATL_FULL      (1 << 2)
+#define                HCBUFSTAT_ITL0_DONE     (1 << 3)
+#define                HCBUFSTAT_ITL1_DONE     (1 << 4)
+#define                HCBUFSTAT_ATL_DONE      (1 << 5)
+#define        HCRDITL0LEN     0x2d
+#define        HCRDITL1LEN     0x2e
+#define        HCITLPORT       0x40
+#define        HCATLPORT       0x41
+
+/* Philips transfer descriptor */
+struct ptd {
+       u16 count;
+#define        PTD_COUNT_MSK   (0x3ff << 0)
+#define        PTD_TOGGLE_MSK  (1 << 10)
+#define        PTD_ACTIVE_MSK  (1 << 11)
+#define        PTD_CC_MSK      (0xf << 12)
+       u16 mps;
+#define        PTD_MPS_MSK     (0x3ff << 0)
+#define        PTD_SPD_MSK     (1 << 10)
+#define        PTD_LAST_MSK    (1 << 11)
+#define        PTD_EP_MSK      (0xf << 12)
+       u16 len;
+#define        PTD_LEN_MSK     (0x3ff << 0)
+#define        PTD_DIR_MSK     (3 << 10)
+#define        PTD_DIR_SETUP   (0)
+#define        PTD_DIR_OUT     (1)
+#define        PTD_DIR_IN      (2)
+#define        PTD_B5_5_MSK    (1 << 13)
+       u16 faddr;
+#define        PTD_FA_MSK      (0x7f << 0)
+#define        PTD_FMT_MSK     (1 << 7)
+} __attribute__ ((packed, aligned(2)));
+
+/* PTD accessor macros. */
+#define PTD_GET_COUNT(p)       (((p)->count & PTD_COUNT_MSK) >> 0)
+#define PTD_COUNT(v)           (((v) << 0) & PTD_COUNT_MSK)
+#define PTD_GET_TOGGLE(p)      (((p)->count & PTD_TOGGLE_MSK) >> 10)
+#define PTD_TOGGLE(v)          (((v) << 10) & PTD_TOGGLE_MSK)
+#define PTD_GET_ACTIVE(p)      (((p)->count & PTD_ACTIVE_MSK) >> 11)
+#define PTD_ACTIVE(v)          (((v) << 11) & PTD_ACTIVE_MSK)
+#define PTD_GET_CC(p)          (((p)->count & PTD_CC_MSK) >> 12)
+#define PTD_CC(v)              (((v) << 12) & PTD_CC_MSK)
+#define PTD_GET_MPS(p)         (((p)->mps & PTD_MPS_MSK) >> 0)
+#define PTD_MPS(v)             (((v) << 0) & PTD_MPS_MSK)
+#define PTD_GET_SPD(p)         (((p)->mps & PTD_SPD_MSK) >> 10)
+#define PTD_SPD(v)             (((v) << 10) & PTD_SPD_MSK)
+#define PTD_GET_LAST(p)                (((p)->mps & PTD_LAST_MSK) >> 11)
+#define PTD_LAST(v)            (((v) << 11) & PTD_LAST_MSK)
+#define PTD_GET_EP(p)          (((p)->mps & PTD_EP_MSK) >> 12)
+#define PTD_EP(v)              (((v) << 12) & PTD_EP_MSK)
+#define PTD_GET_LEN(p)         (((p)->len & PTD_LEN_MSK) >> 0)
+#define PTD_LEN(v)             (((v) << 0) & PTD_LEN_MSK)
+#define PTD_GET_DIR(p)         (((p)->len & PTD_DIR_MSK) >> 10)
+#define PTD_DIR(v)             (((v) << 10) & PTD_DIR_MSK)
+#define PTD_GET_B5_5(p)                (((p)->len & PTD_B5_5_MSK) >> 13)
+#define PTD_B5_5(v)            (((v) << 13) & PTD_B5_5_MSK)
+#define PTD_GET_FA(p)          (((p)->faddr & PTD_FA_MSK) >> 0)
+#define PTD_FA(v)              (((v) << 0) & PTD_FA_MSK)
+#define PTD_GET_FMT(p)         (((p)->faddr & PTD_FMT_MSK) >> 7)
+#define PTD_FMT(v)             (((v) << 7) & PTD_FMT_MSK)
+
+/*  Hardware transfer status codes -- CC from ptd->count */
+#define TD_CC_NOERROR      0x00
+#define TD_CC_CRC          0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL        0x04
+#define TD_DEVNOTRESP      0x05
+#define TD_PIDCHECKFAIL    0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN     0x08
+#define TD_DATAUNDERRUN    0x09
+    /* 0x0A, 0x0B reserved for hardware */
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+    /* 0x0E, 0x0F reserved for HCD */
+#define TD_NOTACCESSED     0x0F
+
+/* map PTD status codes (CC) to errno values */
+static const int cc_to_error[16] = {
+       /* No  Error  */ 0,
+       /* CRC Error  */ -EILSEQ,
+       /* Bit Stuff  */ -EPROTO,
+       /* Data Togg  */ -EILSEQ,
+       /* Stall      */ -EPIPE,
+       /* DevNotResp */ -ETIMEDOUT,
+       /* PIDCheck   */ -EPROTO,
+       /* UnExpPID   */ -EPROTO,
+       /* DataOver   */ -EOVERFLOW,
+       /* DataUnder  */ -EREMOTEIO,
+       /* (for hw)   */ -EIO,
+       /* (for hw)   */ -EIO,
+       /* BufferOver */ -ECOMM,
+       /* BuffUnder  */ -ENOSR,
+       /* (for HCD)  */ -EALREADY,
+       /* (for HCD)  */ -EALREADY
+};
+
+/*--------------------------------------------------------------*/
+
+#define        LOG2_PERIODIC_SIZE      5       /* arbitrary; this matches OHCI */
+#define        PERIODIC_SIZE           (1 << LOG2_PERIODIC_SIZE)
+
+struct isp116x {
+       spinlock_t lock;
+       struct work_struct rh_resume;
+
+       void __iomem *addr_reg;
+       void __iomem *data_reg;
+
+       struct isp116x_platform_data *board;
+
+       struct proc_dir_entry *pde;
+       unsigned long stat1, stat2, stat4, stat8, stat16;
+
+       /* HC registers */
+       u32 intenb;             /* "OHCI" interrupts */
+       u16 irqenb;             /* uP interrupts */
+
+       /* Root hub registers */
+       u32 rhdesca;
+       u32 rhdescb;
+       u32 rhstatus;
+       u32 rhport[2];
+
+       /* async schedule: control, bulk */
+       struct list_head async;
+
+       /* periodic schedule: int */
+       u16 load[PERIODIC_SIZE];
+       struct isp116x_ep *periodic[PERIODIC_SIZE];
+       unsigned periodic_count;
+       u16 fmindex;
+
+       /* Schedule for the current frame */
+       struct isp116x_ep *atl_active;
+       int atl_buflen;
+       int atl_bufshrt;
+       int atl_last_dir;
+       atomic_t atl_finishing;
+};
+
+static inline struct isp116x *hcd_to_isp116x(struct usb_hcd *hcd)
+{
+       return (struct isp116x *)(hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *isp116x_to_hcd(struct isp116x *isp116x)
+{
+       return container_of((void *)isp116x, struct usb_hcd, hcd_priv);
+}
+
+struct isp116x_ep {
+       struct usb_host_endpoint *hep;
+       struct usb_device *udev;
+       struct ptd ptd;
+
+       u8 maxpacket;
+       u8 epnum;
+       u8 nextpid;
+       u16 error_count;
+       u16 length;             /* of current packet */
+       unsigned char *data;    /* to databuf */
+       /* queue of active EP's (the ones scheduled for the
+          current frame) */
+       struct isp116x_ep *active;
+
+       /* periodic schedule */
+       u16 period;
+       u16 branch;
+       u16 load;
+       struct isp116x_ep *next;
+
+       /* async schedule */
+       struct list_head schedule;
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define DBG(stuff...)          printk(KERN_DEBUG "116x: " 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 "116x: " stuff)
+#define WARN(stuff...)         printk(KERN_WARNING "116x: " stuff)
+#define INFO(stuff...)         printk(KERN_INFO "116x: " stuff)
+
+/* ------------------------------------------------- */
+
+#if defined(USE_PLATFORM_DELAY)
+#if defined(USE_NDELAY)
+#error USE_PLATFORM_DELAY and USE_NDELAY simultaneously defined.
+#endif
+#define        isp116x_delay(h,d)      (h)->board->delay(      \
+                               isp116x_to_hcd(h)->self.controller,d)
+#define isp116x_check_platform_delay(h)        ((h)->board->delay == NULL)
+#elif defined(USE_NDELAY)
+#define        isp116x_delay(h,d)      ndelay(d)
+#define isp116x_check_platform_delay(h)        0
+#else
+#define        isp116x_delay(h,d)      do{}while(0)
+#define isp116x_check_platform_delay(h)        0
+#endif
+
+#if defined(DEBUG)
+#define        IRQ_TEST()      BUG_ON(!irqs_disabled())
+#else
+#define        IRQ_TEST()      do{}while(0)
+#endif
+
+static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
+{
+       IRQ_TEST();
+       writew(reg & 0xff, isp116x->addr_reg);
+       isp116x_delay(isp116x, 300);
+}
+
+static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val)
+{
+       writew(val, isp116x->data_reg);
+       isp116x_delay(isp116x, 150);
+}
+
+static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val)
+{
+       __raw_writew(val, isp116x->data_reg);
+       isp116x_delay(isp116x, 150);
+}
+
+static inline u16 isp116x_read_data16(struct isp116x *isp116x)
+{
+       u16 val;
+
+       val = readw(isp116x->data_reg);
+       isp116x_delay(isp116x, 150);
+       return val;
+}
+
+static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x)
+{
+       u16 val;
+
+       val = __raw_readw(isp116x->data_reg);
+       isp116x_delay(isp116x, 150);
+       return val;
+}
+
+static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val)
+{
+       writew(val & 0xffff, isp116x->data_reg);
+       isp116x_delay(isp116x, 150);
+       writew(val >> 16, isp116x->data_reg);
+       isp116x_delay(isp116x, 150);
+}
+
+static inline u32 isp116x_read_data32(struct isp116x *isp116x)
+{
+       u32 val;
+
+       val = (u32) readw(isp116x->data_reg);
+       isp116x_delay(isp116x, 150);
+       val |= ((u32) readw(isp116x->data_reg)) << 16;
+       isp116x_delay(isp116x, 150);
+       return val;
+}
+
+/* Let's keep register access functions out of line. Hint:
+   we wait at least 150 ns at every access.
+*/
+static u16 isp116x_read_reg16(struct isp116x *isp116x, unsigned reg)
+{
+       isp116x_write_addr(isp116x, reg);
+       return isp116x_read_data16(isp116x);
+}
+
+static u32 isp116x_read_reg32(struct isp116x *isp116x, unsigned reg)
+{
+       isp116x_write_addr(isp116x, reg);
+       return isp116x_read_data32(isp116x);
+}
+
+static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg,
+                               unsigned val)
+{
+       isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
+       isp116x_write_data16(isp116x, (u16) (val & 0xffff));
+}
+
+static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg,
+                               unsigned val)
+{
+       isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
+       isp116x_write_data32(isp116x, (u32) val);
+}
+
+#define isp116x_show_reg(d,r) {                                        \
+       if ((r) < 0x20) {                                       \
+               DBG("%-12s[%02x]: %08x\n", #r,                  \
+                       r, isp116x_read_reg32(d, r));           \
+       } else {                                                \
+               DBG("%-12s[%02x]:     %04x\n", #r,              \
+                       r, isp116x_read_reg16(d, r));           \
+       }                                                       \
+}
+
+static inline void isp116x_show_regs(struct isp116x *isp116x)
+{
+       isp116x_show_reg(isp116x, HCREVISION);
+       isp116x_show_reg(isp116x, HCCONTROL);
+       isp116x_show_reg(isp116x, HCCMDSTAT);
+       isp116x_show_reg(isp116x, HCINTSTAT);
+       isp116x_show_reg(isp116x, HCINTENB);
+       isp116x_show_reg(isp116x, HCFMINTVL);
+       isp116x_show_reg(isp116x, HCFMREM);
+       isp116x_show_reg(isp116x, HCFMNUM);
+       isp116x_show_reg(isp116x, HCLSTHRESH);
+       isp116x_show_reg(isp116x, HCRHDESCA);
+       isp116x_show_reg(isp116x, HCRHDESCB);
+       isp116x_show_reg(isp116x, HCRHSTATUS);
+       isp116x_show_reg(isp116x, HCRHPORT1);
+       isp116x_show_reg(isp116x, HCRHPORT2);
+       isp116x_show_reg(isp116x, HCHWCFG);
+       isp116x_show_reg(isp116x, HCDMACFG);
+       isp116x_show_reg(isp116x, HCXFERCTR);
+       isp116x_show_reg(isp116x, HCuPINT);
+       isp116x_show_reg(isp116x, HCuPINTENB);
+       isp116x_show_reg(isp116x, HCCHIPID);
+       isp116x_show_reg(isp116x, HCSCRATCH);
+       isp116x_show_reg(isp116x, HCITLBUFLEN);
+       isp116x_show_reg(isp116x, HCATLBUFLEN);
+       isp116x_show_reg(isp116x, HCBUFSTAT);
+       isp116x_show_reg(isp116x, HCRDITL0LEN);
+       isp116x_show_reg(isp116x, HCRDITL1LEN);
+}
+
+#if defined(URB_TRACE)
+
+#define PIPETYPE(pipe)  ({ char *__s;                  \
+       if (usb_pipecontrol(pipe))      __s = "ctrl";   \
+       else if (usb_pipeint(pipe))     __s = "int";    \
+       else if (usb_pipebulk(pipe))    __s = "bulk";   \
+       else                            __s = "iso";    \
+       __s;})
+#define PIPEDIR(pipe)   ({ usb_pipein(pipe) ? "in" : "out"; })
+#define URB_NOTSHORT(urb) ({ (urb)->transfer_flags & URB_SHORT_NOT_OK ? \
+       "short_not_ok" : ""; })
+
+/* print debug info about the URB */
+static void urb_dbg(struct urb *urb, char *msg)
+{
+       unsigned int pipe;
+
+       if (!urb) {
+               DBG("%s: zero urb\n", msg);
+               return;
+       }
+       pipe = urb->pipe;
+       DBG("%s: FA %d ep%d%s %s: len %d/%d %s\n", msg,
+           usb_pipedevice(pipe), usb_pipeendpoint(pipe),
+           PIPEDIR(pipe), PIPETYPE(pipe),
+           urb->transfer_buffer_length, urb->actual_length, URB_NOTSHORT(urb));
+}
+
+#else
+
+#define  urb_dbg(urb,msg)   do{}while(0)
+
+#endif                         /* ! defined(URB_TRACE) */
+
+#if defined(PTD_TRACE)
+
+#define PTD_DIR_STR(ptd)  ({char __c;          \
+       switch(PTD_GET_DIR(ptd)){               \
+       case 0:  __c = 's'; break;              \
+       case 1:  __c = 'o'; break;              \
+       default: __c = 'i'; break;              \
+       }; __c;})
+
+/*
+  Dump PTD info. The code documents the format
+  perfectly, right :)
+*/
+static inline void dump_ptd(struct ptd *ptd)
+{
+       printk("td: %x %d%c%d %d,%d,%d  %x %x%x%x\n",
+              PTD_GET_CC(ptd), PTD_GET_FA(ptd),
+              PTD_DIR_STR(ptd), PTD_GET_EP(ptd),
+              PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd),
+              PTD_GET_TOGGLE(ptd), PTD_GET_ACTIVE(ptd),
+              PTD_GET_SPD(ptd), PTD_GET_LAST(ptd));
+}
+
+static inline void dump_ptd_out_data(struct ptd *ptd, u8 * buf)
+{
+       int k;
+
+       if (PTD_GET_DIR(ptd) != PTD_DIR_IN && PTD_GET_LEN(ptd)) {
+               printk("-> ");
+               for (k = 0; k < PTD_GET_LEN(ptd); ++k)
+                       printk("%02x ", ((u8 *) buf)[k]);
+               printk("\n");
+       }
+}
+
+static inline void dump_ptd_in_data(struct ptd *ptd, u8 * buf)
+{
+       int k;
+
+       if (PTD_GET_DIR(ptd) == PTD_DIR_IN && PTD_GET_COUNT(ptd)) {
+               printk("<- ");
+               for (k = 0; k < PTD_GET_COUNT(ptd); ++k)
+                       printk("%02x ", ((u8 *) buf)[k]);
+               printk("\n");
+       }
+       if (PTD_GET_LAST(ptd))
+               printk("-\n");
+}
+
+#else
+
+#define dump_ptd(ptd)               do{}while(0)
+#define dump_ptd_in_data(ptd,buf)   do{}while(0)
+#define dump_ptd_out_data(ptd,buf)  do{}while(0)
+
+#endif                         /* ! defined(PTD_TRACE) */
index 1e27f10c1592c97f120e5abc9d408fdf3d273dff..13cd2177b557749bd3890b41351e14f6441f80db 100644 (file)
 #include <linux/init.h>
 #include <linux/timer.h>
 #include <linux/list.h>
-#include <linux/interrupt.h>  /* for in_interrupt () */
 #include <linux/usb.h>
 #include <linux/usb_otg.h>
-#include "../core/hcd.h"
 #include <linux/dma-mapping.h> 
-#include <linux/dmapool.h>    /* needed by ohci-mem.c when no PCI */
+#include <linux/dmapool.h>
+#include <linux/reboot.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 
+#include "../core/hcd.h"
 
-#define DRIVER_VERSION "2004 Nov 08"
+#define DRIVER_VERSION "2005 April 22"
 #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
 #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
 
@@ -141,6 +141,7 @@ static const char   hcd_name [] = "ohci_hcd";
 static void ohci_dump (struct ohci_hcd *ohci, int verbose);
 static int ohci_init (struct ohci_hcd *ohci);
 static void ohci_stop (struct usb_hcd *hcd);
+static int ohci_reboot (struct notifier_block *, unsigned long , void *);
 
 #include "ohci-hub.c"
 #include "ohci-dbg.c"
@@ -420,6 +421,23 @@ static void ohci_usb_reset (struct ohci_hcd *ohci)
        ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
 }
 
+/* reboot notifier forcibly disables IRQs and DMA, helping kexec and
+ * other cases where the next software may expect clean state from the
+ * "firmware".  this is bus-neutral, unlike shutdown() methods.
+ */
+static int
+ohci_reboot (struct notifier_block *block, unsigned long code, void *null)
+{
+       struct ohci_hcd *ohci;
+
+       ohci = container_of (block, struct ohci_hcd, reboot_notifier);
+       ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+       ohci_usb_reset (ohci);
+       /* flush the writes */
+       (void) ohci_readl (ohci, &ohci->regs->control);
+       return 0;
+}
+
 /*-------------------------------------------------------------------------*
  * HC functions
  *-------------------------------------------------------------------------*/
@@ -487,13 +505,10 @@ static int ohci_init (struct ohci_hcd *ohci)
 /* Start an OHCI controller, set the BUS operational
  * resets USB and controller
  * enable interrupts 
- * connect the virtual root hub
  */
 static int ohci_run (struct ohci_hcd *ohci)
 {
        u32                     mask, temp;
-       struct usb_device       *udev;
-       struct usb_bus          *bus;
        int                     first = ohci->fminterval == 0;
 
        disable (ohci);
@@ -654,37 +669,13 @@ retry:
 
        // POTPGT delay is bits 24-31, in 2 ms units.
        mdelay ((temp >> 23) & 0x1fe);
-       bus = &ohci_to_hcd(ohci)->self;
        ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
 
        ohci_dump (ohci, 1);
 
-       udev = bus->root_hub;
-       if (udev) {
-               return 0;
-       }
-       /* connect the virtual root hub */
-       udev = usb_alloc_dev (NULL, bus, 0);
-       if (!udev) {
-               disable (ohci);
-               ohci->hc_control &= ~OHCI_CTRL_HCFS;
-               ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
-               return -ENOMEM;
-       }
-
-       udev->speed = USB_SPEED_FULL;
-       if (usb_hcd_register_root_hub (udev, ohci_to_hcd(ohci)) != 0) {
-               usb_put_dev (udev);
-               disable (ohci);
-               ohci->hc_control &= ~OHCI_CTRL_HCFS;
-               ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
-               return -ENODEV;
-       }
-       if (ohci->power_budget)
-               hub_set_power_budget(udev, ohci->power_budget);
+       if (ohci_to_hcd(ohci)->self.root_hub == NULL)
+               create_debug_files (ohci);
 
-       create_debug_files (ohci);
        return 0;
 }
 
@@ -781,6 +772,7 @@ static void ohci_stop (struct usb_hcd *hcd)
        ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
        
        remove_debug_files (ohci);
+       unregister_reboot_notifier (&ohci->reboot_notifier);
        ohci_mem_cleanup (ohci);
        if (ohci->hcca) {
                dma_free_coherent (hcd->self.controller, 
index e55682b4919d0b9eab5fd4560bb476695fe46c47..23735a36af00c5fae6131f1b5a28ebde5aae4584 100644 (file)
@@ -29,6 +29,7 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
        spin_lock_init (&ohci->lock);
        INIT_LIST_HEAD (&ohci->pending);
        INIT_WORK (&ohci->rh_resume, ohci_rh_resume, ohci_to_hcd(ohci));
+       ohci->reboot_notifier.notifier_call = ohci_reboot;
 }
 
 /*-------------------------------------------------------------------------*/
index 8aab5907afe9ad442012ec4c00aecd46dd88c50b..b62d69937694891b50746a7398141bd99d10d25b 100644 (file)
@@ -181,7 +181,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
        if (config->otg) {
                ohci_to_hcd(ohci)->self.otg_port = config->otg;
                /* default/minimum OTG power budget:  8 mA */
-               ohci->power_budget = 8;
+               ohci_to_hcd(ohci)->power_budget = 8;
        }
 
        /* boards can use OTG transceivers in non-OTG modes */
@@ -230,7 +230,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
 
                /* TPS2045 switch for internal transceiver (port 1) */
                if (machine_is_omap_osk()) {
-                       ohci->power_budget = 250;
+                       ohci_to_hcd(ohci)->power_budget = 250;
 
                        rh &= ~RH_A_NOCP;
 
index 57fd07d005493bb49525806d5fb61928021262c1..eede6be098d2c4b5e68c96aa0fa485ec64b8a1ae 100644 (file)
  * This file is licenced under the GPL.
  */
  
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PPC_PMAC
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
 #include <asm/pci-bridge.h>
 #include <asm/prom.h>
-#ifndef CONFIG_PM
-#      define CONFIG_PM
-#endif
 #endif
 
 #ifndef CONFIG_PCI
@@ -132,7 +129,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
        /* let things settle down a bit */
        msleep (100);
        
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PPC_PMAC
        if (_machine == _MACH_Pmac) {
                struct device_node      *of_node;
  
@@ -141,7 +138,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
                if (of_node)
                        pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
        }
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PPC_PMAC */
        return 0;
 }
 
@@ -151,7 +148,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
        struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
        int                     retval = 0;
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PPC_PMAC
        if (_machine == _MACH_Pmac) {
                struct device_node *of_node;
 
@@ -160,7 +157,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
                if (of_node)
                        pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
        }
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PPC_PMAC */
 
        /* resume root hub */
        if (time_before (jiffies, ohci->next_statechange))
index 22e1ac138ac0686bc4e72baba0d412d5f9c4022e..71cdd2262860d129fc1776179b561f3f0ff5dcb4 100644 (file)
@@ -371,7 +371,6 @@ struct ohci_hcd {
         * other external transceivers should be software-transparent 
         */
        struct otg_transceiver  *transceiver;
-       unsigned                power_budget;
 
        /*
         * memory management for queue data structures
@@ -390,6 +389,7 @@ struct ohci_hcd {
        u32                     fminterval;             /* saved register */
 
        struct work_struct      rh_resume;
+       struct notifier_block   reboot_notifier;
 
        unsigned long           flags;          /* for HC bugs */
 #define        OHCI_QUIRK_AMD756       0x01                    /* erratum #4 */
index 99d43f758ad0e85d524d00cedaf93bed8793ac15..6c3f910bc30700620804f5621207a5e3b634af0f 100644 (file)
@@ -1563,29 +1563,15 @@ static int
 sl811h_start(struct usb_hcd *hcd)
 {
        struct sl811            *sl811 = hcd_to_sl811(hcd);
-       struct usb_device       *udev;
 
        /* chip has been reset, VBUS power is off */
-
-       udev = usb_alloc_dev(NULL, &hcd->self, 0);
-       if (!udev)
-               return -ENOMEM;
-
-       udev->speed = USB_SPEED_FULL;
        hcd->state = HC_STATE_RUNNING;
 
-       if (sl811->board)
+       if (sl811->board) {
                hcd->can_wakeup = sl811->board->can_wakeup;
-
-       if (usb_hcd_register_root_hub(udev, hcd) != 0) {
-               usb_put_dev(udev);
-               sl811h_stop(hcd);
-               return -ENODEV;
+               hcd->power_budget = sl811->board->power * 2;
        }
 
-       if (sl811->board && sl811->board->power)
-               hub_set_power_budget(udev, sl811->board->power * 2);
-
        /* enable power and interupts */
        port_power(sl811, 1);
 
index 6e173265095c398e183c1887b6d0f4c22367645d..269d8ef01459d7834f699eb6f5c08ebf61ad2ecc 100644 (file)
@@ -68,13 +68,6 @@ static const char driver_name[DEV_NAME_LEN]  = "sl811_cs";
 
 static dev_link_t *dev_list = NULL;
 
-static int irq_list[4] = { -1 };
-static int irq_list_count;
-
-module_param_array(irq_list, int, &irq_list_count, 0444);
-
-INT_MODULE_PARM(irq_mask, 0xdeb8);
-
 typedef struct local_info_t {
        dev_link_t              link;
        dev_node_t              node;
@@ -373,7 +366,7 @@ static dev_link_t *sl811_cs_attach(void)
        local_info_t *local;
        dev_link_t *link;
        client_reg_t client_reg;
-       int ret, i;
+       int ret;
 
        local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
        if (!local)
@@ -385,11 +378,6 @@ static dev_link_t *sl811_cs_attach(void)
        /* Initialize */
        link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
        link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
-       if (irq_list[0] == -1)
-               link->irq.IRQInfo2 = irq_mask;
-       else
-               for (i = 0; i < irq_list_count; i++)
-                       link->irq.IRQInfo2 |= 1 << irq_list[i];
        link->irq.Handler = NULL;
 
        link->conf.Attributes = 0;
@@ -418,6 +406,12 @@ static dev_link_t *sl811_cs_attach(void)
        return link;
 }
 
+static struct pcmcia_device_id sl811_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0xc015, 0x0001), /* RATOC USB HOST CF+ Card */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, sl811_ids);
+
 static struct pcmcia_driver sl811_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -425,6 +419,7 @@ static struct pcmcia_driver sl811_cs_driver = {
        },
        .attach         = sl811_cs_attach,
        .detach         = sl811_cs_detach,
+       .id_table       = sl811_ids,
 };
 
 /*====================================================================*/
index 24c73c5a343545dd20a72e2ef4cd74ca68b84cfb..4538a98b6f9d3ec2381dd9daf0dd82ab4b0af843 100644 (file)
@@ -237,6 +237,37 @@ static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
        return out - buf;
 }
 
+static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len)
+{
+       char *out = buf;
+       char *rh_state;
+
+       /* Try to make sure there's enough memory */
+       if (len < 60)
+               return 0;
+
+       switch (uhci->rh_state) {
+           case UHCI_RH_RESET:
+               rh_state = "reset";             break;
+           case UHCI_RH_SUSPENDED:
+               rh_state = "suspended";         break;
+           case UHCI_RH_AUTO_STOPPED:
+               rh_state = "auto-stopped";      break;
+           case UHCI_RH_RESUMING:
+               rh_state = "resuming";          break;
+           case UHCI_RH_SUSPENDING:
+               rh_state = "suspending";        break;
+           case UHCI_RH_RUNNING:
+               rh_state = "running";           break;
+           case UHCI_RH_RUNNING_NODEVS:
+               rh_state = "running, no devs";  break;
+           default:
+               rh_state = "?";                 break;
+       }
+       out += sprintf(out, "Root-hub state: %s\n", rh_state);
+       return out - buf;
+}
+
 static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
 {
        char *out = buf;
@@ -408,6 +439,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
 
        spin_lock_irqsave(&uhci->lock, flags);
 
+       out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
        out += sprintf(out, "HC status\n");
        out += uhci_show_status(uhci, out, len - (out - buf));
 
index 49bd83ee0c75bd77eded16e1fa3d02484f2d784a..0d5d2545bf07ba151a40e617e52583a2a096f62b 100644 (file)
  * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
  *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
  * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu
  *
  * Intel documents this fairly well, and as far as I know there
  * are no royalties or anything like that, but even so there are
  * people who decided that they want to do the same thing in a
  * completely different way.
  *
- * WARNING! The USB documentation is downright evil. Most of it
- * is just crap, written by a committee. You're better off ignoring
- * most of it, the important stuff is:
- *  - the low-level protocol (fairly simple but lots of small details)
- *  - working around the horridness of the rest
  */
 
 #include <linux/config.h>
@@ -64,7 +59,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v2.2"
+#define DRIVER_VERSION "v2.3"
 #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \
 Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
 Alan Stern"
@@ -89,8 +84,9 @@ static char *errbuf;
 
 static kmem_cache_t *uhci_up_cachep;   /* urb_priv */
 
+static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
+static void wakeup_rh(struct uhci_hcd *uhci);
 static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
-static void hc_state_transitions(struct uhci_hcd *uhci);
 
 /* If a transfer is still active after this much time, turn off FSBR */
 #define IDLE_TIMEOUT   msecs_to_jiffies(50)
@@ -101,308 +97,352 @@ static void hc_state_transitions(struct uhci_hcd *uhci);
 /* to make sure it doesn't hog all of the bandwidth */
 #define DEPTH_INTERVAL 5
 
+static inline void restart_timer(struct uhci_hcd *uhci)
+{
+       mod_timer(&uhci->stall_timer, jiffies + msecs_to_jiffies(100));
+}
+
 #include "uhci-hub.c"
 #include "uhci-debug.c"
 #include "uhci-q.c"
 
-static int init_stall_timer(struct usb_hcd *hcd);
-
-static void stall_callback(unsigned long ptr)
+/*
+ * Make sure the controller is completely inactive, unable to
+ * generate interrupts or do DMA.
+ */
+static void reset_hc(struct uhci_hcd *uhci)
 {
-       struct usb_hcd *hcd = (struct usb_hcd *)ptr;
-       struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-       struct urb_priv *up;
-       unsigned long flags;
+       int port;
 
-       spin_lock_irqsave(&uhci->lock, flags);
-       uhci_scan_schedule(uhci, NULL);
-
-       list_for_each_entry(up, &uhci->urb_list, urb_list) {
-               struct urb *u = up->urb;
-
-               spin_lock(&u->lock);
-
-               /* Check if the FSBR timed out */
-               if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
-                       uhci_fsbr_timeout(uhci, u);
+       /* Turn off PIRQ enable and SMI enable.  (This also turns off the
+        * BIOS's USB Legacy Support.)  Turn off all the R/WC bits too.
+        */
+       pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+                       USBLEGSUP_RWC);
 
-               spin_unlock(&u->lock);
-       }
+       /* Reset the HC - this will force us to get a
+        * new notification of any already connected
+        * ports due to the virtual disconnect that it
+        * implies.
+        */
+       outw(USBCMD_HCRESET, uhci->io_addr + USBCMD);
+       mb();
+       udelay(5);
+       if (inw(uhci->io_addr + USBCMD) & USBCMD_HCRESET)
+               dev_warn(uhci_dev(uhci), "HCRESET not completed yet!\n");
 
-       /* Really disable FSBR */
-       if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
-               uhci->fsbrtimeout = 0;
-               uhci->skel_term_qh->link = UHCI_PTR_TERM;
-       }
+       /* Just to be safe, disable interrupt requests and
+        * make sure the controller is stopped.
+        */
+       outw(0, uhci->io_addr + USBINTR);
+       outw(0, uhci->io_addr + USBCMD);
 
-       /* Poll for and perform state transitions */
-       hc_state_transitions(uhci);
-       if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED))
-               uhci_check_ports(uhci);
+       /* HCRESET doesn't affect the Suspend, Reset, and Resume Detect
+        * bits in the port status and control registers.
+        * We have to clear them by hand.
+        */
+       for (port = 0; port < uhci->rh_numports; ++port)
+               outw(0, uhci->io_addr + USBPORTSC1 + (port * 2));
 
-       init_stall_timer(hcd);
-       spin_unlock_irqrestore(&uhci->lock, flags);
+       uhci->port_c_suspend = uhci->suspended_ports =
+                       uhci->resuming_ports = 0;
+       uhci->rh_state = UHCI_RH_RESET;
+       uhci->is_stopped = UHCI_IS_STOPPED;
+       uhci_to_hcd(uhci)->state = HC_STATE_HALT;
+       uhci_to_hcd(uhci)->poll_rh = 0;
 }
 
-static int init_stall_timer(struct usb_hcd *hcd)
+/*
+ * Last rites for a defunct/nonfunctional controller
+ * or one we don't want to use any more.
+ */
+static void hc_died(struct uhci_hcd *uhci)
 {
-       struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-
-       init_timer(&uhci->stall_timer);
-       uhci->stall_timer.function = stall_callback;
-       uhci->stall_timer.data = (unsigned long)hcd;
-       uhci->stall_timer.expires = jiffies + msecs_to_jiffies(100);
-       add_timer(&uhci->stall_timer);
-
-       return 0;
+       reset_hc(uhci);
+       uhci->hc_inaccessible = 1;
+       del_timer(&uhci->stall_timer);
 }
 
-static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
+/*
+ * Initialize a controller that was newly discovered or has just been
+ * resumed.  In either case we can't be sure of its previous state.
+ */
+static void check_and_reset_hc(struct uhci_hcd *uhci)
 {
-       struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-       unsigned long io_addr = uhci->io_addr;
-       unsigned short status;
+       u16 legsup;
+       unsigned int cmd, intr;
 
        /*
-        * Read the interrupt status, and write it back to clear the
-        * interrupt cause.  Contrary to the UHCI specification, the
-        * "HC Halted" status bit is persistent: it is RO, not R/WC.
+        * When restarting a suspended controller, we expect all the
+        * settings to be the same as we left them:
+        *
+        *      PIRQ and SMI disabled, no R/W bits set in USBLEGSUP;
+        *      Controller is stopped and configured with EGSM set;
+        *      No interrupts enabled except possibly Resume Detect.
+        *
+        * If any of these conditions are violated we do a complete reset.
         */
-       status = inw(io_addr + USBSTS);
-       if (!(status & ~USBSTS_HCH))    /* shared interrupt, not mine */
-               return IRQ_NONE;
-       outw(status, io_addr + USBSTS);         /* Clear it */
-
-       if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
-               if (status & USBSTS_HSE)
-                       dev_err(uhci_dev(uhci), "host system error, "
-                                       "PCI problems?\n");
-               if (status & USBSTS_HCPE)
-                       dev_err(uhci_dev(uhci), "host controller process "
-                                       "error, something bad happened!\n");
-               if ((status & USBSTS_HCH) && uhci->state > 0) {
-                       dev_err(uhci_dev(uhci), "host controller halted, "
-                                       "very bad!\n");
-                       /* FIXME: Reset the controller, fix the offending TD */
-               }
+       pci_read_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, &legsup);
+       if (legsup & ~(USBLEGSUP_RO | USBLEGSUP_RWC)) {
+               dev_dbg(uhci_dev(uhci), "%s: legsup = 0x%04x\n",
+                               __FUNCTION__, legsup);
+               goto reset_needed;
        }
 
-       if (status & USBSTS_RD)
-               uhci->resume_detect = 1;
+       cmd = inw(uhci->io_addr + USBCMD);
+       if ((cmd & USBCMD_RS) || !(cmd & USBCMD_CF) || !(cmd & USBCMD_EGSM)) {
+               dev_dbg(uhci_dev(uhci), "%s: cmd = 0x%04x\n",
+                               __FUNCTION__, cmd);
+               goto reset_needed;
+       }
 
-       spin_lock(&uhci->lock);
-       uhci_scan_schedule(uhci, regs);
-       spin_unlock(&uhci->lock);
+       intr = inw(uhci->io_addr + USBINTR);
+       if (intr & (~USBINTR_RESUME)) {
+               dev_dbg(uhci_dev(uhci), "%s: intr = 0x%04x\n",
+                               __FUNCTION__, intr);
+               goto reset_needed;
+       }
+       return;
 
-       return IRQ_HANDLED;
+reset_needed:
+       dev_dbg(uhci_dev(uhci), "Performing full reset\n");
+       reset_hc(uhci);
 }
 
-static void reset_hc(struct uhci_hcd *uhci)
+/*
+ * Store the basic register settings needed by the controller.
+ */
+static void configure_hc(struct uhci_hcd *uhci)
 {
-       unsigned long io_addr = uhci->io_addr;
+       /* Set the frame length to the default: 1 ms exactly */
+       outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
 
-       /* Turn off PIRQ, SMI, and all interrupts.  This also turns off
-        * the BIOS's USB Legacy Support.
-        */
-       pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
-       outw(0, uhci->io_addr + USBINTR);
+       /* Store the frame list base address */
+       outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
 
-       /* Global reset for 50ms */
-       uhci->state = UHCI_RESET;
-       outw(USBCMD_GRESET, io_addr + USBCMD);
-       msleep(50);
-       outw(0, io_addr + USBCMD);
+       /* Set the current frame number */
+       outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
 
-       /* Another 10ms delay */
-       msleep(10);
-       uhci->resume_detect = 0;
-       uhci->is_stopped = UHCI_IS_STOPPED;
+       /* Mark controller as running before we enable interrupts */
+       uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
+       mb();
+
+       /* Enable PIRQ */
+       pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+                       USBLEGSUP_DEFAULT);
 }
 
-static void suspend_hc(struct uhci_hcd *uhci)
+
+static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
 {
-       unsigned long io_addr = uhci->io_addr;
+       int port;
 
-       dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
-       uhci->state = UHCI_SUSPENDED;
-       uhci->resume_detect = 0;
-       outw(USBCMD_EGSM, io_addr + USBCMD);
+       switch (to_pci_dev(uhci_dev(uhci))->vendor) {
+           default:
+               break;
 
-       /* FIXME: Wait for the controller to actually stop */
-       uhci_get_current_frame_number(uhci);
-       uhci->is_stopped = UHCI_IS_STOPPED;
+           case PCI_VENDOR_ID_GENESYS:
+               /* Genesys Logic's GL880S controllers don't generate
+                * resume-detect interrupts.
+                */
+               return 1;
 
-       uhci_scan_schedule(uhci, NULL);
+           case PCI_VENDOR_ID_INTEL:
+               /* Some of Intel's USB controllers have a bug that causes
+                * resume-detect interrupts if any port has an over-current
+                * condition.  To make matters worse, some motherboards
+                * hardwire unused USB ports' over-current inputs active!
+                * To prevent problems, we will not enable resume-detect
+                * interrupts if any ports are OC.
+                */
+               for (port = 0; port < uhci->rh_numports; ++port) {
+                       if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
+                                       USBPORTSC_OC)
+                               return 1;
+               }
+               break;
+       }
+       return 0;
 }
 
-static void wakeup_hc(struct uhci_hcd *uhci)
+static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state)
+__releases(uhci->lock)
+__acquires(uhci->lock)
 {
-       unsigned long io_addr = uhci->io_addr;
+       int auto_stop;
+       int int_enable;
 
-       switch (uhci->state) {
-               case UHCI_SUSPENDED:            /* Start the resume */
-                       dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
-
-                       /* Global resume for >= 20ms */
-                       outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD);
-                       uhci->state = UHCI_RESUMING_1;
-                       uhci->state_end = jiffies + msecs_to_jiffies(20);
-                       uhci->is_stopped = 0;
-                       break;
+       auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
+       dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__,
+                       (auto_stop ? " (auto-stop)" : ""));
 
-               case UHCI_RESUMING_1:           /* End global resume */
-                       uhci->state = UHCI_RESUMING_2;
-                       outw(0, io_addr + USBCMD);
-                       /* Falls through */
-
-               case UHCI_RESUMING_2:           /* Wait for EOP to be sent */
-                       if (inw(io_addr + USBCMD) & USBCMD_FGR)
-                               break;
-
-                       /* Run for at least 1 second, and
-                        * mark it configured with a 64-byte max packet */
-                       uhci->state = UHCI_RUNNING_GRACE;
-                       uhci->state_end = jiffies + HZ;
-                       outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP,
-                                       io_addr + USBCMD);
-                       break;
+       /* If we get a suspend request when we're already auto-stopped
+        * then there's nothing to do.
+        */
+       if (uhci->rh_state == UHCI_RH_AUTO_STOPPED) {
+               uhci->rh_state = new_state;
+               return;
+       }
 
-               case UHCI_RUNNING_GRACE:        /* Now allowed to suspend */
-                       uhci->state = UHCI_RUNNING;
-                       break;
+       /* Enable resume-detect interrupts if they work.
+        * Then enter Global Suspend mode, still configured.
+        */
+       int_enable = (resume_detect_interrupts_are_broken(uhci) ?
+                       0 : USBINTR_RESUME);
+       outw(int_enable, uhci->io_addr + USBINTR);
+       outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD);
+       mb();
+       udelay(5);
 
-               default:
-                       break;
+       /* If we're auto-stopping then no devices have been attached
+        * for a while, so there shouldn't be any active URBs and the
+        * controller should stop after a few microseconds.  Otherwise
+        * we will give the controller one frame to stop.
+        */
+       if (!auto_stop && !(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) {
+               uhci->rh_state = UHCI_RH_SUSPENDING;
+               spin_unlock_irq(&uhci->lock);
+               msleep(1);
+               spin_lock_irq(&uhci->lock);
+               if (uhci->hc_inaccessible)      /* Died */
+                       return;
        }
-}
+       if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH))
+               dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n");
 
-static int ports_active(struct uhci_hcd *uhci)
-{
-       unsigned long io_addr = uhci->io_addr;
-       int connection = 0;
-       int i;
+       uhci_get_current_frame_number(uhci);
+       smp_wmb();
 
-       for (i = 0; i < uhci->rh_numports; i++)
-               connection |= (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_CCS);
+       uhci->rh_state = new_state;
+       uhci->is_stopped = UHCI_IS_STOPPED;
+       del_timer(&uhci->stall_timer);
+       uhci_to_hcd(uhci)->poll_rh = !int_enable;
 
-       return connection;
+       uhci_scan_schedule(uhci, NULL);
 }
 
-static int suspend_allowed(struct uhci_hcd *uhci)
+static void start_rh(struct uhci_hcd *uhci)
 {
-       unsigned long io_addr = uhci->io_addr;
-       int i;
-
-       if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL)
-               return 1;
+       uhci->is_stopped = 0;
+       smp_wmb();
 
-       /* Some of Intel's USB controllers have a bug that causes false
-        * resume indications if any port has an over current condition.
-        * To prevent problems, we will not allow a global suspend if
-        * any ports are OC.
-        *
-        * Some motherboards using Intel's chipsets (but not using all
-        * the USB ports) appear to hardwire the over current inputs active
-        * to disable the USB ports.
+       /* Mark it configured and running with a 64-byte max packet.
+        * All interrupts are enabled, even though RESUME won't do anything.
         */
-
-       /* check for over current condition on any port */
-       for (i = 0; i < uhci->rh_numports; i++) {
-               if (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_OC)
-                       return 0;
-       }
-
-       return 1;
+       outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, uhci->io_addr + USBCMD);
+       outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
+                       uhci->io_addr + USBINTR);
+       mb();
+       uhci->rh_state = UHCI_RH_RUNNING;
+       uhci_to_hcd(uhci)->poll_rh = 1;
+       restart_timer(uhci);
 }
 
-static void hc_state_transitions(struct uhci_hcd *uhci)
+static void wakeup_rh(struct uhci_hcd *uhci)
+__releases(uhci->lock)
+__acquires(uhci->lock)
 {
-       switch (uhci->state) {
-               case UHCI_RUNNING:
+       dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__,
+                       uhci->rh_state == UHCI_RH_AUTO_STOPPED ?
+                               " (auto-start)" : "");
 
-                       /* global suspend if nothing connected for 1 second */
-                       if (!ports_active(uhci) && suspend_allowed(uhci)) {
-                               uhci->state = UHCI_SUSPENDING_GRACE;
-                               uhci->state_end = jiffies + HZ;
-                       }
-                       break;
-
-               case UHCI_SUSPENDING_GRACE:
-                       if (ports_active(uhci))
-                               uhci->state = UHCI_RUNNING;
-                       else if (time_after_eq(jiffies, uhci->state_end))
-                               suspend_hc(uhci);
-                       break;
-
-               case UHCI_SUSPENDED:
-
-                       /* wakeup if requested by a device */
-                       if (uhci->resume_detect)
-                               wakeup_hc(uhci);
-                       break;
+       /* If we are auto-stopped then no devices are attached so there's
+        * no need for wakeup signals.  Otherwise we send Global Resume
+        * for 20 ms.
+        */
+       if (uhci->rh_state == UHCI_RH_SUSPENDED) {
+               uhci->rh_state = UHCI_RH_RESUMING;
+               outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF,
+                               uhci->io_addr + USBCMD);
+               spin_unlock_irq(&uhci->lock);
+               msleep(20);
+               spin_lock_irq(&uhci->lock);
+               if (uhci->hc_inaccessible)      /* Died */
+                       return;
+
+               /* End Global Resume and wait for EOP to be sent */
+               outw(USBCMD_CF, uhci->io_addr + USBCMD);
+               mb();
+               udelay(4);
+               if (inw(uhci->io_addr + USBCMD) & USBCMD_FGR)
+                       dev_warn(uhci_dev(uhci), "FGR not stopped yet!\n");
+       }
 
-               case UHCI_RESUMING_1:
-               case UHCI_RESUMING_2:
-               case UHCI_RUNNING_GRACE:
-                       if (time_after_eq(jiffies, uhci->state_end))
-                               wakeup_hc(uhci);
-                       break;
+       start_rh(uhci);
 
-               default:
-                       break;
-       }
+       /* Restart root hub polling */
+       mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
 }
 
-/*
- * Store the current frame number in uhci->frame_number if the controller
- * is runnning
- */
-static void uhci_get_current_frame_number(struct uhci_hcd *uhci)
+static void stall_callback(unsigned long _uhci)
 {
+       struct uhci_hcd *uhci = (struct uhci_hcd *) _uhci;
+       unsigned long flags;
+
+       spin_lock_irqsave(&uhci->lock, flags);
+       uhci_scan_schedule(uhci, NULL);
+       check_fsbr(uhci);
+
        if (!uhci->is_stopped)
-               uhci->frame_number = inw(uhci->io_addr + USBFRNUM);
+               restart_timer(uhci);
+       spin_unlock_irqrestore(&uhci->lock, flags);
 }
 
-static int start_hc(struct uhci_hcd *uhci)
+static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
 {
-       unsigned long io_addr = uhci->io_addr;
-       int timeout = 10;
+       struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+       unsigned short status;
+       unsigned long flags;
 
        /*
-        * Reset the HC - this will force us to get a
-        * new notification of any already connected
-        * ports due to the virtual disconnect that it
-        * implies.
+        * Read the interrupt status, and write it back to clear the
+        * interrupt cause.  Contrary to the UHCI specification, the
+        * "HC Halted" status bit is persistent: it is RO, not R/WC.
         */
-       outw(USBCMD_HCRESET, io_addr + USBCMD);
-       while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {
-               if (--timeout < 0) {
-                       dev_err(uhci_dev(uhci), "USBCMD_HCRESET timed out!\n");
-                       return -ETIMEDOUT;
+       status = inw(uhci->io_addr + USBSTS);
+       if (!(status & ~USBSTS_HCH))    /* shared interrupt, not mine */
+               return IRQ_NONE;
+       outw(status, uhci->io_addr + USBSTS);           /* Clear it */
+
+       if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
+               if (status & USBSTS_HSE)
+                       dev_err(uhci_dev(uhci), "host system error, "
+                                       "PCI problems?\n");
+               if (status & USBSTS_HCPE)
+                       dev_err(uhci_dev(uhci), "host controller process "
+                                       "error, something bad happened!\n");
+               if (status & USBSTS_HCH) {
+                       spin_lock_irqsave(&uhci->lock, flags);
+                       if (uhci->rh_state >= UHCI_RH_RUNNING) {
+                               dev_err(uhci_dev(uhci),
+                                       "host controller halted, "
+                                       "very bad!\n");
+                               hc_died(uhci);
+                               spin_unlock_irqrestore(&uhci->lock, flags);
+                               return IRQ_HANDLED;
+                       }
+                       spin_unlock_irqrestore(&uhci->lock, flags);
                }
-               msleep(1);
        }
 
-       /* Mark controller as running before we enable interrupts */
-       uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
-
-       /* Turn on PIRQ and all interrupts */
-       pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
-                       USBLEGSUP_DEFAULT);
-       outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
-               io_addr + USBINTR);
+       if (status & USBSTS_RD)
+               usb_hcd_poll_rh_status(hcd);
 
-       /* Start at frame 0 */
-       outw(0, io_addr + USBFRNUM);
-       outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD);
+       spin_lock_irqsave(&uhci->lock, flags);
+       uhci_scan_schedule(uhci, regs);
+       spin_unlock_irqrestore(&uhci->lock, flags);
 
-       /* Run and mark it configured with a 64-byte max packet */
-       uhci->state = UHCI_RUNNING_GRACE;
-       uhci->state_end = jiffies + HZ;
-       outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
-       uhci->is_stopped = 0;
+       return IRQ_HANDLED;
+}
 
-       return 0;
+/*
+ * Store the current frame number in uhci->frame_number if the controller
+ * is runnning
+ */
+static void uhci_get_current_frame_number(struct uhci_hcd *uhci)
+{
+       if (!uhci->is_stopped)
+               uhci->frame_number = inw(uhci->io_addr + USBFRNUM);
 }
 
 /*
@@ -448,16 +488,58 @@ static void release_uhci(struct uhci_hcd *uhci)
 static int uhci_reset(struct usb_hcd *hcd)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+       unsigned io_size = (unsigned) hcd->rsrc_len;
+       int port;
 
        uhci->io_addr = (unsigned long) hcd->rsrc_start;
 
-       /* Kick BIOS off this hardware and reset, so we won't get
-        * interrupts from any previous setup.
+       /* The UHCI spec says devices must have 2 ports, and goes on to say
+        * they may have more but gives no way to determine how many there
+        * are.  However according to the UHCI spec, Bit 7 of the port
+        * status and control register is always set to 1.  So we try to
+        * use this to our advantage.  Another common failure mode when
+        * a nonexistent register is addressed is to return all ones, so
+        * we test for that also.
         */
-       reset_hc(uhci);
+       for (port = 0; port < (io_size - USBPORTSC1) / 2; port++) {
+               unsigned int portstatus;
+
+               portstatus = inw(uhci->io_addr + USBPORTSC1 + (port * 2));
+               if (!(portstatus & 0x0080) || portstatus == 0xffff)
+                       break;
+       }
+       if (debug)
+               dev_info(uhci_dev(uhci), "detected %d ports\n", port);
+
+       /* Anything greater than 7 is weird so we'll ignore it. */
+       if (port > UHCI_RH_MAXCHILD) {
+               dev_info(uhci_dev(uhci), "port count misdetected? "
+                               "forcing to 2 ports\n");
+               port = 2;
+       }
+       uhci->rh_numports = port;
+
+       /* Kick BIOS off this hardware and reset if the controller
+        * isn't already safely quiescent.
+        */
+       check_and_reset_hc(uhci);
        return 0;
 }
 
+/* Make sure the controller is quiescent and that we're not using it
+ * any more.  This is mainly for the benefit of programs which, like kexec,
+ * expect the hardware to be idle: not doing DMA or generating IRQs.
+ *
+ * This routine may be called in a damaged or failing kernel.  Hence we
+ * do not acquire the spinlock before shutting down the controller.
+ */
+static void uhci_shutdown(struct pci_dev *pdev)
+{
+       struct usb_hcd *hcd = (struct usb_hcd *) pci_get_drvdata(pdev);
+
+       hc_died(hcd_to_uhci(hcd));
+}
+
 /*
  * Allocate a frame list, and then setup the skeleton
  *
@@ -478,17 +560,20 @@ static int uhci_start(struct usb_hcd *hcd)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
        int retval = -EBUSY;
-       int i, port;
-       unsigned io_size;
+       int i;
        dma_addr_t dma_handle;
-       struct usb_device *udev;
        struct dentry *dentry;
 
-       io_size = (unsigned) hcd->rsrc_len;
+       hcd->uses_new_polling = 1;
+       if (pci_find_capability(to_pci_dev(uhci_dev(uhci)), PCI_CAP_ID_PM))
+               hcd->can_wakeup = 1;            /* Assume it supports PME# */
 
-       dentry = debugfs_create_file(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, &uhci_debug_operations);
+       dentry = debugfs_create_file(hcd->self.bus_name,
+                       S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci,
+                       &uhci_debug_operations);
        if (!dentry) {
-               dev_err(uhci_dev(uhci), "couldn't create uhci debugfs entry\n");
+               dev_err(uhci_dev(uhci),
+                               "couldn't create uhci debugfs entry\n");
                retval = -ENOMEM;
                goto err_create_debug_entry;
        }
@@ -510,6 +595,10 @@ static int uhci_start(struct usb_hcd *hcd)
 
        init_waitqueue_head(&uhci->waitqh);
 
+       init_timer(&uhci->stall_timer);
+       uhci->stall_timer.function = stall_callback;
+       uhci->stall_timer.data = (unsigned long) uhci;
+
        uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
                        &dma_handle, 0);
        if (!uhci->fl) {
@@ -536,46 +625,14 @@ static int uhci_start(struct usb_hcd *hcd)
                goto err_create_qh_pool;
        }
 
-       /* Initialize the root hub */
-
-       /* UHCI specs says devices must have 2 ports, but goes on to say */
-       /*  they may have more but give no way to determine how many they */
-       /*  have. However, according to the UHCI spec, Bit 7 is always set */
-       /*  to 1. So we try to use this to our advantage */
-       for (port = 0; port < (io_size - 0x10) / 2; port++) {
-               unsigned int portstatus;
-
-               portstatus = inw(uhci->io_addr + 0x10 + (port * 2));
-               if (!(portstatus & 0x0080))
-                       break;
-       }
-       if (debug)
-               dev_info(uhci_dev(uhci), "detected %d ports\n", port);
-
-       /* This is experimental so anything less than 2 or greater than 8 is */
-       /*  something weird and we'll ignore it */
-       if (port < 2 || port > UHCI_RH_MAXCHILD) {
-               dev_info(uhci_dev(uhci), "port count misdetected? "
-                               "forcing to 2 ports\n");
-               port = 2;
-       }
-
-       uhci->rh_numports = port;
-
-       udev = usb_alloc_dev(NULL, &hcd->self, 0);
-       if (!udev) {
-               dev_err(uhci_dev(uhci), "unable to allocate root hub\n");
-               goto err_alloc_root_hub;
-       }
-
-       uhci->term_td = uhci_alloc_td(uhci, udev);
+       uhci->term_td = uhci_alloc_td(uhci);
        if (!uhci->term_td) {
                dev_err(uhci_dev(uhci), "unable to allocate terminating TD\n");
                goto err_alloc_term_td;
        }
 
        for (i = 0; i < UHCI_NUM_SKELQH; i++) {
-               uhci->skelqh[i] = uhci_alloc_qh(uhci, udev);
+               uhci->skelqh[i] = uhci_alloc_qh(uhci);
                if (!uhci->skelqh[i]) {
                        dev_err(uhci_dev(uhci), "unable to allocate QH\n");
                        goto err_alloc_skelqh;
@@ -641,32 +698,17 @@ static int uhci_start(struct usb_hcd *hcd)
 
        /*
         * Some architectures require a full mb() to enforce completion of
-        * the memory writes above before the I/O transfers in start_hc().
+        * the memory writes above before the I/O transfers in configure_hc().
         */
        mb();
-       if ((retval = start_hc(uhci)) != 0)
-               goto err_alloc_skelqh;
-
-       init_stall_timer(hcd);
-
-       udev->speed = USB_SPEED_FULL;
-
-       if (usb_hcd_register_root_hub(udev, hcd) != 0) {
-               dev_err(uhci_dev(uhci), "unable to start root hub\n");
-               retval = -ENOMEM;
-               goto err_start_root_hub;
-       }
 
+       configure_hc(uhci);
+       start_rh(uhci);
        return 0;
 
 /*
  * error exits:
  */
-err_start_root_hub:
-       reset_hc(uhci);
-
-       del_timer_sync(&uhci->stall_timer);
-
 err_alloc_skelqh:
        for (i = 0; i < UHCI_NUM_SKELQH; i++)
                if (uhci->skelqh[i]) {
@@ -678,9 +720,6 @@ err_alloc_skelqh:
        uhci->term_td = NULL;
 
 err_alloc_term_td:
-       usb_put_dev(udev);
-
-err_alloc_root_hub:
        dma_pool_destroy(uhci->qh_pool);
        uhci->qh_pool = NULL;
 
@@ -705,73 +744,114 @@ static void uhci_stop(struct usb_hcd *hcd)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
-       del_timer_sync(&uhci->stall_timer);
-       reset_hc(uhci);
-
        spin_lock_irq(&uhci->lock);
+       reset_hc(uhci);
        uhci_scan_schedule(uhci, NULL);
        spin_unlock_irq(&uhci->lock);
-       
+
+       del_timer_sync(&uhci->stall_timer);
        release_uhci(uhci);
 }
 
 #ifdef CONFIG_PM
+static int uhci_rh_suspend(struct usb_hcd *hcd)
+{
+       struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+       spin_lock_irq(&uhci->lock);
+       if (!uhci->hc_inaccessible)             /* Not dead */
+               suspend_rh(uhci, UHCI_RH_SUSPENDED);
+       spin_unlock_irq(&uhci->lock);
+       return 0;
+}
+
+static int uhci_rh_resume(struct usb_hcd *hcd)
+{
+       struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+       int rc = 0;
+
+       spin_lock_irq(&uhci->lock);
+       if (uhci->hc_inaccessible) {
+               if (uhci->rh_state == UHCI_RH_SUSPENDED) {
+                       dev_warn(uhci_dev(uhci), "HC isn't running!\n");
+                       rc = -ENODEV;
+               }
+               /* Otherwise the HC is dead */
+       } else
+               wakeup_rh(uhci);
+       spin_unlock_irq(&uhci->lock);
+       return rc;
+}
+
 static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+       int rc = 0;
+
+       dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
 
        spin_lock_irq(&uhci->lock);
+       if (uhci->hc_inaccessible)      /* Dead or already suspended */
+               goto done;
 
-       /* Don't try to suspend broken motherboards, reset instead */
-       if (suspend_allowed(uhci))
-               suspend_hc(uhci);
-       else {
-               spin_unlock_irq(&uhci->lock);
-               reset_hc(uhci);
-               spin_lock_irq(&uhci->lock);
-               uhci_scan_schedule(uhci, NULL);
-       }
+#ifndef CONFIG_USB_SUSPEND
+       /* Otherwise this would never happen */
+       suspend_rh(uhci, UHCI_RH_SUSPENDED);
+#endif
+
+       if (uhci->rh_state > UHCI_RH_SUSPENDED) {
+               dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n");
+               hcd->state = HC_STATE_RUNNING;
+               rc = -EBUSY;
+               goto done;
+       };
 
+       /* All PCI host controllers are required to disable IRQ generation
+        * at the source, so we must turn off PIRQ.
+        */
+       pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
+       uhci->hc_inaccessible = 1;
+
+       /* FIXME: Enable non-PME# remote wakeup? */
+
+done:
        spin_unlock_irq(&uhci->lock);
-       return 0;
+       if (rc == 0)
+               del_timer_sync(&hcd->rh_timer);
+       return rc;
 }
 
 static int uhci_resume(struct usb_hcd *hcd)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-       int rc;
 
-       pci_set_master(to_pci_dev(uhci_dev(uhci)));
+       dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
 
+       if (uhci->rh_state == UHCI_RH_RESET)    /* Dead */
+               return 0;
        spin_lock_irq(&uhci->lock);
 
-       if (uhci->state == UHCI_SUSPENDED) {
+       /* FIXME: Disable non-PME# remote wakeup? */
 
-               /*
-                * Some systems don't maintain the UHCI register values
-                * during a PM suspend/resume cycle, so reinitialize
-                * the Frame Number, Framelist Base Address, Interrupt
-                * Enable, and Legacy Support registers.
-                */
-               pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
-                               0);
-               outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
-               outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
-               outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |
-                               USBINTR_SP, uhci->io_addr + USBINTR);
-               uhci->resume_detect = 1;
-               pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
-                               USBLEGSUP_DEFAULT);
-       } else {
-               spin_unlock_irq(&uhci->lock);
-               reset_hc(uhci);
-               if ((rc = start_hc(uhci)) != 0)
-                       return rc;
-               spin_lock_irq(&uhci->lock);
-       }
-       hcd->state = HC_STATE_RUNNING;
+       uhci->hc_inaccessible = 0;
+
+       /* The BIOS may have changed the controller settings during a
+        * system wakeup.  Check it and reconfigure to avoid problems.
+        */
+       check_and_reset_hc(uhci);
+       configure_hc(uhci);
+
+#ifndef CONFIG_USB_SUSPEND
+       /* Otherwise this would never happen */
+       wakeup_rh(uhci);
+#endif
+       if (uhci->rh_state == UHCI_RH_RESET)
+               suspend_rh(uhci, UHCI_RH_SUSPENDED);
 
        spin_unlock_irq(&uhci->lock);
+
+       if (hcd->poll_rh)
+               usb_hcd_poll_rh_status(hcd);
        return 0;
 }
 #endif
@@ -788,13 +868,15 @@ static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd,
 static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-       int frame_number;
        unsigned long flags;
+       int is_stopped;
+       int frame_number;
 
        /* Minimize latency by avoiding the spinlock */
        local_irq_save(flags);
-       rmb();
-       frame_number = (uhci->is_stopped ? uhci->frame_number :
+       is_stopped = uhci->is_stopped;
+       smp_rmb();
+       frame_number = (is_stopped ? uhci->frame_number :
                        inw(uhci->io_addr + USBFRNUM));
        local_irq_restore(flags);
        return frame_number;
@@ -817,6 +899,8 @@ static const struct hc_driver uhci_driver = {
 #ifdef CONFIG_PM
        .suspend =              uhci_suspend,
        .resume =               uhci_resume,
+       .hub_suspend =          uhci_rh_suspend,
+       .hub_resume =           uhci_rh_resume,
 #endif
        .stop =                 uhci_stop,
 
@@ -845,6 +929,7 @@ static struct pci_driver uhci_pci_driver = {
 
        .probe =        usb_hcd_pci_probe,
        .remove =       usb_hcd_pci_remove,
+       .shutdown =     uhci_shutdown,
 
 #ifdef CONFIG_PM
        .suspend =      usb_hcd_pci_suspend,
index 02255d69e1fefadfc45f17f53bf3ffdd240e8a36..bf9c5f9b508b9eb4e8d8eef7fbab0a94454eb158 100644 (file)
@@ -41,6 +41,7 @@
 #define USBFRNUM       6
 #define USBFLBASEADD   8
 #define USBSOF         12
+#define   USBSOF_DEFAULT       64      /* Frame length is exactly 1 ms */
 
 /* USB port status and control registers */
 #define USBPORTSC1     16
@@ -66,6 +67,8 @@
 /* Legacy support register */
 #define USBLEGSUP              0xc0
 #define   USBLEGSUP_DEFAULT    0x2000  /* only PIRQ enable set */
+#define   USBLEGSUP_RWC                0x8f00  /* the R/WC bits */
+#define   USBLEGSUP_RO         0x5040  /* R/O and reserved bits */
 
 #define UHCI_NULL_DATA_SIZE    0x7FF   /* for UHCI controller TD */
 
@@ -111,7 +114,6 @@ struct uhci_qh {
        /* Software fields */
        dma_addr_t dma_handle;
 
-       struct usb_device *dev;
        struct urb_priv *urbp;
 
        struct list_head list;          /* P: uhci->frame_list_lock */
@@ -203,7 +205,6 @@ struct uhci_td {
        /* Software fields */
        dma_addr_t dma_handle;
 
-       struct usb_device *dev;
        struct urb *urb;
 
        struct list_head list;          /* P: urb->lock */
@@ -314,26 +315,32 @@ static inline int __interval_to_skel(int interval)
 }
 
 /*
- * Device states for the host controller.
+ * States for the root hub.
  *
  * To prevent "bouncing" in the presence of electrical noise,
- * we insist on a 1-second "grace" period, before switching to
- * the RUNNING or SUSPENDED states, during which the state is
- * not allowed to change.
- *
- * The resume process is divided into substates in order to avoid
- * potentially length delays during the timer handler.
- *
- * States in which the host controller is halted must have values <= 0.
+ * when there are no devices attached we delay for 1 second in the
+ * RUNNING_NODEVS state before switching to the AUTO_STOPPED state.
+ * 
+ * (Note that the AUTO_STOPPED state won't be necessary once the hub
+ * driver learns to autosuspend.)
  */
-enum uhci_state {
-       UHCI_RESET,
-       UHCI_RUNNING_GRACE,             /* Before RUNNING */
-       UHCI_RUNNING,                   /* The normal state */
-       UHCI_SUSPENDING_GRACE,          /* Before SUSPENDED */
-       UHCI_SUSPENDED = -10,           /* When no devices are attached */
-       UHCI_RESUMING_1,
-       UHCI_RESUMING_2
+enum uhci_rh_state {
+       /* In the following states the HC must be halted.
+        * These two must come first */
+       UHCI_RH_RESET,
+       UHCI_RH_SUSPENDED,
+
+       UHCI_RH_AUTO_STOPPED,
+       UHCI_RH_RESUMING,
+
+       /* In this state the HC changes from running to halted,
+        * so it can legally appear either way. */
+       UHCI_RH_SUSPENDING,
+
+       /* In the following states it's an error if the HC is halted.
+        * These two must come last */
+       UHCI_RH_RUNNING,                /* The normal state */
+       UHCI_RH_RUNNING_NODEVS,         /* Running with no devices attached */
 };
 
 /*
@@ -363,15 +370,16 @@ struct uhci_hcd {
        int fsbr;                               /* Full-speed bandwidth reclamation */
        unsigned long fsbrtimeout;              /* FSBR delay */
 
-       enum uhci_state state;                  /* FIXME: needs a spinlock */
-       unsigned long state_end;                /* Time of next transition */
+       enum uhci_rh_state rh_state;
+       unsigned long auto_stop_time;           /* When to AUTO_STOP */
+
        unsigned int frame_number;              /* As of last check */
        unsigned int is_stopped;
 #define UHCI_IS_STOPPED                9999            /* Larger than a frame # */
 
        unsigned int scan_in_progress:1;        /* Schedule scan is running */
        unsigned int need_rescan:1;             /* Redo the schedule scan */
-       unsigned int resume_detect:1;           /* Need a Global Resume */
+       unsigned int hc_inaccessible:1;         /* HC is suspended or dead */
 
        /* Support for port suspend/resume/reset */
        unsigned long port_c_suspend;           /* Bit-arrays of ports */
@@ -451,4 +459,11 @@ struct urb_priv {
  * #2 urb->lock
  */
 
+
+/* Some special IDs */
+
+#define PCI_VENDOR_ID_GENESYS          0x17a0
+#define PCI_DEVICE_ID_GL880S_UHCI      0x8083
+#define PCI_DEVICE_ID_GL880S_EHCI      0x8084
+
 #endif
index 4c45ba8390f8a51fa9750e534bd2ef0618caf2d1..4eace2b19ddb830602b339059e7a953633a73d39 100644 (file)
@@ -33,9 +33,24 @@ static __u8 root_hub_hub_des[] =
 /* status change bits:  nonzero writes will clear */
 #define RWC_BITS       (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC)
 
-static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
+/* A port that either is connected or has a changed-bit set will prevent
+ * us from AUTO_STOPPING.
+ */
+static int any_ports_active(struct uhci_hcd *uhci)
+{
+       int port;
+
+       for (port = 0; port < uhci->rh_numports; ++port) {
+               if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) &
+                               (USBPORTSC_CCS | RWC_BITS)) ||
+                               test_bit(port, &uhci->port_c_suspend))
+                       return 1;
+       }
+       return 0;
+}
+
+static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf)
 {
-       struct uhci_hcd *uhci = hcd_to_uhci(hcd);
        int port;
 
        *buf = 0;
@@ -44,8 +59,6 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
                                test_bit(port, &uhci->port_c_suspend))
                        *buf |= (1 << (port + 1));
        }
-       if (*buf && uhci->state == UHCI_SUSPENDED)
-               uhci->resume_detect = 1;
        return !!*buf;
 }
 
@@ -115,6 +128,11 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
                                set_bit(port, &uhci->resuming_ports);
                                uhci->ports_timeout = jiffies +
                                                msecs_to_jiffies(20);
+
+                               /* Make sure we see the port again
+                                * after the resuming period is over. */
+                               mod_timer(&uhci_to_hcd(uhci)->rh_timer,
+                                               uhci->ports_timeout);
                        } else if (time_after_eq(jiffies,
                                                uhci->ports_timeout)) {
                                uhci_finish_suspend(uhci, port, port_addr);
@@ -123,6 +141,60 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
        }
 }
 
+static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+       struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+       unsigned long flags;
+       int status;
+
+       spin_lock_irqsave(&uhci->lock, flags);
+       if (uhci->hc_inaccessible) {
+               status = 0;
+               goto done;
+       }
+
+       uhci_check_ports(uhci);
+       status = get_hub_status_data(uhci, buf);
+
+       switch (uhci->rh_state) {
+           case UHCI_RH_SUSPENDING:
+           case UHCI_RH_SUSPENDED:
+               /* if port change, ask to be resumed */
+               if (status)
+                       usb_hcd_resume_root_hub(hcd);
+               break;
+
+           case UHCI_RH_AUTO_STOPPED:
+               /* if port change, auto start */
+               if (status)
+                       wakeup_rh(uhci);
+               break;
+
+           case UHCI_RH_RUNNING:
+               /* are any devices attached? */
+               if (!any_ports_active(uhci)) {
+                       uhci->rh_state = UHCI_RH_RUNNING_NODEVS;
+                       uhci->auto_stop_time = jiffies + HZ;
+               }
+               break;
+
+           case UHCI_RH_RUNNING_NODEVS:
+               /* auto-stop if nothing connected for 1 second */
+               if (any_ports_active(uhci))
+                       uhci->rh_state = UHCI_RH_RUNNING;
+               else if (time_after_eq(jiffies, uhci->auto_stop_time))
+                       suspend_rh(uhci, UHCI_RH_AUTO_STOPPED);
+               break;
+
+           default:
+               break;
+       }
+
+done:
+       spin_unlock_irqrestore(&uhci->lock, flags);
+       return status;
+}
+
 /* size of returned buffer is part of USB spec */
 static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        u16 wIndex, char *buf, u16 wLength)
@@ -134,6 +206,9 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
        u16 wPortChange, wPortStatus;
        unsigned long flags;
 
+       if (uhci->hc_inaccessible)
+               return -ETIMEDOUT;
+
        spin_lock_irqsave(&uhci->lock, flags);
        switch (typeReq) {
 
index 2a7c19501f248386138591962f4a5899e1c99947..5f18084a116db21b355cec3aacb42826332ae382 100644 (file)
@@ -32,6 +32,8 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci);
  */
 static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
 {
+       if (uhci->is_stopped)
+               mod_timer(&uhci->stall_timer, jiffies);
        uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); 
 }
 
@@ -46,7 +48,7 @@ static inline void uhci_moveto_complete(struct uhci_hcd *uhci,
        list_move_tail(&urbp->urb_list, &uhci->complete_list);
 }
 
-static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev)
+static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
 {
        dma_addr_t dma_handle;
        struct uhci_td *td;
@@ -61,14 +63,11 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *d
        td->buffer = 0;
 
        td->frame = -1;
-       td->dev = dev;
 
        INIT_LIST_HEAD(&td->list);
        INIT_LIST_HEAD(&td->remove_list);
        INIT_LIST_HEAD(&td->fl_list);
 
-       usb_get_dev(dev);
-
        return td;
 }
 
@@ -168,13 +167,10 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
        if (!list_empty(&td->fl_list))
                dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
 
-       if (td->dev)
-               usb_put_dev(td->dev);
-
        dma_pool_free(uhci->td_pool, td, td->dma_handle);
 }
 
-static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *dev)
+static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci)
 {
        dma_addr_t dma_handle;
        struct uhci_qh *qh;
@@ -188,14 +184,11 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *d
        qh->element = UHCI_PTR_TERM;
        qh->link = UHCI_PTR_TERM;
 
-       qh->dev = dev;
        qh->urbp = NULL;
 
        INIT_LIST_HEAD(&qh->list);
        INIT_LIST_HEAD(&qh->remove_list);
 
-       usb_get_dev(dev);
-
        return qh;
 }
 
@@ -206,9 +199,6 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
        if (!list_empty(&qh->remove_list))
                dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh);
 
-       if (qh->dev)
-               usb_put_dev(qh->dev);
-
        dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 }
 
@@ -597,7 +587,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
        /*
         * Build the TD for the control request setup packet
         */
-       td = uhci_alloc_td(uhci, urb->dev);
+       td = uhci_alloc_td(uhci);
        if (!td)
                return -ENOMEM;
 
@@ -626,7 +616,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
                if (pktsze > maxsze)
                        pktsze = maxsze;
 
-               td = uhci_alloc_td(uhci, urb->dev);
+               td = uhci_alloc_td(uhci);
                if (!td)
                        return -ENOMEM;
 
@@ -644,7 +634,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
        /*
         * Build the final TD for control status 
         */
-       td = uhci_alloc_td(uhci, urb->dev);
+       td = uhci_alloc_td(uhci);
        if (!td)
                return -ENOMEM;
 
@@ -666,7 +656,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
        uhci_fill_td(td, status | TD_CTRL_IOC,
                destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0);
 
-       qh = uhci_alloc_qh(uhci, urb->dev);
+       qh = uhci_alloc_qh(uhci);
        if (!qh)
                return -ENOMEM;
 
@@ -865,7 +855,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
                                status &= ~TD_CTRL_SPD;
                }
 
-               td = uhci_alloc_td(uhci, urb->dev);
+               td = uhci_alloc_td(uhci);
                if (!td)
                        return -ENOMEM;
 
@@ -891,7 +881,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
         */
        if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) &&
            !len && urb->transfer_buffer_length) {
-               td = uhci_alloc_td(uhci, urb->dev);
+               td = uhci_alloc_td(uhci);
                if (!td)
                        return -ENOMEM;
 
@@ -913,7 +903,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
         * flag setting. */
        td->status |= cpu_to_le32(TD_CTRL_IOC);
 
-       qh = uhci_alloc_qh(uhci, urb->dev);
+       qh = uhci_alloc_qh(uhci);
        if (!qh)
                return -ENOMEM;
 
@@ -1096,7 +1086,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
                if (!urb->iso_frame_desc[i].length)
                        continue;
 
-               td = uhci_alloc_td(uhci, urb->dev);
+               td = uhci_alloc_td(uhci);
                if (!td)
                        return -ENOMEM;
 
@@ -1497,6 +1487,7 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
  rescan:
        uhci->need_rescan = 0;
 
+       uhci_clear_next_interrupt(uhci);
        uhci_get_current_frame_number(uhci);
 
        if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age)
@@ -1537,3 +1528,26 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
        /* Wake up anyone waiting for an URB to complete */
        wake_up_all(&uhci->waitqh);
 }
+
+static void check_fsbr(struct uhci_hcd *uhci)
+{
+       struct urb_priv *up;
+
+       list_for_each_entry(up, &uhci->urb_list, urb_list) {
+               struct urb *u = up->urb;
+
+               spin_lock(&u->lock);
+
+               /* Check if the FSBR timed out */
+               if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
+                       uhci_fsbr_timeout(uhci, u);
+
+               spin_unlock(&u->lock);
+       }
+
+       /* Really disable FSBR */
+       if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
+               uhci->fsbrtimeout = 0;
+               uhci->skel_term_qh->link = UHCI_PTR_TERM;
+       }
+}
index d28e7eab6f981804a345b4afc14349339c35e2e0..fd59f6bdd67faa72b9964c0884334f43a22e1256 100644 (file)
@@ -151,6 +151,18 @@ config USB_WACOM
          To compile this driver as a module, choose M here: the
          module will be called wacom.
 
+config USB_ACECAD
+       tristate "Acecad Flair tablet support"
+       depends on USB && INPUT
+       help
+         Say Y here if you want to use the USB version of the Acecad Flair
+         tablet.  Make sure to say Y to "Mouse support"
+         (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+         (CONFIG_INPUT_EVDEV) as well.
+
+         To compile this driver as a module, choose M here: the
+         module will be called acecad.
+
 config USB_KBTAB
        tristate "KB Gear JamStudio tablet support"
        depends on USB && INPUT
@@ -190,6 +202,18 @@ config USB_MTOUCH
          To compile this driver as a module, choose M here: the
          module will be called mtouchusb.
 
+config USB_ITMTOUCH
+       tristate "ITM Touch USB Touchscreen Driver"
+       depends on USB && INPUT
+       ---help---
+         Say Y here if you want to use a ITM Touch USB
+         Touchscreen controller.
+
+         This touchscreen is used in LG 1510SF monitors.
+
+         To compile this driver as a module, choose M here: the
+         module will be called itmtouch.
+
 config USB_EGALAX
        tristate "eGalax TouchKit USB Touchscreen Driver"
        depends on USB && INPUT
index 6bcedd16b0a1812a44c65bf7a37c7d1e17425e31..831b2b0f1f051072050f80e23eae9ee3e19f3c0a 100644 (file)
@@ -33,7 +33,9 @@ obj-$(CONFIG_USB_KBD)         += usbkbd.o
 obj-$(CONFIG_USB_KBTAB)                += kbtab.o
 obj-$(CONFIG_USB_MOUSE)                += usbmouse.o
 obj-$(CONFIG_USB_MTOUCH)       += mtouchusb.o
+obj-$(CONFIG_USB_ITMTOUCH)     += itmtouch.o
 obj-$(CONFIG_USB_EGALAX)       += touchkitusb.o
 obj-$(CONFIG_USB_POWERMATE)    += powermate.o
 obj-$(CONFIG_USB_WACOM)                += wacom.o
+obj-$(CONFIG_USB_ACECAD)       += acecad.o
 obj-$(CONFIG_USB_XPAD)         += xpad.o
diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c
new file mode 100644 (file)
index 0000000..ebcf7c9
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ *  Copyright (c) 2001-2005 Edouard TISSERANT   <edouard.tisserant@wanadoo.fr>
+ *  Copyright (c) 2004-2005 Stephane VOLTZ      <svoltz@numericable.fr>
+ *
+ *  USB Acecad "Acecad Flair" tablet support
+ *
+ *  Changelog:
+ *      v3.2 - Added sysfs support
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v3.2"
+#define DRIVER_DESC    "USB Acecad Flair tablet driver"
+#define DRIVER_LICENSE "GPL"
+#define DRIVER_AUTHOR  "Edouard TISSERANT <edouard.tisserant@wanadoo.fr>"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_ACECAD   0x0460
+#define USB_DEVICE_ID_FLAIR    0x0004
+#define USB_DEVICE_ID_302      0x0008
+
+struct usb_acecad {
+       char name[128];
+       char phys[64];
+       struct usb_device *usbdev;
+       struct input_dev dev;
+       struct urb *irq;
+
+       signed char *data;
+       dma_addr_t data_dma;
+};
+
+static void usb_acecad_irq(struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_acecad *acecad = urb->context;
+       unsigned char *data = acecad->data;
+       struct input_dev *dev = &acecad->dev;
+       int prox, status;
+
+       switch (urb->status) {
+               case 0:
+                       /* success */
+                       break;
+               case -ECONNRESET:
+               case -ENOENT:
+               case -ESHUTDOWN:
+                       /* this urb is terminated, clean up */
+                       dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+                       return;
+               default:
+                       dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+                       goto resubmit;
+       }
+
+       prox = (data[0] & 0x04) >> 2;
+       input_report_key(dev, BTN_TOOL_PEN, prox);
+
+       if (prox) {
+               int x = data[1] | (data[2] << 8);
+               int y = data[3] | (data[4] << 8);
+               /*Pressure should compute the same way for flair and 302*/
+               int pressure = data[5] | ((int)data[6] << 8);
+               int touch = data[0] & 0x01;
+               int stylus = (data[0] & 0x10) >> 4;
+               int stylus2 = (data[0] & 0x20) >> 5;
+               input_report_abs(dev, ABS_X, x);
+               input_report_abs(dev, ABS_Y, y);
+               input_report_abs(dev, ABS_PRESSURE, pressure);
+               input_report_key(dev, BTN_TOUCH, touch);
+               input_report_key(dev, BTN_STYLUS, stylus);
+               input_report_key(dev, BTN_STYLUS2, stylus2);
+       }
+
+       /* event termination */
+       input_sync(dev);
+
+resubmit:
+       status = usb_submit_urb (urb, GFP_ATOMIC);
+       if (status)
+               err ("can't resubmit intr, %s-%s/input0, status %d",
+                       acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status);
+}
+
+static int usb_acecad_open(struct input_dev *dev)
+{
+       struct usb_acecad *acecad = dev->private;
+
+       acecad->irq->dev = acecad->usbdev;
+       if (usb_submit_urb(acecad->irq, GFP_KERNEL))
+               return -EIO;
+
+       return 0;
+}
+
+static void usb_acecad_close(struct input_dev *dev)
+{
+       struct usb_acecad *acecad = dev->private;
+
+       usb_kill_urb(acecad->irq);
+}
+
+static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_host_interface *interface = intf->cur_altsetting;
+       struct usb_endpoint_descriptor *endpoint;
+       struct usb_acecad *acecad;
+       int pipe, maxp;
+       char path[64];
+
+       if (interface->desc.bNumEndpoints != 1)
+               return -ENODEV;
+
+       endpoint = &interface->endpoint[0].desc;
+
+       if (!(endpoint->bEndpointAddress & 0x80))
+               return -ENODEV;
+
+       if ((endpoint->bmAttributes & 3) != 3)
+               return -ENODEV;
+
+       pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+       maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+       acecad = kcalloc(1, sizeof(struct usb_acecad), GFP_KERNEL);
+       if (!acecad)
+               return -ENOMEM;
+
+       acecad->data = usb_buffer_alloc(dev, 8, SLAB_KERNEL, &acecad->data_dma);
+       if (!acecad->data)
+               goto fail1;
+
+       acecad->irq = usb_alloc_urb(0, GFP_KERNEL);
+       if (!acecad->irq)
+               goto fail2;
+
+       if (dev->manufacturer)
+               strlcpy(acecad->name, dev->manufacturer, sizeof(acecad->name));
+
+       if (dev->product) {
+               if (dev->manufacturer)
+                       strlcat(acecad->name, " ", sizeof(acecad->name));
+               strlcat(acecad->name, dev->product, sizeof(acecad->name));
+       }
+
+       usb_make_path(dev, path, sizeof(path));
+       snprintf(acecad->phys, sizeof(acecad->phys), "%s/input0", path);
+
+       acecad->usbdev = dev;
+
+       acecad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+       acecad->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+       acecad->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+       acecad->dev.keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
+
+       switch (id->driver_info) {
+               case 0:
+                       acecad->dev.absmax[ABS_X] = 5000;
+                       acecad->dev.absmax[ABS_Y] = 3750;
+                       acecad->dev.absmax[ABS_PRESSURE] = 512;
+                       if (!strlen(acecad->name))
+                               snprintf(acecad->name, sizeof(acecad->name),
+                                       "USB Acecad Flair Tablet %04x:%04x",
+                                       dev->descriptor.idVendor, dev->descriptor.idProduct);
+                       break;
+               case 1:
+                       acecad->dev.absmax[ABS_X] = 3000;
+                       acecad->dev.absmax[ABS_Y] = 2250;
+                       acecad->dev.absmax[ABS_PRESSURE] = 1024;
+                       if (!strlen(acecad->name))
+                               snprintf(acecad->name, sizeof(acecad->name),
+                                       "USB Acecad 302 Tablet %04x:%04x",
+                                       dev->descriptor.idVendor, dev->descriptor.idProduct);
+                       break;
+       }
+
+       acecad->dev.absfuzz[ABS_X] = 4;
+       acecad->dev.absfuzz[ABS_Y] = 4;
+
+       acecad->dev.private = acecad;
+       acecad->dev.open = usb_acecad_open;
+       acecad->dev.close = usb_acecad_close;
+
+       acecad->dev.name = acecad->name;
+       acecad->dev.phys = acecad->phys;
+       acecad->dev.id.bustype = BUS_USB;
+       acecad->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
+       acecad->dev.id.product = le16_to_cpu(dev->descriptor.idProduct);
+       acecad->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
+       acecad->dev.dev = &intf->dev;
+
+       usb_fill_int_urb(acecad->irq, dev, pipe,
+                       acecad->data, maxp > 8 ? 8 : maxp,
+                       usb_acecad_irq, acecad, endpoint->bInterval);
+       acecad->irq->transfer_dma = acecad->data_dma;
+       acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       input_register_device(&acecad->dev);
+
+       printk(KERN_INFO "input: %s with packet size %d on %s\n",
+               acecad->name, maxp, path);
+
+       usb_set_intfdata(intf, acecad);
+
+       return 0;
+
+ fail2:        usb_buffer_free(dev, 8, acecad->data, acecad->data_dma);
+ fail1:        kfree(acecad);
+       return -ENOMEM;
+}
+
+static void usb_acecad_disconnect(struct usb_interface *intf)
+{
+       struct usb_acecad *acecad = usb_get_intfdata(intf);
+
+       usb_set_intfdata(intf, NULL);
+       if (acecad) {
+               usb_kill_urb(acecad->irq);
+               input_unregister_device(&acecad->dev);
+               usb_free_urb(acecad->irq);
+               usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma);
+               kfree(acecad);
+       }
+}
+
+static struct usb_device_id usb_acecad_id_table [] = {
+       { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_FLAIR), .driver_info = 0 },
+       { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_302),   .driver_info = 1 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(usb, usb_acecad_id_table);
+
+static struct usb_driver usb_acecad_driver = {
+       .owner =        THIS_MODULE,
+       .name =         "usb_acecad",
+       .probe =        usb_acecad_probe,
+       .disconnect =   usb_acecad_disconnect,
+       .id_table =     usb_acecad_id_table,
+};
+
+static int __init usb_acecad_init(void)
+{
+       int result = usb_register(&usb_acecad_driver);
+       if (result == 0)
+               info(DRIVER_VERSION ":" DRIVER_DESC);
+       return result;
+}
+
+static void __exit usb_acecad_exit(void)
+{
+       usb_deregister(&usb_acecad_driver);
+}
+
+module_init(usb_acecad_init);
+module_exit(usb_acecad_exit);
index e991f7ed73306359828d8ebd4f74f308555c4abe..6bb0f25e8e935a0db0d5a68743740255f8f4e149 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Native support for the Aiptek HyperPen USB Tablets
  *  (4000U/5000U/6000U/8000U/12000U)
- *  
+ *
  *  Copyright (c) 2001      Chris Atenasio   <chris@crud.net>
  *  Copyright (c) 2002-2004 Bryan W. Headley <bwheadley@earthlink.net>
  *
@@ -31,7 +31,7 @@
  *           - Added support for the sysfs interface, deprecating the
  *             procfs interface for 2.5.x kernel. Also added support for
  *             Wheel command. Bryan W. Headley July-15-2003.
- *      v1.2 - Reworked jitter timer as a kernel thread. 
+ *      v1.2 - Reworked jitter timer as a kernel thread.
  *             Bryan W. Headley November-28-2003/Jan-10-2004.
  *      v1.3 - Repaired issue of kernel thread going nuts on single-processor
  *             machines, introduced programmableDelay as a command line
  * NOTE:
  *      This kernel driver is augmented by the "Aiptek" XFree86 input
  *      driver for your X server, as well as the Gaiptek GUI Front-end
- *      "Tablet Manager". 
- *      These three products are highly interactive with one another, 
+ *      "Tablet Manager".
+ *      These three products are highly interactive with one another,
  *      so therefore it's easier to document them all as one subsystem.
- *      Please visit the project's "home page", located at, 
+ *      Please visit the project's "home page", located at,
  *      http://aiptektablet.sourceforge.net.
  *
  * This program is free software; you can redistribute it and/or modify
  * Command/Data    Description     Return Bytes    Return Value
  * 0x10/0x00       SwitchToMouse       0
  * 0x10/0x01       SwitchToTablet      0
- * 0x18/0x04       SetResolution       0 
+ * 0x18/0x04       SetResolution       0
  * 0x12/0xFF       AutoGainOn          0
  * 0x17/0x00       FilterOn            0
  * 0x01/0x00       GetXExtension       2           MaxX
 #define AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE 2
 #define AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED              3
 
-       /* Time to wait (in ms) to help mask hand jittering 
+       /* Time to wait (in ms) to help mask hand jittering
         * when pressing the stylus buttons.
         */
 #define AIPTEK_JITTER_DELAY_DEFAULT                    50
@@ -324,7 +324,6 @@ struct aiptek {
        struct aiptek_settings curSetting;      /* tablet's current programmable */
        struct aiptek_settings newSetting;      /* ... and new param settings    */
        unsigned int ifnum;                     /* interface number for IO       */
-       int openCount;                          /* module use counter            */
        int diagnostic;                         /* tablet diagnostic codes       */
        unsigned long eventCount;               /* event count                   */
        int inDelay;                            /* jitter: in jitter delay?      */
@@ -791,7 +790,7 @@ exit:
  * specific Aiptek model numbers, because there has been overlaps,
  * use, and reuse of id's in existing models. Certain models have
  * been known to use more than one ID, indicative perhaps of
- * manufacturing revisions. In any event, we consider these 
+ * manufacturing revisions. In any event, we consider these
  * IDs to not be model-specific nor unique.
  */
 static const struct usb_device_id aiptek_ids[] = {
@@ -814,15 +813,9 @@ static int aiptek_open(struct input_dev *inputdev)
 {
        struct aiptek *aiptek = inputdev->private;
 
-       if (aiptek->openCount++ > 0) {
-               return 0;
-       }
-
        aiptek->urb->dev = aiptek->usbdev;
-       if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0) {
-               aiptek->openCount--;
+       if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0)
                return -EIO;
-       }
 
        return 0;
 }
@@ -834,13 +827,11 @@ static void aiptek_close(struct input_dev *inputdev)
 {
        struct aiptek *aiptek = inputdev->private;
 
-       if (--aiptek->openCount == 0) {
-               usb_kill_urb(aiptek->urb);
-       }
+       usb_kill_urb(aiptek->urb);
 }
 
 /***********************************************************************
- * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x, 
+ * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x,
  * where they were known as usb_set_report and usb_get_report.
  */
 static int
@@ -2252,7 +2243,6 @@ static void aiptek_disconnect(struct usb_interface *intf)
                                AIPTEK_PACKET_LENGTH,
                                aiptek->data, aiptek->data_dma);
                kfree(aiptek);
-               aiptek = NULL;
        }
 }
 
index 860df26323b163ede689f4b259ff9dcef19e405c..654ac454744db7acd7ddc454ce749f90599d3ce8 100644 (file)
@@ -1,15 +1,15 @@
-/* 
+/*
  *  USB ATI Remote support
  *
  *  Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
  *  Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
  *
  *  This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
- *  porting to the 2.6 kernel interfaces, along with other modification 
+ *  porting to the 2.6 kernel interfaces, along with other modification
  *  to better match the style of the existing usb/input drivers.  However, the
  *  protocol and hardware handling is essentially unchanged from 2.1.1.
- *  
- *  The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by 
+ *
+ *  The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
  *  Vojtech Pavlik.
  *
  *  Changes:
  *            Added support for the "Lola" remote contributed by:
  *                Seth Cohn <sethcohn@yahoo.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 
+ * 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
- * 
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *
  * Hardware & software notes
  *
- * These remote controls are distributed by ATI as part of their 
- * "All-In-Wonder" video card packages.  The receiver self-identifies as a 
+ * These remote controls are distributed by ATI as part of their
+ * "All-In-Wonder" video card packages.  The receiver self-identifies as a
  * "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
  *
- * The "Lola" remote is available from X10.  See: 
+ * The "Lola" remote is available from X10.  See:
  *    http://www.x10.com/products/lola_sg1.htm
  * The Lola is similar to the ATI remote but has no mouse support, and slightly
  * different keys.
  *
- * It is possible to use multiple receivers and remotes on multiple computers 
+ * It is possible to use multiple receivers and remotes on multiple computers
  * simultaneously by configuring them to use specific channels.
- * 
- * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.  
- * Actually, it may even support more, at least in some revisions of the 
+ *
+ * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
+ * Actually, it may even support more, at least in some revisions of the
  * hardware.
  *
  * Each remote can be configured to transmit on one channel as follows:
- *   - Press and hold the "hand icon" button.  
- *   - When the red LED starts to blink, let go of the "hand icon" button. 
- *   - When it stops blinking, input the channel code as two digits, from 01 
+ *   - Press and hold the "hand icon" button.
+ *   - When the red LED starts to blink, let go of the "hand icon" button.
+ *   - When it stops blinking, input the channel code as two digits, from 01
  *     to 16, and press the hand icon again.
- * 
+ *
  * The timing can be a little tricky.  Try loading the module with debug=1
  * to have the kernel print out messages about the remote control number
  * and mask.  Note: debugging prints remote numbers as zero-based hexadecimal.
  *
  * The driver has a "channel_mask" parameter. This bitmask specifies which
- * channels will be ignored by the module.  To mask out channels, just add 
+ * channels will be ignored by the module.  To mask out channels, just add
  * all the 2^channel_number values together.
  *
  * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
- * ignore signals coming from remote controls transmitting on channel 4, but 
+ * ignore signals coming from remote controls transmitting on channel 4, but
  * accept all other channels.
  *
- * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be 
+ * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
  * ignored.
  *
- * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this 
+ * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
  * parameter are unused.
  *
  */
 /*
  * Module and Version Information, Module Parameters
  */
-#define ATI_REMOTE_VENDOR_ID   0x0bc7
-#define ATI_REMOTE_PRODUCT_ID  0x004
-#define LOLA_REMOTE_PRODUCT_ID         0x002
+
+#define ATI_REMOTE_VENDOR_ID   0x0bc7
+#define ATI_REMOTE_PRODUCT_ID  0x004
+#define LOLA_REMOTE_PRODUCT_ID 0x002
 #define MEDION_REMOTE_PRODUCT_ID 0x006
 
-#define DRIVER_VERSION                 "2.2.1"
+#define DRIVER_VERSION         "2.2.1"
 #define DRIVER_AUTHOR           "Torrey Hoffman <thoffman@arnor.net>"
 #define DRIVER_DESC             "ATI/X10 RF USB Remote Control"
 
 #define DATA_BUFSIZE      63    /* size of URB data buffers */
 #define ATI_INPUTNUM      1     /* Which input device to register as */
 
-static unsigned long channel_mask = 0;
+static unsigned long channel_mask;
 module_param(channel_mask, ulong, 0444);
 MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0444);
 MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
 
 #define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
 #undef err
 #define err(format, arg...) printk(KERN_ERR format , ## arg)
+
 static struct usb_device_id ati_remote_table[] = {
        { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
        { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
@@ -148,7 +148,7 @@ static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
 /* Acceleration curve for directional control pad */
 static char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
 
-/* Duplicate event filtering time. 
+/* Duplicate event filtering time.
  * Sequential, identical KIND_FILTERED inputs with less than
  * FILTER_TIME jiffies between them are considered as repeat
  * events. The hardware generates 5 events for the first keypress
@@ -161,10 +161,10 @@ static char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
 static DECLARE_MUTEX(disconnect_sem);
 
 struct ati_remote {
-       struct input_dev idev;          
+       struct input_dev idev;
        struct usb_device *udev;
        struct usb_interface *interface;
-               
+
        struct urb *irq_urb;
        struct urb *out_urb;
        struct usb_endpoint_descriptor *endpoint_in;
@@ -174,13 +174,11 @@ struct ati_remote {
        dma_addr_t inbuf_dma;
        dma_addr_t outbuf_dma;
 
-       int open;                   /* open counter */
-       
        unsigned char old_data[2];  /* Detect duplicate events */
        unsigned long old_jiffies;
        unsigned long acc_jiffies;  /* handle acceleration */
        unsigned int repeat_count;
-       
+
        char name[NAME_BUFSIZE];
        char phys[NAME_BUFSIZE];
 
@@ -206,14 +204,14 @@ static struct
        int type;
        unsigned int code;
        int value;
-}  ati_remote_tbl[] = 
+}  ati_remote_tbl[] =
 {
        /* Directional control pad axes */
        {KIND_ACCEL,   0x35, 0x70, EV_REL, REL_X, -1},   /* left */
        {KIND_ACCEL,   0x36, 0x71, EV_REL, REL_X, 1},    /* right */
        {KIND_ACCEL,   0x37, 0x72, EV_REL, REL_Y, -1},   /* up */
        {KIND_ACCEL,   0x38, 0x73, EV_REL, REL_Y, 1},    /* down */
-       /* Directional control pad diagonals */ 
+       /* Directional control pad diagonals */
        {KIND_LU,      0x39, 0x74, EV_REL, 0, 0},        /* left up */
        {KIND_RU,      0x3a, 0x75, EV_REL, 0, 0},        /* right up */
        {KIND_LD,      0x3c, 0x77, EV_REL, 0, 0},        /* left down */
@@ -225,7 +223,7 @@ static struct
        {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
        {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
 
-       /* Artificial "doubleclick" events are generated by the hardware. 
+       /* Artificial "doubleclick" events are generated by the hardware.
         * They are mapped to the "side" and "extra" mouse buttons here. */
        {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
        {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
@@ -273,15 +271,15 @@ static struct
        {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1},       /* ( >) */
        {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},     /* (<<) */
        {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},    /* (>>) */
-       {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */ 
+       {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */
        {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1},      /* ('') */
        {KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1},   /* (<-) */
        {KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1},       /* (>+) */
        {KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1},       /* PLAYING */
        {KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1},       /* TOP */
        {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1},        /* END */
-       {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1},     /* SELECT */    
-       
+       {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1},     /* SELECT */
+
        {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
 };
 
@@ -315,7 +313,7 @@ static void ati_remote_dump(unsigned char *data, unsigned int len)
        if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
                warn("Weird byte 0x%02x", data[0]);
        else if (len == 4)
-               warn("Weird key %02x %02x %02x %02x", 
+               warn("Weird key %02x %02x %02x %02x",
                     data[0], data[1], data[2], data[3]);
        else
                warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...",
@@ -328,25 +326,16 @@ static void ati_remote_dump(unsigned char *data, unsigned int len)
 static int ati_remote_open(struct input_dev *inputdev)
 {
        struct ati_remote *ati_remote = inputdev->private;
-       int retval = 0;
-
-       down(&disconnect_sem);
-
-       if (ati_remote->open++)
-               goto exit;
 
        /* On first open, submit the read urb which was set up previously. */
        ati_remote->irq_urb->dev = ati_remote->udev;
        if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
-               dev_err(&ati_remote->interface->dev, 
+               dev_err(&ati_remote->interface->dev,
                        "%s: usb_submit_urb failed!\n", __FUNCTION__);
-               ati_remote->open--;
-               retval = -EIO;
+               return -EIO;
        }
 
-exit:
-       up(&disconnect_sem);
-       return retval;
+       return 0;
 }
 
 /*
@@ -355,9 +344,8 @@ exit:
 static void ati_remote_close(struct input_dev *inputdev)
 {
        struct ati_remote *ati_remote = inputdev->private;
-       
-       if (!--ati_remote->open)
-               usb_kill_urb(ati_remote->irq_urb);
+
+       usb_kill_urb(ati_remote->irq_urb);
 }
 
 /*
@@ -366,13 +354,13 @@ static void ati_remote_close(struct input_dev *inputdev)
 static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs)
 {
        struct ati_remote *ati_remote = urb->context;
-       
+
        if (urb->status) {
                dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
                        __FUNCTION__, urb->status);
                return;
        }
-       
+
        ati_remote->send_flags |= SEND_FLAG_COMPLETE;
        wmb();
        wake_up(&ati_remote->wait);
@@ -380,16 +368,16 @@ static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs)
 
 /*
  *     ati_remote_sendpacket
- *             
+ *
  *     Used to send device initialization strings
  */
 static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
 {
        int retval = 0;
-       
+
        /* Set up out_urb */
        memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
-       ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);   
+       ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
 
        ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
        ati_remote->out_urb->dev = ati_remote->udev;
@@ -397,17 +385,17 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigne
 
        retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC);
        if (retval) {
-               dev_dbg(&ati_remote->interface->dev, 
+               dev_dbg(&ati_remote->interface->dev,
                         "sendpacket: usb_submit_urb failed: %d\n", retval);
                return retval;
        }
 
        wait_event_timeout(ati_remote->wait,
                ((ati_remote->out_urb->status != -EINPROGRESS) ||
-                       (ati_remote->send_flags & SEND_FLAG_COMPLETE)),
+                       (ati_remote->send_flags & SEND_FLAG_COMPLETE)),
                HZ);
        usb_kill_urb(ati_remote->out_urb);
-       
+
        return retval;
 }
 
@@ -419,15 +407,15 @@ static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
        int i;
 
        for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
-               /* 
-                * Decide if the table entry matches the remote input. 
+               /*
+                * Decide if the table entry matches the remote input.
                 */
                if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
-                   ((((ati_remote_tbl[i].data1 >> 4) - 
-                      (d1 >> 4) + rem) & 0x0f) == 0x0f) && 
+                   ((((ati_remote_tbl[i].data1 >> 4) -
+                      (d1 >> 4) + rem) & 0x0f) == 0x0f) &&
                    (ati_remote_tbl[i].data2 == d2))
                        return i;
-               
+
        }
        return -1;
 }
@@ -435,16 +423,16 @@ static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
 /*
  *     ati_remote_report_input
  */
-static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)     
+static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
 {
        struct ati_remote *ati_remote = urb->context;
        unsigned char *data= ati_remote->inbuf;
-       struct input_dev *dev = &ati_remote->idev; 
+       struct input_dev *dev = &ati_remote->idev;
        int index, acc;
        int remote_num;
-       
+
        /* Deal with strange looking inputs */
-       if ( (urb->actual_length != 4) || (data[0] != 0x14) || 
+       if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
                ((data[3] & 0x0f) != 0x00) ) {
                ati_remote_dump(data, urb->actual_length);
                return;
@@ -453,7 +441,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
        /* Mask unwanted remote channels.  */
        /* note: remote_num is 0-based, channel 1 on remote == 0 here */
        remote_num = (data[3] >> 4) & 0x0f;
-        if (channel_mask & (1 << (remote_num + 1))) { 
+        if (channel_mask & (1 << (remote_num + 1))) {
                dbginfo(&ati_remote->interface->dev,
                        "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n",
                        remote_num, data[1], data[2], channel_mask);
@@ -463,37 +451,36 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
        /* Look up event code index in translation table */
        index = ati_remote_event_lookup(remote_num, data[1], data[2]);
        if (index < 0) {
-               dev_warn(&ati_remote->interface->dev, 
-                        "Unknown input from channel 0x%02x: data %02x,%02x\n", 
+               dev_warn(&ati_remote->interface->dev,
+                        "Unknown input from channel 0x%02x: data %02x,%02x\n",
                         remote_num, data[1], data[2]);
                return;
-       } 
-       dbginfo(&ati_remote->interface->dev, 
+       }
+       dbginfo(&ati_remote->interface->dev,
                "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
                remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
-       
+
        if (ati_remote_tbl[index].kind == KIND_LITERAL) {
                input_regs(dev, regs);
                input_event(dev, ati_remote_tbl[index].type,
                        ati_remote_tbl[index].code,
                        ati_remote_tbl[index].value);
                input_sync(dev);
-               
+
                ati_remote->old_jiffies = jiffies;
                return;
        }
-       
+
        if (ati_remote_tbl[index].kind == KIND_FILTERED) {
                /* Filter duplicate events which happen "too close" together. */
-               if ((ati_remote->old_data[0] == data[1]) && 
-                       (ati_remote->old_data[1] == data[2]) && 
-                       ((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) {
+               if ((ati_remote->old_data[0] == data[1]) &&
+                       (ati_remote->old_data[1] == data[2]) &&
+                       ((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) {
                        ati_remote->repeat_count++;
-               } 
-               else {
+               } else {
                        ati_remote->repeat_count = 0;
                }
-               
+
                ati_remote->old_data[0] = data[1];
                ati_remote->old_data[1] = data[2];
                ati_remote->old_jiffies = jiffies;
@@ -501,7 +488,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
                if ((ati_remote->repeat_count > 0)
                    && (ati_remote->repeat_count < 5))
                        return;
-               
+
 
                input_regs(dev, regs);
                input_event(dev, ati_remote_tbl[index].type,
@@ -511,13 +498,13 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
                input_sync(dev);
 
                return;
-       }                       
-       
-       /* 
+       }
+
+       /*
         * Other event kinds are from the directional control pad, and have an
         * acceleration factor applied to them.  Without this acceleration, the
         * control pad is mostly unusable.
-        * 
+        *
         * If elapsed time since last event is > 1/4 second, user "stopped",
         * so reset acceleration. Otherwise, user is probably holding the control
         * pad down, so we increase acceleration, ramping up over two seconds to
@@ -559,7 +546,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
                input_report_rel(dev, REL_Y, acc);
                break;
        default:
-               dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", 
+               dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
                        ati_remote_tbl[index].kind);
        }
        input_sync(dev);
@@ -586,12 +573,12 @@ static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs)
        case -ESHUTDOWN:
                dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n",
                        __FUNCTION__);
-               return; 
+               return;
        default:                /* error */
-               dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", 
+               dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n",
                        __FUNCTION__, urb->status);
        }
-       
+
        retval = usb_submit_urb(urb, SLAB_ATOMIC);
        if (retval)
                dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
@@ -603,8 +590,6 @@ static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs)
  */
 static void ati_remote_delete(struct ati_remote *ati_remote)
 {
-       if (!ati_remote) return;
-
        if (ati_remote->irq_urb)
                usb_kill_urb(ati_remote->irq_urb);
 
@@ -614,16 +599,16 @@ static void ati_remote_delete(struct ati_remote *ati_remote)
        input_unregister_device(&ati_remote->idev);
 
        if (ati_remote->inbuf)
-               usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, 
+               usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
                                ati_remote->inbuf, ati_remote->inbuf_dma);
-               
+
        if (ati_remote->outbuf)
-               usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, 
+               usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
                                ati_remote->outbuf, ati_remote->outbuf_dma);
-       
+
        if (ati_remote->irq_urb)
                usb_free_urb(ati_remote->irq_urb);
-       
+
        if (ati_remote->out_urb)
                usb_free_urb(ati_remote->out_urb);
 
@@ -636,51 +621,52 @@ static void ati_remote_input_init(struct ati_remote *ati_remote)
        int i;
 
        idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
-       idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) | 
+       idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
                                          BIT(BTN_SIDE) | BIT(BTN_EXTRA) );
        idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
        for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
                if (ati_remote_tbl[i].type == EV_KEY)
                        set_bit(ati_remote_tbl[i].code, idev->keybit);
-       
+
        idev->private = ati_remote;
        idev->open = ati_remote_open;
        idev->close = ati_remote_close;
-       
+
        idev->name = ati_remote->name;
        idev->phys = ati_remote->phys;
-       
-       idev->id.bustype = BUS_USB;             
+
+       idev->id.bustype = BUS_USB;
        idev->id.vendor = le16_to_cpu(ati_remote->udev->descriptor.idVendor);
        idev->id.product = le16_to_cpu(ati_remote->udev->descriptor.idProduct);
        idev->id.version = le16_to_cpu(ati_remote->udev->descriptor.bcdDevice);
+       idev->dev = &(ati_remote->udev->dev);
 }
 
 static int ati_remote_initialize(struct ati_remote *ati_remote)
 {
        struct usb_device *udev = ati_remote->udev;
        int pipe, maxp;
-               
+
        init_waitqueue_head(&ati_remote->wait);
 
        /* Set up irq_urb */
        pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
        maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
        maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
-       
-       usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf, 
-                        maxp, ati_remote_irq_in, ati_remote, 
+
+       usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
+                        maxp, ati_remote_irq_in, ati_remote,
                         ati_remote->endpoint_in->bInterval);
        ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
        ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-       
+
        /* Set up out_urb */
        pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
        maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
        maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
 
-       usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf, 
-                        maxp, ati_remote_irq_out, ati_remote, 
+       usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
+                        maxp, ati_remote_irq_out, ati_remote,
                         ati_remote->endpoint_out->bInterval);
        ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
        ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@@ -688,11 +674,11 @@ static int ati_remote_initialize(struct ati_remote *ati_remote)
        /* send initialization strings */
        if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
            (ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
-               dev_err(&ati_remote->interface->dev, 
+               dev_err(&ati_remote->interface->dev,
                         "Initializing ati_remote hardware failed.\n");
                return 1;
        }
-       
+
        return 0;
 }
 
@@ -769,7 +755,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
 
        if (!strlen(ati_remote->name))
                sprintf(ati_remote->name, DRIVER_DESC "(%04x,%04x)",
-                       le16_to_cpu(ati_remote->udev->descriptor.idVendor), 
+                       le16_to_cpu(ati_remote->udev->descriptor.idVendor),
                        le16_to_cpu(ati_remote->udev->descriptor.idProduct));
 
        /* Device Hardware Initialization - fills in ati_remote->idev from udev. */
@@ -781,11 +767,11 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
        ati_remote_input_init(ati_remote);
        input_register_device(&ati_remote->idev);
 
-       dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n", 
+       dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n",
                 ati_remote->name, path);
 
        usb_set_intfdata(interface, ati_remote);
-       
+
 error:
        if (retval)
                ati_remote_delete(ati_remote);
@@ -800,18 +786,14 @@ static void ati_remote_disconnect(struct usb_interface *interface)
 {
        struct ati_remote *ati_remote;
 
-       down(&disconnect_sem);
-
        ati_remote = usb_get_intfdata(interface);
        usb_set_intfdata(interface, NULL);
        if (!ati_remote) {
                warn("%s - null device?\n", __FUNCTION__);
                return;
        }
-       
-       ati_remote_delete(ati_remote);
 
-       up(&disconnect_sem);
+       ati_remote_delete(ati_remote);
 }
 
 /*
@@ -820,7 +802,7 @@ static void ati_remote_disconnect(struct usb_interface *interface)
 static int __init ati_remote_init(void)
 {
        int result;
-       
+
        result = usb_register(&ati_remote_driver);
        if (result)
                err("usb_register error #%d\n", result);
@@ -838,8 +820,8 @@ static void __exit ati_remote_exit(void)
        usb_deregister(&ati_remote_driver);
 }
 
-/* 
- *     module specification 
+/*
+ *     module specification
  */
 
 module_init(ati_remote_init);
index 740dec1f521dde53d3ae480d0f61418b7f1d1eef..100b49bd1d3e0bf8730d98d52ffa3ff01eacdadd 100644 (file)
@@ -232,7 +232,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
        report->size += parser->global.report_size * parser->global.report_count;
 
        if (!parser->local.usage_index) /* Ignore padding fields */
-               return 0; 
+               return 0;
 
        usages = max_t(int, parser->local.usage_index, parser->global.report_count);
 
@@ -765,7 +765,7 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n)
 static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
 {
        report += (offset >> 5) << 2; offset &= 31;
-       return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1 << n) - 1);
+       return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1ULL << n) - 1);
 }
 
 static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
@@ -1233,6 +1233,13 @@ int hid_wait_io(struct hid_device *hid)
        return 0;
 }
 
+static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle)
+{
+       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report,
+               ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
 static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
                unsigned char type, void *buf, int size)
 {
@@ -1301,10 +1308,6 @@ void hid_init_reports(struct hid_device *hid)
 
        if (err)
                warn("timeout initializing reports\n");
-
-       usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
-               HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
-               hid->ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
 }
 
 #define USB_VENDOR_ID_WACOM            0x056a
@@ -1318,6 +1321,10 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_DEVICE_ID_WACOM_INTUOS3    0x00B0
 #define USB_DEVICE_ID_WACOM_CINTIQ     0x003F
 
+#define USB_VENDOR_ID_ACECAD           0x0460
+#define USB_DEVICE_ID_ACECAD_FLAIR     0x0004
+#define USB_DEVICE_ID_ACECAD_302       0x0008
+
 #define USB_VENDOR_ID_KBGEAR           0x084e
 #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
 
@@ -1502,6 +1509,9 @@ static struct hid_blacklist {
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
 
+       { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
+
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
@@ -1590,6 +1600,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
                return NULL;
        }
 
+       hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
+
        if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
                dbg("reading report descriptor failed");
                kfree(rdesc);
@@ -1635,7 +1647,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
                /* Change the polling interval of mice. */
                if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
                        interval = hid_mousepoll_interval;
-               
+
                if (endpoint->bEndpointAddress & USB_DIR_IN) {
                        if (hid->urbin)
                                continue;
index 2b91705740a730ca4334d34aea3e845abb01450d..52437e5e2e7806fa20a81ae67c733ac0dec5d9be 100644 (file)
@@ -67,7 +67,7 @@ static const struct hid_usage_entry hid_usage_table[] = {
       {0, 0x44, "Vbry"},
       {0, 0x45, "Vbrz"},
       {0, 0x46, "Vno"},
-    {0, 0x80, "SystemControl"}, 
+    {0, 0x80, "SystemControl"},
       {0, 0x81, "SystemPowerDown"},
       {0, 0x82, "SystemSleep"},
       {0, 0x83, "SystemWakeUp"},
@@ -347,7 +347,7 @@ __inline__ static void tab(int n) {
 
 static void hid_dump_field(struct hid_field *field, int n) {
        int j;
-       
+
        if (field->physical) {
                tab(n);
                printk("Physical(");
@@ -408,7 +408,7 @@ static void hid_dump_field(struct hid_field *field, int n) {
                                        printk("%s", units[sys][i]);
                                        if(nibble != 1) {
                                                /* This is a _signed_ nibble(!) */
-       
+
                                                int val = nibble & 0x7;
                                                if(nibble & 0x08)
                                                        val = -((0x7 & ~val) +1);
@@ -443,7 +443,7 @@ static void __attribute__((unused)) hid_dump_device(struct hid_device *device) {
        struct list_head *list;
        unsigned i,k;
        static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
-       
+
        for (i = 0; i < HID_REPORT_TYPES; i++) {
                report_enum = device->report_enum + i;
                list = report_enum->report_list.next;
@@ -664,8 +664,8 @@ static char *keys[KEY_MAX + 1] = {
 static char *relatives[REL_MAX + 1] = {
        [REL_X] = "X",                  [REL_Y] = "Y",
        [REL_Z] = "Z",                  [REL_HWHEEL] = "HWheel",
-       [REL_DIAL] = "Dial",            [REL_WHEEL] = "Wheel", 
-       [REL_MISC] = "Misc",    
+       [REL_DIAL] = "Dial",            [REL_WHEEL] = "Wheel",
+       [REL_MISC] = "Misc",
 };
 
 static char *absolutes[ABS_MAX + 1] = {
@@ -690,9 +690,9 @@ static char *misc[MSC_MAX + 1] = {
 };
 
 static char *leds[LED_MAX + 1] = {
-       [LED_NUML] = "NumLock",         [LED_CAPSL] = "CapsLock", 
+       [LED_NUML] = "NumLock",         [LED_CAPSL] = "CapsLock",
        [LED_SCROLLL] = "ScrollLock",   [LED_COMPOSE] = "Compose",
-       [LED_KANA] = "Kana",            [LED_SLEEP] = "Sleep", 
+       [LED_KANA] = "Kana",            [LED_SLEEP] = "Sleep",
        [LED_SUSPEND] = "Suspend",      [LED_MUTE] = "Mute",
        [LED_MISC] = "Misc",
 };
index 5553c3553e9d12825b29f424678f528e4c50f525..9ac1e90953347e1171f66a9316c9734b79db589b 100644 (file)
@@ -164,7 +164,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
                                case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
                                case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
-                                       if (field->flags & HID_MAIN_ITEM_RELATIVE) 
+                                       if (field->flags & HID_MAIN_ITEM_RELATIVE)
                                                map_rel(usage->hid & 0xf);
                                        else
                                                map_abs(usage->hid & 0xf);
@@ -297,7 +297,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                case HID_UP_MSVENDOR:
 
                        goto ignore;
-                       
+
                case HID_UP_PID:
 
                        set_bit(EV_FF, input->evbit);
@@ -349,7 +349,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                goto ignore;
 
        if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
-                (usage->type == EV_REL) && (usage->code == REL_WHEEL)) 
+                (usage->type == EV_REL) && (usage->code == REL_WHEEL))
                        set_bit(REL_HWHEEL, bit);
 
        if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
@@ -365,11 +365,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                        a = field->logical_minimum = 0;
                        b = field->logical_maximum = 255;
                }
-               
+
                if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK)
                        input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
                else    input_set_abs_params(input, usage->code, a, b, 0, 0);
-               
+
        }
 
        if (usage->hat_min < usage->hat_max || usage->hat_dir) {
@@ -420,7 +420,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
                return;
        }
 
-       if (usage->hat_min < usage->hat_max || usage->hat_dir) { 
+       if (usage->hat_min < usage->hat_max || usage->hat_dir) {
                int hat_dir = usage->hat_dir;
                if (!hat_dir)
                        hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
@@ -551,7 +551,7 @@ int hidinput_connect(struct hid_device *hid)
        for (i = 0; i < hid->maxcollection; i++)
                if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
                    hid->collection[i].type == HID_COLLECTION_PHYSICAL)
-                       if (IS_INPUT_APPLICATION(hid->collection[i].usage))
+                       if (IS_INPUT_APPLICATION(hid->collection[i].usage))
                                break;
 
        if (i == hid->maxcollection)
@@ -592,7 +592,7 @@ int hidinput_connect(struct hid_device *hid)
                                for (j = 0; j < report->field[i]->maxusage; j++)
                                        hidinput_configure_usage(hidinput, report->field[i],
                                                                 report->field[i]->usage + j);
-                       
+
                        if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
                                /* This will leave hidinput NULL, so that it
                                 * allocates another one if we have more inputs on
index 0d7404bab92f7236f5d21506f74aaccb9c534666..0c4c77aa31eac7731a0ec21f5313978016dfbc03 100644 (file)
@@ -94,7 +94,7 @@ struct lgff_device {
                                        isn't really necessary */
 
        unsigned long flags[1];      /* Contains various information about the
-                                       state of the driver for this device */  
+                                       state of the driver for this device */
 
        struct timer_list timer;
 };
@@ -234,7 +234,7 @@ static struct hid_report* hid_lgff_duplicate_report(struct hid_report* report)
                kfree(ret);
                return NULL;
        }
-       memset(ret->field[0]->value, 0, sizeof(s32[8]));        
+       memset(ret->field[0]->value, 0, sizeof(s32[8]));
 
        return ret;
 }
@@ -295,11 +295,11 @@ static int hid_lgff_event(struct hid_device *hid, struct input_dev* input,
        unsigned long flags;
 
        if (type != EV_FF)                     return -EINVAL;
-               if (!LGFF_CHECK_OWNERSHIP(code, lgff)) return -EACCES;
+       if (!LGFF_CHECK_OWNERSHIP(code, lgff)) return -EACCES;
        if (value < 0)                         return -EINVAL;
 
        spin_lock_irqsave(&lgff->lock, flags);
-       
+
        if (value > 0) {
                if (test_bit(EFFECT_STARTED, effect->flags)) {
                        spin_unlock_irqrestore(&lgff->lock, flags);
@@ -345,7 +345,7 @@ static int hid_lgff_flush(struct input_dev *dev, struct file *file)
                  and perform ioctls on the same fd all at the same time */
                if ( current->pid == lgff->effects[i].owner
                     && test_bit(EFFECT_USED, lgff->effects[i].flags)) {
-                       
+
                        if (hid_lgff_erase(dev, i))
                                warn("erase effect %d failed", i);
                }
@@ -378,7 +378,7 @@ static int hid_lgff_upload_effect(struct input_dev* input,
        struct lgff_effect new;
        int id;
        unsigned long flags;
-       
+
        dbg("ioctl rumble");
 
        if (!test_bit(effect->type, input->ffbit)) return -EINVAL;
@@ -441,7 +441,7 @@ static void hid_lgff_timer(unsigned long timer_data)
 
        spin_lock_irqsave(&lgff->lock, flags);
 
-       for (i=0; i<LGFF_EFFECTS; ++i) {
+       for (i=0; i<LGFF_EFFECTS; ++i) {
                struct lgff_effect* effect = lgff->effects +i;
 
                if (test_bit(EFFECT_PLAYING, effect->flags)) {
@@ -491,7 +491,7 @@ static void hid_lgff_timer(unsigned long timer_data)
                                set_bit(EFFECT_PLAYING, lgff->effects[i].flags);
                        }
                }
-       }
+       }
 
 #define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
 
@@ -524,5 +524,5 @@ static void hid_lgff_timer(unsigned long timer_data)
                add_timer(&lgff->timer);
        }
 
-       spin_unlock_irqrestore(&lgff->lock, flags);
+       spin_unlock_irqrestore(&lgff->lock, flags);
 }
index 6d9329c698d90bfbe5347aa85f00ad0655b1635d..c1b6b69bc4a46979eca2f9b31a6922f9de34f313 100644 (file)
@@ -118,7 +118,7 @@ struct hid_item {
 #define HID_MAIN_ITEM_CONSTANT         0x001
 #define HID_MAIN_ITEM_VARIABLE         0x002
 #define HID_MAIN_ITEM_RELATIVE         0x004
-#define HID_MAIN_ITEM_WRAP             0x008   
+#define HID_MAIN_ITEM_WRAP             0x008
 #define HID_MAIN_ITEM_NONLINEAR                0x010
 #define HID_MAIN_ITEM_NO_PREFERRED     0x020
 #define HID_MAIN_ITEM_NULL_STATE       0x040
@@ -172,14 +172,14 @@ struct hid_item {
 #define HID_USAGE_PAGE         0xffff0000
 
 #define HID_UP_UNDEFINED       0x00000000
-#define HID_UP_GENDESK                 0x00010000
-#define HID_UP_KEYBOARD        0x00070000
-#define HID_UP_LED             0x00080000
-#define HID_UP_BUTTON          0x00090000
-#define HID_UP_ORDINAL                 0x000a0000
+#define HID_UP_GENDESK         0x00010000
+#define HID_UP_KEYBOARD                0x00070000
+#define HID_UP_LED             0x00080000
+#define HID_UP_BUTTON          0x00090000
+#define HID_UP_ORDINAL         0x000a0000
 #define HID_UP_CONSUMER                0x000c0000
-#define HID_UP_DIGITIZER       0x000d0000
-#define HID_UP_PID             0x000f0000
+#define HID_UP_DIGITIZER       0x000d0000
+#define HID_UP_PID             0x000f0000
 #define HID_UP_HPVENDOR         0xff7f0000
 #define HID_UP_MSVENDOR                0xff000000
 
@@ -406,7 +406,7 @@ struct hid_device {                                                 /* device report descriptor */
        dma_addr_t outbuf_dma;                                          /* Output buffer dma */
        spinlock_t outlock;                                             /* Output fifo spinlock */
 
-       unsigned claimed;                                               /* Claimed by hidinput, hiddev? */      
+       unsigned claimed;                                               /* Claimed by hidinput, hiddev? */
        unsigned quirks;                                                /* Various quirks the device can pull on us */
 
        struct list_head inputs;                                        /* The list of inputs */
index 96b7c9067951dd32cc6b0a3362c99b2586f6b722..4c13331b5f41d0694f3e44356e92af540de2192d 100644 (file)
@@ -95,7 +95,7 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
                        return NULL;
                rinfo->report_id = ((struct hid_report *) list)->id;
                break;
-               
+
        case HID_REPORT_ID_NEXT:
                list = (struct list_head *)
                        report_enum->report_id_hash[rinfo->report_id & HID_REPORT_ID_MASK];
@@ -106,7 +106,7 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
                        return NULL;
                rinfo->report_id = ((struct hid_report *) list)->id;
                break;
-               
+
        default:
                return NULL;
        }
@@ -158,7 +158,7 @@ static void hiddev_send_event(struct hid_device *hid,
                if (uref->field_index != HID_FIELD_INDEX_NONE ||
                    (list->flags & HIDDEV_FLAG_REPORT) != 0) {
                        list->buffer[list->head] = *uref;
-                       list->head = (list->head + 1) & 
+                       list->head = (list->head + 1) &
                                (HIDDEV_BUFFER_SIZE - 1);
                        kill_fasync(&list->fasync, SIGIO, POLL_IN);
                }
@@ -179,9 +179,9 @@ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
        unsigned type = field->report_type;
        struct hiddev_usage_ref uref;
 
-       uref.report_type = 
+       uref.report_type =
          (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
-         ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : 
+         ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
           ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0));
        uref.report_id = field->report->id;
        uref.field_index = field->index;
@@ -199,9 +199,9 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
        struct hiddev_usage_ref uref;
 
        memset(&uref, 0, sizeof(uref));
-       uref.report_type = 
+       uref.report_type =
          (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
-         ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : 
+         ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
           ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0));
        uref.report_id = report->id;
        uref.field_index = HID_FIELD_INDEX_NONE;
@@ -236,7 +236,7 @@ static int hiddev_release(struct inode * inode, struct file * file)
        *listptr = (*listptr)->next;
 
        if (!--list->hiddev->open) {
-               if (list->hiddev->exist) 
+               if (list->hiddev->exist)
                        hid_close(list->hiddev->hid);
                else
                        kfree(list->hiddev);
@@ -303,7 +303,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
                if (list->head == list->tail) {
                        add_wait_queue(&list->hiddev->wait, &wait);
                        set_current_state(TASK_INTERRUPTIBLE);
-                       
+
                        while (list->head == list->tail) {
                                if (file->f_flags & O_NONBLOCK) {
                                        retval = -EAGAIN;
@@ -317,7 +317,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
                                        retval = -EIO;
                                        break;
                                }
-                               
+
                                schedule();
                        }
 
@@ -329,7 +329,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
                        return retval;
 
 
-               while (list->head != list->tail && 
+               while (list->head != list->tail &&
                       retval + event_size <= count) {
                        if ((list->flags & HIDDEV_FLAG_UREF) == 0) {
                                if (list->buffer[list->tail].field_index !=
@@ -405,10 +405,10 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                        return -EINVAL;
 
                for (i = 0; i < hid->maxcollection; i++)
-                       if (hid->collection[i].type == 
+                       if (hid->collection[i].type ==
                            HID_COLLECTION_APPLICATION && arg-- == 0)
                                break;
-               
+
                if (i == hid->maxcollection)
                        return -EINVAL;
 
@@ -562,7 +562,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                if (!uref_multi)
                        return -ENOMEM;
                uref = &uref_multi->uref;
-               if (copy_from_user(uref, user_arg, sizeof(*uref))) 
+               if (copy_from_user(uref, user_arg, sizeof(*uref)))
                        goto fault;
 
                rinfo.report_type = uref->report_type;
@@ -595,7 +595,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                        return -ENOMEM;
                uref = &uref_multi->uref;
                if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
-                       if (copy_from_user(uref_multi, user_arg, 
+                       if (copy_from_user(uref_multi, user_arg,
                                           sizeof(*uref_multi)))
                                goto fault;
                } else {
@@ -603,7 +603,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                                goto fault;
                }
 
-               if (cmd != HIDIOCGUSAGE && 
+               if (cmd != HIDIOCGUSAGE &&
                    cmd != HIDIOCGUSAGES &&
                    uref->report_type == HID_REPORT_TYPE_INPUT)
                        goto inval;
@@ -651,16 +651,16 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                                return field->usage[uref->usage_index].collection_index;
                        case HIDIOCGUSAGES:
                                for (i = 0; i < uref_multi->num_values; i++)
-                                       uref_multi->values[i] = 
+                                       uref_multi->values[i] =
                                            field->value[uref->usage_index + i];
-                               if (copy_to_user(user_arg, uref_multi, 
+                               if (copy_to_user(user_arg, uref_multi,
                                                 sizeof(*uref_multi)))
                                        goto fault;
                                goto goodreturn;
                        case HIDIOCSUSAGES:
                                for (i = 0; i < uref_multi->num_values; i++)
-                                       field->value[uref->usage_index + i] = 
-                                           uref_multi->values[i];
+                                       field->value[uref->usage_index + i] =
+                                           uref_multi->values[i];
                                goto goodreturn;
                }
 
@@ -670,7 +670,7 @@ goodreturn:
 fault:
                kfree(uref_multi);
                return -EFAULT;
-inval:         
+inval:
                kfree(uref_multi);
                return -EINVAL;
 
@@ -734,7 +734,7 @@ static struct usb_class_driver hiddev_class = {
        .name =         "usb/hid/hiddev%d",
        .fops =         &hiddev_fops,
        .mode =         S_IFCHR | S_IRUGO | S_IWUSR,
-               .minor_base =   HIDDEV_MINOR_BASE,
+       .minor_base =   HIDDEV_MINOR_BASE,
 };
 
 /*
@@ -747,7 +747,7 @@ int hiddev_connect(struct hid_device *hid)
        int retval;
 
        for (i = 0; i < hid->maxcollection; i++)
-               if (hid->collection[i].type == 
+               if (hid->collection[i].type ==
                    HID_COLLECTION_APPLICATION &&
                    !IS_INPUT_APPLICATION(hid->collection[i].usage))
                        break;
@@ -755,11 +755,11 @@ int hiddev_connect(struct hid_device *hid)
        if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
                return -1;
 
-       if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
+       if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
                return -1;
        memset(hiddev, 0, sizeof(struct hiddev));
 
-       retval = usb_register_dev(hid->intf, &hiddev_class);
+       retval = usb_register_dev(hid->intf, &hiddev_class);
        if (retval) {
                err("Not able to get a minor for this device.");
                kfree(hiddev);
@@ -768,12 +768,12 @@ int hiddev_connect(struct hid_device *hid)
 
        init_waitqueue_head(&hiddev->wait);
 
-       hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
+       hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
 
        hiddev->hid = hid;
        hiddev->exist = 1;
 
-       hid->minor = hid->intf->minor;
+       hid->minor = hid->intf->minor;
        hid->hiddev = hiddev;
 
        return 0;
@@ -818,7 +818,7 @@ void hiddev_disconnect(struct hid_device *hid)
 /* We never attach in this manner, and rely on HID to connect us.  This
  * is why there is no disconnect routine defined in the usb_driver either.
  */
-static int hiddev_usbd_probe(struct usb_interface *intf, 
+static int hiddev_usbd_probe(struct usb_interface *intf,
                             const struct usb_device_id *hiddev_info)
 {
        return -ENODEV;
diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c
new file mode 100644 (file)
index 0000000..47dec6a
--- /dev/null
@@ -0,0 +1,268 @@
+/******************************************************************************
+ * itmtouch.c  --  Driver for ITM touchscreen panel
+ *
+ * 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.
+ *
+ * Based upon original work by Chris Collins <xfire-itmtouch@xware.cx>.
+ *
+ * Kudos to ITM for providing me with the datasheet for the panel,
+ * even though it was a day later than I had finished writing this
+ * driver.
+ *
+ * It has meant that I've been able to correct my interpretation of the
+ * protocol packets however.
+ *
+ * CC -- 2003/9/29
+ *
+ * History
+ * 1.0 & 1.1  2003 (CC) vojtech@suse.cz
+ *   Original version for 2.4.x kernels
+ *
+ * 1.2  02/03/2005 (HCE) hc@mivu.no
+ *   Complete rewrite to support Linux 2.6.10, thanks to mtouchusb.c for hints.
+ *   Unfortunately no calibration support at this time.
+ *
+ * 1.2.1  09/03/2005 (HCE) hc@mivu.no
+ *   Code cleanup and adjusting syntax to start matching kernel standards
+ *
+ *****************************************************************************/
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_DEBUG
+       #define DEBUG
+#else
+       #undef DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+/* only an 8 byte buffer necessary for a single packet */
+#define ITM_BUFSIZE                    8
+#define PATH_SIZE                      64
+
+#define USB_VENDOR_ID_ITMINC           0x0403
+#define USB_PRODUCT_ID_TOUCHPANEL      0xf9e9
+
+#define DRIVER_AUTHOR "Hans-Christian Egtvedt <hc@mivu.no>"
+#define DRIVER_VERSION "v1.2.1"
+#define DRIVER_DESC "USB ITM Inc Touch Panel Driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE( DRIVER_LICENSE );
+
+struct itmtouch_dev {
+       struct usb_device       *usbdev; /* usb device */
+       struct input_dev        inputdev; /* input device */
+       struct urb              *readurb; /* urb */
+       char                    rbuf[ITM_BUFSIZE]; /* data */
+       int                     users;
+       char name[128];
+       char phys[64];
+};
+
+static struct usb_device_id itmtouch_ids [] = {
+       { USB_DEVICE(USB_VENDOR_ID_ITMINC, USB_PRODUCT_ID_TOUCHPANEL) },
+       { }
+};
+
+static void itmtouch_irq(struct urb *urb, struct pt_regs *regs)
+{
+       struct itmtouch_dev * itmtouch = urb->context;
+       unsigned char *data = urb->transfer_buffer;
+       struct input_dev *dev = &itmtouch->inputdev;
+       int retval;
+
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -ETIMEDOUT:
+               /* this urb is timing out */
+               dbg("%s - urb timed out - was the device unplugged?",
+                   __FUNCTION__);
+               return;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d",
+                   __FUNCTION__, urb->status);
+               return;
+       default:
+               dbg("%s - nonzero urb status received: %d",
+                   __FUNCTION__, urb->status);
+               goto exit;
+       }
+
+       input_regs(dev, regs);
+
+       /* if pressure has been released, then don't report X/Y */
+       if (data[7] & 0x20) {
+               input_report_abs(dev, ABS_X, (data[0] & 0x1F) << 7 | (data[3] & 0x7F));
+               input_report_abs(dev, ABS_Y, (data[1] & 0x1F) << 7 | (data[4] & 0x7F));
+       }
+
+       input_report_abs(dev, ABS_PRESSURE, (data[2] & 1) << 7 | (data[5] & 0x7F));
+       input_report_key(dev, BTN_TOUCH, ~data[7] & 0x20);
+       input_sync(dev);
+
+exit:
+       retval = usb_submit_urb (urb, GFP_ATOMIC);
+       if (retval)
+               printk(KERN_ERR "%s - usb_submit_urb failed with result: %d",
+                               __FUNCTION__, retval);
+}
+
+static int itmtouch_open(struct input_dev *input)
+{
+       struct itmtouch_dev *itmtouch = input->private;
+
+       itmtouch->readurb->dev = itmtouch->usbdev;
+
+       if (usb_submit_urb(itmtouch->readurb, GFP_KERNEL))
+               return -EIO;
+
+       return 0;
+}
+
+static void itmtouch_close(struct input_dev *input)
+{
+       struct itmtouch_dev *itmtouch = input->private;
+
+       usb_kill_urb(itmtouch->readurb);
+}
+
+static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct itmtouch_dev *itmtouch;
+       struct usb_host_interface *interface;
+       struct usb_endpoint_descriptor *endpoint;
+       struct usb_device *udev = interface_to_usbdev(intf);
+       unsigned int pipe;
+       unsigned int maxp;
+       char path[PATH_SIZE];
+
+       interface = intf->cur_altsetting;
+       endpoint = &interface->endpoint[0].desc;
+
+       if (!(itmtouch = kcalloc(1, sizeof(struct itmtouch_dev), GFP_KERNEL))) {
+               err("%s - Out of memory.", __FUNCTION__);
+               return -ENOMEM;
+       }
+
+       itmtouch->usbdev = udev;
+
+       itmtouch->inputdev.private = itmtouch;
+       itmtouch->inputdev.open = itmtouch_open;
+       itmtouch->inputdev.close = itmtouch_close;
+
+       usb_make_path(udev, path, PATH_SIZE);
+
+       itmtouch->inputdev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+       itmtouch->inputdev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+       itmtouch->inputdev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+       itmtouch->inputdev.name = itmtouch->name;
+       itmtouch->inputdev.phys = itmtouch->phys;
+       itmtouch->inputdev.id.bustype = BUS_USB;
+       itmtouch->inputdev.id.vendor = udev->descriptor.idVendor;
+       itmtouch->inputdev.id.product = udev->descriptor.idProduct;
+       itmtouch->inputdev.id.version = udev->descriptor.bcdDevice;
+       itmtouch->inputdev.dev = &intf->dev;
+
+       if (!strlen(itmtouch->name))
+               sprintf(itmtouch->name, "USB ITM touchscreen");
+
+       /* device limits */
+       /* as specified by the ITM datasheet, X and Y are 12bit,
+        * Z (pressure) is 8 bit. However, the fields are defined up
+        * to 14 bits for future possible expansion.
+        */
+       input_set_abs_params(&itmtouch->inputdev, ABS_X, 0, 0x0FFF, 2, 0);
+       input_set_abs_params(&itmtouch->inputdev, ABS_Y, 0, 0x0FFF, 2, 0);
+       input_set_abs_params(&itmtouch->inputdev, ABS_PRESSURE, 0, 0xFF, 2, 0);
+
+       /* initialise the URB so we can read from the transport stream */
+       pipe = usb_rcvintpipe(itmtouch->usbdev, endpoint->bEndpointAddress);
+       maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+
+       if (maxp > ITM_BUFSIZE)
+               maxp = ITM_BUFSIZE;
+
+       itmtouch->readurb = usb_alloc_urb(0, GFP_KERNEL);
+
+       if (!itmtouch->readurb) {
+               dbg("%s - usb_alloc_urb failed: itmtouch->readurb", __FUNCTION__);
+               kfree(itmtouch);
+               return -ENOMEM;
+       }
+
+       usb_fill_int_urb(itmtouch->readurb, itmtouch->usbdev, pipe, itmtouch->rbuf,
+                        maxp, itmtouch_irq, itmtouch, endpoint->bInterval);
+
+       input_register_device(&itmtouch->inputdev);
+
+       printk(KERN_INFO "itmtouch: %s registered on %s\n", itmtouch->name, path);
+       usb_set_intfdata(intf, itmtouch);
+
+       return 0;
+}
+
+static void itmtouch_disconnect(struct usb_interface *intf)
+{
+       struct itmtouch_dev *itmtouch = usb_get_intfdata(intf);
+
+       usb_set_intfdata(intf, NULL);
+
+       if (itmtouch) {
+               input_unregister_device(&itmtouch->inputdev);
+               usb_kill_urb(itmtouch->readurb);
+               usb_free_urb(itmtouch->readurb);
+               kfree(itmtouch);
+       }
+}
+
+MODULE_DEVICE_TABLE(usb, itmtouch_ids);
+
+static struct usb_driver itmtouch_driver = {
+       .owner =        THIS_MODULE,
+       .name =         "itmtouch",
+       .probe =        itmtouch_probe,
+       .disconnect =   itmtouch_disconnect,
+       .id_table =     itmtouch_ids,
+};
+
+static int __init itmtouch_init(void)
+{
+       info(DRIVER_DESC " " DRIVER_VERSION);
+       info(DRIVER_AUTHOR);
+       return usb_register(&itmtouch_driver);
+}
+
+static void __exit itmtouch_exit(void)
+{
+       usb_deregister(&itmtouch_driver);
+}
+
+module_init(itmtouch_init);
+module_exit(itmtouch_exit);
index a68c5b4e7b3756f6820d180b5f07d65bd1ec52e6..d2f0f90a9bcdab3dba31232ff059e863aae948e6 100644 (file)
@@ -36,7 +36,6 @@ struct kbtab {
        struct input_dev dev;
        struct usb_device *usbdev;
        struct urb *irq;
-       int open;
        int x, y;
        int button;
        int pressure;
@@ -79,12 +78,12 @@ static void kbtab_irq(struct urb *urb, struct pt_regs *regs)
        /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/
        input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
 
-       if( -1 == kb_pressure_click){ 
+       if (-1 == kb_pressure_click) {
                input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);
        } else {
                input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0);
        };
-       
+
        input_sync(dev);
 
  exit:
@@ -105,14 +104,9 @@ static int kbtab_open(struct input_dev *dev)
 {
        struct kbtab *kbtab = dev->private;
 
-       if (kbtab->open++)
-               return 0;
-
        kbtab->irq->dev = kbtab->usbdev;
-       if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) {
-               kbtab->open--;
+       if (usb_submit_urb(kbtab->irq, GFP_KERNEL))
                return -EIO;
-       }
 
        return 0;
 }
@@ -121,8 +115,7 @@ static void kbtab_close(struct input_dev *dev)
 {
        struct kbtab *kbtab = dev->private;
 
-       if (!--kbtab->open)
-               usb_kill_urb(kbtab->irq);
+       usb_kill_urb(kbtab->irq);
 }
 
 static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -161,7 +154,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
        kbtab->dev.absmax[ABS_X] = 0x2000;
        kbtab->dev.absmax[ABS_Y] = 0x1750;
        kbtab->dev.absmax[ABS_PRESSURE] = 0xff;
-       
+
        kbtab->dev.absfuzz[ABS_X] = 4;
        kbtab->dev.absfuzz[ABS_Y] = 4;
 
index ab1a2a30ce7ca273c683533826fc859965767119..09b5cc7c66de15167a5445bae090694cb6e9b08f 100644 (file)
@@ -42,9 +42,9 @@
 #include <linux/config.h>
 
 #ifdef CONFIG_USB_DEBUG
-        #define DEBUG
+       #define DEBUG
 #else
-        #undef DEBUG
+       #undef DEBUG
 #endif
 
 #include <linux/kernel.h>
@@ -93,275 +93,255 @@ module_param(raw_coordinates, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(raw_coordinates, "report raw coordinate values (y, default) or hardware-calibrated coordinate values (n)");
 
 struct mtouch_usb {
-        unsigned char *data;
-        dma_addr_t data_dma;
-        struct urb *irq;
-        struct usb_device *udev;
-        struct input_dev input;
-        int open;
-        char name[128];
-        char phys[64];
+       unsigned char *data;
+       dma_addr_t data_dma;
+       struct urb *irq;
+       struct usb_device *udev;
+       struct input_dev input;
+       char name[128];
+       char phys[64];
 };
 
-static struct usb_device_id mtouchusb_devices [] = {
-        { USB_DEVICE(0x0596, 0x0001) },
-        { }
+static struct usb_device_id mtouchusb_devices[] = {
+       { USB_DEVICE(0x0596, 0x0001) },
+       { }
 };
 
 static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
 {
-        struct mtouch_usb *mtouch = urb->context;
-        int retval;
-
-        switch (urb->status) {
-                case 0:
-                        /* success */
-                        break;
-                case -ETIMEDOUT:
-                        /* this urb is timing out */
-                        dbg("%s - urb timed out - was the device unplugged?",
-                            __FUNCTION__);
-                        return;
-                case -ECONNRESET:
-                case -ENOENT:
-                case -ESHUTDOWN:
-                        /* this urb is terminated, clean up */
-                        dbg("%s - urb shutting down with status: %d",
-                            __FUNCTION__, urb->status);
-                        return;
-                default:
-                        dbg("%s - nonzero urb status received: %d",
-                            __FUNCTION__, urb->status);
-                        goto exit;
-        }
-
-        input_regs(&mtouch->input, regs);
-        input_report_key(&mtouch->input, BTN_TOUCH,
-                         MTOUCHUSB_GET_TOUCHED(mtouch->data));
-        input_report_abs(&mtouch->input, ABS_X,
-                         MTOUCHUSB_GET_XC(mtouch->data));
-        input_report_abs(&mtouch->input, ABS_Y,
+       struct mtouch_usb *mtouch = urb->context;
+       int retval;
+
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -ETIMEDOUT:
+               /* this urb is timing out */
+               dbg("%s - urb timed out - was the device unplugged?",
+                   __FUNCTION__);
+               return;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d",
+                   __FUNCTION__, urb->status);
+               return;
+       default:
+               dbg("%s - nonzero urb status received: %d",
+                   __FUNCTION__, urb->status);
+               goto exit;
+       }
+
+       input_regs(&mtouch->input, regs);
+       input_report_key(&mtouch->input, BTN_TOUCH,
+                        MTOUCHUSB_GET_TOUCHED(mtouch->data));
+       input_report_abs(&mtouch->input, ABS_X, MTOUCHUSB_GET_XC(mtouch->data));
+       input_report_abs(&mtouch->input, ABS_Y,
                         (raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC)
-                         - MTOUCHUSB_GET_YC(mtouch->data));
-        input_sync(&mtouch->input);
+                        - MTOUCHUSB_GET_YC(mtouch->data));
+       input_sync(&mtouch->input);
 
 exit:
-        retval = usb_submit_urb (urb, GFP_ATOMIC);
-        if (retval)
-                err ("%s - usb_submit_urb failed with result: %d",
-                     __FUNCTION__, retval);
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval)
+               err("%s - usb_submit_urb failed with result: %d",
+                   __FUNCTION__, retval);
 }
 
-static int mtouchusb_open (struct input_dev *input)
+static int mtouchusb_open(struct input_dev *input)
 {
-        struct mtouch_usb *mtouch = input->private;
+       struct mtouch_usb *mtouch = input->private;
 
-        if (mtouch->open++)
-                return 0;
+       mtouch->irq->dev = mtouch->udev;
 
-        mtouch->irq->dev = mtouch->udev;
+       if (usb_submit_urb(mtouch->irq, GFP_ATOMIC))
+               return -EIO;
 
-        if (usb_submit_urb (mtouch->irq, GFP_ATOMIC)) {
-                mtouch->open--;
-                return -EIO;
-        }
-
-        return 0;
+       return 0;
 }
 
-static void mtouchusb_close (struct input_dev *input)
+static void mtouchusb_close(struct input_dev *input)
 {
-        struct mtouch_usb *mtouch = input->private;
+       struct mtouch_usb *mtouch = input->private;
 
-        if (!--mtouch->open)
-                usb_kill_urb (mtouch->irq);
+       usb_kill_urb(mtouch->irq);
 }
 
 static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
 {
-        dbg("%s - called", __FUNCTION__);
+       dbg("%s - called", __FUNCTION__);
 
-        mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE,
-                                        SLAB_ATOMIC, &mtouch->data_dma);
+       mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE,
+                                       SLAB_ATOMIC, &mtouch->data_dma);
 
-        if (!mtouch->data)
-                return -1;
+       if (!mtouch->data)
+               return -1;
 
-        return 0;
+       return 0;
 }
 
 static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
 {
-        dbg("%s - called", __FUNCTION__);
+       dbg("%s - called", __FUNCTION__);
 
-        if (mtouch->data)
-                usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE,
-                                mtouch->data, mtouch->data_dma);
+       if (mtouch->data)
+               usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE,
+                               mtouch->data, mtouch->data_dma);
 }
 
 static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
-        struct mtouch_usb *mtouch;
-        struct usb_host_interface *interface;
-        struct usb_endpoint_descriptor *endpoint;
-        struct usb_device *udev = interface_to_usbdev (intf);
-        char path[64];
-        int nRet;
-
-        dbg("%s - called", __FUNCTION__);
-
-        dbg("%s - setting interface", __FUNCTION__);
-        interface = intf->cur_altsetting;
-
-        dbg("%s - setting endpoint", __FUNCTION__);
-        endpoint = &interface->endpoint[0].desc;
-
-        if (!(mtouch = kmalloc (sizeof (struct mtouch_usb), GFP_KERNEL))) {
-                err("%s - Out of memory.", __FUNCTION__);
-                return -ENOMEM;
-        }
-
-        memset(mtouch, 0, sizeof(struct mtouch_usb));
-        mtouch->udev = udev;
-
-        dbg("%s - allocating buffers", __FUNCTION__);
-        if (mtouchusb_alloc_buffers(udev, mtouch)) {
-                mtouchusb_free_buffers(udev, mtouch);
-                kfree(mtouch);
-                return -ENOMEM;
-        }
-
-        mtouch->input.private = mtouch;
-        mtouch->input.open = mtouchusb_open;
-        mtouch->input.close = mtouchusb_close;
-
-        usb_make_path(udev, path, 64);
-        sprintf(mtouch->phys, "%s/input0", path);
-
-        mtouch->input.name = mtouch->name;
-        mtouch->input.phys = mtouch->phys;
-        mtouch->input.id.bustype = BUS_USB;
-        mtouch->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
-        mtouch->input.id.product = le16_to_cpu(udev->descriptor.idProduct);
-        mtouch->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice);
-        mtouch->input.dev = &intf->dev;
-
-        mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-        mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
-        mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
-
-        /* Used to Scale Compensated Data and Flip Y */
-        mtouch->input.absmin[ABS_X] =  MTOUCHUSB_MIN_XC;
-        mtouch->input.absmax[ABS_X] =  raw_coordinates ? \
-                                       MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC;
-        mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
-        mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
-        mtouch->input.absmin[ABS_Y] =  MTOUCHUSB_MIN_YC;
-        mtouch->input.absmax[ABS_Y] =  raw_coordinates ? \
-                                       MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC;
-        mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
-        mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
+       struct mtouch_usb *mtouch;
+       struct usb_host_interface *interface;
+       struct usb_endpoint_descriptor *endpoint;
+       struct usb_device *udev = interface_to_usbdev(intf);
+       char path[64];
+       int nRet;
+
+       dbg("%s - called", __FUNCTION__);
+
+       dbg("%s - setting interface", __FUNCTION__);
+       interface = intf->cur_altsetting;
+
+       dbg("%s - setting endpoint", __FUNCTION__);
+       endpoint = &interface->endpoint[0].desc;
+
+       if (!(mtouch = kmalloc(sizeof(struct mtouch_usb), GFP_KERNEL))) {
+               err("%s - Out of memory.", __FUNCTION__);
+               return -ENOMEM;
+       }
+
+       memset(mtouch, 0, sizeof(struct mtouch_usb));
+       mtouch->udev = udev;
+
+       dbg("%s - allocating buffers", __FUNCTION__);
+       if (mtouchusb_alloc_buffers(udev, mtouch)) {
+               mtouchusb_free_buffers(udev, mtouch);
+               kfree(mtouch);
+               return -ENOMEM;
+       }
+
+       mtouch->input.private = mtouch;
+       mtouch->input.open = mtouchusb_open;
+       mtouch->input.close = mtouchusb_close;
+
+       usb_make_path(udev, path, 64);
+       sprintf(mtouch->phys, "%s/input0", path);
+
+       mtouch->input.name = mtouch->name;
+       mtouch->input.phys = mtouch->phys;
+       mtouch->input.id.bustype = BUS_USB;
+       mtouch->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
+       mtouch->input.id.product = le16_to_cpu(udev->descriptor.idProduct);
+       mtouch->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice);
+       mtouch->input.dev = &intf->dev;
+
+       mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+       mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+       mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+       /* Used to Scale Compensated Data and Flip Y */
+       mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC;
+       mtouch->input.absmax[ABS_X] = raw_coordinates ?
+                                       MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC;
+       mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
+       mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
+       mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MIN_YC;
+       mtouch->input.absmax[ABS_Y] = raw_coordinates ?
+                                       MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC;
+       mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
+       mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
 
        if (udev->manufacturer)
                strcat(mtouch->name, udev->manufacturer);
        if (udev->product)
                sprintf(mtouch->name, "%s %s", mtouch->name, udev->product);
 
-        if (!strlen(mtouch->name))
-                sprintf(mtouch->name, "USB Touchscreen %04x:%04x",
-                        mtouch->input.id.vendor, mtouch->input.id.product);
-
-        nRet = usb_control_msg(mtouch->udev,
-                               usb_rcvctrlpipe(udev, 0),
-                               MTOUCHUSB_RESET,
-                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               1,
-                               0,
-                               NULL,
-                               0,
-                               USB_CTRL_SET_TIMEOUT);
-        dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
-            __FUNCTION__, nRet);
-
-        dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__);
-        mtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
-        if (!mtouch->irq) {
-                dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__);
-                mtouchusb_free_buffers(udev, mtouch);
-                kfree(mtouch);
-                return -ENOMEM;
-        }
-
-        dbg("%s - usb_fill_int_urb", __FUNCTION__);
-        usb_fill_int_urb(mtouch->irq,
-                         mtouch->udev,
-                         usb_rcvintpipe(mtouch->udev, 0x81),
-                         mtouch->data,
-                         MTOUCHUSB_REPORT_DATA_SIZE,
-                         mtouchusb_irq,
-                         mtouch,
-                         endpoint->bInterval);
-
-        dbg("%s - input_register_device", __FUNCTION__);
-        input_register_device(&mtouch->input);
-
-        nRet = usb_control_msg(mtouch->udev,
-                               usb_rcvctrlpipe(udev, 0),
-                               MTOUCHUSB_ASYNC_REPORT,
-                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               1,
-                               1,
-                               NULL,
-                               0,
-                               USB_CTRL_SET_TIMEOUT);
-        dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
-            __FUNCTION__, nRet);
-
-        printk(KERN_INFO "input: %s on %s\n", mtouch->name, path);
-        usb_set_intfdata(intf, mtouch);
-
-        return 0;
+       if (!strlen(mtouch->name))
+               sprintf(mtouch->name, "USB Touchscreen %04x:%04x",
+                       mtouch->input.id.vendor, mtouch->input.id.product);
+
+       nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0),
+                              MTOUCHUSB_RESET,
+                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                              1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+       dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
+           __FUNCTION__, nRet);
+
+       dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__);
+       mtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
+       if (!mtouch->irq) {
+               dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__);
+               mtouchusb_free_buffers(udev, mtouch);
+               kfree(mtouch);
+               return -ENOMEM;
+       }
+
+       dbg("%s - usb_fill_int_urb", __FUNCTION__);
+       usb_fill_int_urb(mtouch->irq, mtouch->udev,
+                        usb_rcvintpipe(mtouch->udev, 0x81),
+                        mtouch->data, MTOUCHUSB_REPORT_DATA_SIZE,
+                        mtouchusb_irq, mtouch, endpoint->bInterval);
+
+       dbg("%s - input_register_device", __FUNCTION__);
+       input_register_device(&mtouch->input);
+
+       nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0),
+                              MTOUCHUSB_ASYNC_REPORT,
+                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                              1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
+       dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
+           __FUNCTION__, nRet);
+
+       printk(KERN_INFO "input: %s on %s\n", mtouch->name, path);
+       usb_set_intfdata(intf, mtouch);
+
+       return 0;
 }
 
 static void mtouchusb_disconnect(struct usb_interface *intf)
 {
-        struct mtouch_usb *mtouch = usb_get_intfdata (intf);
-
-        dbg("%s - called", __FUNCTION__);
-        usb_set_intfdata(intf, NULL);
-        if (mtouch) {
-                dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__);
-                usb_kill_urb(mtouch->irq);
-                input_unregister_device(&mtouch->input);
-                usb_free_urb(mtouch->irq);
-                mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch);
-                kfree(mtouch);
-        }
+       struct mtouch_usb *mtouch = usb_get_intfdata(intf);
+
+       dbg("%s - called", __FUNCTION__);
+       usb_set_intfdata(intf, NULL);
+       if (mtouch) {
+               dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__);
+               usb_kill_urb(mtouch->irq);
+               input_unregister_device(&mtouch->input);
+               usb_free_urb(mtouch->irq);
+               mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch);
+               kfree(mtouch);
+       }
 }
 
-MODULE_DEVICE_TABLE (usb, mtouchusb_devices);
+MODULE_DEVICE_TABLE(usb, mtouchusb_devices);
 
 static struct usb_driver mtouchusb_driver = {
-        .owner =      THIS_MODULE,
-        .name =       "mtouchusb",
-        .probe =      mtouchusb_probe,
-        .disconnect = mtouchusb_disconnect,
-        .id_table =   mtouchusb_devices,
+       .owner          = THIS_MODULE,
+       .name           = "mtouchusb",
+       .probe          = mtouchusb_probe,
+       .disconnect     = mtouchusb_disconnect,
+       .id_table       = mtouchusb_devices,
 };
 
-static int __init mtouchusb_init(void) {
-        dbg("%s - called", __FUNCTION__);
-        return usb_register(&mtouchusb_driver);
+static int __init mtouchusb_init(void)
+{
+       dbg("%s - called", __FUNCTION__);
+       return usb_register(&mtouchusb_driver);
 }
 
-static void __exit mtouchusb_cleanup(void) {
-        dbg("%s - called", __FUNCTION__);
-        usb_deregister(&mtouchusb_driver);
+static void __exit mtouchusb_cleanup(void)
+{
+       dbg("%s - called", __FUNCTION__);
+       usb_deregister(&mtouchusb_driver);
 }
 
 module_init(mtouchusb_init);
 module_exit(mtouchusb_cleanup);
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
index 7fa2f9b9fb69ad26e58ade761d2672a37bcbbdab..3975b309d55fbb11e1ba0b7d0887f6c150e2fecd 100644 (file)
@@ -10,7 +10,7 @@
  * back to the host when polled by the USB controller.
  *
  * Testing with the knob I have has shown that it measures approximately 94 "clicks"
- * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was 
+ * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was
  * a variable speed cordless electric drill) has shown that the device can measure
  * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from
  * the host. If it counts more than 7 clicks before it is polled, it will wrap back
@@ -120,9 +120,9 @@ exit:
 /* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
 static void powermate_sync_state(struct powermate_device *pm)
 {
-       if (pm->requires_update == 0) 
+       if (pm->requires_update == 0)
                return; /* no updates are required */
-       if (pm->config->status == -EINPROGRESS) 
+       if (pm->config->status == -EINPROGRESS)
                return; /* an update is already in progress; it'll issue this update when it completes */
 
        if (pm->requires_update & UPDATE_PULSE_ASLEEP){
@@ -142,7 +142,7 @@ static void powermate_sync_state(struct powermate_device *pm)
                   2: multiply the speed
                   the argument only has an effect for operations 0 and 2, and ranges between
                   1 (least effect) to 255 (maximum effect).
-       
+
                   thus, several states are equivalent and are coalesced into one state.
 
                   we map this onto a range from 0 to 510, with:
@@ -151,7 +151,7 @@ static void powermate_sync_state(struct powermate_device *pm)
                   256 -- 510  -- use multiple (510 = fastest).
 
                   Only values of 'arg' quite close to 255 are particularly useful/spectacular.
-               */    
+               */
                if (pm->pulse_speed < 255){
                        op = 0;                   // divide
                        arg = 255 - pm->pulse_speed;
@@ -199,14 +199,14 @@ static void powermate_config_complete(struct urb *urb, struct pt_regs *regs)
 
        if (urb->status)
                printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
-       
+
        spin_lock_irqsave(&pm->lock, flags);
        powermate_sync_state(pm);
        spin_unlock_irqrestore(&pm->lock, flags);
 }
 
 /* Set the LED up as described and begin the sync with the hardware if required */
-static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, 
+static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
                                int pulse_table, int pulse_asleep, int pulse_awake)
 {
        unsigned long flags;
@@ -229,7 +229,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
        /* mark state updates which are required */
        if (static_brightness != pm->static_brightness){
                pm->static_brightness = static_brightness;
-               pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;                
+               pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;
        }
        if (pulse_asleep != pm->pulse_asleep){
                pm->pulse_asleep = pulse_asleep;
@@ -246,7 +246,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
        }
 
        powermate_sync_state(pm);
-   
+
        spin_unlock_irqrestore(&pm->lock, flags);
 }
 
@@ -257,19 +257,19 @@ static int powermate_input_event(struct input_dev *dev, unsigned int type, unsig
        struct powermate_device *pm = dev->private;
 
        if (type == EV_MSC && code == MSC_PULSELED){
-               /*  
+               /*
                    bits  0- 7: 8 bits: LED brightness
                    bits  8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster.
                    bits 17-18: 2 bits: pulse table (0, 1, 2 valid)
                    bit     19: 1 bit : pulse whilst asleep?
                    bit     20: 1 bit : pulse constantly?
-               */  
+               */
                int static_brightness = command & 0xFF;   // bits 0-7
                int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16
                int pulse_table = (command >> 17) & 0x3;  // bits 17-18
                int pulse_asleep = (command >> 19) & 0x1; // bit 19
                int pulse_awake  = (command >> 20) & 0x1; // bit 20
-  
+
                powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake);
        }
 
@@ -378,7 +378,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
        switch (le16_to_cpu(udev->descriptor.idProduct)) {
        case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break;
        case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break;
-       default: 
+       default:
                pm->input.name = pm_name_soundknob;
                printk(KERN_WARNING "powermate: unknown product id %04x\n",
                       le16_to_cpu(udev->descriptor.idProduct));
@@ -402,11 +402,11 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
        usb_make_path(udev, path, 64);
        snprintf(pm->phys, 64, "%s/input0", path);
        printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.phys);
-       
+
        /* force an update of everything */
        pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS;
        powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters
-  
+
        usb_set_intfdata(intf, pm);
        return 0;
 }
index a71f1bbd0a174949da74acf05bcb170b35053606..386595ee21c0b73c688235126850dc2ce312a987 100644 (file)
@@ -69,7 +69,6 @@ struct touchkit_usb {
        struct urb *irq;
        struct usb_device *udev;
        struct input_dev input;
-       int open;
        char name[128];
        char phys[64];
 };
@@ -134,15 +133,10 @@ static int touchkit_open(struct input_dev *input)
 {
        struct touchkit_usb *touchkit = input->private;
 
-       if (touchkit->open++)
-               return 0;
-
        touchkit->irq->dev = touchkit->udev;
 
-       if (usb_submit_urb(touchkit->irq, GFP_ATOMIC)) {
-               touchkit->open--;
+       if (usb_submit_urb(touchkit->irq, GFP_ATOMIC))
                return -EIO;
-       }
 
        return 0;
 }
@@ -151,8 +145,7 @@ static void touchkit_close(struct input_dev *input)
 {
        struct touchkit_usb *touchkit = input->private;
 
-       if (!--touchkit->open)
-               usb_kill_urb(touchkit->irq);
+       usb_kill_urb(touchkit->irq);
 }
 
 static int touchkit_alloc_buffers(struct usb_device *udev,
index 7038fb9d1ced4290f870cbd682ee5089a494fb3a..f35db1974c4258407e607b5f5ae56ef2df38e72b 100644 (file)
@@ -9,18 +9,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -72,7 +72,6 @@ struct usb_kbd {
        unsigned char newleds;
        char name[128];
        char phys[64];
-       int open;
 
        unsigned char *new;
        struct usb_ctrlrequest *cr;
@@ -166,7 +165,7 @@ static void usb_kbd_led(struct urb *urb, struct pt_regs *regs)
 
        if (urb->status)
                warn("led urb status %d received", urb->status);
-       
+
        if (*(kbd->leds) == kbd->newleds)
                return;
 
@@ -180,14 +179,9 @@ static int usb_kbd_open(struct input_dev *dev)
 {
        struct usb_kbd *kbd = dev->private;
 
-       if (kbd->open++)
-               return 0;
-
        kbd->irq->dev = kbd->usbdev;
-       if (usb_submit_urb(kbd->irq, GFP_KERNEL)) {
-               kbd->open--;
+       if (usb_submit_urb(kbd->irq, GFP_KERNEL))
                return -EIO;
-       }
 
        return 0;
 }
@@ -196,8 +190,7 @@ static void usb_kbd_close(struct input_dev *dev)
 {
        struct usb_kbd *kbd = dev->private;
 
-       if (!--kbd->open)
-               usb_kill_urb(kbd->irq);
+       usb_kill_urb(kbd->irq);
 }
 
 static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
@@ -230,7 +223,7 @@ static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
                usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
 }
 
-static int usb_kbd_probe(struct usb_interface *iface, 
+static int usb_kbd_probe(struct usb_interface *iface,
                         const struct usb_device_id *id)
 {
        struct usb_device * dev = interface_to_usbdev(iface);
@@ -272,7 +265,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
        for (i = 0; i < 255; i++)
                set_bit(usb_kbd_keycode[i], kbd->dev.keybit);
        clear_bit(0, kbd->dev.keybit);
-       
+
        kbd->dev.private = kbd;
        kbd->dev.event = usb_kbd_event;
        kbd->dev.open = usb_kbd_open;
@@ -294,7 +287,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
        sprintf(kbd->phys, "%s/input0", path);
 
        kbd->dev.name = kbd->name;
-       kbd->dev.phys = kbd->phys;      
+       kbd->dev.phys = kbd->phys;
        kbd->dev.id.bustype = BUS_USB;
        kbd->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
        kbd->dev.id.product = le16_to_cpu(dev->descriptor.idProduct);
@@ -329,7 +322,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
 static void usb_kbd_disconnect(struct usb_interface *intf)
 {
        struct usb_kbd *kbd = usb_get_intfdata (intf);
-       
+
        usb_set_intfdata(intf, NULL);
        if (kbd) {
                usb_kill_urb(kbd->irq);
index 01155bbddd43b227d60359471c8a2548a7cc3b50..1ec41b5effe627fee269239b8350a1777fd5ae3f 100644 (file)
@@ -9,18 +9,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -51,7 +51,6 @@ struct usb_mouse {
        struct usb_device *usbdev;
        struct input_dev dev;
        struct urb *irq;
-       int open;
 
        signed char *data;
        dma_addr_t data_dma;
@@ -101,14 +100,9 @@ static int usb_mouse_open(struct input_dev *dev)
 {
        struct usb_mouse *mouse = dev->private;
 
-       if (mouse->open++)
-               return 0;
-
        mouse->irq->dev = mouse->usbdev;
-       if (usb_submit_urb(mouse->irq, GFP_KERNEL)) {
-               mouse->open--;
+       if (usb_submit_urb(mouse->irq, GFP_KERNEL))
                return -EIO;
-       }
 
        return 0;
 }
@@ -117,8 +111,7 @@ static void usb_mouse_close(struct input_dev *dev)
 {
        struct usb_mouse *mouse = dev->private;
 
-       if (!--mouse->open)
-               usb_kill_urb(mouse->irq);
+       usb_kill_urb(mouse->irq);
 }
 
 static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_id * id)
@@ -132,19 +125,19 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_
 
        interface = intf->cur_altsetting;
 
-       if (interface->desc.bNumEndpoints != 1) 
+       if (interface->desc.bNumEndpoints != 1)
                return -ENODEV;
 
        endpoint = &interface->endpoint[0].desc;
-       if (!(endpoint->bEndpointAddress & 0x80)) 
+       if (!(endpoint->bEndpointAddress & 0x80))
                return -ENODEV;
-       if ((endpoint->bmAttributes & 3) != 3) 
+       if ((endpoint->bmAttributes & 3) != 3)
                return -ENODEV;
 
        pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
        maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 
-       if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) 
+       if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL)))
                return -ENOMEM;
        memset(mouse, 0, sizeof(struct usb_mouse));
 
@@ -209,7 +202,7 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_
 static void usb_mouse_disconnect(struct usb_interface *intf)
 {
        struct usb_mouse *mouse = usb_get_intfdata (intf);
-       
+
        usb_set_intfdata(intf, NULL);
        if (mouse) {
                usb_kill_urb(mouse->irq);
@@ -238,7 +231,7 @@ static struct usb_driver usb_mouse_driver = {
 static int __init usb_mouse_init(void)
 {
        int retval = usb_register(&usb_mouse_driver);
-       if (retval == 0) 
+       if (retval == 0)
                info(DRIVER_VERSION ":" DRIVER_DESC);
        return retval;
 }
index fec04dda088ea0edac8181912684337df12206a5..f6b34af66b3d9a23954bb7300dc7446a3867281c 100644 (file)
@@ -9,7 +9,7 @@
  *  Copyright (c) 2000 Daniel Egger            <egger@suse.de>
  *  Copyright (c) 2001 Frederic Lepied         <flepied@mandrakesoft.com>
  *  Copyright (c) 2004 Panagiotis Issaris      <panagiotis.issaris@mech.kuleuven.ac.be>
- *  Copyright (c) 2002-2004 Ping Cheng         <pingc@wacom.com>
+ *  Copyright (c) 2002-2005 Ping Cheng         <pingc@wacom.com>
  *
  *  ChangeLog:
  *      v0.1 (vp)  - Initial release
@@ -18,7 +18,7 @@
  *     v0.4 (sm)  - Support for more Intuos models, menustrip
  *                     relative mode, proximity.
  *     v0.5 (vp)  - Big cleanup, nifty features removed,
- *                     they belong in userspace
+ *                     they belong in userspace
  *     v1.8 (vp)  - Submit URB only when operating, moved to CVS,
  *                     use input_report_key instead of report_btn and
  *                     other cleanups
@@ -51,6 +51,9 @@
  *                - Cleanups here and there
  *    v1.30.1 (pi) - Added Graphire3 support
  *     v1.40 (pc) - Add support for several new devices, fix eraser reporting, ...
+ *     v1.43 (pc) - Added support for Cintiq 21UX
+                  - Fixed a Graphire bug
+                  - Merged wacom_intuos3_irq into wacom_intuos_irq
  */
 
 /*
@@ -72,7 +75,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.40"
+#define DRIVER_VERSION "v1.43"
 #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
 #define DRIVER_LICENSE "GPL"
@@ -83,6 +86,16 @@ MODULE_LICENSE(DRIVER_LICENSE);
 
 #define USB_VENDOR_ID_WACOM    0x056a
 
+enum {
+       PENPARTNER = 0,
+       GRAPHIRE,
+       PL,
+       INTUOS,
+       INTUOS3,
+       CINTIQ,
+       MAX_TYPE
+};
+
 struct wacom_features {
        char *name;
        int pktlen;
@@ -102,7 +115,6 @@ struct wacom {
        struct urb *irq;
        struct wacom_features *features;
        int tool[2];
-       int open;
        __u32 serial[2];
        char phys[32];
 };
@@ -149,7 +161,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
        prox = data[1] & 0x40;
 
        input_regs(dev, regs);
-       
+
        if (prox) {
 
                pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
@@ -166,8 +178,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
                if (!wacom->tool[0]) {
                        /* Going into proximity select tool */
                        wacom->tool[1] = (data[4] & 0x20)? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
-               }
-               else {
+               } else {
                        /* was entered with stylus2 pressed */
                        if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20) ) {
                                /* report out proximity for previous tool */
@@ -182,16 +193,15 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
                        wacom->tool[1] = BTN_TOOL_PEN;
                }
                input_report_key(dev, wacom->tool[1], prox); /* report in proximity for tool */
-               input_report_abs(dev, ABS_X, data[3] | ((__u32)data[2] << 7) | ((__u32)(data[1] & 0x03) << 14));
-               input_report_abs(dev, ABS_Y, data[6] | ((__u32)data[5] << 7) | ((__u32)(data[4] & 0x03) << 14));
+               input_report_abs(dev, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
+               input_report_abs(dev, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
                input_report_abs(dev, ABS_PRESSURE, pressure);
 
                input_report_key(dev, BTN_TOUCH, data[4] & 0x08);
                input_report_key(dev, BTN_STYLUS, data[4] & 0x10);
                /* Only allow the stylus2 button to be reported for the pen tool. */
                input_report_key(dev, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
-       }
-       else {
+       } else {
                /* report proximity-out of a (valid) tool */
                if (wacom->tool[1] != BTN_TOOL_RUBBER) {
                        /* Unknown tool selected default to pen tool */
@@ -203,7 +213,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
        wacom->tool[0] = prox; /* Save proximity state */
        input_sync(dev);
 
-exit:
+ exit:
        retval = usb_submit_urb (urb, GFP_ATOMIC);
        if (retval)
                err ("%s - usb_submit_urb failed with result %d",
@@ -232,20 +242,16 @@ static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs)
                goto exit;
        }
 
-       if (data[0] != 2)
-       {
+       if (data[0] != 2) {
                printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
                goto exit;
        }
 
        input_regs(dev, regs);
-       if (data[1] & 0x04)
-       {
+       if (data[1] & 0x04) {
                input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x20);
                input_report_key(dev, BTN_TOUCH, data[1] & 0x08);
-       }
-       else
-       {
+       } else {
                input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20);
                input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
        }
@@ -257,7 +263,7 @@ static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs)
 
        input_sync(dev);
 
-exit:
+ exit:
        retval = usb_submit_urb (urb, GFP_ATOMIC);
        if (retval)
                err ("%s - usb_submit_urb failed with result %d",
@@ -300,7 +306,7 @@ static void wacom_penpartner_irq(struct urb *urb, struct pt_regs *regs)
        input_report_key(dev, BTN_STYLUS, (data[5] & 0x40));
        input_sync(dev);
 
-exit:
+ exit:
        retval = usb_submit_urb (urb, GFP_ATOMIC);
        if (retval)
                err ("%s - usb_submit_urb failed with result %d",
@@ -340,47 +346,47 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs)
 
        input_regs(dev, regs);
 
-       switch ((data[1] >> 5) & 3) {
+       if (data[1] & 0x10) { /* in prox */
 
-               case 0: /* Pen */
-                       input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x80);
-                       break;
+               switch ((data[1] >> 5) & 3) {
 
-               case 1: /* Rubber */
-                       input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x80);
-                       break;
-
-               case 2: /* Mouse with wheel */
-                       input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
-                       input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
-                       /* fall through */
+                       case 0: /* Pen */
+                               wacom->tool[0] = BTN_TOOL_PEN;
+                               break;
 
-                case 3: /* Mouse without wheel */
-                       input_report_key(dev, BTN_TOOL_MOUSE, data[7] > 24);
-                       input_report_key(dev, BTN_LEFT, data[1] & 0x01);
-                       input_report_key(dev, BTN_RIGHT, data[1] & 0x02);
-                       input_report_abs(dev, ABS_DISTANCE, data[7]);
+                       case 1: /* Rubber */
+                               wacom->tool[0] = BTN_TOOL_RUBBER;
+                               break;
 
-                       input_report_abs(dev, ABS_X, x);
-                       input_report_abs(dev, ABS_Y, y);
+                       case 2: /* Mouse with wheel */
+                               input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
+                               input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
+                               /* fall through */
 
-                       input_sync(dev);
-                       goto exit;
+                       case 3: /* Mouse without wheel */
+                               wacom->tool[0] = BTN_TOOL_MOUSE;
+                               input_report_key(dev, BTN_LEFT, data[1] & 0x01);
+                               input_report_key(dev, BTN_RIGHT, data[1] & 0x02);
+                               input_report_abs(dev, ABS_DISTANCE, data[7]);
+                               break;
+               }
        }
 
        if (data[1] & 0x80) {
                input_report_abs(dev, ABS_X, x);
                input_report_abs(dev, ABS_Y, y);
        }
+       if (wacom->tool[0] != BTN_TOOL_MOUSE) {
+               input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6]));
+               input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
+               input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
+               input_report_key(dev, BTN_STYLUS2, data[1] & 0x04);
+       }
 
-       input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6]));
-       input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
-       input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
-       input_report_key(dev, BTN_STYLUS2, data[1] & 0x04);
-
+       input_report_key(dev, wacom->tool[0], data[1] & 0x10);
        input_sync(dev);
 
-exit:
+ exit:
        retval = usb_submit_urb (urb, GFP_ATOMIC);
        if (retval)
                err ("%s - usb_submit_urb failed with result %d",
@@ -398,14 +404,13 @@ static int wacom_intuos_inout(struct urb *urb)
        idx = data[1] & 0x01;
 
        /* Enter report */
-       if ((data[1] & 0xfc) == 0xc0)
-       {
+       if ((data[1] & 0xfc) == 0xc0) {
                /* serial number of the tool */
-               wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 28) +
-                       ((__u32)data[4] << 20) + ((__u32)data[5] << 12) +
-                       ((__u32)data[6] << 4) + (data[7] >> 4);
+               wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
+                       (data[4] << 20) + (data[5] << 12) +
+                       (data[6] << 4) + (data[7] >> 4);
 
-               switch (((__u32)data[2] << 4) | (data[3] >> 4)) {
+               switch ((data[2] << 4) | (data[3] >> 4)) {
                        case 0x812: /* Inking pen */
                        case 0x801: /* Intuos3 Inking pen */
                        case 0x012:
@@ -449,7 +454,7 @@ static int wacom_intuos_inout(struct urb *urb)
                        case 0x112:
                        case 0x913: /* Intuos3 Airbrush */
                                wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
-                               break;  /* Airbrush */
+                               break;
                        default: /* Unknown tool */
                                wacom->tool[idx] = BTN_TOOL_PEN;
                }
@@ -478,9 +483,8 @@ static void wacom_intuos_general(struct urb *urb)
        unsigned int t;
 
        /* general pen packet */
-       if ((data[1] & 0xb8) == 0xa0)
-       {
-               t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3);
+       if ((data[1] & 0xb8) == 0xa0) {
+               t = (data[6] << 2) | ((data[7] >> 6) & 3);
                input_report_abs(dev, ABS_PRESSURE, t);
                input_report_abs(dev, ABS_TILT_X,
                                ((data[7] << 1) & 0x7e) | (data[8] >> 7));
@@ -491,10 +495,9 @@ static void wacom_intuos_general(struct urb *urb)
        }
 
        /* airbrush second packet */
-       if ((data[1] & 0xbc) == 0xb4)
-       {
+       if ((data[1] & 0xbc) == 0xb4) {
                input_report_abs(dev, ABS_WHEEL,
-                               ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+                               (data[6] << 2) | ((data[7] >> 6) & 3));
                input_report_abs(dev, ABS_TILT_X,
                                ((data[7] << 1) & 0x7e) | (data[8] >> 7));
                input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
@@ -526,7 +529,7 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs)
                goto exit;
        }
 
-       if (data[0] != 2 && data[0] != 5 && data[0] != 6) {
+       if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) {
                dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
                goto exit;
        }
@@ -536,107 +539,10 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs)
        /* tool number */
        idx = data[1] & 0x01;
 
-       /* process in/out prox events */
-       if (wacom_intuos_inout(urb)) goto exit;
-
-       input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2]));
-       input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4]));
-       input_report_abs(dev, ABS_DISTANCE, data[9]);
-
-       /* process general packets */
-       wacom_intuos_general(urb);
-       
-       if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {             /* 4D mouse or Lens cursor packets */
-
-               if (data[1] & 0x02) {                                           /* Rotation packet */
-
-                       t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7);
-                       input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ? ((t - 1) / 2) : -t / 2);
-
-               } else {
-
-                       if ((data[1] & 0x10) == 0) {                            /* 4D mouse packets */
-
-                               input_report_key(dev, BTN_LEFT,   data[8] & 0x01);
-                               input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
-                               input_report_key(dev, BTN_RIGHT,  data[8] & 0x04);
-
-                               input_report_key(dev, BTN_SIDE,   data[8] & 0x20);
-                               input_report_key(dev, BTN_EXTRA,  data[8] & 0x10);
-                               t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3);
-                               input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
-
-                       } else {
-                               if (wacom->tool[idx] == BTN_TOOL_MOUSE) {       /* 2D mouse packets */  
-                                       input_report_key(dev, BTN_LEFT,   data[8] & 0x04);
-                                       input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
-                                       input_report_key(dev, BTN_RIGHT,  data[8] & 0x10);
-                                       input_report_rel(dev, REL_WHEEL, 
-                                           (-(__u32)(data[8] & 0x01) + (__u32)((data[8] & 0x02) >> 1)));
-                               }
-                               else {     /* Lens cursor packets */
-                                       input_report_key(dev, BTN_LEFT,   data[8] & 0x01);
-                                       input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
-                                       input_report_key(dev, BTN_RIGHT,  data[8] & 0x04);
-                                       input_report_key(dev, BTN_SIDE,   data[8] & 0x10);
-                                       input_report_key(dev, BTN_EXTRA,  data[8] & 0x08);
-                               }
-                       }
-               }
-       }
-       
-       input_report_key(dev, wacom->tool[idx], 1);
-       input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
-       input_sync(dev);
-
-exit:
-       retval = usb_submit_urb (urb, GFP_ATOMIC);
-       if (retval)
-               err ("%s - usb_submit_urb failed with result %d",
-                    __FUNCTION__, retval);
-}
-
-static void wacom_intuos3_irq(struct urb *urb, struct pt_regs *regs)
-{
-       struct wacom *wacom = urb->context;
-       unsigned char *data = wacom->data;
-       struct input_dev *dev = &wacom->dev;
-       unsigned int t;
-       int idx, retval;
-
-       switch (urb->status) {
-       case 0:
-               /* success */
-               break;
-       case -ECONNRESET:
-       case -ENOENT:
-       case -ESHUTDOWN:
-               /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
-               return;
-       default:
-               dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
-               goto exit;
-       }
-
-       /* check for valid report */
-       if (data[0] != 2 && data[0] != 5 && data[0] != 12)
-       {
-               printk(KERN_INFO "wacom_intuos3_irq: received unknown report #%d\n", data[0]);
-               goto exit;
-       }
-
-       input_regs(dev, regs);
-
-       /* tool index is always 0 here since there is no dual input tool */
-       idx = data[1] & 0x01;
-
        /* pad packets. Works as a second tool and is always in prox */
-       if (data[0] == 12)
-       {
+       if (data[0] == 12) {
                /* initiate the pad as a device */
-               if (wacom->tool[1] != BTN_TOOL_FINGER)
-               {
+               if (wacom->tool[1] != BTN_TOOL_FINGER) {
                        wacom->tool[1] = BTN_TOOL_FINGER;
                        input_report_key(dev, wacom->tool[1], 1);
                }
@@ -656,37 +562,78 @@ static void wacom_intuos3_irq(struct urb *urb, struct pt_regs *regs)
        }
 
        /* process in/out prox events */
-       if (wacom_intuos_inout(urb)) goto exit;
+       if (wacom_intuos_inout(urb))
+               goto exit;
 
-       input_report_abs(dev, ABS_X, ((__u32)data[2] << 9) | ((__u32)data[3] << 1) | ((data[9] >> 1) & 1));
-       input_report_abs(dev, ABS_Y, ((__u32)data[4] << 9) | ((__u32)data[5] << 1) | (data[9] & 1));
-       input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
+       /* Cintiq doesn't send data when RDY bit isn't set */
+       if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
+               return;
+
+       if (wacom->features->type >= INTUOS3) {
+               input_report_abs(dev, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
+               input_report_abs(dev, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
+               input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
+       } else {
+               input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2]));
+               input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4]));
+               input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
+       }
 
        /* process general packets */
        wacom_intuos_general(urb);
 
-       if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0)
-       {
-               /* Marker pen rotation packet. Reported as wheel due to valuator limitation */
-               if (data[1] & 0x02)
-               {
-                       t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7);
-                       t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
-                               ((t-1) / 2 + 450)) : (450 - t / 2) ;
-                       input_report_abs(dev, ABS_WHEEL, t);
-               }
+       /* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */
+       if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {
+
+               if (data[1] & 0x02) {
+                       /* Rotation packet */
+                       if (wacom->features->type >= INTUOS3) {
+                               /* I3 marker pen rotation reported as wheel
+                                * due to valuator limitation
+                                */
+                               t = (data[6] << 3) | ((data[7] >> 5) & 7);
+                               t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
+                                       ((t-1) / 2 + 450)) : (450 - t / 2) ;
+                               input_report_abs(dev, ABS_WHEEL, t);
+                       } else {
+                               /* 4D mouse rotation packet */
+                               t = (data[6] << 3) | ((data[7] >> 5) & 7);
+                               input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ?
+                                       ((t - 1) / 2) : -t / 2);
+                       }
 
-               /* 2D mouse packets */
-               if (wacom->tool[idx] == BTN_TOOL_MOUSE)
-               {
+               } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3) {
+                       /* 4D mouse packet */
+                       input_report_key(dev, BTN_LEFT,   data[8] & 0x01);
+                       input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
+                       input_report_key(dev, BTN_RIGHT,  data[8] & 0x04);
+
+                       input_report_key(dev, BTN_SIDE,   data[8] & 0x20);
+                       input_report_key(dev, BTN_EXTRA,  data[8] & 0x10);
+                       t = (data[6] << 2) | ((data[7] >> 6) & 3);
+                       input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
+
+               } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
+                       /* 2D mouse packet */
                        input_report_key(dev, BTN_LEFT,   data[8] & 0x04);
                        input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
                        input_report_key(dev, BTN_RIGHT,  data[8] & 0x10);
-                       input_report_key(dev, BTN_SIDE,   data[8] & 0x40);
-                       input_report_key(dev, BTN_EXTRA,  data[8] & 0x20);
-                       /* mouse wheel is positive when rolled backwards */
-                       input_report_rel(dev, REL_WHEEL,  ((__u32)((data[8] & 0x02) >> 1)
-                                        - (__u32)(data[8] & 0x01)));
+                       input_report_rel(dev, REL_WHEEL, ((data[8] & 0x02) >> 1)
+                                                - (data[8] & 0x01));
+
+                       /* I3 2D mouse side buttons */
+                       if (wacom->features->type == INTUOS3) {
+                               input_report_key(dev, BTN_SIDE,   data[8] & 0x40);
+                               input_report_key(dev, BTN_EXTRA,  data[8] & 0x20);
+                       }
+
+               } else if (wacom->features->type < INTUOS3) {
+                       /* Lens cursor packets */
+                       input_report_key(dev, BTN_LEFT,   data[8] & 0x01);
+                       input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
+                       input_report_key(dev, BTN_RIGHT,  data[8] & 0x04);
+                       input_report_key(dev, BTN_SIDE,   data[8] & 0x10);
+                       input_report_key(dev, BTN_EXTRA,  data[8] & 0x08);
                }
        }
 
@@ -702,35 +649,36 @@ exit:
 }
 
 static struct wacom_features wacom_features[] = {
-       { "Wacom Penpartner",    7,   5040,  3780,  255, 32, 0, wacom_penpartner_irq },
-        { "Wacom Graphire",      8,  10206,  7422,  511, 32, 1, wacom_graphire_irq },
-       { "Wacom Graphire2 4x5", 8,  10206,  7422,  511, 32, 1, wacom_graphire_irq },
-       { "Wacom Graphire2 5x7", 8,  13918, 10206,  511, 32, 1, wacom_graphire_irq },
-       { "Wacom Graphire3",     8,  10208,  7424,  511, 32, 1, wacom_graphire_irq },
-       { "Wacom Graphire3 6x8", 8,  16704, 12064,  511, 32, 1, wacom_graphire_irq },
-       { "Wacom Intuos 4x5",   10,  12700, 10600, 1023, 15, 2, wacom_intuos_irq },
-       { "Wacom Intuos 6x8",   10,  20320, 16240, 1023, 15, 2, wacom_intuos_irq },
-       { "Wacom Intuos 9x12",  10,  30480, 24060, 1023, 15, 2, wacom_intuos_irq },
-       { "Wacom Intuos 12x12", 10,  30480, 31680, 1023, 15, 2, wacom_intuos_irq },
-       { "Wacom Intuos 12x18", 10,  45720, 31680, 1023, 15, 2, wacom_intuos_irq },
-       { "Wacom PL400",         8,   5408,  4056,  255, 32, 3, wacom_pl_irq },
-       { "Wacom PL500",         8,   6144,  4608,  255, 32, 3, wacom_pl_irq },
-       { "Wacom PL600",         8,   6126,  4604,  255, 32, 3, wacom_pl_irq },
-       { "Wacom PL600SX",       8,   6260,  5016,  255, 32, 3, wacom_pl_irq },
-       { "Wacom PL550",         8,   6144,  4608,  511, 32, 3, wacom_pl_irq },
-       { "Wacom PL800",         8,   7220,  5780,  511, 32, 3, wacom_pl_irq },
-       { "Wacom Intuos2 4x5",   10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq },
-       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq },
-       { "Wacom Intuos2 9x12",  10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq },
-       { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq },
-       { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq },
-       { "Wacom Volito",        8,   5104,  3712,  511, 32, 1, wacom_graphire_irq },
-       { "Wacom Cintiq Partner",8,  20480, 15360,  511, 32, 3, wacom_ptu_irq },
-       { "Wacom Intuos3 4x5",   10, 25400, 20320, 1023, 15, 4, wacom_intuos3_irq },
-       { "Wacom Intuos3 6x8",   10, 40640, 30480, 1023, 15, 4, wacom_intuos3_irq },
-       { "Wacom Intuos3 9x12",  10, 60960, 45720, 1023, 15, 4, wacom_intuos3_irq },
-       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq },
-       { }
+       { "Wacom Penpartner",    7,   5040,  3780,  255, 32, PENPARTNER, wacom_penpartner_irq },
+        { "Wacom Graphire",      8,  10206,  7422,  511, 32, GRAPHIRE,   wacom_graphire_irq },
+       { "Wacom Graphire2 4x5", 8,  10206,  7422,  511, 32, GRAPHIRE,   wacom_graphire_irq },
+       { "Wacom Graphire2 5x7", 8,  13918, 10206,  511, 32, GRAPHIRE,   wacom_graphire_irq },
+       { "Wacom Graphire3",     8,  10208,  7424,  511, 32, GRAPHIRE,   wacom_graphire_irq },
+       { "Wacom Graphire3 6x8", 8,  16704, 12064,  511, 32, GRAPHIRE,   wacom_graphire_irq },
+       { "Wacom Intuos 4x5",   10,  12700, 10600, 1023, 15, INTUOS,     wacom_intuos_irq },
+       { "Wacom Intuos 6x8",   10,  20320, 16240, 1023, 15, INTUOS,     wacom_intuos_irq },
+       { "Wacom Intuos 9x12",  10,  30480, 24060, 1023, 15, INTUOS,     wacom_intuos_irq },
+       { "Wacom Intuos 12x12", 10,  30480, 31680, 1023, 15, INTUOS,     wacom_intuos_irq },
+       { "Wacom Intuos 12x18", 10,  45720, 31680, 1023, 15, INTUOS,     wacom_intuos_irq },
+       { "Wacom PL400",         8,   5408,  4056,  255, 32, PL,         wacom_pl_irq },
+       { "Wacom PL500",         8,   6144,  4608,  255, 32, PL,         wacom_pl_irq },
+       { "Wacom PL600",         8,   6126,  4604,  255, 32, PL,         wacom_pl_irq },
+       { "Wacom PL600SX",       8,   6260,  5016,  255, 32, PL,         wacom_pl_irq },
+       { "Wacom PL550",         8,   6144,  4608,  511, 32, PL,         wacom_pl_irq },
+       { "Wacom PL800",         8,   7220,  5780,  511, 32, PL,         wacom_pl_irq },
+       { "Wacom Intuos2 4x5",   10, 12700, 10600, 1023, 15, INTUOS,     wacom_intuos_irq },
+       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 15, INTUOS,     wacom_intuos_irq },
+       { "Wacom Intuos2 9x12",  10, 30480, 24060, 1023, 15, INTUOS,     wacom_intuos_irq },
+       { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, INTUOS,     wacom_intuos_irq },
+       { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, INTUOS,     wacom_intuos_irq },
+       { "Wacom Volito",        8,   5104,  3712,  511, 32, GRAPHIRE,   wacom_graphire_irq },
+       { "Wacom Cintiq Partner",8,  20480, 15360,  511, 32, PL,         wacom_ptu_irq },
+       { "Wacom Intuos3 4x5",   10, 25400, 20320, 1023, 15, INTUOS3,    wacom_intuos_irq },
+       { "Wacom Intuos3 6x8",   10, 40640, 30480, 1023, 15, INTUOS3,    wacom_intuos_irq },
+       { "Wacom Intuos3 9x12",  10, 60960, 45720, 1023, 15, INTUOS3,    wacom_intuos_irq },
+       { "Wacom Cintiq 21UX",   10, 87200, 65600, 1023, 15, CINTIQ,     wacom_intuos_irq },
+       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 15, INTUOS,     wacom_intuos_irq },
+       { }
 };
 
 static struct usb_device_id wacom_ids[] = {
@@ -761,6 +709,7 @@ static struct usb_device_id wacom_ids[] = {
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
        { }
 };
@@ -771,14 +720,9 @@ static int wacom_open(struct input_dev *dev)
 {
        struct wacom *wacom = dev->private;
 
-       if (wacom->open++)
-               return 0;
-
        wacom->irq->dev = wacom->usbdev;
-       if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
-               wacom->open--;
+       if (usb_submit_urb(wacom->irq, GFP_KERNEL))
                return -EIO;
-       }
 
        return 0;
 }
@@ -787,8 +731,7 @@ static void wacom_close(struct input_dev *dev)
 {
        struct wacom *wacom = dev->private;
 
-       if (!--wacom->open)
-               usb_kill_urb(wacom->irq);
+       usb_kill_urb(wacom->irq);
 }
 
 static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -823,32 +766,33 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
 
        switch (wacom->features->type) {
-               case 1:
+               case GRAPHIRE:
                        wacom->dev.evbit[0] |= BIT(EV_REL);
                        wacom->dev.relbit[0] |= BIT(REL_WHEEL);
                        wacom->dev.absbit[0] |= BIT(ABS_DISTANCE);
                        wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
-                       wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
+                       wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
                        break;
 
-               case 4: /* new functions for Intuos3 */
+               case INTUOS3:
+               case CINTIQ:
                        wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
                        wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
                        wacom->dev.absbit[0] |= BIT(ABS_RX) | BIT(ABS_RY);
                        /* fall through */
 
-               case 2:
+               case INTUOS:
                        wacom->dev.evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
                        wacom->dev.mscbit[0] |= BIT(MSC_SERIAL);
                        wacom->dev.relbit[0] |= BIT(REL_WHEEL);
                        wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
-                       wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH)
+                       wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH)
                                                          | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2);
                        wacom->dev.absbit[0] |= BIT(ABS_DISTANCE) | BIT(ABS_WHEEL) | BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | BIT(ABS_THROTTLE);
                        break;
 
-               case 3:
-                       wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
+               case PL:
+                       wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
                        break;
        }
 
index d65edb22e5459a8c3ed032da363fd1b28fe2c889..a7fa1b17dcfedd9fcd386802288da52fec71ebeb 100644 (file)
@@ -104,13 +104,12 @@ MODULE_DEVICE_TABLE (usb, xpad_table);
 struct usb_xpad {
        struct input_dev dev;                   /* input device interface */
        struct usb_device *udev;                /* usb device */
-       
+
        struct urb *irq_in;                     /* urb for interrupt in report */
        unsigned char *idata;                   /* input data */
        dma_addr_t idata_dma;
-       
+
        char phys[65];                          /* physical device path */
-       int open_count;                         /* reference count */
 };
 
 /*
@@ -128,35 +127,35 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
        struct input_dev *dev = &xpad->dev;
 
        input_regs(dev, regs);
-       
+
        /* left stick */
        input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12]));
        input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14]));
-       
+
        /* right stick */
        input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16]));
        input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18]));
-       
+
        /* triggers left/right */
        input_report_abs(dev, ABS_Z, data[10]);
        input_report_abs(dev, ABS_RZ, data[11]);
-       
+
        /* digital pad */
        input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
        input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
-       
+
        /* start/back buttons and stick press left/right */
        input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4);
        input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5);
        input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6);
        input_report_key(dev, BTN_THUMBR, data[2] >> 7);
-       
+
        /* "analog" buttons A, B, X, Y */
        input_report_key(dev, BTN_A, data[4]);
        input_report_key(dev, BTN_B, data[5]);
        input_report_key(dev, BTN_X, data[6]);
        input_report_key(dev, BTN_Y, data[7]);
-       
+
        /* "analog" buttons black, white */
        input_report_key(dev, BTN_C, data[8]);
        input_report_key(dev, BTN_Z, data[9]);
@@ -168,7 +167,7 @@ static void xpad_irq_in(struct urb *urb, struct pt_regs *regs)
 {
        struct usb_xpad *xpad = urb->context;
        int retval;
-       
+
        switch (urb->status) {
        case 0:
                /* success */
@@ -183,7 +182,7 @@ static void xpad_irq_in(struct urb *urb, struct pt_regs *regs)
                dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
                goto exit;
        }
-       
+
        xpad_process_packet(xpad, 0, xpad->idata, regs);
 
 exit:
@@ -196,25 +195,19 @@ exit:
 static int xpad_open (struct input_dev *dev)
 {
        struct usb_xpad *xpad = dev->private;
-       
-       if (xpad->open_count++)
-               return 0;
-       
+
        xpad->irq_in->dev = xpad->udev;
-       if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) {
-               xpad->open_count--;
+       if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
                return -EIO;
-       }
-       
+
        return 0;
 }
 
 static void xpad_close (struct input_dev *dev)
 {
        struct usb_xpad *xpad = dev->private;
-       
-       if (!--xpad->open_count)
-               usb_kill_urb(xpad->irq_in);
+
+       usb_kill_urb(xpad->irq_in);
 }
 
 static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -224,19 +217,19 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
        struct usb_endpoint_descriptor *ep_irq_in;
        char path[64];
        int i;
-       
+
        for (i = 0; xpad_device[i].idVendor; i++) {
                if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) &&
                    (le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct))
                        break;
        }
-       
+
        if ((xpad = kmalloc (sizeof(struct usb_xpad), GFP_KERNEL)) == NULL) {
                err("cannot allocate memory for new pad");
                return -ENOMEM;
        }
        memset(xpad, 0, sizeof(struct usb_xpad));
-       
+
        xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN,
                                       SLAB_ATOMIC, &xpad->idata_dma);
        if (!xpad->idata) {
@@ -251,18 +244,18 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                 kfree(xpad);
                return -ENOMEM;
         }
-       
+
        ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
-       
+
        usb_fill_int_urb(xpad->irq_in, udev,
                         usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
                         xpad->idata, XPAD_PKT_LEN, xpad_irq_in,
                         xpad, ep_irq_in->bInterval);
        xpad->irq_in->transfer_dma = xpad->idata_dma;
        xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-       
+
        xpad->udev = udev;
-       
+
        xpad->dev.id.bustype = BUS_USB;
        xpad->dev.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
        xpad->dev.id.product = le16_to_cpu(udev->descriptor.idProduct);
@@ -273,21 +266,21 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
        xpad->dev.phys = xpad->phys;
        xpad->dev.open = xpad_open;
        xpad->dev.close = xpad_close;
-       
+
        usb_make_path(udev, path, 64);
        snprintf(xpad->phys, 64,  "%s/input0", path);
-       
+
        xpad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-       
+
        for (i = 0; xpad_btn[i] >= 0; i++)
                set_bit(xpad_btn[i], xpad->dev.keybit);
-       
+
        for (i = 0; xpad_abs[i] >= 0; i++) {
-               
+
                signed short t = xpad_abs[i];
-               
+
                set_bit(t, xpad->dev.absbit);
-               
+
                switch (t) {
                        case ABS_X:
                        case ABS_Y:
@@ -310,11 +303,11 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                                break;
                }
        }
-       
+
        input_register_device(&xpad->dev);
-       
+
        printk(KERN_INFO "input: %s on %s", xpad->dev.name, path);
-       
+
        usb_set_intfdata(intf, xpad);
        return 0;
 }
@@ -322,7 +315,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 static void xpad_disconnect(struct usb_interface *intf)
 {
        struct usb_xpad *xpad = usb_get_intfdata (intf);
-       
+
        usb_set_intfdata(intf, NULL);
        if (xpad) {
                usb_kill_urb(xpad->irq_in);
index ae455c8e3702866ca1e54c3bc2c3af8e18324245..7398a7f19c1e4e994c8de5f2343fc6dcfe6255c3 100644 (file)
@@ -1375,9 +1375,13 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
            (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) {
                camera_name = "STV0680";
                PDEBUG (0, "STV(i): STV0680 camera found.");
+       } else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) &&
+                  (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) {
+               camera_name = "Creative WebCam Go Mini";
+               PDEBUG (0, "STV(i): Creative WebCam Go Mini found.");
        } else {
-               PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 values.");
-               PDEBUG (0, "STV(e): Check that the STV0680 camera is connected to the computer.");
+               PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values.");
+               PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer.");
                retval = -ENODEV;
                goto error;
        }
index 7e0e314dcf123e879860a5fdb2d6a9bbd7bbb80e..4459406126036675c89ec2405d5feb64e5af59ad 100644 (file)
 
 #define USB_PENCAM_VENDOR_ID   0x0553
 #define USB_PENCAM_PRODUCT_ID  0x0202
+
+#define USB_CREATIVEGOMINI_VENDOR_ID   0x041e
+#define USB_CREATIVEGOMINI_PRODUCT_ID  0x4007
+
 #define PENCAM_TIMEOUT          1000
 /* fmt 4 */
 #define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
 
 static struct usb_device_id device_table[] = {
        {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
+       {USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)},
        {}
 };
 MODULE_DEVICE_TABLE (usb, device_table);
index ce030d1f1c1f50cf3181fabc5facb8c6e940f1a5..733acc213726ceb70349d099fbb2c29278178abe 100644 (file)
@@ -1,4 +1,4 @@
-/* Siemens ID Mouse driver v0.5
+/* Siemens ID Mouse driver v0.6
 
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
@@ -11,6 +11,9 @@
   Derived from the USB Skeleton driver 1.1,
   Copyright (C) 2003 Greg Kroah-Hartman (greg@kroah.com)
 
+  Additional information provided by Martin Reising
+  <Martin.Reising@natural-computing.de>
+
 */
 
 #include <linux/config.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 
+/* image constants */
 #define WIDTH 225
-#define HEIGHT 288
-#define HEADER "P5 225 288 255 "
+#define HEIGHT 289
+#define HEADER "P5 225 289 255 "
 #define IMGSIZE ((WIDTH * HEIGHT) + sizeof(HEADER)-1)
 
-/* Version Information */
-#define DRIVER_VERSION "0.5"
+/* version information */
+#define DRIVER_VERSION "0.6"
 #define DRIVER_SHORT   "idmouse"
 #define DRIVER_AUTHOR  "Florian 'Floe' Echtler <echtler@fs.tum.de>"
 #define DRIVER_DESC    "Siemens ID Mouse FingerTIP Sensor Driver"
 
-/* Siemens ID Mouse */
-#define USB_IDMOUSE_VENDOR_ID  0x0681
-#define USB_IDMOUSE_PRODUCT_ID 0x0005
-
-/* we still need a minor number */
+/* minor number for misc USB devices */
 #define USB_IDMOUSE_MINOR_BASE 132
 
+/* vendor and device IDs */
+#define ID_SIEMENS 0x0681
+#define ID_IDMOUSE 0x0005
+#define ID_CHERRY  0x0010
+
+/* device ID table */
 static struct usb_device_id idmouse_table[] = {
-       {USB_DEVICE(USB_IDMOUSE_VENDOR_ID, USB_IDMOUSE_PRODUCT_ID)},
-       {} /* null entry at the end */
+       {USB_DEVICE(ID_SIEMENS, ID_IDMOUSE)}, /* Siemens ID Mouse (Professional) */
+       {USB_DEVICE(ID_SIEMENS, ID_CHERRY )}, /* Cherry FingerTIP ID Board       */
+       {}                                    /* terminating null entry          */
 };
 
+/* sensor commands */
+#define FTIP_RESET   0x20
+#define FTIP_ACQUIRE 0x21
+#define FTIP_RELEASE 0x22
+#define FTIP_BLINK   0x23  /* LSB of value = blink pulse width */
+#define FTIP_SCROLL  0x24
+
+#define ftip_command(dev, command, value, index) \
+       usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), command, \
+       USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000)
+
 MODULE_DEVICE_TABLE(usb, idmouse_table);
 
 /* structure to hold all of our device specific stuff */
@@ -57,7 +75,8 @@ struct usb_idmouse {
        struct usb_interface *interface; /* the interface for this device */
 
        unsigned char *bulk_in_buffer; /* the buffer to receive data */
-       size_t bulk_in_size; /* the size of the receive buffer */
+       size_t bulk_in_size; /* the maximum bulk packet size */
+       size_t orig_bi_size; /* same as above, but reported by the device */
        __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
 
        int open; /* if the port is open or not */
@@ -103,7 +122,7 @@ static struct usb_driver idmouse_driver = {
        .id_table = idmouse_table,
 };
 
-// prevent races between open() and disconnect()
+/* prevent races between open() and disconnect() */
 static DECLARE_MUTEX(disconnect_sem);
 
 static int idmouse_create_image(struct usb_idmouse *dev)
@@ -112,42 +131,34 @@ static int idmouse_create_image(struct usb_idmouse *dev)
        int bulk_read = 0;
        int result = 0;
 
-       if (dev->bulk_in_size < sizeof(HEADER))
-               return -ENOMEM;
-
-       memcpy(dev->bulk_in_buffer,HEADER,sizeof(HEADER)-1);
+       memcpy(dev->bulk_in_buffer, HEADER, sizeof(HEADER)-1);
        bytes_read += sizeof(HEADER)-1;
 
-       /* Dump the setup packets. Yes, they are uncommented, simply 
-          because they were sniffed under Windows using SnoopyPro.
-          I _guess_ that 0x22 is a kind of reset command and 0x21 
-          means init..
-       */
-       result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-                               0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
-       if (result < 0)
-               return result;
-       result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-                               0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
+       /* reset the device and set a fast blink rate */
+       result = ftip_command(dev, FTIP_RELEASE, 0, 0);
        if (result < 0)
-               return result;
-       result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-                               0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
+               goto reset;
+       result = ftip_command(dev, FTIP_BLINK,   1, 0);
        if (result < 0)
-               return result;
+               goto reset;
 
-       result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-                               0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
+       /* initialize the sensor - sending this command twice */
+       /* significantly reduces the rate of failed reads     */
+       result = ftip_command(dev, FTIP_ACQUIRE, 0, 0);
        if (result < 0)
-               return result;
-       result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-                               0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
+               goto reset;
+       result = ftip_command(dev, FTIP_ACQUIRE, 0, 0);
        if (result < 0)
-               return result;
-       result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-                               0x20, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
+               goto reset;
+
+       /* start the readout - sending this command twice */
+       /* presumably enables the high dynamic range mode */
+       result = ftip_command(dev, FTIP_RESET,   0, 0);
        if (result < 0)
-               return result;
+               goto reset;
+       result = ftip_command(dev, FTIP_RESET,   0, 0);
+       if (result < 0)
+               goto reset;
 
        /* loop over a blocking bulk read to get data from the device */
        while (bytes_read < IMGSIZE) {
@@ -155,22 +166,40 @@ static int idmouse_create_image(struct usb_idmouse *dev)
                                usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr),
                                dev->bulk_in_buffer + bytes_read,
                                dev->bulk_in_size, &bulk_read, 5000);
-               if (result < 0)
-                       return result;
-               if (signal_pending(current))
-                       return -EINTR;
+               if (result < 0) {
+                       /* Maybe this error was caused by the increased packet size? */
+                       /* Reset to the original value and tell userspace to retry.  */
+                       if (dev->bulk_in_size != dev->orig_bi_size) {
+                               dev->bulk_in_size = dev->orig_bi_size;
+                               result = -EAGAIN;
+                       }
+                       break;
+               }
+               if (signal_pending(current)) {
+                       result = -EINTR;
+                       break;
+               }
                bytes_read += bulk_read;
        }
 
        /* reset the device */
-       result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-                               0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
-       if (result < 0)
-               return result;
+reset:
+       ftip_command(dev, FTIP_RELEASE, 0, 0);
+
+       /* check for valid image */
+       /* right border should be black (0x00) */
+       for (bytes_read = sizeof(HEADER)-1 + WIDTH-1; bytes_read < IMGSIZE; bytes_read += WIDTH)
+               if (dev->bulk_in_buffer[bytes_read] != 0x00)
+                       return -EAGAIN;
 
-       /* should be IMGSIZE == 64815 */
+       /* lower border should be white (0xFF) */
+       for (bytes_read = IMGSIZE-WIDTH; bytes_read < IMGSIZE-1; bytes_read++)
+               if (dev->bulk_in_buffer[bytes_read] != 0xFF)
+                       return -EAGAIN;
+
+       /* should be IMGSIZE == 65040 */
        dbg("read %d bytes fingerprint data", bytes_read);
-       return 0;
+       return result;
 }
 
 static inline void idmouse_delete(struct usb_idmouse *dev)
@@ -282,10 +311,10 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count
 
        dev = (struct usb_idmouse *) file->private_data;
 
-       // lock this object
+       /* lock this object */
        down (&dev->sem);
 
-       // verify that the device wasn't unplugged
+       /* verify that the device wasn't unplugged */
        if (!dev->present) {
                up (&dev->sem);
                return -ENODEV;
@@ -296,8 +325,7 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count
                return 0;
        }
 
-       if (count > IMGSIZE - *ppos)
-               count = IMGSIZE - *ppos;
+       count = min ((loff_t)count, IMGSIZE - (*ppos));
 
        if (copy_to_user (buffer, dev->bulk_in_buffer + *ppos, count)) {
                result = -EFAULT;
@@ -306,7 +334,7 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count
                *ppos += count;
        }
 
-       // unlock the device 
+       /* unlock the device */
        up(&dev->sem);
        return result;
 }
@@ -318,7 +346,6 @@ static int idmouse_probe(struct usb_interface *interface,
        struct usb_idmouse *dev = NULL;
        struct usb_host_interface *iface_desc;
        struct usb_endpoint_descriptor *endpoint;
-       size_t buffer_size;
        int result;
 
        /* check if we have gotten the data or the hid interface */
@@ -344,11 +371,11 @@ static int idmouse_probe(struct usb_interface *interface,
                USB_ENDPOINT_XFER_BULK)) {
 
                /* we found a bulk in endpoint */
-               buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
-               dev->bulk_in_size = buffer_size;
+               dev->orig_bi_size = le16_to_cpu(endpoint->wMaxPacketSize);
+               dev->bulk_in_size = 0x200; /* works _much_ faster */
                dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
                dev->bulk_in_buffer =
-                       kmalloc(IMGSIZE + buffer_size, GFP_KERNEL);
+                       kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL);
 
                if (!dev->bulk_in_buffer) {
                        err("Unable to allocate input buffer.");
index 3104f28f6aa8d130206cacdaf7999cbf63e48f1f..cda7249a90b285225df15bb99b2d3af6e5b91589 100644 (file)
@@ -461,7 +461,7 @@ static int perform_sglist (
 
 static unsigned realworld = 1;
 module_param (realworld, uint, 0);
-MODULE_PARM_DESC (realworld, "clear to demand stricter ch9 compliance");
+MODULE_PARM_DESC (realworld, "clear to demand stricter spec compliance");
 
 static int get_altsetting (struct usbtest_dev *dev)
 {
@@ -604,9 +604,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
                                USB_DIR_IN | USB_RECIP_DEVICE,
                                0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT);
                if (retval != 1 || dev->buf [0] != expected) {
-                       dev_dbg (&iface->dev,
-                               "get config --> %d (%d)\n", retval,
-                               expected);
+                       dev_dbg (&iface->dev, "get config --> %d %d (1 %d)\n",
+                               retval, dev->buf[0], expected);
                        return (retval < 0) ? retval : -EDOM;
                }
        }
@@ -1243,7 +1242,7 @@ static int ctrl_out (struct usbtest_dev *dev,
        char                    *what = "?";
        struct usb_device       *udev;
        
-       if (length > 0xffff || vary >= length)
+       if (length < 1 || length > 0xffff || vary >= length)
                return -EINVAL;
 
        buf = kmalloc(length, SLAB_KERNEL);
@@ -1266,6 +1265,11 @@ static int ctrl_out (struct usbtest_dev *dev,
                                0, 0, buf, len, USB_CTRL_SET_TIMEOUT);
                if (retval != len) {
                        what = "write";
+                       if (retval >= 0) {
+                               INFO(dev, "ctrl_out, wlen %d (expected %d)\n",
+                                               retval, len);
+                               retval = -EBADMSG;
+                       }
                        break;
                }
 
@@ -1275,6 +1279,11 @@ static int ctrl_out (struct usbtest_dev *dev,
                                0, 0, buf, len, USB_CTRL_GET_TIMEOUT);
                if (retval != len) {
                        what = "read";
+                       if (retval >= 0) {
+                               INFO(dev, "ctrl_out, rlen %d (expected %d)\n",
+                                               retval, len);
+                               retval = -EBADMSG;
+                       }
                        break;
                }
 
@@ -1293,8 +1302,13 @@ 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
+                * status stage is IN, not OUT like other ep0in transfers.
+                */
                if (len > length)
-                       len = 0;
+                       len = realworld ? 1 : 0;
        }
 
        if (retval < 0)
@@ -1519,6 +1533,11 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
        if (down_interruptible (&dev->sem))
                return -ERESTARTSYS;
 
+       if (intf->dev.power.power_state != PMSG_ON) {
+               up (&dev->sem);
+               return -EHOSTUNREACH;
+       }
+
        /* some devices, like ez-usb default devices, need a non-default
         * altsetting to have any active endpoints.  some tests change
         * altsettings; force a default so most tests don't need to check.
@@ -1762,8 +1781,10 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
        case 14:
                if (!dev->info->ctrl_out)
                        break;
-               dev_dbg (&intf->dev, "TEST 14:  %d ep0out, 0..%d vary %d\n",
-                               param->iterations, param->length, param->vary);
+               dev_dbg (&intf->dev, "TEST 14:  %d ep0out, %d..%d vary %d\n",
+                               param->iterations,
+                               realworld ? 1 : 0, param->length,
+                               param->vary);
                retval = ctrl_out (dev, param->iterations, 
                                param->length, param->vary);
                break;
@@ -1927,6 +1948,27 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
        return 0;
 }
 
+static int usbtest_suspend (struct usb_interface *intf, pm_message_t message)
+{
+       struct usbtest_dev      *dev = usb_get_intfdata (intf);
+
+       down (&dev->sem);
+       intf->dev.power.power_state = PMSG_SUSPEND;
+       up (&dev->sem);
+       return 0;
+}
+
+static int usbtest_resume (struct usb_interface *intf)
+{
+       struct usbtest_dev      *dev = usb_get_intfdata (intf);
+
+       down (&dev->sem);
+       intf->dev.power.power_state = PMSG_ON;
+       up (&dev->sem);
+       return 0;
+}
+
+
 static void usbtest_disconnect (struct usb_interface *intf)
 {
        struct usbtest_dev      *dev = usb_get_intfdata (intf);
@@ -2115,6 +2157,8 @@ static struct usb_driver usbtest_driver = {
        .probe =        usbtest_probe,
        .ioctl =        usbtest_ioctl,
        .disconnect =   usbtest_disconnect,
+       .suspend =      usbtest_suspend,
+       .resume =       usbtest_resume,
 };
 
 /*-------------------------------------------------------------------------*/
index d976790312aaeb1f6f2a319aa211cc23d3ab6469..5f4496d8dbac558155860cba9dc78c984a1ac3ac 100644 (file)
@@ -1166,7 +1166,7 @@ static void pegasus_set_multicast(struct net_device *net)
                pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;
                if (netif_msg_link(pegasus))
                        pr_info("%s: Promiscuous mode enabled.\n", net->name);
-       } else if ((net->mc_count > multicast_filter_limit) ||
+       } else if (net->mc_count ||
                   (net->flags & IFF_ALLMULTI)) {
                pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;
                pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
index 13ccedef5c7e0d22c9c9e057e84dde2127b0037a..b98f2a833442a6eed7d0cf28bf3d6993e2325c27 100644 (file)
@@ -249,6 +249,8 @@ PEGASUS_DEV( "Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a,
                DEFAULT_GPIO_RESET)
 PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
                DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005,
+               DEFAULT_GPIO_RESET | PEGASUS_II)
 PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b,
                DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1,
index 8fb223385f2fb78fc0f7446fba1966bf97c39330..626b016addff5837dc334bf7e0c5f27927b25666 100644 (file)
@@ -667,7 +667,7 @@ static void rtl8150_set_multicast(struct net_device *netdev)
        if (netdev->flags & IFF_PROMISC) {
                dev->rx_creg |= cpu_to_le16(0x0001);
                info("%s: promiscuous mode", netdev->name);
-       } else if ((netdev->mc_count > multicast_filter_limit) ||
+       } else if (netdev->mc_count ||
                   (netdev->flags & IFF_ALLMULTI)) {
                dev->rx_creg &= cpu_to_le16(0xfffe);
                dev->rx_creg |= cpu_to_le16(0x0002);
index 4cbb408af72749b5f2f432c10bac69ebe4e2e1b7..8a945f4f36939d35bc8b5d541b8e9d0b7cb9be06 100644 (file)
@@ -1429,7 +1429,7 @@ static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf)
                        info->ether = (void *) buf;
                        if (info->ether->bLength != sizeof *info->ether) {
                                dev_dbg (&intf->dev, "CDC ether len %u\n",
-                                       info->u->bLength);
+                                       info->ether->bLength);
                                goto bad_desc;
                        }
                        dev->net->mtu = le16_to_cpup (
index 341ae5f732ddf3de18492c17342a97c4a3442360..3b387b005739150dc0de494f726a917b2d2981d0 100644 (file)
@@ -1884,12 +1884,53 @@ static void zd1201_disconnect(struct usb_interface *interface)
        kfree(zd);
 }
 
+#ifdef CONFIG_PM
+
+static int zd1201_suspend(struct usb_interface *interface,
+                          pm_message_t message)
+{
+       struct zd1201 *zd = usb_get_intfdata(interface);
+
+       netif_device_detach(zd->dev);
+
+       zd->was_enabled = zd->mac_enabled;
+
+       if (zd->was_enabled)
+               return zd1201_disable(zd);
+       else
+               return 0;
+}
+
+static int zd1201_resume(struct usb_interface *interface)
+{
+       struct zd1201 *zd = usb_get_intfdata(interface);
+
+       if (!zd || !zd->dev)
+               return -ENODEV;
+
+       netif_device_attach(zd->dev);
+
+       if (zd->was_enabled)
+               return zd1201_enable(zd);
+       else
+               return 0;
+}
+
+#else
+
+#define zd1201_suspend NULL
+#define zd1201_resume  NULL
+
+#endif
+
 static struct usb_driver zd1201_usb = {
        .owner = THIS_MODULE,
        .name = "zd1201",
        .probe = zd1201_probe,
        .disconnect = zd1201_disconnect,
        .id_table = zd1201_table,
+       .suspend = zd1201_suspend,
+       .resume = zd1201_resume,
 };
 
 static int __init zd1201_init(void)
index 1627c71e80525189ad6718828447d0938deb0db5..235f0ee34b24d56d45282ea6e6eacb186594f87e 100644 (file)
@@ -46,6 +46,7 @@ struct zd1201 {
        char                    essid[IW_ESSID_MAX_SIZE+1];
        int                     essidlen;
        int                     mac_enabled;
+       int                     was_enabled;
        int                     monitor;
        int                     encode_enabled;
        int                     encode_restricted;
index 46a204cd40e19c614a795407e63b4c91debb6a64..b5b431067b086bedabcf3f83851b5d55a2c2e214 100644 (file)
@@ -213,10 +213,14 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
                return (0);
        }
 
-       if (port->write_urb->status == -EINPROGRESS) {
+       spin_lock(&port->lock);
+       if (port->write_urb_busy) {
+               spin_unlock(&port->lock);
                dbg("%s - already writing", __FUNCTION__);
-               return (0);
+               return 0;
        }
+       port->write_urb_busy = 1;
+       spin_unlock(&port->lock);
 
        spin_lock_irqsave(&priv->lock, flags);
 
@@ -224,6 +228,7 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
                /* To much data for buffer. Reset buffer. */
                priv->wrfilled=0;
                spin_unlock_irqrestore(&priv->lock, flags);
+               port->write_urb_busy = 0;
                return (0);
        }
 
@@ -268,6 +273,7 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
                        priv->wrfilled=0;
                        priv->wrsent=0;
                        spin_unlock_irqrestore(&priv->lock, flags);
+                       port->write_urb_busy = 0;
                        return 0;
                }
 
@@ -412,7 +418,8 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs
        struct cyberjack_private *priv = usb_get_serial_port_data(port);
 
        dbg("%s - port %d", __FUNCTION__, port->number);
-       
+
+       port->write_urb_busy = 0;
        if (urb->status) {
                dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
                return;
@@ -424,12 +431,6 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs
        if( priv->wrfilled ) {
                int length, blksize, result;
 
-               if (port->write_urb->status == -EINPROGRESS) {
-                       dbg("%s - already writing", __FUNCTION__);
-                       spin_unlock(&priv->lock);
-                       return;
-               }
-
                dbg("%s - transmitting data (frame n)", __FUNCTION__);
 
                length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?
index 99214aa3cd19ba03f05c1db91eef572e72c59083..ddde5fb13f6b33a9003cebcd94a118ee1f37d821 100644 (file)
@@ -174,10 +174,14 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
 
        /* only do something if we have a bulk out endpoint */
        if (serial->num_bulk_out) {
-               if (port->write_urb->status == -EINPROGRESS) {
+               spin_lock(&port->lock);
+               if (port->write_urb_busy) {
+                       spin_unlock(&port->lock);
                        dbg("%s - already writing", __FUNCTION__);
-                       return (0);
+                       return 0;
                }
+               port->write_urb_busy = 1;
+               spin_unlock(&port->lock);
 
                count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
 
@@ -195,17 +199,20 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
                                     usb_serial_generic_write_bulk_callback), port);
 
                /* send the data out the bulk port */
+               port->write_urb_busy = 1;
                result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-               if (result)
+               if (result) {
                        dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
-               else
+                       /* don't have to grab the lock here, as we will retry if != 0 */
+                       port->write_urb_busy = 0;
+               } else
                        result = count;
 
                return result;
        }
 
        /* no bulk out, so return 0 bytes written */
-       return (0);
+       return 0;
 }
 
 int usb_serial_generic_write_room (struct usb_serial_port *port)
@@ -214,9 +221,9 @@ int usb_serial_generic_write_room (struct usb_serial_port *port)
        int room = 0;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
-       
+
        if (serial->num_bulk_out) {
-               if (port->write_urb->status != -EINPROGRESS)
+               if (port->write_urb_busy)
                        room = port->bulk_out_size;
        }
 
@@ -232,7 +239,7 @@ int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port)
        dbg("%s - port %d", __FUNCTION__, port->number);
 
        if (serial->num_bulk_out) {
-               if (port->write_urb->status == -EINPROGRESS)
+               if (port->write_urb_busy)
                        chars = port->write_urb->transfer_buffer_length;
        }
 
@@ -291,6 +298,7 @@ void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *re
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
+       port->write_urb_busy = 0;
        if (urb->status) {
                dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
                return;
index 3bd69c4ef24b6bdaf6e9f3b837c48f64b2d0e6a7..c05c2a2a0f31ddf31f0bde26cd68c32a59560824 100644 (file)
@@ -818,11 +818,6 @@ static void ipaq_write_gather(struct usb_serial_port *port)
        struct ipaq_packet      *pkt, *tmp;
        struct urb              *urb = port->write_urb;
 
-       if (urb->status == -EINPROGRESS) {
-               /* Should never happen */
-               err("%s - flushing while urb is active !", __FUNCTION__);
-               return;
-       }
        room = URBDATA_SIZE;
        list_for_each_entry_safe(pkt, tmp, &priv->queue, list) {
                count = min(room, (int)(pkt->len - pkt->written));
index 11105d74f461dec2961193ffab0f89091b4781be..85e242459c2765449b7bc2ee3e0ec3dc189c4308 100644 (file)
@@ -399,16 +399,21 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int
                dbg("%s - write request of 0 bytes", __FUNCTION__);
                return 0;
        }
-       
-       /* Racy and broken, FIXME properly! */
-       if (port->write_urb->status == -EINPROGRESS)
+
+       spin_lock(&port->lock);
+       if (port->write_urb_busy) {
+               spin_unlock(&port->lock);
+               dbg("%s - already writing", __FUNCTION__);
                return 0;
+       }
+       port->write_urb_busy = 1;
+       spin_unlock(&port->lock);
 
        count = min(count, port->bulk_out_size);
        memcpy(port->bulk_out_buffer, buf, count);
 
        dbg("%s count now:%d", __FUNCTION__, count);
-       
+
        usb_fill_bulk_urb(port->write_urb, dev,
                          usb_sndbulkpipe(dev, port->bulk_out_endpointAddress),
                          port->write_urb->transfer_buffer,
@@ -418,6 +423,7 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int
 
        ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
        if (ret != 0) {
+               port->write_urb_busy = 0;
                dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __FUNCTION__, ret);
                return ret;
        }
index 59f234df5f89555e96beb87fd54c9cb6dc1d7465..937b2fdd7171ab04a045caac5edffb2775f8e210 100644 (file)
@@ -341,10 +341,14 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
        if (count == 0)
                return 0;
 
-       if (port->write_urb->status == -EINPROGRESS) {
-               dbg ("%s - already writing", __FUNCTION__);
+       spin_lock(&port->lock);
+       if (port->write_urb_busy) {
+               spin_unlock(&port->lock);
+               dbg("%s - already writing", __FUNCTION__);
                return 0;
        }
+       port->write_urb_busy = 1;
+       spin_unlock(&port->lock);
 
        transfer_buffer = port->write_urb->transfer_buffer;
        transfer_size = min(count, port->bulk_out_size - 1);
@@ -374,9 +378,10 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
        port->write_urb->transfer_flags = URB_ZERO_PACKET;
 
        result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
-       if (result)
+       if (result) {
+               port->write_urb_busy = 0;
                dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
-       else
+       else
                result = transfer_size;
 
        return result;
@@ -387,7 +392,8 @@ static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
-       
+
+       port->write_urb_busy = 0;
        if (urb->status) {
                dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
                return;
index 7fd0aa9eccf6e104db982f96ff30acbf7822c704..635c384cb15a600219d111d5b5eccd3be5695cb0 100644 (file)
@@ -520,9 +520,13 @@ static int keyspan_pda_write(struct usb_serial_port *port,
           the TX urb is in-flight (wait until it completes)
           the device is full (wait until it says there is room)
        */
-       if (port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) {
-               return( 0 );
+       spin_lock(&port->lock);
+       if (port->write_urb_busy || priv->tx_throttled) {
+               spin_unlock(&port->lock);
+               return 0;
        }
+       port->write_urb_busy = 1;
+       spin_unlock(&port->lock);
 
        /* At this point the URB is in our control, nobody else can submit it
           again (the only sudden transition was the one from EINPROGRESS to
@@ -570,7 +574,7 @@ static int keyspan_pda_write(struct usb_serial_port *port,
                memcpy (port->write_urb->transfer_buffer, buf, count);
                /* send the data out the bulk port */
                port->write_urb->transfer_buffer_length = count;
-               
+
                priv->tx_room -= count;
 
                port->write_urb->dev = port->serial->dev;
@@ -593,6 +597,8 @@ static int keyspan_pda_write(struct usb_serial_port *port,
 
        rc = count;
 exit:
+       if (rc < 0)
+               port->write_urb_busy = 0;
        return rc;
 }
 
@@ -602,6 +608,7 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb, struct pt_regs *re
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
        struct keyspan_pda_private *priv;
 
+       port->write_urb_busy = 0;
        priv = usb_get_serial_port_data(port);
 
        /* queue up a wakeup at scheduler time */
@@ -626,12 +633,12 @@ static int keyspan_pda_write_room (struct usb_serial_port *port)
 static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
 {
        struct keyspan_pda_private *priv;
-       
+
        priv = usb_get_serial_port_data(port);
-       
+
        /* when throttled, return at least WAKEUP_CHARS to tell select() (via
           n_tty.c:normal_poll() ) that we're not writeable. */
-       if( port->write_urb->status == -EINPROGRESS || priv->tx_throttled )
+       if (port->write_urb_busy || priv->tx_throttled)
                return 256;
        return 0;
 }
index b5f2c06d4f3e6a69e713dc4250cd6519ac00ec75..6a99ae192df110d8022d6d8c157d4741808ceaa6 100644 (file)
@@ -254,10 +254,15 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
                dbg("%s - write request of 0 bytes", __FUNCTION__);
                return (0);
        }
-       if (wport->write_urb->status == -EINPROGRESS) {
+
+       spin_lock(&port->lock);
+       if (port->write_urb_busy) {
+               spin_unlock(&port->lock);
                dbg("%s - already writing", __FUNCTION__);
-               return (0);
+               return 0;
        }
+       port->write_urb_busy = 1;
+       spin_unlock(&port->lock);
 
        count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
 
@@ -275,9 +280,10 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
 
        wport->write_urb->dev = serial->dev;
        result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
-       if (result)
+       if (result) {
+               port->write_urb_busy = 0;
                err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
-       else
+       else
                result = count;
 
        return result;
@@ -291,7 +297,7 @@ static int omninet_write_room (struct usb_serial_port *port)
 
        int room = 0; // Default: no room
 
-       if (wport->write_urb->status != -EINPROGRESS)
+       if (wport->write_urb_busy)
                room = wport->bulk_out_size - OMNINET_HEADERLEN;
 
 //     dbg("omninet_write_room returns %d", room);
@@ -306,6 +312,7 @@ static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
 
 //     dbg("omninet_write_bulk_callback, port %0x\n", port);
 
+       port->write_urb_busy = 0;
        if (urb->status) {
                dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
                return;
index 0e85ed6c6c195ced68b8e9b0c99769cb4517981f..96a17568cbf1f4cdc8a684984c9b78c5d7e3f858 100644 (file)
@@ -299,10 +299,14 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i
                dbg ("%s - write request of 0 bytes", __FUNCTION__);
                return (0);
        }
-       if (port->write_urb->status == -EINPROGRESS) {
-               dbg ("%s - already writing", __FUNCTION__);
-               return (0);
+       spin_lock(&port->lock);
+       if (port->write_urb_busy) {
+               spin_unlock(&port->lock);
+               dbg("%s - already writing", __FUNCTION__);
+               return 0;
        }
+       port->write_urb_busy = 1;
+       spin_unlock(&port->lock);
 
        packet_length = port->bulk_out_size;    // get max packetsize
 
@@ -354,6 +358,7 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i
 #endif
        port->write_urb->dev = port->serial->dev;
        if ((result = usb_submit_urb (port->write_urb, GFP_KERNEL))) {
+               port->write_urb_busy = 0;
                err ("%s - failed submitting write urb, error %d", __FUNCTION__, result);
                return 0;
        }
@@ -368,7 +373,7 @@ static int safe_write_room (struct usb_serial_port *port)
 
        dbg ("%s", __FUNCTION__);
 
-       if (port->write_urb->status != -EINPROGRESS)
+       if (port->write_urb_busy)
                room = port->bulk_out_size - (safe ? 2 : 0);
 
        if (room) {
index 5da76dd8fb285681d4f5774b2468dc14794ec910..0267b26dde18ae5b72b38c0d02722b0ac982e07b 100644 (file)
@@ -1047,6 +1047,7 @@ int usb_serial_probe(struct usb_interface *interface,
                memset(port, 0x00, sizeof(struct usb_serial_port));
                port->number = i + serial->minor;
                port->serial = serial;
+               spin_lock_init(&port->lock);
                INIT_WORK(&port->work, usb_serial_port_softint, port);
                serial->port[i] = port;
        }
index d1f0c4057fa61e88be238a5cd0ac8ff99e388487..57f92f054c75ded3572f5ee9ee0845f69ab317fc 100644 (file)
@@ -69,6 +69,7 @@
  * usb_serial_port: structure for the specific ports of a device.
  * @serial: pointer back to the struct usb_serial owner of this port.
  * @tty: pointer to the corresponding tty for this port.
+ * @lock: spinlock to grab when updating portions of this structure.
  * @number: the number of the port (the minor number).
  * @interrupt_in_buffer: pointer to the interrupt in buffer for this port.
  * @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
@@ -98,6 +99,7 @@
 struct usb_serial_port {
        struct usb_serial *     serial;
        struct tty_struct *     tty;
+       spinlock_t              lock;
        unsigned char           number;
 
        unsigned char *         interrupt_in_buffer;
@@ -117,6 +119,7 @@ struct usb_serial_port {
        unsigned char *         bulk_out_buffer;
        int                     bulk_out_size;
        struct urb *            write_urb;
+       int                     write_urb_busy;
        __u8                    bulk_out_endpointAddress;
 
        wait_queue_head_t       write_wait;
index e43eddc3d44ba7891a11df4b66faca5282f611ca..af294bb68c35de7707a8f827a8463b32d3188ded 100644 (file)
@@ -155,6 +155,15 @@ static int slave_configure(struct scsi_device *sdev)
                 * If this device makes that mistake, tell the sd driver. */
                if (us->flags & US_FL_FIX_CAPACITY)
                        sdev->fix_capacity = 1;
+
+               /* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
+                * Hardware Error) when any low-level error occurs,
+                * recoverable or not.  Setting this flag tells the SCSI
+                * midlayer to retry such commands, which frequently will
+                * succeed and fix the error.  The worst this can lead to
+                * is an occasional series of retries that will all fail. */
+               sdev->retry_hwerror = 1;
+
        } else {
 
                /* Non-disk-type devices don't need to blacklist any pages
@@ -255,50 +264,23 @@ static int device_reset(struct scsi_cmnd *srb)
 
        /* lock the device pointers and do the reset */
        down(&(us->dev_semaphore));
-       if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
-               result = FAILED;
-               US_DEBUGP("No reset during disconnect\n");
-       } else
-               result = us->transport_reset(us);
+       result = us->transport_reset(us);
        up(&(us->dev_semaphore));
 
-       return result;
+       return result < 0 ? FAILED : SUCCESS;
 }
 
-/* This resets the device's USB port. */
-/* It refuses to work if there's more than one interface in
- * the device, so that other users are not affected. */
+/* Simulate a SCSI bus reset by resetting the device's USB port. */
 /* This is always called with scsi_lock(host) held */
 static int bus_reset(struct scsi_cmnd *srb)
 {
        struct us_data *us = host_to_us(srb->device->host);
-       int result, rc;
+       int result;
 
        US_DEBUGP("%s called\n", __FUNCTION__);
 
-       /* The USB subsystem doesn't handle synchronisation between
-        * a device's several drivers. Therefore we reset only devices
-        * with just one interface, which we of course own. */
-
        down(&(us->dev_semaphore));
-       if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
-               result = -EIO;
-               US_DEBUGP("No reset during disconnect\n");
-       } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) {
-               result = -EBUSY;
-               US_DEBUGP("Refusing to reset a multi-interface device\n");
-       } else {
-               rc = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
-               if (rc < 0) {
-                       US_DEBUGP("unable to lock device for reset: %d\n", rc);
-                       result = rc;
-               } else {
-                       result = usb_reset_device(us->pusb_dev);
-                       if (rc)
-                               usb_unlock_device(us->pusb_dev);
-                       US_DEBUGP("usb_reset_device returns %d\n", result);
-               }
-       }
+       result = usb_stor_port_reset(us);
        up(&(us->dev_semaphore));
 
        /* lock the host for the return */
@@ -320,6 +302,14 @@ void usb_stor_report_device_reset(struct us_data *us)
        }
 }
 
+/* Report a driver-initiated bus reset to the SCSI layer.
+ * Calling this for a SCSI-initiated reset is unnecessary but harmless.
+ * The caller must own the SCSI host lock. */
+void usb_stor_report_bus_reset(struct us_data *us)
+{
+       scsi_report_bus_reset(us_to_host(us), 0);
+}
+
 /***********************************************************************
  * /proc/scsi/ functions
  ***********************************************************************/
index d0a49af026c4258d6d4eae9f853b8011f1f9414e..737e4fa6045f8395aa6bf26759adefc03a72555c 100644 (file)
@@ -42,6 +42,7 @@
 #define _SCSIGLUE_H_
 
 extern void usb_stor_report_device_reset(struct us_data *us);
+extern void usb_stor_report_bus_reset(struct us_data *us);
 
 extern unsigned char usb_stor_sense_invalidCDB[18];
 extern struct scsi_host_template usb_stor_host_template;
index 9743e289cd3b1d68b49aba1298ad79fb2cfe5c3c..e6b1c6cf07f24a66eea868df9730e0baac53f15b 100644 (file)
@@ -266,8 +266,9 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
                NULL, 0, 3*HZ);
 
        /* reset the endpoint toggle */
-       usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
-               usb_pipeout(pipe), 0);
+       if (result >= 0)
+               usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
+                               usb_pipeout(pipe), 0);
 
        US_DEBUGP("%s: result = %d\n", __FUNCTION__, result);
        return result;
@@ -540,15 +541,15 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
         */
        if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
                US_DEBUGP("-- command was aborted\n");
-               goto Handle_Abort;
+               srb->result = DID_ABORT << 16;
+               goto Handle_Errors;
        }
 
        /* if there is a transport error, reset and don't auto-sense */
        if (result == USB_STOR_TRANSPORT_ERROR) {
                US_DEBUGP("-- transport indicates error, resetting\n");
-               us->transport_reset(us);
                srb->result = DID_ERROR << 16;
-               return;
+               goto Handle_Errors;
        }
 
        /* if the transport provided its own sense data, don't auto-sense */
@@ -668,7 +669,8 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
 
                if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
                        US_DEBUGP("-- auto-sense aborted\n");
-                       goto Handle_Abort;
+                       srb->result = DID_ABORT << 16;
+                       goto Handle_Errors;
                }
                if (temp_result != USB_STOR_TRANSPORT_GOOD) {
                        US_DEBUGP("-- auto-sense failure\n");
@@ -677,9 +679,9 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
                         * multi-target device, since failure of an
                         * auto-sense is perfectly valid
                         */
-                       if (!(us->flags & US_FL_SCM_MULT_TARG))
-                               us->transport_reset(us);
                        srb->result = DID_ERROR << 16;
+                       if (!(us->flags & US_FL_SCM_MULT_TARG))
+                               goto Handle_Errors;
                        return;
                }
 
@@ -720,12 +722,28 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
 
        return;
 
-       /* abort processing: the bulk-only transport requires a reset
-        * following an abort */
-  Handle_Abort:
-       srb->result = DID_ABORT << 16;
-       if (us->protocol == US_PR_BULK)
+       /* Error and abort processing: try to resynchronize with the device
+        * by issuing a port reset.  If that fails, try a class-specific
+        * device reset. */
+  Handle_Errors:
+
+       /* Let the SCSI layer know we are doing a reset, set the
+        * RESETTING bit, and clear the ABORTING bit so that the reset
+        * may proceed. */
+       scsi_lock(us_to_host(us));
+       usb_stor_report_bus_reset(us);
+       set_bit(US_FLIDX_RESETTING, &us->flags);
+       clear_bit(US_FLIDX_ABORTING, &us->flags);
+       scsi_unlock(us_to_host(us));
+
+       result = usb_stor_port_reset(us);
+       if (result < 0) {
+               scsi_lock(us_to_host(us));
+               usb_stor_report_device_reset(us);
+               scsi_unlock(us_to_host(us));
                us->transport_reset(us);
+       }
+       clear_bit(US_FLIDX_RESETTING, &us->flags);
 }
 
 /* Stop the current URB transfer */
@@ -1124,7 +1142,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
  * It's handy that every transport mechanism uses the control endpoint for
  * resets.
  *
- * Basically, we send a reset with a 20-second timeout, so we don't get
+ * Basically, we send a reset with a 5-second timeout, so we don't get
  * jammed attempting to do the reset.
  */
 static int usb_stor_reset_common(struct us_data *us,
@@ -1133,28 +1151,18 @@ static int usb_stor_reset_common(struct us_data *us,
 {
        int result;
        int result2;
-       int rc = FAILED;
 
-       /* Let the SCSI layer know we are doing a reset, set the
-        * RESETTING bit, and clear the ABORTING bit so that the reset
-        * may proceed.
-        */
-       scsi_lock(us_to_host(us));
-       usb_stor_report_device_reset(us);
-       set_bit(US_FLIDX_RESETTING, &us->flags);
-       clear_bit(US_FLIDX_ABORTING, &us->flags);
-       scsi_unlock(us_to_host(us));
+       if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+               US_DEBUGP("No reset during disconnect\n");
+               return -EIO;
+       }
 
-       /* A 20-second timeout may seem rather long, but a LaCie
-        * StudioDrive USB2 device takes 16+ seconds to get going
-        * following a powerup or USB attach event.
-        */
        result = usb_stor_control_msg(us, us->send_ctrl_pipe,
                        request, requesttype, value, index, data, size,
-                       20*HZ);
+                       5*HZ);
        if (result < 0) {
                US_DEBUGP("Soft reset failed: %d\n", result);
-               goto Done;
+               return result;
        }
 
        /* Give the device some time to recover from the reset,
@@ -1164,7 +1172,7 @@ static int usb_stor_reset_common(struct us_data *us,
                        HZ*6);
        if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
                US_DEBUGP("Reset interrupted by disconnect\n");
-               goto Done;
+               return -EIO;
        }
 
        US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
@@ -1173,17 +1181,14 @@ static int usb_stor_reset_common(struct us_data *us,
        US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n");
        result2 = usb_stor_clear_halt(us, us->send_bulk_pipe);
 
-       /* return a result code based on the result of the control message */
-       if (result < 0 || result2 < 0) {
+       /* return a result code based on the result of the clear-halts */
+       if (result >= 0)
+               result = result2;
+       if (result < 0)
                US_DEBUGP("Soft reset failed\n");
-               goto Done;
-       }
-       US_DEBUGP("Soft reset done\n");
-       rc = SUCCESS;
-
-  Done:
-       clear_bit(US_FLIDX_RESETTING, &us->flags);
-       return rc;
+       else
+               US_DEBUGP("Soft reset done\n");
+       return result;
 }
 
 /* This issues a CB[I] Reset to the device in question
@@ -1213,3 +1218,32 @@ int usb_stor_Bulk_reset(struct us_data *us)
                                 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                                 0, us->ifnum, NULL, 0);
 }
+
+/* Issue a USB port reset to the device.  But don't do anything if
+ * there's more than one interface in the device, so that other users
+ * are not affected. */
+int usb_stor_port_reset(struct us_data *us)
+{
+       int result, rc;
+
+       if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+               result = -EIO;
+               US_DEBUGP("No reset during disconnect\n");
+       } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) {
+               result = -EBUSY;
+               US_DEBUGP("Refusing to reset a multi-interface device\n");
+       } else {
+               result = rc =
+                       usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
+               if (result < 0) {
+                       US_DEBUGP("unable to lock device for reset: %d\n",
+                                       result);
+               } else {
+                       result = usb_reset_device(us->pusb_dev);
+                       if (rc)
+                               usb_unlock_device(us->pusb_dev);
+                       US_DEBUGP("usb_reset_device returns %d\n", result);
+               }
+       }
+       return result;
+}
index e25f8d8fc74197c8808202dff85cc0b917964fce..8d9e0663f8fe4e23ffe6b6f9bf1c9fc58a6d1ff6 100644 (file)
@@ -171,4 +171,5 @@ extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
 extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
                void *buf, unsigned int length, int use_sg, int *residual);
 
+extern int usb_stor_port_reset(struct us_data *us);
 #endif
index 35c1ca6b5a8eb828613fe87fbfac1dfeaaa918fe..77e7fc258aa2a7c104da2ba0a74a203525849d4d 100644 (file)
@@ -847,10 +847,8 @@ retry:
                wait_event_interruptible_timeout(us->delay_wait,
                                test_bit(US_FLIDX_DISCONNECTING, &us->flags),
                                delay_use * HZ);
-               if (current->flags & PF_FREEZE) {
-                       refrigerator(PF_FREEZE);
+               if (try_to_freeze())
                        goto retry;
-               }
        }
 
        /* If the device is still connected, perform the scanning */
index 9789115980a5ff0a3074a3495f6a9928745dca69..7bc1d44d88147d5368e2301a78254dba1f25f4bd 100644 (file)
@@ -350,10 +350,8 @@ static int default_vmode __initdata = VMODE_1024_768_60;
 static int default_cmode __initdata = CMODE_8;
 #endif
 
-#ifdef CONFIG_PMAC_PBOOK
 static int default_crt_on __initdata = 0;
 static int default_lcd_on __initdata = 1;
-#endif
 
 #ifdef CONFIG_MTRR
 static int mtrr = 1;
@@ -1249,7 +1247,6 @@ static int aty128_crtc_to_var(const struct aty128_crtc *crtc,
        return 0;
 }
 
-#ifdef CONFIG_PMAC_PBOOK
 static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
 {
        if (on) {
@@ -1284,7 +1281,6 @@ static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
                aty_st_le32(LVDS_GEN_CNTL, reg);
        }
 }
-#endif /* CONFIG_PMAC_PBOOK */
 
 static void aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
 {
@@ -1491,12 +1487,10 @@ static int aty128fb_set_par(struct fb_info *info)
        info->fix.visual = par->crtc.bpp == 8 ? FB_VISUAL_PSEUDOCOLOR
                : FB_VISUAL_DIRECTCOLOR;
 
-#ifdef CONFIG_PMAC_PBOOK
        if (par->chip_gen == rage_M3) {
                aty128_set_crt_enable(par, par->crt_on);
                aty128_set_lcd_enable(par, par->lcd_on);
        }
-#endif
        if (par->accel_flags & FB_ACCELF_TEXT)
                aty128_init_engine(par);
 
@@ -1652,7 +1646,6 @@ static int __init aty128fb_setup(char *options)
                return 0;
 
        while ((this_opt = strsep(&options, ",")) != NULL) {
-#ifdef CONFIG_PMAC_PBOOK
                if (!strncmp(this_opt, "lcd:", 4)) {
                        default_lcd_on = simple_strtoul(this_opt+4, NULL, 0);
                        continue;
@@ -1660,7 +1653,6 @@ static int __init aty128fb_setup(char *options)
                        default_crt_on = simple_strtoul(this_opt+4, NULL, 0);
                        continue;
                }
-#endif
 #ifdef CONFIG_MTRR
                if(!strncmp(this_opt, "nomtrr", 6)) {
                        mtrr = 0;
@@ -1752,10 +1744,8 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *
        info->fbops = &aty128fb_ops;
        info->flags = FBINFO_FLAG_DEFAULT;
 
-#ifdef CONFIG_PMAC_PBOOK
        par->lcd_on = default_lcd_on;
        par->crt_on = default_crt_on;
-#endif
 
        var = default_var;
 #ifdef CONFIG_PPC_PMAC
@@ -2035,12 +2025,10 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
 
        aty_st_8(CRTC_EXT_CNTL+1, state);
 
-#ifdef CONFIG_PMAC_PBOOK
        if (par->chip_gen == rage_M3) {
                aty128_set_crt_enable(par, par->crt_on && !blank);
                aty128_set_lcd_enable(par, par->lcd_on && !blank);
        }
-#endif 
 #ifdef CONFIG_PMAC_BACKLIGHT
        if ((_machine == _MACH_Pmac) && !blank)
                set_backlight_enable(1);
@@ -2124,7 +2112,6 @@ static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
                          u_long arg, struct fb_info *info)
 {
-#ifdef CONFIG_PMAC_PBOOK
        struct aty128fb_par *par = info->par;
        u32 value;
        int rc;
@@ -2149,7 +2136,6 @@ static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
                value = (par->crt_on << 1) | par->lcd_on;
                return put_user(value, (__u32 __user *)arg);
        }
-#endif
        return -EINVAL;
 }
 
index cacd88cc84ab6e56c680ae8b543e06e7a6e89034..b6fe30c3ad6253691417d61552643805ac31d57b 100644 (file)
@@ -111,15 +111,15 @@ static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
 void au1100_nocursor(struct display *p, int mode, int xx, int yy){};
 
 static struct fb_ops au1100fb_ops = {
-       owner:          THIS_MODULE,
-       fb_get_fix:     fbgen_get_fix,
-       fb_get_var:     fbgen_get_var,
-       fb_set_var:     fbgen_set_var,
-       fb_get_cmap:    fbgen_get_cmap,
-       fb_set_cmap:    fbgen_set_cmap,
-       fb_pan_display: fbgen_pan_display,
-        fb_ioctl:       au1100fb_ioctl,
-       fb_mmap:        au1100fb_mmap,
+       .owner          = THIS_MODULE,
+       .fb_get_fix     = fbgen_get_fix,
+       .fb_get_var     = fbgen_get_var,
+       .fb_set_var     = fbgen_set_var,
+       .fb_get_cmap    = fbgen_get_cmap,
+       .fb_set_cmap    = fbgen_set_cmap,
+       .fb_pan_display = fbgen_pan_display,
+        .fb_ioctl      = au1100fb_ioctl,
+       .fb_mmap        = au1100fb_mmap,
 };
 
 static void au1100_detect(void)
index 95e72550d43ff4b373ec3615b57b9399ce574a76..e75a965ec760324ff3ebe5705ebdeb4fb4c97ac6 100644 (file)
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/console.h>
 #include <asm/io.h>
 
 #ifdef CONFIG_PMAC_BACKLIGHT
 #include <asm/backlight.h>
 #endif
-#ifdef CONFIG_PMAC_PBOOK
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#endif
 
 /*
  * Since we access the display with inb/outb to fixed port numbers,
  * we can only handle one 6555x chip.  -- paulus
  */
-static struct fb_info chipsfb_info;
-
 #define write_ind(num, val, ap, dp)    do { \
        outb((num), (ap)); outb((val), (dp)); \
 } while (0)
@@ -74,14 +69,6 @@ static struct fb_info chipsfb_info;
        inb(0x3da); read_ind(num, var, 0x3c0, 0x3c1); \
 } while (0)
 
-#ifdef CONFIG_PMAC_PBOOK
-static unsigned char *save_framebuffer;
-int chips_sleep_notify(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier chips_sleep_notifier = {
-       chips_sleep_notify, SLEEP_LEVEL_VIDEO,
-};
-#endif
-
 /*
  * Exported functions
  */
@@ -356,6 +343,8 @@ static struct fb_var_screeninfo chipsfb_var __initdata = {
 
 static void __init init_chips(struct fb_info *p, unsigned long addr)
 {
+       memset(p->screen_base, 0, 0x100000);
+
        p->fix = chipsfb_fix;
        p->fix.smem_start = addr;
 
@@ -366,34 +355,41 @@ static void __init init_chips(struct fb_info *p, unsigned long addr)
 
        fb_alloc_cmap(&p->cmap, 256, 0);
 
-       if (register_framebuffer(p) < 0) {
-               printk(KERN_ERR "C&T 65550 framebuffer failed to register\n");
-               return;
-       }
-
-       printk(KERN_INFO "fb%d: Chips 65550 frame buffer (%dK RAM detected)\n",
-               p->node, p->fix.smem_len / 1024);
-
        chips_hw_init();
 }
 
 static int __devinit
 chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
 {
-       struct fb_info *p = &chipsfb_info;
+       struct fb_info *p;
        unsigned long addr, size;
        unsigned short cmd;
+       int rc = -ENODEV;
+
+       if (pci_enable_device(dp) < 0) {
+               dev_err(&dp->dev, "Cannot enable PCI device\n");
+               goto err_out;
+       }
 
        if ((dp->resource[0].flags & IORESOURCE_MEM) == 0)
-               return -ENODEV;
+               goto err_disable;
        addr = pci_resource_start(dp, 0);
        size = pci_resource_len(dp, 0);
        if (addr == 0)
-               return -ENODEV;
-       if (p->screen_base != 0)
-               return -EBUSY;
-       if (!request_mem_region(addr, size, "chipsfb"))
-               return -EBUSY;
+               goto err_disable;
+
+       p = framebuffer_alloc(0, &dp->dev);
+       if (p == NULL) {
+               dev_err(&dp->dev, "Cannot allocate framebuffer structure\n");
+               rc = -ENOMEM;
+               goto err_disable;
+       }
+
+       if (pci_request_region(dp, 0, "chipsfb") != 0) {
+               dev_err(&dp->dev, "Cannot request framebuffer\n");
+               rc = -EBUSY;
+               goto err_release_fb;
+       }
 
 #ifdef __BIG_ENDIAN
        addr += 0x800000;       // Use big-endian aperture
@@ -411,37 +407,89 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
        set_backlight_enable(1);
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
+#ifdef CONFIG_PPC
        p->screen_base = __ioremap(addr, 0x200000, _PAGE_NO_CACHE);
+#else
+       p->screen_base = ioremap(addr, 0x200000);
+#endif
        if (p->screen_base == NULL) {
-               release_mem_region(addr, size);
-               return -ENOMEM;
+               dev_err(&dp->dev, "Cannot map framebuffer\n");
+               rc = -ENOMEM;
+               goto err_release_pci;
        }
+
+       pci_set_drvdata(dp, p);
        p->device = &dp->dev;
+
        init_chips(p, addr);
 
-#ifdef CONFIG_PMAC_PBOOK
-       pmu_register_sleep_notifier(&chips_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+       if (register_framebuffer(p) < 0) {
+               dev_err(&dp->dev,"C&T 65550 framebuffer failed to register\n");
+               goto err_unmap;
+       }
+
+       dev_info(&dp->dev,"fb%d: Chips 65550 frame buffer"
+                " (%dK RAM detected)\n",
+                p->node, p->fix.smem_len / 1024);
 
-       pci_set_drvdata(dp, p);
        return 0;
+
+ err_unmap:
+       iounmap(p->screen_base);
+ err_release_pci:
+       pci_release_region(dp, 0);
+ err_release_fb:
+       framebuffer_release(p);
+ err_disable:
+ err_out:
+       return rc;
 }
 
 static void __devexit chipsfb_remove(struct pci_dev *dp)
 {
        struct fb_info *p = pci_get_drvdata(dp);
 
-       if (p != &chipsfb_info || p->screen_base == NULL)
+       if (p->screen_base == NULL)
                return;
        unregister_framebuffer(p);
        iounmap(p->screen_base);
        p->screen_base = NULL;
-       release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0));
+       pci_release_region(dp, 0);
+}
+
+#ifdef CONFIG_PM
+static int chipsfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+        struct fb_info *p = pci_get_drvdata(pdev);
+
+       if (state == pdev->dev.power.power_state)
+               return 0;
+       if (state != PM_SUSPEND_MEM)
+               goto done;
+
+       acquire_console_sem();
+       chipsfb_blank(1, p);
+       fb_set_suspend(p, 1);
+       release_console_sem();
+ done:
+       pdev->dev.power.power_state = state;
+       return 0;
+}
+
+static int chipsfb_pci_resume(struct pci_dev *pdev)
+{
+        struct fb_info *p = pci_get_drvdata(pdev);
 
-#ifdef CONFIG_PMAC_PBOOK
-       pmu_unregister_sleep_notifier(&chips_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+       acquire_console_sem();
+       fb_set_suspend(p, 0);
+       chipsfb_blank(0, p);
+       release_console_sem();
+
+       pdev->dev.power.power_state = PMSG_ON;
+       return 0;
 }
+#endif /* CONFIG_PM */
+
 
 static struct pci_device_id chipsfb_pci_tbl[] = {
        { PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_65550, PCI_ANY_ID, PCI_ANY_ID },
@@ -455,6 +503,10 @@ static struct pci_driver chipsfb_driver = {
        .id_table =     chipsfb_pci_tbl,
        .probe =        chipsfb_pci_init,
        .remove =       __devexit_p(chipsfb_remove),
+#ifdef CONFIG_PM
+       .suspend =      chipsfb_pci_suspend,
+       .resume =       chipsfb_pci_resume,
+#endif
 };
 
 int __init chips_init(void)
@@ -472,48 +524,4 @@ static void __exit chipsfb_exit(void)
        pci_unregister_driver(&chipsfb_driver);
 }
 
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * Save the contents of the frame buffer when we go to sleep,
- * and restore it when we wake up again.
- */
-int
-chips_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
-       struct fb_info *p = &chipsfb_info;
-       int nb = p->var.yres * p->fix.line_length;
-
-       if (p->screen_base == NULL)
-               return PBOOK_SLEEP_OK;
-
-       switch (when) {
-       case PBOOK_SLEEP_REQUEST:
-               save_framebuffer = vmalloc(nb);
-               if (save_framebuffer == NULL)
-                       return PBOOK_SLEEP_REFUSE;
-               break;
-       case PBOOK_SLEEP_REJECT:
-               if (save_framebuffer) {
-                       vfree(save_framebuffer);
-                       save_framebuffer = NULL;
-               }
-               break;
-       case PBOOK_SLEEP_NOW:
-               chipsfb_blank(1, p);
-               if (save_framebuffer)
-                       memcpy(save_framebuffer, p->screen_base, nb);
-               break;
-       case PBOOK_WAKE:
-               if (save_framebuffer) {
-                       memcpy(p->screen_base, save_framebuffer, nb);
-                       vfree(save_framebuffer);
-                       save_framebuffer = NULL;
-               }
-               chipsfb_blank(0, p);
-               break;
-       }
-       return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
 MODULE_LICENSE("GPL");
index e4b91a4b936c9c9125d42eb799973fab6b7aec83..cbff98337aa6b37069e62bd03d4fc67c7e5eb15a 100644 (file)
@@ -156,7 +156,6 @@ config FONT_6x11
 config FONT_7x14
        bool "console 7x14 font (not supported by all drivers)" if FONTS
        depends on FRAMEBUFFER_CONSOLE
-       default y if !SPARC32 && !SPARC64 && !FONTS
        help
          Console font with characters just a bit smaller than the default.
          If the standard 8x16 font is a little too big for you, say Y.
@@ -197,8 +196,8 @@ config FONT_SUN12x22
          standard font is unreadable for you, say Y, otherwise say N.
 
 config FONT_10x18
-       bool "console 10x18 font (not supported by all drivers)"
-       depends on FONTS
+       bool "console 10x18 font (not supported by all drivers)" if FONTS
+       depends on FRAMEBUFFER_CONSOLE
        help
          This is a high resolution console font for machines with very
          big letters. It fits between the sun 12x22 and the normal 8x16 font.
index 277d733c6d00a4150436c42b234aec4edc572b15..7dfbf39b4ed3c9c59ea502bd9a507d1a7a224c75 100644 (file)
@@ -228,8 +228,6 @@ static ssize_t store_virtual(struct class_device *class_device,
        if (last - buf >= count)
                return -EINVAL;
        var.yres_virtual = simple_strtoul(last, &last, 0);
-       printk(KERN_ERR "fb: xres %d yres %d\n", var.xres_virtual,
-              var.yres_virtual);
 
        if ((err = activate(fb_info, &var)))
                return err;
index 76fd3a519b8af1d1d637a308c6d1e969bf99b37c..a18dd024fc86a9384b67c49391c1685ca75e95f3 100644 (file)
@@ -197,10 +197,7 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m) {
        DBG(__FUNCTION__)
 
        hw->SEQ[0] = 0x00;
-       if (fwidth == 9)
-               hw->SEQ[1] = 0x00;
-       else
-               hw->SEQ[1] = 0x01;      /* or 0x09 */
+       hw->SEQ[1] = 0x01;      /* or 0x09 */
        hw->SEQ[2] = 0x0F;      /* bitplanes */
        hw->SEQ[3] = 0x00;
        hw->SEQ[4] = 0x0E;
index f3069b01e248efa1eaf86e00fec16ff6047fc048..9ed1a931dd315c8008d7d6b952f1a34900c2222f 100644 (file)
@@ -389,10 +389,11 @@ static int __init vesafb_probe(struct device *device)
                unsigned int temp_size = size_total;
                /* Find the largest power-of-two */
                while (temp_size & (temp_size - 1))
-                       temp_size &= (temp_size - 1);
-                        
-                /* Try and find a power of two to add */
-               while (temp_size && mtrr_add(vesafb_fix.smem_start, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) {
+                       temp_size &= (temp_size - 1);
+
+               /* Try and find a power of two to add */
+               while (temp_size > PAGE_SIZE &&
+                       mtrr_add(vesafb_fix.smem_start, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) {
                        temp_size >>= 1;
                }
        }
index b460927ec32ad78432660372a7fa20ab49dedfef..312cf3220f12dfa9f81f1515cb793efa3fa7db32 100644 (file)
@@ -646,7 +646,7 @@ static int w1_control(void *data)
        while (!control_needs_exit || have_to_wait) {
                have_to_wait = 0;
 
-               try_to_freeze(PF_FREEZE);
+               try_to_freeze();
                msleep_interruptible(w1_timeout * 1000);
 
                if (signal_pending(current))
@@ -725,7 +725,7 @@ int w1_process(void *data)
        allow_signal(SIGTERM);
 
        while (!test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
-               try_to_freeze(PF_FREEZE);
+               try_to_freeze();
                msleep_interruptible(w1_timeout * 1000);
 
                if (signal_pending(current))
index a7c0cc3203cba461c6a243e11af710d9fbcf7354..062177956239b1c25c6199579e9f72faecc21212 100644 (file)
@@ -50,6 +50,23 @@ config EXT2_FS_SECURITY
          If you are not using a security module that requires using
          extended attributes for file security labels, say N.
 
+config EXT2_FS_XIP
+       bool "Ext2 execute in place support"
+       depends on EXT2_FS
+       help
+         Execute in place can be used on memory-backed block devices. If you
+         enable this option, you can select to mount block devices which are
+         capable of this feature without using the page cache.
+
+         If you do not use a block device that is capable of using this,
+         or if unsure, say N.
+
+config FS_XIP
+# execute in place
+       bool
+       depends on EXT2_FS_XIP
+       default y
+
 config EXT3_FS
        tristate "Ext3 journalling file system support"
        help
@@ -717,6 +734,12 @@ config PROC_KCORE
        bool "/proc/kcore support" if !ARM
        depends on PROC_FS && MMU
 
+config PROC_VMCORE
+        bool "/proc/vmcore support (EXPERIMENTAL)"
+        depends on PROC_FS && EMBEDDED && EXPERIMENTAL && CRASH_DUMP
+        help
+        Exports the dump image of crashed kernel in ELF format.
+
 config SYSFS
        bool "sysfs file system support" if EMBEDDED
        default y
@@ -1413,6 +1436,8 @@ config NFSD_V4
        bool "Provide NFSv4 server support (EXPERIMENTAL)"
        depends on NFSD_V3 && EXPERIMENTAL
        select NFSD_TCP
+       select CRYPTO_MD5
+       select CRYPTO
        help
          If you would like to include the NFSv4 server as well as the NFSv2
          and NFSv3 servers, say Y here.  This feature is experimental, and
index fc92e59e9faffe9a81ecb404e9f16f0aaaf2a55c..20edcf28bfd217d7d7d3c434293de6f5d40c91e0 100644 (file)
@@ -10,6 +10,7 @@ obj-y :=      open.o read_write.o file_table.o buffer.o  bio.o super.o \
                ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \
                attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
                seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \
+               ioprio.o
 
 obj-$(CONFIG_EPOLL)            += eventpoll.o
 obj-$(CONFIG_COMPAT)           += compat.o
index 6fc88ae8ad9477fd3e12d5d151ef7a142266dfee..7ac07d0d47b91b90e4c40dc16216e50b5876d0af 100644 (file)
@@ -116,7 +116,7 @@ static int kafsasyncd(void *arg)
                remove_wait_queue(&kafsasyncd_sleepq, &myself);
                set_current_state(TASK_RUNNING);
 
-               try_to_freeze(PF_FREEZE);
+               try_to_freeze();
 
                /* discard pending signals */
                afs_discard_my_signals();
index 86e710dd057e766ed89a59c83c8d4ea3c02ff5e0..65bc05ab81826b417513f203a5b7e930d7b9fed7 100644 (file)
@@ -91,7 +91,7 @@ static int kafstimod(void *arg)
                        complete_and_exit(&kafstimod_dead, 0);
                }
 
-               try_to_freeze(PF_FREEZE);
+               try_to_freeze();
 
                /* discard pending signals */
                afs_discard_my_signals();
index 7afa222f68028a338eae68907ae231a446cc398c..06d7d4390fe7dd8562e8433ce3a29b2b9ee4e241 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -58,6 +58,7 @@ static DEFINE_SPINLOCK(fput_lock);
 static LIST_HEAD(fput_head);
 
 static void aio_kick_handler(void *);
+static void aio_queue_work(struct kioctx *);
 
 /* aio_setup
  *     Creates the slab caches used by the aio routines, panic on
@@ -747,6 +748,14 @@ out:
                 * has already been kicked */
                if (kiocbIsKicked(iocb)) {
                        __queue_kicked_iocb(iocb);
+
+                       /*
+                        * __queue_kicked_iocb will always return 1 here, because
+                        * iocb->ki_run_list is empty at this point so it should
+                        * be safe to unconditionally queue the context into the
+                        * work queue.
+                        */
+                       aio_queue_work(ctx);
                }
        }
        return ret;
index 13e5938a64f6338072e06c16ad8b73e366cad024..561e63a149667abafef2c92aabe287e0eae2f27d 100644 (file)
@@ -278,7 +278,7 @@ EXPORT_SYMBOL(thaw_bdev);
  */
 static void do_sync(unsigned long wait)
 {
-       wakeup_bdflush(0);
+       wakeup_pdflush(0);
        sync_inodes(0);         /* All mappings, inodes and their blockdevs */
        DQUOT_SYNC(NULL);
        sync_supers();          /* Write the superblocks */
@@ -497,7 +497,7 @@ static void free_more_memory(void)
        struct zone **zones;
        pg_data_t *pgdat;
 
-       wakeup_bdflush(1024);
+       wakeup_pdflush(1024);
        yield();
 
        for_each_pgdat(pgdat) {
index e82aac9cc2f5b9d39101e372cdab81dd971725a0..a69a5d8a406f982be7eb6cb1fc9c4ff59a858ffa 100644 (file)
@@ -150,7 +150,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
        struct char_device_struct *cd = NULL, **cp;
        int i = major_to_index(major);
 
-       up(&chrdevs_lock);
+       down(&chrdevs_lock);
        for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
                if ((*cp)->major == major &&
                    (*cp)->baseminor == baseminor &&
index 1d55e7e6734247e8464899f308d94f8d0a398f4b..0d06097bc995f93cd0074c424cbf24d221b80490 100644 (file)
@@ -215,7 +215,7 @@ static struct page *dio_get_page(struct dio *dio)
 static void dio_complete(struct dio *dio, loff_t offset, ssize_t bytes)
 {
        if (dio->end_io && dio->result)
-               dio->end_io(dio->inode, offset, bytes, dio->map_bh.b_private);
+               dio->end_io(dio->iocb, offset, bytes, dio->map_bh.b_private);
        if (dio->lock_type == DIO_LOCKING)
                up_read(&dio->inode->i_alloc_sem);
 }
index 37212b039a4ab834770bfd663f503dcaa669a37a..b9732335bcdcd6006733a9561e9ef8ceb8769117 100644 (file)
@@ -409,13 +409,10 @@ out_dqlock:
  * for this sb+type at all. */
 static void invalidate_dquots(struct super_block *sb, int type)
 {
-       struct dquot *dquot;
-       struct list_head *head;
+       struct dquot *dquot, *tmp;
 
        spin_lock(&dq_list_lock);
-       for (head = inuse_list.next; head != &inuse_list;) {
-               dquot = list_entry(head, struct dquot, dq_inuse);
-               head = head->next;
+       list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) {
                if (dquot->dq_sb != sb)
                        continue;
                if (dquot->dq_type != type)
index ee240a14e70f91404af63c39b62d09ef3020e952..c5d02da73bc3dd192d42465bc544f719ab2cba90 100644 (file)
@@ -10,3 +10,4 @@ ext2-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
 ext2-$(CONFIG_EXT2_FS_XATTR)    += xattr.o xattr_user.o xattr_trusted.o
 ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o
 ext2-$(CONFIG_EXT2_FS_SECURITY)         += xattr_security.o
+ext2-$(CONFIG_EXT2_FS_XIP)      += xip.o
index 8f0fd726c3f1fb4a89263acbc60fc095c95f0b84..eed521d22cf08900f397444f0b743c2c53411143 100644 (file)
@@ -147,9 +147,11 @@ extern struct file_operations ext2_dir_operations;
 /* file.c */
 extern struct inode_operations ext2_file_inode_operations;
 extern struct file_operations ext2_file_operations;
+extern struct file_operations ext2_xip_file_operations;
 
 /* inode.c */
 extern struct address_space_operations ext2_aops;
+extern struct address_space_operations ext2_aops_xip;
 extern struct address_space_operations ext2_nobh_aops;
 
 /* namei.c */
index f5e86141ec541202676d96cd0e3a10f13f057155..a484412fc7821bc37dfff95c5141c37ac7cbe3e2 100644 (file)
@@ -55,6 +55,20 @@ struct file_operations ext2_file_operations = {
        .sendfile       = generic_file_sendfile,
 };
 
+#ifdef CONFIG_EXT2_FS_XIP
+struct file_operations ext2_xip_file_operations = {
+       .llseek         = generic_file_llseek,
+       .read           = xip_file_read,
+       .write          = xip_file_write,
+       .ioctl          = ext2_ioctl,
+       .mmap           = xip_file_mmap,
+       .open           = generic_file_open,
+       .release        = ext2_release_file,
+       .fsync          = ext2_sync_file,
+       .sendfile       = xip_file_sendfile,
+};
+#endif
+
 struct inode_operations ext2_file_inode_operations = {
        .truncate       = ext2_truncate,
 #ifdef CONFIG_EXT2_FS_XATTR
index a50d9db4b6e4265759b07344546485e77c6afd34..53dceb0c659308c661a9c8e7deeced2dff27502e 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/mpage.h>
 #include "ext2.h"
 #include "acl.h"
+#include "xip.h"
 
 MODULE_AUTHOR("Remy Card and others");
 MODULE_DESCRIPTION("Second Extended Filesystem");
@@ -594,6 +595,16 @@ out:
        if (err)
                goto cleanup;
 
+       if (ext2_use_xip(inode->i_sb)) {
+               /*
+                * we need to clear the block
+                */
+               err = ext2_clear_xip_target (inode,
+                       le32_to_cpu(chain[depth-1].key));
+               if (err)
+                       goto cleanup;
+       }
+
        if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0)
                goto changed;
 
@@ -691,6 +702,11 @@ struct address_space_operations ext2_aops = {
        .writepages             = ext2_writepages,
 };
 
+struct address_space_operations ext2_aops_xip = {
+       .bmap                   = ext2_bmap,
+       .get_xip_page           = ext2_get_xip_page,
+};
+
 struct address_space_operations ext2_nobh_aops = {
        .readpage               = ext2_readpage,
        .readpages              = ext2_readpages,
@@ -910,7 +926,9 @@ void ext2_truncate (struct inode * inode)
        iblock = (inode->i_size + blocksize-1)
                                        >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
 
-       if (test_opt(inode->i_sb, NOBH))
+       if (mapping_is_xip(inode->i_mapping))
+               xip_truncate_page(inode->i_mapping, inode->i_size);
+       else if (test_opt(inode->i_sb, NOBH))
                nobh_truncate_page(inode->i_mapping, inode->i_size);
        else
                block_truncate_page(inode->i_mapping,
@@ -1110,11 +1128,16 @@ void ext2_read_inode (struct inode * inode)
 
        if (S_ISREG(inode->i_mode)) {
                inode->i_op = &ext2_file_inode_operations;
-               inode->i_fop = &ext2_file_operations;
-               if (test_opt(inode->i_sb, NOBH))
+               if (ext2_use_xip(inode->i_sb)) {
+                       inode->i_mapping->a_ops = &ext2_aops_xip;
+                       inode->i_fop = &ext2_xip_file_operations;
+               } else if (test_opt(inode->i_sb, NOBH)) {
                        inode->i_mapping->a_ops = &ext2_nobh_aops;
-               else
+                       inode->i_fop = &ext2_file_operations;
+               } else {
                        inode->i_mapping->a_ops = &ext2_aops;
+                       inode->i_fop = &ext2_file_operations;
+               }
        } else if (S_ISDIR(inode->i_mode)) {
                inode->i_op = &ext2_dir_inode_operations;
                inode->i_fop = &ext2_dir_operations;
index 3176b3d3ffa87afce47431963f44ddcd67cf251b..c5513953c825daccbfbfae119e71bec81dec63c0 100644 (file)
@@ -34,6 +34,7 @@
 #include "ext2.h"
 #include "xattr.h"
 #include "acl.h"
+#include "xip.h"
 
 /*
  * Couple of helper functions - make the code slightly cleaner.
@@ -127,11 +128,16 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, st
        int err = PTR_ERR(inode);
        if (!IS_ERR(inode)) {
                inode->i_op = &ext2_file_inode_operations;
-               inode->i_fop = &ext2_file_operations;
-               if (test_opt(inode->i_sb, NOBH))
+               if (ext2_use_xip(inode->i_sb)) {
+                       inode->i_mapping->a_ops = &ext2_aops_xip;
+                       inode->i_fop = &ext2_xip_file_operations;
+               } else if (test_opt(inode->i_sb, NOBH)) {
                        inode->i_mapping->a_ops = &ext2_nobh_aops;
-               else
+                       inode->i_fop = &ext2_file_operations;
+               } else {
                        inode->i_mapping->a_ops = &ext2_aops;
+                       inode->i_fop = &ext2_file_operations;
+               }
                mark_inode_dirty(inode);
                err = ext2_add_nondir(dentry, inode);
        }
index 661c3d98d946bd5222e14dd697bec58319ea8f5f..876e391f2871b1b146a786a11631c212076415ce 100644 (file)
@@ -31,6 +31,7 @@
 #include "ext2.h"
 #include "xattr.h"
 #include "acl.h"
+#include "xip.h"
 
 static void ext2_sync_super(struct super_block *sb,
                            struct ext2_super_block *es);
@@ -257,7 +258,7 @@ enum {
        Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
        Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
        Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh,
-       Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
+       Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip,
        Opt_ignore, Opt_err,
 };
 
@@ -286,6 +287,7 @@ static match_table_t tokens = {
        {Opt_nouser_xattr, "nouser_xattr"},
        {Opt_acl, "acl"},
        {Opt_noacl, "noacl"},
+       {Opt_xip, "xip"},
        {Opt_ignore, "grpquota"},
        {Opt_ignore, "noquota"},
        {Opt_ignore, "quota"},
@@ -397,6 +399,13 @@ static int parse_options (char * options,
                        printk("EXT2 (no)acl options not supported\n");
                        break;
 #endif
+               case Opt_xip:
+#ifdef CONFIG_EXT2_FS_XIP
+                       set_opt (sbi->s_mount_opt, XIP);
+#else
+                       printk("EXT2 xip option not supported\n");
+#endif
+                       break;
                case Opt_ignore:
                        break;
                default:
@@ -640,6 +649,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
                ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ?
                 MS_POSIXACL : 0);
 
+       ext2_xip_verify_sb(sb); /* see if bdev supports xip, unset
+                                   EXT2_MOUNT_XIP if not */
+
        if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV &&
            (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) ||
             EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
@@ -668,6 +680,13 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
 
        blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);
 
+       if ((ext2_use_xip(sb)) && ((blocksize != PAGE_SIZE) ||
+                                 (sb->s_blocksize != blocksize))) {
+               if (!silent)
+                       printk("XIP: Unsupported blocksize\n");
+               goto failed_mount;
+       }
+
        /* If the blocksize doesn't match, re-read the thing.. */
        if (sb->s_blocksize != blocksize) {
                brelse(bh);
@@ -916,6 +935,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
 {
        struct ext2_sb_info * sbi = EXT2_SB(sb);
        struct ext2_super_block * es;
+       unsigned long old_mount_opt = sbi->s_mount_opt;
 
        /*
         * Allow the "check" option to be passed as a remount option.
@@ -927,6 +947,11 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
                ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
 
        es = sbi->s_es;
+       if (((sbi->s_mount_opt & EXT2_MOUNT_XIP) !=
+           (old_mount_opt & EXT2_MOUNT_XIP)) &&
+           invalidate_inodes(sb))
+               ext2_warning(sb, __FUNCTION__, "busy inodes while remounting "\
+                            "xip remain in cache (no functional problem)");
        if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
                return 0;
        if (*flags & MS_RDONLY) {
diff --git a/fs/ext2/xip.c b/fs/ext2/xip.c
new file mode 100644 (file)
index 0000000..d44431d
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  linux/fs/ext2/xip.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ * Author: Carsten Otte (cotte@de.ibm.com)
+ */
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/buffer_head.h>
+#include <linux/ext2_fs_sb.h>
+#include <linux/ext2_fs.h>
+#include "ext2.h"
+#include "xip.h"
+
+static inline int
+__inode_direct_access(struct inode *inode, sector_t sector, unsigned long *data) {
+       BUG_ON(!inode->i_sb->s_bdev->bd_disk->fops->direct_access);
+       return inode->i_sb->s_bdev->bd_disk->fops
+               ->direct_access(inode->i_sb->s_bdev,sector,data);
+}
+
+int
+ext2_clear_xip_target(struct inode *inode, int block) {
+       sector_t sector = block*(PAGE_SIZE/512);
+       unsigned long data;
+       int rc;
+
+       rc = __inode_direct_access(inode, sector, &data);
+       if (rc)
+               return rc;
+       clear_page((void*)data);
+       return 0;
+}
+
+void ext2_xip_verify_sb(struct super_block *sb)
+{
+       struct ext2_sb_info *sbi = EXT2_SB(sb);
+
+       if ((sbi->s_mount_opt & EXT2_MOUNT_XIP)) {
+               if ((sb->s_bdev == NULL) ||
+                       sb->s_bdev->bd_disk == NULL ||
+                       sb->s_bdev->bd_disk->fops == NULL ||
+                       sb->s_bdev->bd_disk->fops->direct_access == NULL) {
+                       sbi->s_mount_opt &= (~EXT2_MOUNT_XIP);
+                       ext2_warning(sb, __FUNCTION__,
+                               "ignoring xip option - not supported by bdev");
+               }
+       }
+}
+
+struct page*
+ext2_get_xip_page(struct address_space *mapping, sector_t blockno,
+                  int create)
+{
+       int rc;
+       unsigned long data;
+       struct buffer_head tmp;
+
+       tmp.b_state = 0;
+       tmp.b_blocknr = 0;
+       rc = ext2_get_block(mapping->host, blockno/(PAGE_SIZE/512) , &tmp,
+                               create);
+       if (rc)
+               return ERR_PTR(rc);
+       if (tmp.b_blocknr == 0) {
+               /* SPARSE block */
+               BUG_ON(create);
+               return ERR_PTR(-ENODATA);
+       }
+
+       rc = __inode_direct_access
+               (mapping->host,tmp.b_blocknr*(PAGE_SIZE/512) ,&data);
+       if (rc)
+               return ERR_PTR(rc);
+
+       SetPageUptodate(virt_to_page(data));
+       return virt_to_page(data);
+}
diff --git a/fs/ext2/xip.h b/fs/ext2/xip.h
new file mode 100644 (file)
index 0000000..aa85331
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *  linux/fs/ext2/xip.h
+ *
+ * Copyright (C) 2005 IBM Corporation
+ * Author: Carsten Otte (cotte@de.ibm.com)
+ */
+
+#ifdef CONFIG_EXT2_FS_XIP
+extern void ext2_xip_verify_sb (struct super_block *);
+extern int ext2_clear_xip_target (struct inode *, int);
+
+static inline int ext2_use_xip (struct super_block *sb)
+{
+       struct ext2_sb_info *sbi = EXT2_SB(sb);
+       return (sbi->s_mount_opt & EXT2_MOUNT_XIP);
+}
+struct page* ext2_get_xip_page (struct address_space *, sector_t, int);
+#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_page)
+#else
+#define mapping_is_xip(map)                    0
+#define ext2_xip_verify_sb(sb)                 do { } while (0)
+#define ext2_use_xip(sb)                       0
+#define ext2_clear_xip_target(inode, chain)    0
+#define ext2_get_xip_page                      NULL
+#endif
index 133f5aa581bb6f7d17bdb0ef2285b5b8a8da762c..3ac38266fc9e598c21a89593d5893f27b10bfc25 100644 (file)
@@ -393,7 +393,8 @@ ext3_acl_chmod(struct inode *inode)
                int retries = 0;
 
        retry:
-               handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
+               handle = ext3_journal_start(inode,
+                               EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
                if (IS_ERR(handle)) {
                        error = PTR_ERR(handle);
                        ext3_std_error(inode->i_sb, error);
@@ -503,7 +504,7 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value,
                acl = NULL;
 
 retry:
-       handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
+       handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
        error = ext3_set_acl(handle, inode, type, acl);
index ccd632fcc6d87e7f32711133818e69a6de2a10ad..e463dca008e4a9ad16cb54ca2dcdba7ef1793168 100644 (file)
@@ -749,24 +749,24 @@ fail_access:
  *     to find a free region that is of my size and has not
  *     been reserved.
  *
- *     on succeed, it returns the reservation window to be appended to.
- *     failed, return NULL.
  */
-static struct ext3_reserve_window_node *find_next_reservable_window(
+static int find_next_reservable_window(
                                struct ext3_reserve_window_node *search_head,
-                               unsigned long size, int *start_block,
+                               struct ext3_reserve_window_node *my_rsv,
+                               struct super_block * sb, int start_block,
                                int last_block)
 {
        struct rb_node *next;
        struct ext3_reserve_window_node *rsv, *prev;
        int cur;
+       int size = my_rsv->rsv_goal_size;
 
        /* TODO: make the start of the reservation window byte-aligned */
        /* cur = *start_block & ~7;*/
-       cur = *start_block;
+       cur = start_block;
        rsv = search_head;
        if (!rsv)
-               return NULL;
+               return -1;
 
        while (1) {
                if (cur <= rsv->rsv_end)
@@ -782,11 +782,11 @@ static struct ext3_reserve_window_node *find_next_reservable_window(
                 * space with expected-size (or more)...
                 */
                if (cur > last_block)
-                       return NULL;            /* fail */
+                       return -1;              /* fail */
 
                prev = rsv;
                next = rb_next(&rsv->rsv_node);
-               rsv = list_entry(next, struct ext3_reserve_window_node, rsv_node);
+               rsv = list_entry(next,struct ext3_reserve_window_node,rsv_node);
 
                /*
                 * Reached the last reservation, we can just append to the
@@ -813,8 +813,25 @@ static struct ext3_reserve_window_node *find_next_reservable_window(
         * return the reservation window that we could append to.
         * succeed.
         */
-       *start_block = cur;
-       return prev;
+
+       if ((prev != my_rsv) && (!rsv_is_empty(&my_rsv->rsv_window)))
+               rsv_window_remove(sb, my_rsv);
+
+       /*
+        * Let's book the whole avaliable window for now.  We will check the
+        * disk bitmap later and then, if there are free blocks then we adjust
+        * the window size if it's larger than requested.
+        * Otherwise, we will remove this node from the tree next time
+        * call find_next_reservable_window.
+        */
+       my_rsv->rsv_start = cur;
+       my_rsv->rsv_end = cur + size - 1;
+       my_rsv->rsv_alloc_hit = 0;
+
+       if (prev != my_rsv)
+               ext3_rsv_window_add(sb, my_rsv);
+
+       return 0;
 }
 
 /**
@@ -852,6 +869,7 @@ static struct ext3_reserve_window_node *find_next_reservable_window(
  *     @sb: the super block
  *     @group: the group we are trying to allocate in
  *     @bitmap_bh: the block group block bitmap
+ *
  */
 static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
                int goal, struct super_block *sb,
@@ -860,10 +878,10 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
        struct ext3_reserve_window_node *search_head;
        int group_first_block, group_end_block, start_block;
        int first_free_block;
-       int reservable_space_start;
-       struct ext3_reserve_window_node *prev_rsv;
        struct rb_root *fs_rsv_root = &EXT3_SB(sb)->s_rsv_window_root;
        unsigned long size;
+       int ret;
+       spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock;
 
        group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
                                group * EXT3_BLOCKS_PER_GROUP(sb);
@@ -875,6 +893,7 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
                start_block = goal + group_first_block;
 
        size = my_rsv->rsv_goal_size;
+
        if (!rsv_is_empty(&my_rsv->rsv_window)) {
                /*
                 * if the old reservation is cross group boundary
@@ -908,6 +927,8 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
                        my_rsv->rsv_goal_size= size;
                }
        }
+
+       spin_lock(rsv_lock);
        /*
         * shift the search start to the window near the goal block
         */
@@ -921,11 +942,16 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
         * need to check the bitmap after we found a reservable window.
         */
 retry:
-       prev_rsv = find_next_reservable_window(search_head, size,
-                                               &start_block, group_end_block);
-       if (prev_rsv == NULL)
-               goto failed;
-       reservable_space_start = start_block;
+       ret = find_next_reservable_window(search_head, my_rsv, sb,
+                                               start_block, group_end_block);
+
+       if (ret == -1) {
+               if (!rsv_is_empty(&my_rsv->rsv_window))
+                       rsv_window_remove(sb, my_rsv);
+               spin_unlock(rsv_lock);
+               return -1;
+       }
+
        /*
         * On success, find_next_reservable_window() returns the
         * reservation window where there is a reservable space after it.
@@ -937,8 +963,9 @@ retry:
         * block. Search start from the start block of the reservable space
         * we just found.
         */
+       spin_unlock(rsv_lock);
        first_free_block = bitmap_search_next_usable_block(
-                       reservable_space_start - group_first_block,
+                       my_rsv->rsv_start - group_first_block,
                        bitmap_bh, group_end_block - group_first_block + 1);
 
        if (first_free_block < 0) {
@@ -946,54 +973,29 @@ retry:
                 * no free block left on the bitmap, no point
                 * to reserve the space. return failed.
                 */
-               goto failed;
+               spin_lock(rsv_lock);
+               if (!rsv_is_empty(&my_rsv->rsv_window))
+                       rsv_window_remove(sb, my_rsv);
+               spin_unlock(rsv_lock);
+               return -1;              /* failed */
        }
+
        start_block = first_free_block + group_first_block;
        /*
         * check if the first free block is within the
-        * free space we just found
+        * free space we just reserved
         */
-       if ((start_block >= reservable_space_start) &&
-         (start_block < reservable_space_start + size))
-               goto found_rsv_window;
+       if (start_block >= my_rsv->rsv_start && start_block < my_rsv->rsv_end)
+               return 0;               /* success */
        /*
         * if the first free bit we found is out of the reservable space
-        * this means there is no free block on the reservable space
-        * we should continue search for next reservable space,
+        * continue search for next reservable space,
         * start from where the free block is,
         * we also shift the list head to where we stopped last time
         */
-       search_head = prev_rsv;
+       search_head = my_rsv;
+       spin_lock(rsv_lock);
        goto retry;
-
-found_rsv_window:
-       /*
-        * great! the reservable space contains some free blocks.
-        * if the search returns that we should add the new
-        * window just next to where the old window, we don't
-        * need to remove the old window first then add it to the
-        * same place, just update the new start and new end.
-        */
-       if (my_rsv != prev_rsv)  {
-               if (!rsv_is_empty(&my_rsv->rsv_window))
-                       rsv_window_remove(sb, my_rsv);
-       }
-       my_rsv->rsv_start = reservable_space_start;
-       my_rsv->rsv_end = my_rsv->rsv_start + size - 1;
-       my_rsv->rsv_alloc_hit = 0;
-       if (my_rsv != prev_rsv)  {
-               ext3_rsv_window_add(sb, my_rsv);
-       }
-       return 0;               /* succeed */
-failed:
-       /*
-        * failed to find a new reservation window in the current
-        * group, remove the current(stale) reservation window
-        * if there is any
-        */
-       if (!rsv_is_empty(&my_rsv->rsv_window))
-               rsv_window_remove(sb, my_rsv);
-       return -1;              /* failed */
 }
 
 /*
@@ -1023,7 +1025,6 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
                        int goal, struct ext3_reserve_window_node * my_rsv,
                        int *errp)
 {
-       spinlock_t *rsv_lock;
        unsigned long group_first_block;
        int ret = 0;
        int fatal;
@@ -1052,7 +1053,6 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
                ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, NULL);
                goto out;
        }
-       rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock;
        /*
         * goal is a group relative block number (if there is a goal)
         * 0 < goal < EXT3_BLOCKS_PER_GROUP(sb)
@@ -1078,30 +1078,21 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
         * then we could go to allocate from the reservation window directly.
         */
        while (1) {
-               struct ext3_reserve_window rsv_copy;
-
-               rsv_copy._rsv_start = my_rsv->rsv_start;
-               rsv_copy._rsv_end = my_rsv->rsv_end;
-
-               if (rsv_is_empty(&rsv_copy) || (ret < 0) ||
-                       !goal_in_my_reservation(&rsv_copy, goal, group, sb)) {
-                       spin_lock(rsv_lock);
+               if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) ||
+                       !goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb)) {
                        ret = alloc_new_reservation(my_rsv, goal, sb,
                                                        group, bitmap_bh);
-                       rsv_copy._rsv_start = my_rsv->rsv_start;
-                       rsv_copy._rsv_end = my_rsv->rsv_end;
-                       spin_unlock(rsv_lock);
                        if (ret < 0)
                                break;                  /* failed */
 
-                       if (!goal_in_my_reservation(&rsv_copy, goal, group, sb))
+                       if (!goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb))
                                goal = -1;
                }
-               if ((rsv_copy._rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb))
-                   || (rsv_copy._rsv_end < group_first_block))
+               if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb))
+                   || (my_rsv->rsv_end < group_first_block))
                        BUG();
                ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal,
-                                          &rsv_copy);
+                                          &my_rsv->rsv_window);
                if (ret >= 0) {
                        my_rsv->rsv_alloc_hit++;
                        break;                          /* succeed */
index 5ad8cf0292df5bd53a18e480b5ce282935905d7d..98e78345ead930a7705f1b7202a315263863bdeb 100644 (file)
@@ -36,7 +36,11 @@ static int ext3_release_file (struct inode * inode, struct file * filp)
        /* if we are the last writer on the inode, drop the block reservation */
        if ((filp->f_mode & FMODE_WRITE) &&
                        (atomic_read(&inode->i_writecount) == 1))
+       {
+               down(&EXT3_I(inode)->truncate_sem);
                ext3_discard_reservation(inode);
+               up(&EXT3_I(inode)->truncate_sem);
+       }
        if (is_dx(inode) && filp->private_data)
                ext3_htree_free_dir_info(filp->private_data);
 
index 0d5fa73b18dc1542700ddbf2285c0b2ffe3b9e18..0b2db4f618cbec499832a0969b14f827a839245c 100644 (file)
@@ -128,7 +128,7 @@ static unsigned long blocks_for_truncate(struct inode *inode)
        if (needed > EXT3_MAX_TRANS_DATA) 
                needed = EXT3_MAX_TRANS_DATA;
 
-       return EXT3_DATA_TRANS_BLOCKS + needed;
+       return EXT3_DATA_TRANS_BLOCKS(inode->i_sb) + needed;
 }
 
 /* 
@@ -2763,7 +2763,8 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
 
                /* (user+group)*(old+new) structure, inode write (sb,
                 * inode block, ? - but truncate inode update has it) */
-               handle = ext3_journal_start(inode, 4*EXT3_QUOTA_INIT_BLOCKS+3);
+               handle = ext3_journal_start(inode, 2*(EXT3_QUOTA_INIT_BLOCKS(inode->i_sb)+
+                                       EXT3_QUOTA_DEL_BLOCKS(inode->i_sb))+3);
                if (IS_ERR(handle)) {
                        error = PTR_ERR(handle);
                        goto err_out;
@@ -2861,7 +2862,7 @@ static int ext3_writepage_trans_blocks(struct inode *inode)
 #ifdef CONFIG_QUOTA
        /* We know that structure was already allocated during DQUOT_INIT so
         * we will be updating only the data blocks + inodes */
-       ret += 2*EXT3_QUOTA_TRANS_BLOCKS;
+       ret += 2*EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb);
 #endif
 
        return ret;
index 60e44e6dd7a603165f7c214a801777aa24e426ad..50378d8ff84b28cd90318159fb9708cbec9e2e76 100644 (file)
@@ -1645,9 +1645,9 @@ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode,
        int err, retries = 0;
 
 retry:
-       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
                                        EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
-                                       2*EXT3_QUOTA_INIT_BLOCKS);
+                                       2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -1679,9 +1679,9 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry,
                return -EINVAL;
 
 retry:
-       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
                                        EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
-                                       2*EXT3_QUOTA_INIT_BLOCKS);
+                                       2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -1715,9 +1715,9 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode)
                return -EMLINK;
 
 retry:
-       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
                                        EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
-                                       2*EXT3_QUOTA_INIT_BLOCKS);
+                                       2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -2006,7 +2006,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry)
        /* Initialize quotas before so that eventual writes go in
         * separate transaction */
        DQUOT_INIT(dentry->d_inode);
-       handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
+       handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -2065,7 +2065,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
        /* Initialize quotas before so that eventual writes go
         * in separate transaction */
        DQUOT_INIT(dentry->d_inode);
-       handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
+       handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -2120,9 +2120,9 @@ static int ext3_symlink (struct inode * dir,
                return -ENAMETOOLONG;
 
 retry:
-       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
                                        EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
-                                       2*EXT3_QUOTA_INIT_BLOCKS);
+                                       2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -2174,7 +2174,7 @@ static int ext3_link (struct dentry * old_dentry,
                return -EMLINK;
 
 retry:
-       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
                                        EXT3_INDEX_EXTRA_TRANS_BLOCKS);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
@@ -2216,7 +2216,8 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
         * in separate transaction */
        if (new_dentry->d_inode)
                DQUOT_INIT(new_dentry->d_inode);
-       handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS +
+       handle = ext3_journal_start(old_dir, 2 *
+                                       EXT3_DATA_TRANS_BLOCKS(old_dir->i_sb) +
                                        EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
index 9630fbfdc24a20f245adb74b1ff92012f2a15eea..a6d1779d7de4a00fcc205142bb54dd2e83efb0a2 100644 (file)
@@ -589,7 +589,7 @@ enum {
        Opt_commit, Opt_journal_update, Opt_journal_inum,
        Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
-       Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0,
+       Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
        Opt_ignore, Opt_barrier, Opt_err, Opt_resize,
 };
 
@@ -634,10 +634,10 @@ static match_table_t tokens = {
        {Opt_grpjquota, "grpjquota=%s"},
        {Opt_jqfmt_vfsold, "jqfmt=vfsold"},
        {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
-       {Opt_ignore, "grpquota"},
-       {Opt_ignore, "noquota"},
-       {Opt_ignore, "quota"},
-       {Opt_ignore, "usrquota"},
+       {Opt_quota, "grpquota"},
+       {Opt_noquota, "noquota"},
+       {Opt_quota, "quota"},
+       {Opt_quota, "usrquota"},
        {Opt_barrier, "barrier=%u"},
        {Opt_err, NULL},
        {Opt_resize, "resize"},
@@ -876,6 +876,7 @@ set_qf_name:
                                sbi->s_qf_names[qtype] = NULL;
                                return 0;
                        }
+                       set_opt(sbi->s_mount_opt, QUOTA);
                        break;
                case Opt_offusrjquota:
                        qtype = USRQUOTA;
@@ -898,6 +899,17 @@ clear_qf_name:
                case Opt_jqfmt_vfsv0:
                        sbi->s_jquota_fmt = QFMT_VFS_V0;
                        break;
+               case Opt_quota:
+                       set_opt(sbi->s_mount_opt, QUOTA);
+                       break;
+               case Opt_noquota:
+                       if (sb_any_quota_enabled(sb)) {
+                               printk(KERN_ERR "EXT3-fs: Cannot change quota "
+                                       "options when quota turned on.\n");
+                               return 0;
+                       }
+                       clear_opt(sbi->s_mount_opt, QUOTA);
+                       break;
 #else
                case Opt_usrjquota:
                case Opt_grpjquota:
@@ -909,6 +921,9 @@ clear_qf_name:
                                "EXT3-fs: journalled quota options not "
                                "supported.\n");
                        break;
+               case Opt_quota:
+               case Opt_noquota:
+                       break;
 #endif
                case Opt_abort:
                        set_opt(sbi->s_mount_opt, ABORT);
@@ -929,7 +944,8 @@ clear_qf_name:
                                        "for remount\n");
                                return 0;
                        }
-                       match_int(&args[0], &option);
+                       if (match_int(&args[0], &option) != 0)
+                               return 0;
                        *n_blocks_count = option;
                        break;
                case Opt_nobh:
@@ -2238,7 +2254,7 @@ static int ext3_dquot_initialize(struct inode *inode, int type)
        int ret, err;
 
        /* We may create quota structure so we need to reserve enough blocks */
-       handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS);
+       handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS(inode->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
        ret = dquot_initialize(inode, type);
@@ -2254,7 +2270,7 @@ static int ext3_dquot_drop(struct inode *inode)
        int ret, err;
 
        /* We may delete quota structure so we need to reserve enough blocks */
-       handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS);
+       handle = ext3_journal_start(inode, 2*EXT3_QUOTA_DEL_BLOCKS(inode->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
        ret = dquot_drop(inode);
@@ -2272,7 +2288,7 @@ static int ext3_write_dquot(struct dquot *dquot)
 
        inode = dquot_to_inode(dquot);
        handle = ext3_journal_start(inode,
-                                       EXT3_QUOTA_TRANS_BLOCKS);
+                                       EXT3_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
        ret = dquot_commit(dquot);
@@ -2288,7 +2304,7 @@ static int ext3_acquire_dquot(struct dquot *dquot)
        handle_t *handle;
 
        handle = ext3_journal_start(dquot_to_inode(dquot),
-                                       EXT3_QUOTA_INIT_BLOCKS);
+                                       EXT3_QUOTA_INIT_BLOCKS(dquot->dq_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
        ret = dquot_acquire(dquot);
@@ -2304,7 +2320,7 @@ static int ext3_release_dquot(struct dquot *dquot)
        handle_t *handle;
 
        handle = ext3_journal_start(dquot_to_inode(dquot),
-                                       EXT3_QUOTA_INIT_BLOCKS);
+                                       EXT3_QUOTA_DEL_BLOCKS(dquot->dq_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
        ret = dquot_release(dquot);
@@ -2361,6 +2377,8 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
        int err;
        struct nameidata nd;
 
+       if (!test_opt(sb, QUOTA))
+               return -EINVAL;
        /* Not journalling quota? */
        if (!EXT3_SB(sb)->s_qf_names[USRQUOTA] &&
            !EXT3_SB(sb)->s_qf_names[GRPQUOTA])
index 4cbc6d0212d34406ac69ee67bac392bd7a312fea..3f9dfa643b197d353053a619a232f71d6390dfdc 100644 (file)
@@ -1044,7 +1044,7 @@ ext3_xattr_set(struct inode *inode, int name_index, const char *name,
        int error, retries = 0;
 
 retry:
-       handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
+       handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
        if (IS_ERR(handle)) {
                error = PTR_ERR(handle);
        } else {
index 8ccee8415488af2eab846aaa017d68d25a7bba8d..3e31c4a736f1832a088782cb32790a88593a50e9 100644 (file)
@@ -1331,12 +1331,21 @@ void __exit fat_cache_destroy(void);
 
 static int __init init_fat_fs(void)
 {
-       int ret;
+       int err;
 
-       ret = fat_cache_init();
-       if (ret < 0)
-               return ret;
-       return fat_init_inodecache();
+       err = fat_cache_init();
+       if (err)
+               return err;
+
+       err = fat_init_inodecache();
+       if (err)
+               goto failed;
+
+       return 0;
+
+failed:
+       fat_cache_destroy();
+       return err;
 }
 
 static void __exit exit_fat_fs(void)
index 8da0252642a499f6428bd83a2b971f06710940b9..583bd78086d8a83e97dc821584409ccdeb20a20a 100644 (file)
@@ -37,7 +37,6 @@
  * superblocks of the Veritas Filesystem.
  */
 #include <linux/types.h>
-#include "vxfs_kcompat.h"
 
 
 /*
index bc4b57da306a4609e4e597702e928f69519e99c3..d3f6b2835bc86b78c1fc73238803be149656ce4e 100644 (file)
@@ -101,7 +101,7 @@ vxfs_bmap_ext4(struct inode *ip, long bn)
        return 0;
 
 fail_size:
-       printk("vxfs: indirect extent to big!\n");
+       printk("vxfs: indirect extent too big!\n");
 fail_buf:
        return 0;
 }
index 05b19f70bf97efdd47872566e15e6638c41aa1b7..6dee109aeea406d853ea7d3dfc4eea41294d98d2 100644 (file)
@@ -78,17 +78,18 @@ vxfs_getfsh(struct inode *ip, int which)
        struct buffer_head              *bp;
 
        bp = vxfs_bread(ip, which);
-       if (buffer_mapped(bp)) {
+       if (bp) {
                struct vxfs_fsh         *fhp;
 
-               if (!(fhp = kmalloc(sizeof(*fhp), SLAB_KERNEL)))
-                       return NULL;
+               if (!(fhp = kmalloc(sizeof(*fhp), GFP_KERNEL)))
+                       goto out;
                memcpy(fhp, bp->b_data, sizeof(*fhp));
 
-               brelse(bp);
+               put_bh(bp);
                return (fhp);
        }
-
+out:
+       brelse(bp);
        return NULL;
 }
 
diff --git a/fs/freevxfs/vxfs_kcompat.h b/fs/freevxfs/vxfs_kcompat.h
deleted file mode 100644 (file)
index 342a4cc..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef _VXFS_KCOMPAT_H
-#define _VXFS_KCOMPAT_H
-
-#include <linux/version.h>
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-
-#include <linux/blkdev.h>
-
-typedef long sector_t;
-
-/* From include/linux/fs.h (Linux 2.5.2-pre3)  */
-static inline struct buffer_head * sb_bread(struct super_block *sb, int block)
-{
-       return bread(sb->s_dev, block, sb->s_blocksize);
-}
-
-/* Dito.  */
-static inline void map_bh(struct buffer_head *bh, struct super_block *sb, int block)
-{
-       bh->b_state |= 1 << BH_Mapped;
-       bh->b_dev = sb->s_dev;
-       bh->b_blocknr = block;
-}
-
-/* From fs/block_dev.c (Linux 2.5.2-pre2)  */
-static inline int sb_set_blocksize(struct super_block *sb, int size)
-{
-       int bits;
-       if (set_blocksize(sb->s_dev, size) < 0)
-               return 0;
-       sb->s_blocksize = size;
-       for (bits = 9, size >>= 9; size >>= 1; bits++)
-               ;
-       sb->s_blocksize_bits = bits;
-       return sb->s_blocksize;
-}
-
-/* Dito.  */
-static inline int sb_min_blocksize(struct super_block *sb, int size)
-{
-       int minsize = get_hardsect_size(sb->s_dev);
-       if (size < minsize)
-               size = minsize;
-       return sb_set_blocksize(sb, size);
-}
-
-#endif /* Kernel 2.4 */
-#endif /* _VXFS_KCOMPAT_H */
index 506ae251d2c0195f4abeeb177a730d5869aeb79a..554eb455722cbb3812837d3bc1b7b64290ebcc30 100644 (file)
@@ -61,13 +61,13 @@ struct file_operations vxfs_dir_operations = {
 };
 
  
-static __inline__ u_long
+static inline u_long
 dir_pages(struct inode *inode)
 {
        return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 }
  
-static __inline__ u_long
+static inline u_long
 dir_blocks(struct inode *ip)
 {
        u_long                  bsize = ip->i_sb->s_blocksize;
@@ -79,7 +79,7 @@ dir_blocks(struct inode *ip)
  *
  * len <= VXFS_NAMELEN and de != NULL are guaranteed by caller.
  */
-static __inline__ int
+static inline int
 vxfs_match(int len, const char * const name, struct vxfs_direct *de)
 {
        if (len != de->d_namelen)
@@ -89,7 +89,7 @@ vxfs_match(int len, const char * const name, struct vxfs_direct *de)
        return !memcmp(name, de->d_name, len);
 }
 
-static __inline__ struct vxfs_direct *
+static inline struct vxfs_direct *
 vxfs_next_entry(struct vxfs_direct *de)
 {
        return ((struct vxfs_direct *)((char*)de + de->d_reclen));
index 7a204e31aad95dd8790650cb492ae5fab023df4c..133476201d8438ef5dc43dccf74e6c76ccbcc2b0 100644 (file)
@@ -38,7 +38,7 @@
 #include "vxfs_olt.h"
 
 
-static __inline__ void
+static inline void
 vxfs_get_fshead(struct vxfs_oltfshead *fshp, struct vxfs_sb_info *infp)
 {
        if (infp->vsi_fshino)
@@ -46,7 +46,7 @@ vxfs_get_fshead(struct vxfs_oltfshead *fshp, struct vxfs_sb_info *infp)
        infp->vsi_fshino = fshp->olt_fsino[0];
 }
 
-static __inline__ void
+static inline void
 vxfs_get_ilist(struct vxfs_oltilist *ilistp, struct vxfs_sb_info *infp)
 {
        if (infp->vsi_iext)
@@ -54,7 +54,7 @@ vxfs_get_ilist(struct vxfs_oltilist *ilistp, struct vxfs_sb_info *infp)
        infp->vsi_iext = ilistp->olt_iext[0]; 
 }
 
-static __inline__ u_long
+static inline u_long
 vxfs_oblock(struct super_block *sbp, daddr_t block, u_long bsize)
 {
        if (sbp->s_blocksize % bsize)
@@ -104,8 +104,8 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
                goto fail;
        }
 
-       oaddr = (char *)bp->b_data + op->olt_size;
-       eaddr = (char *)bp->b_data + (infp->vsi_oltsize * sbp->s_blocksize);
+       oaddr = bp->b_data + op->olt_size;
+       eaddr = bp->b_data + (infp->vsi_oltsize * sbp->s_blocksize);
 
        while (oaddr < eaddr) {
                struct vxfs_oltcommon   *ocp =
index 5e305612054a5519ab4f34efa92f372a686bc17c..50aae77651b29c9c6558ee50f77ebe7ee6e55011 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/slab.h>
 #include <linux/pagemap.h>
 
-#include "vxfs_kcompat.h"
 #include "vxfs_extern.h"
 
 
index 0ae2c7b8182a2eebc2c4db2bd5d553880f55ce93..27f66d3e8a0413091ab58b3f0b85fae788a224fe 100644 (file)
@@ -155,12 +155,11 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
 
        sbp->s_flags |= MS_RDONLY;
 
-       infp = kmalloc(sizeof(*infp), GFP_KERNEL);
+       infp = kcalloc(1, sizeof(*infp), GFP_KERNEL);
        if (!infp) {
                printk(KERN_WARNING "vxfs: unable to allocate incore superblock\n");
                return -ENOMEM;
        }
-       memset(infp, 0, sizeof(*infp));
 
        bsize = sb_min_blocksize(sbp, BLOCK_SIZE);
        if (!bsize) {
@@ -196,7 +195,7 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
 #endif
 
        sbp->s_magic = rsbp->vs_magic;
-       sbp->s_fs_info = (void *)infp;
+       sbp->s_fs_info = infp;
 
        infp->vsi_raw = rsbp;
        infp->vsi_bp = bp;
@@ -263,7 +262,7 @@ vxfs_init(void)
                        sizeof(struct vxfs_inode_info), 0, 
                        SLAB_RECLAIM_ACCOUNT, NULL, NULL);
        if (vxfs_inode_cachep)
-               return (register_filesystem(&vxfs_fs_type));
+               return register_filesystem(&vxfs_fs_type);
        return -ENOMEM;
 }
 
diff --git a/fs/ioprio.c b/fs/ioprio.c
new file mode 100644 (file)
index 0000000..663e420
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * fs/ioprio.c
+ *
+ * Copyright (C) 2004 Jens Axboe <axboe@suse.de>
+ *
+ * Helper functions for setting/querying io priorities of processes. The
+ * system calls closely mimmick getpriority/setpriority, see the man page for
+ * those. The prio argument is a composite of prio class and prio data, where
+ * the data argument has meaning within that class. The standard scheduling
+ * classes have 8 distinct prio levels, with 0 being the highest prio and 7
+ * being the lowest.
+ *
+ * IOW, setting BE scheduling class with prio 2 is done ala:
+ *
+ * unsigned int prio = (IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT) | 2;
+ *
+ * ioprio_set(PRIO_PROCESS, pid, prio);
+ *
+ * See also Documentation/block/ioprio.txt
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/ioprio.h>
+#include <linux/blkdev.h>
+
+static int set_task_ioprio(struct task_struct *task, int ioprio)
+{
+       struct io_context *ioc;
+
+       if (task->uid != current->euid &&
+           task->uid != current->uid && !capable(CAP_SYS_NICE))
+               return -EPERM;
+
+       task_lock(task);
+
+       task->ioprio = ioprio;
+
+       ioc = task->io_context;
+       if (ioc && ioc->set_ioprio)
+               ioc->set_ioprio(ioc, ioprio);
+
+       task_unlock(task);
+       return 0;
+}
+
+asmlinkage int sys_ioprio_set(int which, int who, int ioprio)
+{
+       int class = IOPRIO_PRIO_CLASS(ioprio);
+       int data = IOPRIO_PRIO_DATA(ioprio);
+       struct task_struct *p, *g;
+       struct user_struct *user;
+       int ret;
+
+       switch (class) {
+               case IOPRIO_CLASS_RT:
+                       if (!capable(CAP_SYS_ADMIN))
+                               return -EPERM;
+                       /* fall through, rt has prio field too */
+               case IOPRIO_CLASS_BE:
+                       if (data >= IOPRIO_BE_NR || data < 0)
+                               return -EINVAL;
+
+                       break;
+               case IOPRIO_CLASS_IDLE:
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       ret = -ESRCH;
+       read_lock_irq(&tasklist_lock);
+       switch (which) {
+               case IOPRIO_WHO_PROCESS:
+                       if (!who)
+                               p = current;
+                       else
+                               p = find_task_by_pid(who);
+                       if (p)
+                               ret = set_task_ioprio(p, ioprio);
+                       break;
+               case IOPRIO_WHO_PGRP:
+                       if (!who)
+                               who = process_group(current);
+                       do_each_task_pid(who, PIDTYPE_PGID, p) {
+                               ret = set_task_ioprio(p, ioprio);
+                               if (ret)
+                                       break;
+                       } while_each_task_pid(who, PIDTYPE_PGID, p);
+                       break;
+               case IOPRIO_WHO_USER:
+                       if (!who)
+                               user = current->user;
+                       else
+                               user = find_user(who);
+
+                       if (!user)
+                               break;
+
+                       do_each_thread(g, p) {
+                               if (p->uid != who)
+                                       continue;
+                               ret = set_task_ioprio(p, ioprio);
+                               if (ret)
+                                       break;
+                       } while_each_thread(g, p);
+
+                       if (who)
+                               free_uid(user);
+                       break;
+               default:
+                       ret = -EINVAL;
+       }
+
+       read_unlock_irq(&tasklist_lock);
+       return ret;
+}
+
+asmlinkage int sys_ioprio_get(int which, int who)
+{
+       struct task_struct *g, *p;
+       struct user_struct *user;
+       int ret = -ESRCH;
+
+       read_lock_irq(&tasklist_lock);
+       switch (which) {
+               case IOPRIO_WHO_PROCESS:
+                       if (!who)
+                               p = current;
+                       else
+                               p = find_task_by_pid(who);
+                       if (p)
+                               ret = p->ioprio;
+                       break;
+               case IOPRIO_WHO_PGRP:
+                       if (!who)
+                               who = process_group(current);
+                       do_each_task_pid(who, PIDTYPE_PGID, p) {
+                               if (ret == -ESRCH)
+                                       ret = p->ioprio;
+                               else
+                                       ret = ioprio_best(ret, p->ioprio);
+                       } while_each_task_pid(who, PIDTYPE_PGID, p);
+                       break;
+               case IOPRIO_WHO_USER:
+                       if (!who)
+                               user = current->user;
+                       else
+                               user = find_user(who);
+
+                       if (!user)
+                               break;
+
+                       do_each_thread(g, p) {
+                               if (p->uid != user->uid)
+                                       continue;
+                               if (ret == -ESRCH)
+                                       ret = p->ioprio;
+                               else
+                                       ret = ioprio_best(ret, p->ioprio);
+                       } while_each_thread(g, p);
+
+                       if (who)
+                               free_uid(user);
+                       break;
+               default:
+                       ret = -EINVAL;
+       }
+
+       read_unlock_irq(&tasklist_lock);
+       return ret;
+}
+
index 1e6f2e2ad4a33d48b6ed38d8e21f0ed68f865b88..5e7b439495171c9d0fcfa7f28b2fa51aab489823 100644 (file)
@@ -167,7 +167,7 @@ loop:
        }
 
        wake_up(&journal->j_wait_done_commit);
-       if (current->flags & PF_FREEZE) {
+       if (freezing(current)) {
                /*
                 * The simpler the better. Flushing journal isn't a
                 * good idea, because that depends on threads that may
@@ -175,7 +175,7 @@ loop:
                 */
                jbd_debug(1, "Now suspending kjournald\n");
                spin_unlock(&journal->j_state_lock);
-               refrigerator(PF_FREEZE);
+               refrigerator();
                spin_lock(&journal->j_state_lock);
        } else {
                /*
index 8cc6893fc56cd61a44015313e3cc5a907dff1115..fc589ddd0762d6491a3ab7d151c760a36e6d08d1 100644 (file)
@@ -175,8 +175,64 @@ jffs_hexdump(struct mtd_info *mtd, loff_t pos, int size)
        }
 }
 
+/* Print the contents of a node.  */
+static void
+jffs_print_node(struct jffs_node *n)
+{
+       D(printk("jffs_node: 0x%p\n", n));
+       D(printk("{\n"));
+       D(printk("        0x%08x, /* version  */\n", n->version));
+       D(printk("        0x%08x, /* data_offset  */\n", n->data_offset));
+       D(printk("        0x%08x, /* data_size  */\n", n->data_size));
+       D(printk("        0x%08x, /* removed_size  */\n", n->removed_size));
+       D(printk("        0x%08x, /* fm_offset  */\n", n->fm_offset));
+       D(printk("        0x%02x,       /* name_size  */\n", n->name_size));
+       D(printk("        0x%p, /* fm,  fm->offset: %u  */\n",
+                n->fm, (n->fm ? n->fm->offset : 0)));
+       D(printk("        0x%p, /* version_prev  */\n", n->version_prev));
+       D(printk("        0x%p, /* version_next  */\n", n->version_next));
+       D(printk("        0x%p, /* range_prev  */\n", n->range_prev));
+       D(printk("        0x%p, /* range_next  */\n", n->range_next));
+       D(printk("}\n"));
+}
+
 #endif
 
+/* Print the contents of a raw inode.  */
+static void
+jffs_print_raw_inode(struct jffs_raw_inode *raw_inode)
+{
+       D(printk("jffs_raw_inode: inode number: %u\n", raw_inode->ino));
+       D(printk("{\n"));
+       D(printk("        0x%08x, /* magic  */\n", raw_inode->magic));
+       D(printk("        0x%08x, /* ino  */\n", raw_inode->ino));
+       D(printk("        0x%08x, /* pino  */\n", raw_inode->pino));
+       D(printk("        0x%08x, /* version  */\n", raw_inode->version));
+       D(printk("        0x%08x, /* mode  */\n", raw_inode->mode));
+       D(printk("        0x%04x,     /* uid  */\n", raw_inode->uid));
+       D(printk("        0x%04x,     /* gid  */\n", raw_inode->gid));
+       D(printk("        0x%08x, /* atime  */\n", raw_inode->atime));
+       D(printk("        0x%08x, /* mtime  */\n", raw_inode->mtime));
+       D(printk("        0x%08x, /* ctime  */\n", raw_inode->ctime));
+       D(printk("        0x%08x, /* offset  */\n", raw_inode->offset));
+       D(printk("        0x%08x, /* dsize  */\n", raw_inode->dsize));
+       D(printk("        0x%08x, /* rsize  */\n", raw_inode->rsize));
+       D(printk("        0x%02x,       /* nsize  */\n", raw_inode->nsize));
+       D(printk("        0x%02x,       /* nlink  */\n", raw_inode->nlink));
+       D(printk("        0x%02x,       /* spare  */\n",
+                raw_inode->spare));
+       D(printk("        %u,          /* rename  */\n",
+                raw_inode->rename));
+       D(printk("        %u,          /* deleted  */\n",
+                raw_inode->deleted));
+       D(printk("        0x%02x,       /* accurate  */\n",
+                raw_inode->accurate));
+       D(printk("        0x%08x, /* dchksum  */\n", raw_inode->dchksum));
+       D(printk("        0x%04x,     /* nchksum  */\n", raw_inode->nchksum));
+       D(printk("        0x%04x,     /* chksum  */\n", raw_inode->chksum));
+       D(printk("}\n"));
+}
+
 #define flash_safe_acquire(arg)
 #define flash_safe_release(arg)
 
@@ -2507,64 +2563,6 @@ jffs_update_file(struct jffs_file *f, struct jffs_node *node)
        return 0;
 }
 
-/* Print the contents of a node.  */
-void
-jffs_print_node(struct jffs_node *n)
-{
-       D(printk("jffs_node: 0x%p\n", n));
-       D(printk("{\n"));
-       D(printk("        0x%08x, /* version  */\n", n->version));
-       D(printk("        0x%08x, /* data_offset  */\n", n->data_offset));
-       D(printk("        0x%08x, /* data_size  */\n", n->data_size));
-       D(printk("        0x%08x, /* removed_size  */\n", n->removed_size));
-       D(printk("        0x%08x, /* fm_offset  */\n", n->fm_offset));
-       D(printk("        0x%02x,       /* name_size  */\n", n->name_size));
-       D(printk("        0x%p, /* fm,  fm->offset: %u  */\n",
-                n->fm, (n->fm ? n->fm->offset : 0)));
-       D(printk("        0x%p, /* version_prev  */\n", n->version_prev));
-       D(printk("        0x%p, /* version_next  */\n", n->version_next));
-       D(printk("        0x%p, /* range_prev  */\n", n->range_prev));
-       D(printk("        0x%p, /* range_next  */\n", n->range_next));
-       D(printk("}\n"));
-}
-
-
-/* Print the contents of a raw inode.  */
-void
-jffs_print_raw_inode(struct jffs_raw_inode *raw_inode)
-{
-       D(printk("jffs_raw_inode: inode number: %u\n", raw_inode->ino));
-       D(printk("{\n"));
-       D(printk("        0x%08x, /* magic  */\n", raw_inode->magic));
-       D(printk("        0x%08x, /* ino  */\n", raw_inode->ino));
-       D(printk("        0x%08x, /* pino  */\n", raw_inode->pino));
-       D(printk("        0x%08x, /* version  */\n", raw_inode->version));
-       D(printk("        0x%08x, /* mode  */\n", raw_inode->mode));
-       D(printk("        0x%04x,     /* uid  */\n", raw_inode->uid));
-       D(printk("        0x%04x,     /* gid  */\n", raw_inode->gid));
-       D(printk("        0x%08x, /* atime  */\n", raw_inode->atime));
-       D(printk("        0x%08x, /* mtime  */\n", raw_inode->mtime));
-       D(printk("        0x%08x, /* ctime  */\n", raw_inode->ctime));
-       D(printk("        0x%08x, /* offset  */\n", raw_inode->offset));
-       D(printk("        0x%08x, /* dsize  */\n", raw_inode->dsize));
-       D(printk("        0x%08x, /* rsize  */\n", raw_inode->rsize));
-       D(printk("        0x%02x,       /* nsize  */\n", raw_inode->nsize));
-       D(printk("        0x%02x,       /* nlink  */\n", raw_inode->nlink));
-       D(printk("        0x%02x,       /* spare  */\n",
-                raw_inode->spare));
-       D(printk("        %u,          /* rename  */\n",
-                raw_inode->rename));
-       D(printk("        %u,          /* deleted  */\n",
-                raw_inode->deleted));
-       D(printk("        0x%02x,       /* accurate  */\n",
-                raw_inode->accurate));
-       D(printk("        0x%08x, /* dchksum  */\n", raw_inode->dchksum));
-       D(printk("        0x%04x,     /* nchksum  */\n", raw_inode->nchksum));
-       D(printk("        0x%04x,     /* chksum  */\n", raw_inode->chksum));
-       D(printk("}\n"));
-}
-
-
 /* Print the contents of a file.  */
 #if 0
 int
index 4ae97b17911c581908cb8324455aa176c72428ad..5c7abe0e26953555549a3361109d5110da7a106f 100644 (file)
@@ -49,8 +49,6 @@ int jffs_garbage_collect_thread(void *c);
 void jffs_garbage_collect_trigger(struct jffs_control *c);
 
 /* For debugging purposes.  */
-void jffs_print_node(struct jffs_node *n);
-void jffs_print_raw_inode(struct jffs_raw_inode *raw_inode);
 #if 0
 int jffs_print_file(struct jffs_file *f);
 #endif  /*  0  */
index 0cab8da49d3c445fb6ed0d7dda4f9ebbb613f510..053e3a98a276ec1f63d0a7035355d06b94474cdd 100644 (file)
@@ -31,6 +31,60 @@ static void jffs_free_fm(struct jffs_fm *n);
 extern kmem_cache_t     *fm_cache;
 extern kmem_cache_t     *node_cache;
 
+#if CONFIG_JFFS_FS_VERBOSE > 0
+void
+jffs_print_fmcontrol(struct jffs_fmcontrol *fmc)
+{
+       D(printk("struct jffs_fmcontrol: 0x%p\n", fmc));
+       D(printk("{\n"));
+       D(printk("        %u, /* flash_size  */\n", fmc->flash_size));
+       D(printk("        %u, /* used_size  */\n", fmc->used_size));
+       D(printk("        %u, /* dirty_size  */\n", fmc->dirty_size));
+       D(printk("        %u, /* free_size  */\n", fmc->free_size));
+       D(printk("        %u, /* sector_size  */\n", fmc->sector_size));
+       D(printk("        %u, /* min_free_size  */\n", fmc->min_free_size));
+       D(printk("        %u, /* max_chunk_size  */\n", fmc->max_chunk_size));
+       D(printk("        0x%p, /* mtd  */\n", fmc->mtd));
+       D(printk("        0x%p, /* head  */    "
+                "(head->offset = 0x%08x)\n",
+                fmc->head, (fmc->head ? fmc->head->offset : 0)));
+       D(printk("        0x%p, /* tail  */    "
+                "(tail->offset + tail->size = 0x%08x)\n",
+                fmc->tail,
+                (fmc->tail ? fmc->tail->offset + fmc->tail->size : 0)));
+       D(printk("        0x%p, /* head_extra  */\n", fmc->head_extra));
+       D(printk("        0x%p, /* tail_extra  */\n", fmc->tail_extra));
+       D(printk("}\n"));
+}
+#endif  /*  CONFIG_JFFS_FS_VERBOSE > 0  */
+
+#if CONFIG_JFFS_FS_VERBOSE > 2
+static void
+jffs_print_fm(struct jffs_fm *fm)
+{
+       D(printk("struct jffs_fm: 0x%p\n", fm));
+       D(printk("{\n"));
+       D(printk("       0x%08x, /* offset  */\n", fm->offset));
+       D(printk("       %u, /* size  */\n", fm->size));
+       D(printk("       0x%p, /* prev  */\n", fm->prev));
+       D(printk("       0x%p, /* next  */\n", fm->next));
+       D(printk("       0x%p, /* nodes  */\n", fm->nodes));
+       D(printk("}\n"));
+}
+#endif  /*  CONFIG_JFFS_FS_VERBOSE > 2  */
+
+#if 0
+void
+jffs_print_node_ref(struct jffs_node_ref *ref)
+{
+       D(printk("struct jffs_node_ref: 0x%p\n", ref));
+       D(printk("{\n"));
+       D(printk("       0x%p, /* node  */\n", ref->node));
+       D(printk("       0x%p, /* next  */\n", ref->next));
+       D(printk("}\n"));
+}
+#endif  /*  0  */
+
 /* This function creates a new shiny flash memory control structure.  */
 struct jffs_fmcontrol *
 jffs_build_begin(struct jffs_control *c, int unit)
@@ -742,54 +796,3 @@ int jffs_get_node_inuse(void)
 {
        return no_jffs_node;
 }
-
-void
-jffs_print_fmcontrol(struct jffs_fmcontrol *fmc)
-{
-       D(printk("struct jffs_fmcontrol: 0x%p\n", fmc));
-       D(printk("{\n"));
-       D(printk("        %u, /* flash_size  */\n", fmc->flash_size));
-       D(printk("        %u, /* used_size  */\n", fmc->used_size));
-       D(printk("        %u, /* dirty_size  */\n", fmc->dirty_size));
-       D(printk("        %u, /* free_size  */\n", fmc->free_size));
-       D(printk("        %u, /* sector_size  */\n", fmc->sector_size));
-       D(printk("        %u, /* min_free_size  */\n", fmc->min_free_size));
-       D(printk("        %u, /* max_chunk_size  */\n", fmc->max_chunk_size));
-       D(printk("        0x%p, /* mtd  */\n", fmc->mtd));
-       D(printk("        0x%p, /* head  */    "
-                "(head->offset = 0x%08x)\n",
-                fmc->head, (fmc->head ? fmc->head->offset : 0)));
-       D(printk("        0x%p, /* tail  */    "
-                "(tail->offset + tail->size = 0x%08x)\n",
-                fmc->tail,
-                (fmc->tail ? fmc->tail->offset + fmc->tail->size : 0)));
-       D(printk("        0x%p, /* head_extra  */\n", fmc->head_extra));
-       D(printk("        0x%p, /* tail_extra  */\n", fmc->tail_extra));
-       D(printk("}\n"));
-}
-
-void
-jffs_print_fm(struct jffs_fm *fm)
-{
-       D(printk("struct jffs_fm: 0x%p\n", fm));
-       D(printk("{\n"));
-       D(printk("       0x%08x, /* offset  */\n", fm->offset));
-       D(printk("       %u, /* size  */\n", fm->size));
-       D(printk("       0x%p, /* prev  */\n", fm->prev));
-       D(printk("       0x%p, /* next  */\n", fm->next));
-       D(printk("       0x%p, /* nodes  */\n", fm->nodes));
-       D(printk("}\n"));
-}
-
-#if 0
-void
-jffs_print_node_ref(struct jffs_node_ref *ref)
-{
-       D(printk("struct jffs_node_ref: 0x%p\n", ref));
-       D(printk("{\n"));
-       D(printk("       0x%p, /* node  */\n", ref->node));
-       D(printk("       0x%p, /* next  */\n", ref->next));
-       D(printk("}\n"));
-}
-#endif  /*  0  */
-
index bc291c4318225496cf6ce47bf877db524046d7fd..f64151e741225141f632400ddfded9788c6bb794 100644 (file)
@@ -139,8 +139,9 @@ int jffs_add_node(struct jffs_node *node);
 void jffs_fmfree_partly(struct jffs_fmcontrol *fmc, struct jffs_fm *fm,
                        __u32 size);
 
+#if CONFIG_JFFS_FS_VERBOSE > 0
 void jffs_print_fmcontrol(struct jffs_fmcontrol *fmc);
-void jffs_print_fm(struct jffs_fm *fm);
+#endif
 #if 0
 void jffs_print_node_ref(struct jffs_node_ref *ref);
 #endif  /*  0  */
index 1be6de27dd81142842be0acc56e1a94533580d54..638836b277d444d36c07acc8284a0824e99769f2 100644 (file)
@@ -92,7 +92,7 @@ static int jffs2_garbage_collect_thread(void *_c)
                        schedule();
                }
 
-               if (try_to_freeze(0))
+               if (try_to_freeze())
                        continue;
 
                cond_resched();
index 7c8387ed4192be68cd090956e430cf12eb5ac936..79d07624bfe1787fff2b5ee3b3c8e1479b34ffe3 100644 (file)
@@ -2359,9 +2359,9 @@ int jfsIOWait(void *arg)
                        lbmStartIO(bp);
                        spin_lock_irq(&log_redrive_lock);
                }
-               if (current->flags & PF_FREEZE) {
+               if (freezing(current)) {
                        spin_unlock_irq(&log_redrive_lock);
-                       refrigerator(PF_FREEZE);
+                       refrigerator();
                } else {
                        add_wait_queue(&jfs_IO_thread_wait, &wq);
                        set_current_state(TASK_INTERRUPTIBLE);
index 8cbaaff1d5fa05628f18b0e8213e0ce66dfe3839..121c981ff45363bef9af40c859132ba3e03007f0 100644 (file)
@@ -2788,9 +2788,9 @@ int jfs_lazycommit(void *arg)
                /* In case a wakeup came while all threads were active */
                jfs_commit_thread_waking = 0;
 
-               if (current->flags & PF_FREEZE) {
+               if (freezing(current)) {
                        LAZY_UNLOCK(flags);
-                       refrigerator(PF_FREEZE);
+                       refrigerator();
                } else {
                        DECLARE_WAITQUEUE(wq, current);
 
@@ -2987,9 +2987,9 @@ int jfs_sync(void *arg)
                /* Add anon_list2 back to anon_list */
                list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list);
 
-               if (current->flags & PF_FREEZE) {
+               if (freezing(current)) {
                        TXN_UNLOCK();
-                       refrigerator(PF_FREEZE);
+                       refrigerator();
                } else {
                        DECLARE_WAITQUEUE(wq, current);
 
index 5025563e7379675b7df2834427aabb0800f4b740..58101dff2c66de94fc4fa82bf13696e9d9b8d665 100644 (file)
@@ -183,6 +183,7 @@ struct file_operations simple_dir_operations = {
        .llseek         = dcache_dir_lseek,
        .read           = generic_read_dir,
        .readdir        = dcache_readdir,
+       .fsync          = simple_sync_file,
 };
 
 struct inode_operations simple_dir_inode_operations = {
index fd77ed1d710de4f198c275960f1bb4898f19ef3e..14b3ce87fa29cd96162678fb754936e22c99caec 100644 (file)
@@ -313,7 +313,7 @@ static int nlm_wait_on_grace(wait_queue_head_t *queue)
        prepare_to_wait(queue, &wait, TASK_INTERRUPTIBLE);
        if (!signalled ()) {
                schedule_timeout(NLMCLNT_GRACE_WAIT);
-               try_to_freeze(PF_FREEZE);
+               try_to_freeze();
                if (!signalled ())
                        status = 0;
        }
index b82e470912e8352a8c24add072dd67b6ea852b5b..6e242556b903814bc6a79330f2723173beb0cda8 100644 (file)
@@ -191,7 +191,9 @@ lockd(struct svc_rqst *rqstp)
                printk(KERN_DEBUG
                        "lockd: new process, skipping host shutdown\n");
        wake_up(&lockd_exit);
-               
+
+       flush_signals(current);
+
        /* Exit the RPC thread */
        svc_exit_thread(rqstp);
 
index 3b93e5d750ebf8452ea1264251c5b55cc89f48f8..208c079e9fdbf240ce848e27903b237c9c9d764f 100644 (file)
@@ -337,7 +337,7 @@ int may_umount(struct vfsmount *mnt)
 
 EXPORT_SYMBOL(may_umount);
 
-void umount_tree(struct vfsmount *mnt)
+static void umount_tree(struct vfsmount *mnt)
 {
        struct vfsmount *p;
        LIST_HEAD(kill);
index 2dc2d8693968e7d223e96cfc8c4aa4aac27d20d6..a9f7a8ab1d595d30fcb656eea4a1349a7f324d43 100644 (file)
@@ -705,18 +705,6 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
                DPRINTK("ncp_do_readdir: init failed, err=%d\n", err);
                return;
        }
-#ifdef USE_OLD_SLOW_DIRECTORY_LISTING
-       for (;;) {
-               err = ncp_search_for_file_or_subdir(server, &seq, &entry.i);
-               if (err) {
-                       DPRINTK("ncp_do_readdir: search failed, err=%d\n", err);
-                       break;
-               }
-               entry.volume = entry.i.volNumber;
-               if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry))
-                       break;
-       }
-#else
        /* We MUST NOT use server->buffer_size handshaked with server if we are
           using UDP, as for UDP server uses max. buffer size determined by
           MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes). 
@@ -754,7 +742,6 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
                }
        } while (more);
        vfree(buf);
-#endif
        return;
 }
 
index e4eb5ed4bee45636c6a2abd4307dbfd804bc15c1..c755e1848a42366d0a08d4e379680b3fc2665a86 100644 (file)
@@ -845,46 +845,6 @@ out:
        return result;
 }
 
-/* Search for everything */
-int ncp_search_for_file_or_subdir(struct ncp_server *server,
-                                 struct nw_search_sequence *seq,
-                                 struct nw_info_struct *target)
-{
-       int result;
-
-       ncp_init_request(server);
-       ncp_add_byte(server, 3);        /* subfunction */
-       ncp_add_byte(server, server->name_space[seq->volNumber]);
-       ncp_add_byte(server, 0);        /* data stream (???) */
-       ncp_add_word(server, cpu_to_le16(0x8006));      /* Search attribs */
-       ncp_add_dword(server, RIM_ALL);         /* return info mask */
-       ncp_add_mem(server, seq, 9);
-#ifdef CONFIG_NCPFS_NFS_NS
-       if (server->name_space[seq->volNumber] == NW_NS_NFS) {
-               ncp_add_byte(server, 0);        /* 0 byte pattern */
-       } else 
-#endif
-       {
-               ncp_add_byte(server, 2);        /* 2 byte pattern */
-               ncp_add_byte(server, 0xff);     /* following is a wildcard */
-               ncp_add_byte(server, '*');
-       }
-       
-       if ((result = ncp_request(server, 87)) != 0)
-               goto out;
-       memcpy(seq, ncp_reply_data(server, 0), sizeof(*seq));
-       ncp_extract_file_info(ncp_reply_data(server, 10), target);
-
-       ncp_unlock_server(server);
-       
-       result = ncp_obtain_nfs_info(server, target);
-       return result;
-
-out:
-       ncp_unlock_server(server);
-       return result;
-}
-
 int ncp_search_for_fileset(struct ncp_server *server,
                           struct nw_search_sequence *seq,
                           int* more,
index 05ec2e9d90c626e5d61e1d39f81f04f37677f196..9e4dc30c2435c207ddce4d2c67311db24429d457 100644 (file)
@@ -87,9 +87,6 @@ int ncp_open_create_file_or_subdir(struct ncp_server *, struct inode *, char *,
 
 int ncp_initialize_search(struct ncp_server *, struct inode *,
                      struct nw_search_sequence *target);
-int ncp_search_for_file_or_subdir(struct ncp_server *server,
-                             struct nw_search_sequence *seq,
-                             struct nw_info_struct *target);
 int ncp_search_for_fileset(struct ncp_server *server,
                           struct nw_search_sequence *seq,
                           int* more, int* cnt,
index ee3536fc84a3bb49e7d99ab74b2ceffa162c6b89..1b7a3ef2f8131f4f9c02534f55d5a42de4633f67 100644 (file)
@@ -2,7 +2,7 @@
 #include <linux/nfs.h>
 #include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
-#include <linux/xattr_acl.h>
+#include <linux/posix_acl_xattr.h>
 #include <linux/nfsacl.h>
 
 #define NFSDBG_FACILITY        NFSDBG_PROC
@@ -53,9 +53,9 @@ ssize_t nfs3_getxattr(struct dentry *dentry, const char *name,
        struct posix_acl *acl;
        int type, error = 0;
 
-       if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
+       if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
                type = ACL_TYPE_ACCESS;
-       else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
+       else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
                type = ACL_TYPE_DEFAULT;
        else
                return -EOPNOTSUPP;
@@ -82,9 +82,9 @@ int nfs3_setxattr(struct dentry *dentry, const char *name,
        struct posix_acl *acl;
        int type, error;
 
-       if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
+       if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
                type = ACL_TYPE_ACCESS;
-       else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
+       else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
                type = ACL_TYPE_DEFAULT;
        else
                return -EOPNOTSUPP;
@@ -103,9 +103,9 @@ int nfs3_removexattr(struct dentry *dentry, const char *name)
        struct inode *inode = dentry->d_inode;
        int type;
 
-       if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
+       if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
                type = ACL_TYPE_ACCESS;
-       else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
+       else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
                type = ACL_TYPE_DEFAULT;
        else
                return -EOPNOTSUPP;
index 9f043f44c92fe0a0fc3e5c7cfeb281a05adcbe53..ce341dc76d5ec6366d48c94844f4809a2560ab58 100644 (file)
@@ -10,5 +10,5 @@ nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
 nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
 nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
 nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
-                          nfs4acl.o nfs4callback.o
+                          nfs4acl.o nfs4callback.o nfs4recover.o
 nfsd-objs              := $(nfsd-y)
index 11ebf6c4aa54c5e9e4557a68a349444e250fe3b7..4a2105552ac4c5ca46847f3e41d18d9c4acd985e 100644 (file)
@@ -125,7 +125,7 @@ static short ace2type(struct nfs4_ace *);
 static int _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, unsigned int);
 static struct posix_acl *_nfsv4_to_posix_one(struct nfs4_acl *, unsigned int);
 int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t);
-int nfs4_acl_split(struct nfs4_acl *, struct nfs4_acl *);
+static int nfs4_acl_split(struct nfs4_acl *, struct nfs4_acl *);
 
 struct nfs4_acl *
 nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl,
@@ -775,7 +775,7 @@ out_err:
        return pacl;
 }
 
-int
+static int
 nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl)
 {
        struct list_head *h, *n;
index 634465e9cfc6edf57fd819cffe9af0af944aa82d..583c0710e45e3e336a84c8dda2b5e13b0add9bd8 100644 (file)
@@ -54,7 +54,6 @@
 
 /* declarations */
 static void nfs4_cb_null(struct rpc_task *task);
-extern spinlock_t recall_lock;
 
 /* Index of predefined Linux callback client operations */
 
@@ -329,12 +328,12 @@ out:
         .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2,  \
 }
 
-struct rpc_procinfo     nfs4_cb_procedures[] = {
+static struct rpc_procinfo     nfs4_cb_procedures[] = {
     PROC(CB_NULL,      NULL,     enc_cb_null,     dec_cb_null),
     PROC(CB_RECALL,    COMPOUND,   enc_cb_recall,      dec_cb_recall),
 };
 
-struct rpc_version              nfs_cb_version4 = {
+static struct rpc_version       nfs_cb_version4 = {
         .number                 = 1,
         .nrprocs                = sizeof(nfs4_cb_procedures)/sizeof(nfs4_cb_procedures[0]),
         .procs                  = nfs4_cb_procedures
@@ -348,7 +347,7 @@ static struct rpc_version * nfs_cb_version[] = {
 /*
  * Use the SETCLIENTID credential
  */
-struct rpc_cred *
+static struct rpc_cred *
 nfsd4_lookupcred(struct nfs4_client *clp, int taskflags)
 {
         struct auth_cred acred;
@@ -387,9 +386,7 @@ nfsd4_probe_callback(struct nfs4_client *clp)
        char                    hostname[32];
        int status;
 
-       dprintk("NFSD: probe_callback. cb_parsed %d cb_set %d\n",
-                       cb->cb_parsed, atomic_read(&cb->cb_set));
-       if (!cb->cb_parsed || atomic_read(&cb->cb_set))
+       if (atomic_read(&cb->cb_set))
                return;
 
        /* Initialize address */
@@ -427,7 +424,7 @@ nfsd4_probe_callback(struct nfs4_client *clp)
         * XXX AUTH_UNIX only - need AUTH_GSS....
         */
        sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr));
-       clnt = rpc_create_client(xprt, hostname, program, 1, RPC_AUTH_UNIX);
+       clnt = rpc_new_client(xprt, hostname, program, 1, RPC_AUTH_UNIX);
        if (IS_ERR(clnt)) {
                dprintk("NFSD: couldn't create callback client\n");
                goto out_err;
index 4ba540841cf6f7c8866e52ade9de62186d8c403a..5605a26efc57d9db3ca93471f437996dae91056e 100644 (file)
@@ -104,7 +104,7 @@ ent_update(struct ent *new, struct ent *itm)
        ent_init(new, itm);
 }
 
-void
+static void
 ent_put(struct cache_head *ch, struct cache_detail *cd)
 {
        if (cache_put(ch, cd)) {
@@ -186,7 +186,7 @@ warn_no_idmapd(struct cache_detail *detail)
 static int         idtoname_parse(struct cache_detail *, char *, int);
 static struct ent *idtoname_lookup(struct ent *, int);
 
-struct cache_detail idtoname_cache = {
+static struct cache_detail idtoname_cache = {
        .hash_size      = ENT_HASHMAX,
        .hash_table     = idtoname_table,
        .name           = "nfs4.idtoname",
@@ -277,7 +277,7 @@ nametoid_hash(struct ent *ent)
        return hash_str(ent->name, ENT_HASHBITS);
 }
 
-void
+static void
 nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
     int *blen)
 {
@@ -317,9 +317,9 @@ nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
 }
 
 static struct ent *nametoid_lookup(struct ent *, int);
-int                nametoid_parse(struct cache_detail *, char *, int);
+static int         nametoid_parse(struct cache_detail *, char *, int);
 
-struct cache_detail nametoid_cache = {
+static struct cache_detail nametoid_cache = {
        .hash_size      = ENT_HASHMAX,
        .hash_table     = nametoid_table,
        .name           = "nfs4.nametoid",
@@ -330,7 +330,7 @@ struct cache_detail nametoid_cache = {
        .warn_no_listener = warn_no_idmapd,
 };
 
-int
+static int
 nametoid_parse(struct cache_detail *cd, char *buf, int buflen)
 {
        struct ent ent, *res;
index e8158741e8b5c03ff879c948c9adb47e7283035d..d71f14517b9c09fc7cae2209b8c62a9777a427d7 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/param.h>
 #include <linux/major.h>
 #include <linux/slab.h>
+#include <linux/file.h>
 
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
@@ -198,6 +199,11 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
        if (status)
                goto out;
        switch (open->op_claim_type) {
+               case NFS4_OPEN_CLAIM_DELEGATE_CUR:
+                       status = nfserr_inval;
+                       if (open->op_create)
+                               goto out;
+                       /* fall through */
                case NFS4_OPEN_CLAIM_NULL:
                        /*
                         * (1) set CURRENT_FH to the file being opened,
@@ -220,7 +226,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
                        if (status)
                                goto out;
                        break;
-               case NFS4_OPEN_CLAIM_DELEGATE_CUR:
                case NFS4_OPEN_CLAIM_DELEGATE_PREV:
                        printk("NFSD: unsupported OPEN claim type %d\n",
                                open->op_claim_type);
@@ -473,26 +478,27 @@ static inline int
 nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read)
 {
        int status;
-       struct file *filp = NULL;
 
        /* no need to check permission - this will be done in nfsd_read() */
 
+       read->rd_filp = NULL;
        if (read->rd_offset >= OFFSET_MAX)
                return nfserr_inval;
 
        nfs4_lock_state();
        /* check stateid */
        if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid,
-                                       CHECK_FH | RD_STATE, &filp))) {
+                               CHECK_FH | RD_STATE, &read->rd_filp))) {
                dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
                goto out;
        }
+       if (read->rd_filp)
+               get_file(read->rd_filp);
        status = nfs_ok;
 out:
        nfs4_unlock_state();
        read->rd_rqstp = rqstp;
        read->rd_fhp = current_fh;
-       read->rd_filp = filp;
        return status;
 }
 
@@ -532,6 +538,8 @@ nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_rem
 {
        int status;
 
+       if (nfs4_in_grace())
+               return nfserr_grace;
        status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen);
        if (status == nfserr_symlink)
                return nfserr_notdir;
@@ -550,6 +558,9 @@ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh,
 
        if (!save_fh->fh_dentry)
                return status;
+       if (nfs4_in_grace() && !(save_fh->fh_export->ex_flags
+                                       & NFSEXP_NOSUBTREECHECK))
+               return nfserr_grace;
        status = nfsd_rename(rqstp, save_fh, rename->rn_sname,
                             rename->rn_snamelen, current_fh,
                             rename->rn_tname, rename->rn_tnamelen);
@@ -624,6 +635,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
                dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
                goto out;
        }
+       if (filp)
+               get_file(filp);
        nfs4_unlock_state();
 
        write->wr_bytes_written = write->wr_buflen;
@@ -635,6 +648,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
        status =  nfsd_write(rqstp, current_fh, filp, write->wr_offset,
                        write->wr_vec, write->wr_vlen, write->wr_buflen,
                        &write->wr_how_written);
+       if (filp)
+               fput(filp);
 
        if (status == nfserr_symlink)
                status = nfserr_inval;
@@ -923,6 +938,9 @@ encode_op:
                        nfs4_put_stateowner(replay_owner);
                        replay_owner = NULL;
                }
+               /* XXX Ugh, we need to get rid of this kind of special case: */
+               if (op->opnum == OP_READ && op->u.read.rd_filp)
+                       fput(op->u.read.rd_filp);
        }
 
 out:
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
new file mode 100644 (file)
index 0000000..095f174
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+*  linux/fs/nfsd/nfs4recover.c
+*
+*  Copyright (c) 2004 The Regents of the University of Michigan.
+*  All rights reserved.
+*
+*  Andy Adamson <andros@citi.umich.edu>
+*
+*  Redistribution and use in source and binary forms, with or without
+*  modification, are permitted provided that the following conditions
+*  are met:
+*
+*  1. Redistributions of source code must retain the above copyright
+*     notice, this list of conditions and the following disclaimer.
+*  2. 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.
+*  3. Neither the name of the University 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 ``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 REGENTS 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.
+*
+*/
+
+
+#include <linux/sunrpc/svc.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/nfs4.h>
+#include <linux/nfsd/state.h>
+#include <linux/nfsd/xdr4.h>
+#include <linux/param.h>
+#include <linux/file.h>
+#include <linux/namei.h>
+#include <asm/uaccess.h>
+#include <asm/scatterlist.h>
+#include <linux/crypto.h>
+
+
+#define NFSDDBG_FACILITY                NFSDDBG_PROC
+
+/* Globals */
+static struct nameidata rec_dir;
+static int rec_dir_init = 0;
+
+static void
+nfs4_save_user(uid_t *saveuid, gid_t *savegid)
+{
+       *saveuid = current->fsuid;
+       *savegid = current->fsgid;
+       current->fsuid = 0;
+       current->fsgid = 0;
+}
+
+static void
+nfs4_reset_user(uid_t saveuid, gid_t savegid)
+{
+       current->fsuid = saveuid;
+       current->fsgid = savegid;
+}
+
+static void
+md5_to_hex(char *out, char *md5)
+{
+       int i;
+
+       for (i=0; i<16; i++) {
+               unsigned char c = md5[i];
+
+               *out++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1);
+               *out++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1);
+       }
+       *out = '\0';
+}
+
+int
+nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
+{
+       struct xdr_netobj cksum;
+       struct crypto_tfm *tfm;
+       struct scatterlist sg[1];
+       int status = nfserr_resource;
+
+       dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
+                       clname->len, clname->data);
+       tfm = crypto_alloc_tfm("md5", 0);
+       if (tfm == NULL)
+               goto out;
+       cksum.len = crypto_tfm_alg_digestsize(tfm);
+       cksum.data = kmalloc(cksum.len, GFP_KERNEL);
+       if (cksum.data == NULL)
+               goto out;
+       crypto_digest_init(tfm);
+
+       sg[0].page = virt_to_page(clname->data);
+       sg[0].offset = offset_in_page(clname->data);
+       sg[0].length = clname->len;
+
+       crypto_digest_update(tfm, sg, 1);
+       crypto_digest_final(tfm, cksum.data);
+
+       md5_to_hex(dname, cksum.data);
+
+       kfree(cksum.data);
+       status = nfs_ok;
+out:
+       if (tfm)
+               crypto_free_tfm(tfm);
+       return status;
+}
+
+static int
+nfsd4_rec_fsync(struct dentry *dentry)
+{
+       struct file *filp;
+       int status = nfs_ok;
+
+       dprintk("NFSD: nfs4_fsync_rec_dir\n");
+       filp = dentry_open(dget(dentry), mntget(rec_dir.mnt), O_RDWR);
+       if (IS_ERR(filp)) {
+               status = PTR_ERR(filp);
+               goto out;
+       }
+       if (filp->f_op && filp->f_op->fsync)
+               status = filp->f_op->fsync(filp, filp->f_dentry, 0);
+       fput(filp);
+out:
+       if (status)
+               printk("nfsd4: unable to sync recovery directory\n");
+       return status;
+}
+
+int
+nfsd4_create_clid_dir(struct nfs4_client *clp)
+{
+       char *dname = clp->cl_recdir;
+       struct dentry *dentry;
+       uid_t uid;
+       gid_t gid;
+       int status;
+
+       dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
+
+       if (!rec_dir_init || clp->cl_firststate)
+               return 0;
+
+       nfs4_save_user(&uid, &gid);
+
+       /* lock the parent */
+       down(&rec_dir.dentry->d_inode->i_sem);
+
+       dentry = lookup_one_len(dname, rec_dir.dentry, HEXDIR_LEN-1);
+       if (IS_ERR(dentry)) {
+               status = PTR_ERR(dentry);
+               goto out_unlock;
+       }
+       status = -EEXIST;
+       if (dentry->d_inode) {
+               dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n");
+               goto out_put;
+       }
+       status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU);
+out_put:
+       dput(dentry);
+out_unlock:
+       up(&rec_dir.dentry->d_inode->i_sem);
+       if (status == 0) {
+               clp->cl_firststate = 1;
+               status = nfsd4_rec_fsync(rec_dir.dentry);
+       }
+       nfs4_reset_user(uid, gid);
+       dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status);
+       return status;
+}
+
+typedef int (recdir_func)(struct dentry *, struct dentry *);
+
+struct dentry_list {
+       struct dentry *dentry;
+       struct list_head list;
+};
+
+struct dentry_list_arg {
+       struct list_head dentries;
+       struct dentry *parent;
+};
+
+static int
+nfsd4_build_dentrylist(void *arg, const char *name, int namlen,
+               loff_t offset, ino_t ino, unsigned int d_type)
+{
+       struct dentry_list_arg *dla = arg;
+       struct list_head *dentries = &dla->dentries;
+       struct dentry *parent = dla->parent;
+       struct dentry *dentry;
+       struct dentry_list *child;
+
+       if (name && isdotent(name, namlen))
+               return nfs_ok;
+       dentry = lookup_one_len(name, parent, namlen);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
+       child = kmalloc(sizeof(*child), GFP_KERNEL);
+       if (child == NULL)
+               return -ENOMEM;
+       child->dentry = dentry;
+       list_add(&child->list, dentries);
+       return 0;
+}
+
+static int
+nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
+{
+       struct file *filp;
+       struct dentry_list_arg dla = {
+               .parent = dir,
+       };
+       struct list_head *dentries = &dla.dentries;
+       struct dentry_list *child;
+       uid_t uid;
+       gid_t gid;
+       int status;
+
+       if (!rec_dir_init)
+               return 0;
+
+       nfs4_save_user(&uid, &gid);
+
+       filp = dentry_open(dget(dir), mntget(rec_dir.mnt),
+                       O_RDWR);
+       status = PTR_ERR(filp);
+       if (IS_ERR(filp))
+               goto out;
+       INIT_LIST_HEAD(dentries);
+       status = vfs_readdir(filp, nfsd4_build_dentrylist, &dla);
+       fput(filp);
+       while (!list_empty(dentries)) {
+               child = list_entry(dentries->next, struct dentry_list, list);
+               status = f(dir, child->dentry);
+               if (status)
+                       goto out;
+               list_del(&child->list);
+               dput(child->dentry);
+               kfree(child);
+       }
+out:
+       while (!list_empty(dentries)) {
+               child = list_entry(dentries->next, struct dentry_list, list);
+               list_del(&child->list);
+               dput(child->dentry);
+               kfree(child);
+       }
+       nfs4_reset_user(uid, gid);
+       return status;
+}
+
+static int
+nfsd4_remove_clid_file(struct dentry *dir, struct dentry *dentry)
+{
+       int status;
+
+       if (!S_ISREG(dir->d_inode->i_mode)) {
+               printk("nfsd4: non-file found in client recovery directory\n");
+               return -EINVAL;
+       }
+       down(&dir->d_inode->i_sem);
+       status = vfs_unlink(dir->d_inode, dentry);
+       up(&dir->d_inode->i_sem);
+       return status;
+}
+
+static int
+nfsd4_clear_clid_dir(struct dentry *dir, struct dentry *dentry)
+{
+       int status;
+
+       /* For now this directory should already be empty, but we empty it of
+        * any regular files anyway, just in case the directory was created by
+        * a kernel from the future.... */
+       nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file);
+       down(&dir->d_inode->i_sem);
+       status = vfs_rmdir(dir->d_inode, dentry);
+       up(&dir->d_inode->i_sem);
+       return status;
+}
+
+static int
+nfsd4_unlink_clid_dir(char *name, int namlen)
+{
+       struct dentry *dentry;
+       int status;
+
+       dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
+
+       dentry = lookup_one_len(name, rec_dir.dentry, namlen);
+       if (IS_ERR(dentry)) {
+               status = PTR_ERR(dentry);
+               return status;
+       }
+       status = -ENOENT;
+       if (!dentry->d_inode)
+               goto out;
+
+       status = nfsd4_clear_clid_dir(rec_dir.dentry, dentry);
+out:
+       dput(dentry);
+       return status;
+}
+
+void
+nfsd4_remove_clid_dir(struct nfs4_client *clp)
+{
+       uid_t uid;
+       gid_t gid;
+       int status;
+
+       if (!rec_dir_init || !clp->cl_firststate)
+               return;
+
+       nfs4_save_user(&uid, &gid);
+       status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
+       nfs4_reset_user(uid, gid);
+       if (status == 0)
+               status = nfsd4_rec_fsync(rec_dir.dentry);
+       if (status)
+               printk("NFSD: Failed to remove expired client state directory"
+                               " %.*s\n", HEXDIR_LEN, clp->cl_recdir);
+       return;
+}
+
+static int
+purge_old(struct dentry *parent, struct dentry *child)
+{
+       int status;
+
+       if (nfs4_has_reclaimed_state(child->d_name.name))
+               return nfs_ok;
+
+       status = nfsd4_clear_clid_dir(parent, child);
+       if (status)
+               printk("failed to remove client recovery directory %s\n",
+                               child->d_name.name);
+       /* Keep trying, success or failure: */
+       return nfs_ok;
+}
+
+void
+nfsd4_recdir_purge_old(void) {
+       int status;
+
+       if (!rec_dir_init)
+               return;
+       status = nfsd4_list_rec_dir(rec_dir.dentry, purge_old);
+       if (status == 0)
+               status = nfsd4_rec_fsync(rec_dir.dentry);
+       if (status)
+               printk("nfsd4: failed to purge old clients from recovery"
+                       " directory %s\n", rec_dir.dentry->d_name.name);
+       return;
+}
+
+static int
+load_recdir(struct dentry *parent, struct dentry *child)
+{
+       if (child->d_name.len != HEXDIR_LEN - 1) {
+               printk("nfsd4: illegal name %s in recovery directory\n",
+                               child->d_name.name);
+               /* Keep trying; maybe the others are OK: */
+               return nfs_ok;
+       }
+       nfs4_client_to_reclaim(child->d_name.name);
+       return nfs_ok;
+}
+
+int
+nfsd4_recdir_load(void) {
+       int status;
+
+       status = nfsd4_list_rec_dir(rec_dir.dentry, load_recdir);
+       if (status)
+               printk("nfsd4: failed loading clients from recovery"
+                       " directory %s\n", rec_dir.dentry->d_name.name);
+       return status;
+}
+
+/*
+ * Hold reference to the recovery directory.
+ */
+
+void
+nfsd4_init_recdir(char *rec_dirname)
+{
+       uid_t                   uid = 0;
+       gid_t                   gid = 0;
+       int                     status;
+
+       printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
+                       rec_dirname);
+
+       BUG_ON(rec_dir_init);
+
+       nfs4_save_user(&uid, &gid);
+
+       status = path_lookup(rec_dirname, LOOKUP_FOLLOW, &rec_dir);
+       if (status == -ENOENT)
+               printk("NFSD: recovery directory %s doesn't exist\n",
+                               rec_dirname);
+
+       if (!status)
+               rec_dir_init = 1;
+       nfs4_reset_user(uid, gid);
+}
+
+void
+nfsd4_shutdown_recdir(void)
+{
+       if (!rec_dir_init)
+               return;
+       rec_dir_init = 0;
+       path_release(&rec_dir);
+}
index 75e8b137580c29730d84cd6c58ef60f68ec84c3e..89e36526d7f289f32873fe856bd9421d89288311 100644 (file)
 #include <linux/nfs4.h>
 #include <linux/nfsd/state.h>
 #include <linux/nfsd/xdr4.h>
+#include <linux/namei.h>
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
 /* Globals */
 static time_t lease_time = 90;     /* default lease time */
-static time_t old_lease_time = 90; /* past incarnation lease time */
-static u32 nfs4_reclaim_init = 0;
-time_t boot_time;
-static time_t grace_end = 0;
+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;
 static u32 nfs4_init;
-stateid_t zerostateid;             /* bits all 0 */
-stateid_t onestateid;              /* bits all 1 */
-
-/* debug counters */
-u32 list_add_perfile = 0; 
-u32 list_del_perfile = 0;
-u32 add_perclient = 0;
-u32 del_perclient = 0;
-u32 alloc_file = 0;
-u32 free_file = 0;
-u32 vfsopen = 0;
-u32 vfsclose = 0;
-u32 alloc_delegation= 0;
-u32 free_delegation= 0;
+static stateid_t zerostateid;             /* bits all 0 */
+static stateid_t onestateid;              /* bits all 1 */
+
+#define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t)))
+#define ONE_STATEID(stateid)  (!memcmp((stateid), &onestateid, sizeof(stateid_t)))
 
 /* forward declarations */
-struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
+static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
 static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
 static void release_stateid_lockowners(struct nfs4_stateid *open_stp);
+static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
+static void nfs4_set_recdir(char *recdir);
 
 /* Locking:
  *
@@ -90,6 +83,11 @@ static void release_stateid_lockowners(struct nfs4_stateid *open_stp);
  */
 static DECLARE_MUTEX(client_sema);
 
+static kmem_cache_t *stateowner_slab = NULL;
+static kmem_cache_t *file_slab = NULL;
+static kmem_cache_t *stateid_slab = NULL;
+static kmem_cache_t *deleg_slab = NULL;
+
 void
 nfs4_lock_state(void)
 {
@@ -118,16 +116,36 @@ opaque_hashval(const void *ptr, int nbytes)
 /* forward declarations */
 static void release_stateowner(struct nfs4_stateowner *sop);
 static void release_stateid(struct nfs4_stateid *stp, int flags);
-static void release_file(struct nfs4_file *fp);
 
 /*
  * Delegation state
  */
 
 /* recall_lock protects the del_recall_lru */
-spinlock_t recall_lock;
+static spinlock_t recall_lock = SPIN_LOCK_UNLOCKED;
 static struct list_head del_recall_lru;
 
+static void
+free_nfs4_file(struct kref *kref)
+{
+       struct nfs4_file *fp = container_of(kref, struct nfs4_file, fi_ref);
+       list_del(&fp->fi_hash);
+       iput(fp->fi_inode);
+       kmem_cache_free(file_slab, fp);
+}
+
+static inline void
+put_nfs4_file(struct nfs4_file *fi)
+{
+       kref_put(&fi->fi_ref, free_nfs4_file);
+}
+
+static inline void
+get_nfs4_file(struct nfs4_file *fi)
+{
+       kref_get(&fi->fi_ref);
+}
+
 static struct nfs4_delegation *
 alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
 {
@@ -136,13 +154,14 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
        struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback;
 
        dprintk("NFSD alloc_init_deleg\n");
-       if ((dp = kmalloc(sizeof(struct nfs4_delegation),
-               GFP_KERNEL)) == NULL)
+       dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
+       if (dp == NULL)
                return dp;
-       INIT_LIST_HEAD(&dp->dl_del_perfile);
-       INIT_LIST_HEAD(&dp->dl_del_perclnt);
+       INIT_LIST_HEAD(&dp->dl_perfile);
+       INIT_LIST_HEAD(&dp->dl_perclnt);
        INIT_LIST_HEAD(&dp->dl_recall_lru);
        dp->dl_client = clp;
+       get_nfs4_file(fp);
        dp->dl_file = fp;
        dp->dl_flock = NULL;
        get_file(stp->st_vfs_file);
@@ -160,9 +179,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
                        current_fh->fh_handle.fh_size);
        dp->dl_time = 0;
        atomic_set(&dp->dl_count, 1);
-       list_add(&dp->dl_del_perfile, &fp->fi_del_perfile);
-       list_add(&dp->dl_del_perclnt, &clp->cl_del_perclnt);
-       alloc_delegation++;
+       list_add(&dp->dl_perfile, &fp->fi_delegations);
+       list_add(&dp->dl_perclnt, &clp->cl_delegations);
        return dp;
 }
 
@@ -171,8 +189,8 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
 {
        if (atomic_dec_and_test(&dp->dl_count)) {
                dprintk("NFSD: freeing dp %p\n",dp);
-               kfree(dp);
-               free_delegation++;
+               put_nfs4_file(dp->dl_file);
+               kmem_cache_free(deleg_slab, dp);
        }
 }
 
@@ -193,15 +211,14 @@ nfs4_close_delegation(struct nfs4_delegation *dp)
        if (dp->dl_flock)
                setlease(filp, F_UNLCK, &dp->dl_flock);
        nfsd_close(filp);
-       vfsclose++;
 }
 
 /* Called under the state lock. */
 static void
 unhash_delegation(struct nfs4_delegation *dp)
 {
-       list_del_init(&dp->dl_del_perfile);
-       list_del_init(&dp->dl_del_perclnt);
+       list_del_init(&dp->dl_perfile);
+       list_del_init(&dp->dl_perclnt);
        spin_lock(&recall_lock);
        list_del_init(&dp->dl_recall_lru);
        spin_unlock(&recall_lock);
@@ -220,8 +237,8 @@ unhash_delegation(struct nfs4_delegation *dp)
 
 #define clientid_hashval(id) \
        ((id) & CLIENT_HASH_MASK)
-#define clientstr_hashval(name, namelen) \
-       (opaque_hashval((name), (namelen)) & CLIENT_HASH_MASK)
+#define clientstr_hashval(name) \
+       (opaque_hashval((name), 8) & CLIENT_HASH_MASK)
 /*
  * reclaim_str_hashtbl[] holds known client info from previous reset/reboot
  * used in reboot/reset lease grace period processing
@@ -331,11 +348,11 @@ expire_client(struct nfs4_client *clp)
 
        INIT_LIST_HEAD(&reaplist);
        spin_lock(&recall_lock);
-       while (!list_empty(&clp->cl_del_perclnt)) {
-               dp = list_entry(clp->cl_del_perclnt.next, struct nfs4_delegation, dl_del_perclnt);
+       while (!list_empty(&clp->cl_delegations)) {
+               dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
                dprintk("NFSD: expire client. dp %p, fp %p\n", dp,
                                dp->dl_flock);
-               list_del_init(&dp->dl_del_perclnt);
+               list_del_init(&dp->dl_perclnt);
                list_move(&dp->dl_recall_lru, &reaplist);
        }
        spin_unlock(&recall_lock);
@@ -347,26 +364,26 @@ expire_client(struct nfs4_client *clp)
        list_del(&clp->cl_idhash);
        list_del(&clp->cl_strhash);
        list_del(&clp->cl_lru);
-       while (!list_empty(&clp->cl_perclient)) {
-               sop = list_entry(clp->cl_perclient.next, struct nfs4_stateowner, so_perclient);
+       while (!list_empty(&clp->cl_openowners)) {
+               sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient);
                release_stateowner(sop);
        }
        put_nfs4_client(clp);
 }
 
 static struct nfs4_client *
-create_client(struct xdr_netobj name) {
+create_client(struct xdr_netobj name, char *recdir) {
        struct nfs4_client *clp;
 
        if (!(clp = alloc_client(name)))
                goto out;
+       memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
        atomic_set(&clp->cl_count, 1);
        atomic_set(&clp->cl_callback.cb_set, 0);
-       clp->cl_callback.cb_parsed = 0;
        INIT_LIST_HEAD(&clp->cl_idhash);
        INIT_LIST_HEAD(&clp->cl_strhash);
-       INIT_LIST_HEAD(&clp->cl_perclient);
-       INIT_LIST_HEAD(&clp->cl_del_perclnt);
+       INIT_LIST_HEAD(&clp->cl_openowners);
+       INIT_LIST_HEAD(&clp->cl_delegations);
        INIT_LIST_HEAD(&clp->cl_lru);
 out:
        return clp;
@@ -392,11 +409,9 @@ copy_cred(struct svc_cred *target, struct svc_cred *source) {
        get_group_info(target->cr_group_info);
 }
 
-static int
-cmp_name(struct xdr_netobj *n1, struct xdr_netobj *n2) {
-       if (!n1 || !n2)
-               return 0;
-       return((n1->len == n2->len) && !memcmp(n1->data, n2->data, n2->len));
+static inline int
+same_name(const char *n1, const char *n2) {
+       return 0 == memcmp(n1, n2, HEXDIR_LEN);
 }
 
 static int
@@ -446,7 +461,7 @@ check_name(struct xdr_netobj name) {
        return 1;
 }
 
-void
+static void
 add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval)
 {
        unsigned int idhashval;
@@ -458,7 +473,7 @@ add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval)
        clp->cl_time = get_seconds();
 }
 
-void
+static void
 move_to_confirmed(struct nfs4_client *clp)
 {
        unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
@@ -468,8 +483,7 @@ move_to_confirmed(struct nfs4_client *clp)
        list_del_init(&clp->cl_strhash);
        list_del_init(&clp->cl_idhash);
        list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);
-       strhashval = clientstr_hashval(clp->cl_name.data, 
-                       clp->cl_name.len);
+       strhashval = clientstr_hashval(clp->cl_recdir);
        list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]);
        renew_client(clp);
 }
@@ -500,6 +514,30 @@ find_unconfirmed_client(clientid_t *clid)
        return NULL;
 }
 
+static struct nfs4_client *
+find_confirmed_client_by_str(const char *dname, unsigned int hashval)
+{
+       struct nfs4_client *clp;
+
+       list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) {
+               if (same_name(clp->cl_recdir, dname))
+                       return clp;
+       }
+       return NULL;
+}
+
+static struct nfs4_client *
+find_unconfirmed_client_by_str(const char *dname, unsigned int hashval)
+{
+       struct nfs4_client *clp;
+
+       list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) {
+               if (same_name(clp->cl_recdir, dname))
+                       return clp;
+       }
+       return NULL;
+}
+
 /* a helper function for parse_callback */
 static int
 parse_octet(unsigned int *lenp, char **addrp)
@@ -534,7 +572,7 @@ parse_octet(unsigned int *lenp, char **addrp)
 }
 
 /* parse and set the setclientid ipv4 callback address */
-int
+static int
 parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigned short *cbportp)
 {
        int temp = 0;
@@ -570,7 +608,7 @@ parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigne
        return 1;
 }
 
-void
+static void
 gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se)
 {
        struct nfs4_callback *cb = &clp->cl_callback;
@@ -584,14 +622,12 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se)
                goto out_err;
        cb->cb_prog = se->se_callback_prog;
        cb->cb_ident = se->se_callback_ident;
-       cb->cb_parsed = 1;
        return;
 out_err:
        printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
                "will not receive delegations\n",
                clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
 
-       cb->cb_parsed = 0;
        return;
 }
 
@@ -638,59 +674,43 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
        };
        nfs4_verifier           clverifier = setclid->se_verf;
        unsigned int            strhashval;
-       struct nfs4_client *    conf, * unconf, * new, * clp;
+       struct nfs4_client      *conf, *unconf, *new;
        int                     status;
+       char                    dname[HEXDIR_LEN];
        
        status = nfserr_inval;
        if (!check_name(clname))
                goto out;
 
+       status = nfs4_make_rec_clidname(dname, &clname);
+       if (status)
+               goto out;
+
        /* 
         * XXX The Duplicate Request Cache (DRC) has been checked (??)
         * We get here on a DRC miss.
         */
 
-       strhashval = clientstr_hashval(clname.data, clname.len);
+       strhashval = clientstr_hashval(dname);
 
-       conf = NULL;
        nfs4_lock_state();
-       list_for_each_entry(clp, &conf_str_hashtbl[strhashval], cl_strhash) {
-               if (!cmp_name(&clp->cl_name, &clname))
-                       continue;
+       conf = find_confirmed_client_by_str(dname, strhashval);
+       if (conf) {
                /* 
                 * CASE 0:
                 * clname match, confirmed, different principal
                 * or different ip_address
                 */
                status = nfserr_clid_inuse;
-               if (!cmp_creds(&clp->cl_cred,&rqstp->rq_cred)) {
-                       printk("NFSD: setclientid: string in use by client"
-                       "(clientid %08x/%08x)\n",
-                       clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
-                       goto out;
-               }
-               if (clp->cl_addr != ip_addr) { 
+               if (!cmp_creds(&conf->cl_cred, &rqstp->rq_cred)
+                               || conf->cl_addr != ip_addr) {
                        printk("NFSD: setclientid: string in use by client"
                        "(clientid %08x/%08x)\n",
-                       clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
+                       conf->cl_clientid.cl_boot, conf->cl_clientid.cl_id);
                        goto out;
                }
-
-               /* 
-                * cl_name match from a previous SETCLIENTID operation
-                * XXX check for additional matches?
-                */
-               conf = clp;
-               break;
-       }
-       unconf = NULL;
-       list_for_each_entry(clp, &unconf_str_hashtbl[strhashval], cl_strhash) {
-               if (!cmp_name(&clp->cl_name, &clname))
-                       continue;
-               /* cl_name match from a previous SETCLIENTID operation */
-               unconf = clp;
-               break;
        }
+       unconf = find_unconfirmed_client_by_str(dname, strhashval);
        status = nfserr_resource;
        if (!conf) {
                /* 
@@ -699,7 +719,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
                 */
                if (unconf)
                        expire_client(unconf);
-               if (!(new = create_client(clname)))
+               new = create_client(clname, dname);
+               if (new == NULL)
                        goto out;
                copy_verf(new, &clverifier);
                new->cl_addr = ip_addr;
@@ -722,12 +743,16 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
                 * nfs4_client,  but with the new callback info and a 
                 * new cl_confirm
                 */
-               if ((unconf) && 
-                   cmp_verf(&unconf->cl_verifier, &conf->cl_verifier) &&
-                    cmp_clid(&unconf->cl_clientid, &conf->cl_clientid)) {
-                               expire_client(unconf);
+               if (unconf) {
+                       /* Note this is removing unconfirmed {*x***},
+                        * which is stronger than RFC recommended {vxc**}.
+                        * This has the advantage that there is at most
+                        * one {*x***} in either list at any time.
+                        */
+                       expire_client(unconf);
                }
-               if (!(new = create_client(clname)))
+               new = create_client(clname, dname);
+               if (new == NULL)
                        goto out;
                copy_verf(new,&conf->cl_verifier);
                new->cl_addr = ip_addr;
@@ -745,7 +770,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
                 * using input clverifier, clname, and callback info
                 * and generate a new cl_clientid and cl_confirm.
                 */
-               if (!(new = create_client(clname)))
+               new = create_client(clname, dname);
+               if (new == NULL)
                        goto out;
                copy_verf(new,&clverifier);
                new->cl_addr = ip_addr;
@@ -771,7 +797,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
                 * new cl_verifier and a new cl_confirm
                 */
                expire_client(unconf);
-               if (!(new = create_client(clname)))
+               new = create_client(clname, dname);
+               if (new == NULL)
                        goto out;
                copy_verf(new,&clverifier);
                new->cl_addr = ip_addr;
@@ -807,7 +834,7 @@ int
 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm)
 {
        u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
-       struct nfs4_client *clp, *conf = NULL, *unconf = NULL;
+       struct nfs4_client *conf, *unconf;
        nfs4_verifier confirm = setclientid_confirm->sc_confirm; 
        clientid_t * clid = &setclientid_confirm->sc_clientid;
        int status;
@@ -820,102 +847,90 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi
         */
 
        nfs4_lock_state();
-       clp = find_confirmed_client(clid);
-       if (clp) {
-               status = nfserr_inval;
-               /* 
-                * Found a record for this clientid. If the IP addresses
-                * don't match, return ERR_INVAL just as if the record had
-                * not been found.
-                */
-               if (clp->cl_addr != ip_addr) { 
-                       printk("NFSD: setclientid: string in use by client"
-                       "(clientid %08x/%08x)\n",
-                       clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
-                       goto out;
-               }
-               conf = clp;
-       }
-       clp = find_unconfirmed_client(clid);
-       if (clp) {
-               status = nfserr_inval;
-               if (clp->cl_addr != ip_addr) { 
-                       printk("NFSD: setclientid: string in use by client"
-                       "(clientid %08x/%08x)\n",
-                       clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
-                       goto out;
-               }
-               unconf = clp;
-       }
-       /* CASE 1: 
-       * unconf record that matches input clientid and input confirm.
-       * conf record that matches input clientid.
-       * conf  and unconf records match names, verifiers 
-       */
+
+       conf = find_confirmed_client(clid);
+       unconf = find_unconfirmed_client(clid);
+
+       status = nfserr_clid_inuse;
+       if (conf && conf->cl_addr != ip_addr)
+               goto out;
+       if (unconf && unconf->cl_addr != ip_addr)
+               goto out;
+
        if ((conf && unconf) && 
            (cmp_verf(&unconf->cl_confirm, &confirm)) &&
            (cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&
-           (cmp_name(&conf->cl_name,&unconf->cl_name))  &&
+           (same_name(conf->cl_recdir,unconf->cl_recdir))  &&
            (!cmp_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
+               */
                if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred)) 
                        status = nfserr_clid_inuse;
                else {
-                       expire_client(conf);
-                       clp = unconf;
-                       move_to_confirmed(unconf);
+                       /* XXX: We just turn off callbacks until we can handle
+                         * change request correctly. */
+                       atomic_set(&conf->cl_callback.cb_set, 0);
+                       gen_confirm(conf);
+                       expire_client(unconf);
                        status = nfs_ok;
+
                }
-               goto out;
-       } 
-       /* CASE 2:
-        * conf record that matches input clientid.
-        * if unconf record that matches input clientid, then unconf->cl_name
-        * or unconf->cl_verifier don't match the conf record.
-        */
-       if ((conf && !unconf) || 
+       } else if ((conf && !unconf) ||
            ((conf && unconf) && 
             (!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) ||
-             !cmp_name(&conf->cl_name, &unconf->cl_name)))) {
-               if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) {
+             !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.
+                */
+               if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred))
                        status = nfserr_clid_inuse;
-               } else {
-                       clp = conf;
+               else
                        status = nfs_ok;
-               }
-               goto out;
-       }
-       /* CASE 3:
-        * conf record not found.
-        * unconf record found. 
-        * unconf->cl_confirm matches input confirm
-        */ 
-       if (!conf && unconf && cmp_verf(&unconf->cl_confirm, &confirm)) {
+       } else if (!conf && unconf
+                       && cmp_verf(&unconf->cl_confirm, &confirm)) {
+               /* CASE 3:
+                * conf record not found.
+                * unconf record found.
+                * unconf->cl_confirm matches input confirm
+                */
                if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
                        status = nfserr_clid_inuse;
                } else {
-                       status = nfs_ok;
-                       clp = unconf;
+                       unsigned int hash =
+                               clientstr_hashval(unconf->cl_recdir);
+                       conf = find_confirmed_client_by_str(unconf->cl_recdir,
+                                                                       hash);
+                       if (conf) {
+                               nfsd4_remove_clid_dir(conf);
+                               expire_client(conf);
+                       }
                        move_to_confirmed(unconf);
+                       conf = unconf;
+                       status = nfs_ok;
                }
-               goto out;
-       }
-       /* CASE 4:
-        * conf record not found, or if conf, then conf->cl_confirm does not
-        * match input confirm.
-        * unconf record not found, or if unconf, then unconf->cl_confirm 
-        * does not match input confirm.
-        */
-       if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm))) &&
-           (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm, &confirm)))) {
+       } else if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm)))
+           && (!unconf || (unconf && !cmp_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.
+                */
                status = nfserr_stale_clientid;
-               goto out;
+       } else {
+               /* check that we have hit one of the cases...*/
+               status = nfserr_clid_inuse;
        }
-       /* check that we have hit one of the cases...*/
-       status = nfserr_inval;
-       goto out;
 out:
        if (!status)
-               nfsd4_probe_callback(clp);
+               nfsd4_probe_callback(conf);
        nfs4_unlock_state();
        return status;
 }
@@ -961,60 +976,65 @@ alloc_init_file(struct inode *ino)
        struct nfs4_file *fp;
        unsigned int hashval = file_hashval(ino);
 
-       if ((fp = kmalloc(sizeof(struct nfs4_file),GFP_KERNEL))) {
+       fp = kmem_cache_alloc(file_slab, GFP_KERNEL);
+       if (fp) {
+               kref_init(&fp->fi_ref);
                INIT_LIST_HEAD(&fp->fi_hash);
-               INIT_LIST_HEAD(&fp->fi_perfile);
-               INIT_LIST_HEAD(&fp->fi_del_perfile);
+               INIT_LIST_HEAD(&fp->fi_stateids);
+               INIT_LIST_HEAD(&fp->fi_delegations);
                list_add(&fp->fi_hash, &file_hashtbl[hashval]);
                fp->fi_inode = igrab(ino);
                fp->fi_id = current_fileid++;
-               alloc_file++;
                return fp;
        }
        return NULL;
 }
 
 static void
-release_all_files(void)
+nfsd4_free_slab(kmem_cache_t **slab)
 {
-       int i;
-       struct nfs4_file *fp;
+       int status;
 
-       for (i=0;i<FILE_HASH_SIZE;i++) {
-               while (!list_empty(&file_hashtbl[i])) {
-                       fp = list_entry(file_hashtbl[i].next, struct nfs4_file, fi_hash);
-                       /* this should never be more than once... */
-                       if (!list_empty(&fp->fi_perfile) || !list_empty(&fp->fi_del_perfile)) {
-                               printk("ERROR: release_all_files: file %p is open, creating dangling state !!!\n",fp);
-                       }
-                       release_file(fp);
-               }
-       }
+       if (*slab == NULL)
+               return;
+       status = kmem_cache_destroy(*slab);
+       *slab = NULL;
+       WARN_ON(status);
 }
 
-kmem_cache_t *stateowner_slab = NULL;
+static void
+nfsd4_free_slabs(void)
+{
+       nfsd4_free_slab(&stateowner_slab);
+       nfsd4_free_slab(&file_slab);
+       nfsd4_free_slab(&stateid_slab);
+       nfsd4_free_slab(&deleg_slab);
+}
 
 static int
 nfsd4_init_slabs(void)
 {
        stateowner_slab = kmem_cache_create("nfsd4_stateowners",
                        sizeof(struct nfs4_stateowner), 0, 0, NULL, NULL);
-       if (stateowner_slab == NULL) {
-               dprintk("nfsd4: out of memory while initializing nfsv4\n");
-               return -ENOMEM;
-       }
+       if (stateowner_slab == NULL)
+               goto out_nomem;
+       file_slab = kmem_cache_create("nfsd4_files",
+                       sizeof(struct nfs4_file), 0, 0, NULL, NULL);
+       if (file_slab == NULL)
+               goto out_nomem;
+       stateid_slab = kmem_cache_create("nfsd4_stateids",
+                       sizeof(struct nfs4_stateid), 0, 0, NULL, NULL);
+       if (stateid_slab == NULL)
+               goto out_nomem;
+       deleg_slab = kmem_cache_create("nfsd4_delegations",
+                       sizeof(struct nfs4_delegation), 0, 0, NULL, NULL);
+       if (deleg_slab == NULL)
+               goto out_nomem;
        return 0;
-}
-
-static void
-nfsd4_free_slabs(void)
-{
-       int status = 0;
-
-       if (stateowner_slab)
-               status = kmem_cache_destroy(stateowner_slab);
-       stateowner_slab = NULL;
-       BUG_ON(status);
+out_nomem:
+       nfsd4_free_slabs();
+       dprintk("nfsd4: out of memory while initializing nfsv4\n");
+       return -ENOMEM;
 }
 
 void
@@ -1055,14 +1075,13 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
        INIT_LIST_HEAD(&sop->so_idhash);
        INIT_LIST_HEAD(&sop->so_strhash);
        INIT_LIST_HEAD(&sop->so_perclient);
-       INIT_LIST_HEAD(&sop->so_perfilestate);
-       INIT_LIST_HEAD(&sop->so_perlockowner);  /* not used */
+       INIT_LIST_HEAD(&sop->so_stateids);
+       INIT_LIST_HEAD(&sop->so_perstateid);  /* not used */
        INIT_LIST_HEAD(&sop->so_close_lru);
        sop->so_time = 0;
        list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]);
        list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);
-       list_add(&sop->so_perclient, &clp->cl_perclient);
-       add_perclient++;
+       list_add(&sop->so_perclient, &clp->cl_openowners);
        sop->so_is_open_owner = 1;
        sop->so_id = current_ownerid++;
        sop->so_client = clp;
@@ -1080,10 +1099,10 @@ release_stateid_lockowners(struct nfs4_stateid *open_stp)
 {
        struct nfs4_stateowner *lock_sop;
 
-       while (!list_empty(&open_stp->st_perlockowner)) {
-               lock_sop = list_entry(open_stp->st_perlockowner.next,
-                               struct nfs4_stateowner, so_perlockowner);
-               /* list_del(&open_stp->st_perlockowner);  */
+       while (!list_empty(&open_stp->st_lockowners)) {
+               lock_sop = list_entry(open_stp->st_lockowners.next,
+                               struct nfs4_stateowner, so_perstateid);
+               /* list_del(&open_stp->st_lockowners);  */
                BUG_ON(lock_sop->so_is_open_owner);
                release_stateowner(lock_sop);
        }
@@ -1096,14 +1115,12 @@ unhash_stateowner(struct nfs4_stateowner *sop)
 
        list_del(&sop->so_idhash);
        list_del(&sop->so_strhash);
-       if (sop->so_is_open_owner) {
+       if (sop->so_is_open_owner)
                list_del(&sop->so_perclient);
-               del_perclient++;
-       }
-       list_del(&sop->so_perlockowner);
-       while (!list_empty(&sop->so_perfilestate)) {
-               stp = list_entry(sop->so_perfilestate.next, 
-                       struct nfs4_stateid, st_perfilestate);
+       list_del(&sop->so_perstateid);
+       while (!list_empty(&sop->so_stateids)) {
+               stp = list_entry(sop->so_stateids.next,
+                       struct nfs4_stateid, st_perstateowner);
                if (sop->so_is_open_owner)
                        release_stateid(stp, OPEN_STATE);
                else
@@ -1125,14 +1142,14 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *
        unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);
 
        INIT_LIST_HEAD(&stp->st_hash);
-       INIT_LIST_HEAD(&stp->st_perfilestate);
-       INIT_LIST_HEAD(&stp->st_perlockowner);
+       INIT_LIST_HEAD(&stp->st_perstateowner);
+       INIT_LIST_HEAD(&stp->st_lockowners);
        INIT_LIST_HEAD(&stp->st_perfile);
        list_add(&stp->st_hash, &stateid_hashtbl[hashval]);
-       list_add(&stp->st_perfilestate, &sop->so_perfilestate);
-       list_add_perfile++;
-       list_add(&stp->st_perfile, &fp->fi_perfile);
+       list_add(&stp->st_perstateowner, &sop->so_stateids);
+       list_add(&stp->st_perfile, &fp->fi_stateids);
        stp->st_stateowner = sop;
+       get_nfs4_file(fp);
        stp->st_file = fp;
        stp->st_stateid.si_boot = boot_time;
        stp->st_stateid.si_stateownerid = sop->so_id;
@@ -1150,30 +1167,20 @@ release_stateid(struct nfs4_stateid *stp, int flags)
        struct file *filp = stp->st_vfs_file;
 
        list_del(&stp->st_hash);
-       list_del_perfile++;
        list_del(&stp->st_perfile);
-       list_del(&stp->st_perfilestate);
+       list_del(&stp->st_perstateowner);
        if (flags & OPEN_STATE) {
                release_stateid_lockowners(stp);
                stp->st_vfs_file = NULL;
                nfsd_close(filp);
-               vfsclose++;
        } else if (flags & LOCK_STATE)
                locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);
-       kfree(stp);
+       put_nfs4_file(stp->st_file);
+       kmem_cache_free(stateid_slab, stp);
        stp = NULL;
 }
 
 static void
-release_file(struct nfs4_file *fp)
-{
-       free_file++;
-       list_del(&fp->fi_hash);
-       iput(fp->fi_inode);
-       kfree(fp);
-}      
-
-void
 move_to_close_lru(struct nfs4_stateowner *sop)
 {
        dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop);
@@ -1183,11 +1190,10 @@ move_to_close_lru(struct nfs4_stateowner *sop)
        sop->so_time = get_seconds();
 }
 
-void
+static void
 release_state_owner(struct nfs4_stateid *stp, int flag)
 {
        struct nfs4_stateowner *sop = stp->st_stateowner;
-       struct nfs4_file *fp = stp->st_file;
 
        dprintk("NFSD: release_state_owner\n");
        release_stateid(stp, flag);
@@ -1196,12 +1202,8 @@ release_state_owner(struct nfs4_stateid *stp, int flag)
         * released by the laundromat service after the lease period
         * to enable us to handle CLOSE replay
         */
-       if (sop->so_confirmed && list_empty(&sop->so_perfilestate))
+       if (sop->so_confirmed && list_empty(&sop->so_stateids))
                move_to_close_lru(sop);
-       /* unused nfs4_file's are releseed. XXX slab cache? */
-       if (list_empty(&fp->fi_perfile) && list_empty(&fp->fi_del_perfile)) {
-               release_file(fp);
-       }
 }
 
 static int
@@ -1231,8 +1233,10 @@ find_file(struct inode *ino)
        struct nfs4_file *fp;
 
        list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
-               if (fp->fi_inode == ino)
+               if (fp->fi_inode == ino) {
+                       get_nfs4_file(fp);
                        return fp;
+               }
        }
        return NULL;
 }
@@ -1240,7 +1244,7 @@ find_file(struct inode *ino)
 #define TEST_ACCESS(x) ((x > 0 || x < 4)?1:0)
 #define TEST_DENY(x) ((x >= 0 || x < 5)?1:0)
 
-void
+static void
 set_access(unsigned int *access, unsigned long bmap) {
        int i;
 
@@ -1251,7 +1255,7 @@ set_access(unsigned int *access, unsigned long bmap) {
        }
 }
 
-void
+static void
 set_deny(unsigned int *deny, unsigned long bmap) {
        int i;
 
@@ -1277,25 +1281,30 @@ test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {
  * Called to check deny when READ with all zero stateid or
  * WRITE with all zero or all one stateid
  */
-int
+static int
 nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
 {
        struct inode *ino = current_fh->fh_dentry->d_inode;
        struct nfs4_file *fp;
        struct nfs4_stateid *stp;
+       int ret;
 
        dprintk("NFSD: nfs4_share_conflict\n");
 
        fp = find_file(ino);
-       if (fp) {
+       if (!fp)
+               return nfs_ok;
+       ret = nfserr_share_denied;
        /* Search for conflicting share reservations */
-               list_for_each_entry(stp, &fp->fi_perfile, st_perfile) {
-                       if (test_bit(deny_type, &stp->st_deny_bmap) ||
-                           test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))
-                               return nfserr_share_denied;
-               }
+       list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
+               if (test_bit(deny_type, &stp->st_deny_bmap) ||
+                   test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))
+                       goto out;
        }
-       return nfs_ok;
+       ret = nfs_ok;
+out:
+       put_nfs4_file(fp);
+       return ret;
 }
 
 static inline void
@@ -1427,7 +1436,7 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
                return -EAGAIN;
 }
 
-struct lock_manager_operations nfsd_lease_mng_ops = {
+static struct lock_manager_operations nfsd_lease_mng_ops = {
        .fl_break = nfsd_break_deleg_cb,
        .fl_release_private = nfsd_release_deleg_cb,
        .fl_copy_lock = nfsd_copy_lock_deleg_cb,
@@ -1526,6 +1535,51 @@ out:
        return status;
 }
 
+static inline int
+nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
+{
+       if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
+               return nfserr_openmode;
+       else
+               return nfs_ok;
+}
+
+static struct nfs4_delegation *
+find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
+{
+       struct nfs4_delegation *dp;
+
+       list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) {
+               if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid)
+                       return dp;
+       }
+       return NULL;
+}
+
+static int
+nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
+               struct nfs4_delegation **dp)
+{
+       int flags;
+       int status = nfserr_bad_stateid;
+
+       *dp = find_delegation_file(fp, &open->op_delegate_stateid);
+       if (*dp == NULL)
+               goto out;
+       flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ?
+                                               RD_STATE : WR_STATE;
+       status = nfs4_check_delegmode(*dp, flags);
+       if (status)
+               *dp = NULL;
+out:
+       if (open->op_claim_type != NFS4_OPEN_CLAIM_DELEGATE_CUR)
+               return nfs_ok;
+       if (status)
+               return status;
+       open->op_stateowner->so_confirmed = 1;
+       return nfs_ok;
+}
+
 static int
 nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp)
 {
@@ -1533,7 +1587,7 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_state
        int status = nfserr_share_denied;
        struct nfs4_stateowner *sop = open->op_stateowner;
 
-       list_for_each_entry(local, &fp->fi_perfile, st_perfile) {
+       list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
                /* ignore lock owners */
                if (local->st_stateowner->so_is_open_owner == 0)
                        continue;
@@ -1549,25 +1603,37 @@ out:
        return status;
 }
 
+static inline struct nfs4_stateid *
+nfs4_alloc_stateid(void)
+{
+       return kmem_cache_alloc(stateid_slab, GFP_KERNEL);
+}
+
 static int
 nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
+               struct nfs4_delegation *dp,
                struct svc_fh *cur_fh, int flags)
 {
        struct nfs4_stateid *stp;
-       int status;
 
-       stp = kmalloc(sizeof(struct nfs4_stateid), GFP_KERNEL);
+       stp = nfs4_alloc_stateid();
        if (stp == NULL)
                return nfserr_resource;
 
-       status = nfsd_open(rqstp, cur_fh, S_IFREG, flags, &stp->st_vfs_file);
-       if (status) {
-               if (status == nfserr_dropit)
-                       status = nfserr_jukebox;
-               kfree(stp);
-               return status;
+       if (dp) {
+               get_file(dp->dl_vfs_file);
+               stp->st_vfs_file = dp->dl_vfs_file;
+       } else {
+               int status;
+               status = nfsd_open(rqstp, cur_fh, S_IFREG, flags,
+                               &stp->st_vfs_file);
+               if (status) {
+                       if (status == nfserr_dropit)
+                               status = nfserr_jukebox;
+                       kmem_cache_free(stateid_slab, stp);
+                       return status;
+               }
        }
-       vfsopen++;
        *stpp = stp;
        return 0;
 }
@@ -1628,6 +1694,7 @@ nfs4_set_claim_prev(struct nfsd4_open *open, int *status)
                        *status = nfserr_reclaim_bad;
                else {
                        open->op_stateowner->so_confirmed = 1;
+                       open->op_stateowner->so_client->cl_firststate = 1;
                        open->op_stateowner->so_seqid--;
                }
        }
@@ -1646,14 +1713,30 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
        int status, flag = 0;
 
        flag = NFS4_OPEN_DELEGATE_NONE;
-       if (open->op_claim_type != NFS4_OPEN_CLAIM_NULL
-            || !atomic_read(&cb->cb_set) || !sop->so_confirmed)
-               goto out;
-
-       if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
-               flag = NFS4_OPEN_DELEGATE_WRITE;
-       else
-               flag = NFS4_OPEN_DELEGATE_READ;
+       open->op_recall = 0;
+       switch (open->op_claim_type) {
+               case NFS4_OPEN_CLAIM_PREVIOUS:
+                       if (!atomic_read(&cb->cb_set))
+                               open->op_recall = 1;
+                       flag = open->op_delegate_type;
+                       if (flag == NFS4_OPEN_DELEGATE_NONE)
+                               goto out;
+                       break;
+               case NFS4_OPEN_CLAIM_NULL:
+                       /* Let's not give out any delegations till everyone's
+                        * had the chance to reclaim theirs.... */
+                       if (nfs4_in_grace())
+                               goto out;
+                       if (!atomic_read(&cb->cb_set) || !sop->so_confirmed)
+                               goto out;
+                       if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
+                               flag = NFS4_OPEN_DELEGATE_WRITE;
+                       else
+                               flag = NFS4_OPEN_DELEGATE_READ;
+                       break;
+               default:
+                       goto out;
+       }
 
        dp = alloc_init_deleg(sop->so_client, stp, fh, flag);
        if (dp == NULL) {
@@ -1687,6 +1770,10 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
                     dp->dl_stateid.si_fileid,
                     dp->dl_stateid.si_generation);
 out:
+       if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS
+                       && flag == NFS4_OPEN_DELEGATE_NONE
+                       && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
+               printk("NFSD: WARNING: refusing delegation reclaim\n");
        open->op_delegate_type = flag;
 }
 
@@ -1699,6 +1786,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
        struct nfs4_file *fp = NULL;
        struct inode *ino = current_fh->fh_dentry->d_inode;
        struct nfs4_stateid *stp = NULL;
+       struct nfs4_delegation *dp = NULL;
        int status;
 
        status = nfserr_inval;
@@ -1713,7 +1801,13 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
        if (fp) {
                if ((status = nfs4_check_open(fp, open, &stp)))
                        goto out;
+               status = nfs4_check_deleg(fp, open, &dp);
+               if (status)
+                       goto out;
        } else {
+               status = nfserr_bad_stateid;
+               if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
+                       goto out;
                status = nfserr_resource;
                fp = alloc_init_file(ino);
                if (fp == NULL)
@@ -1736,7 +1830,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
                        flags = MAY_WRITE;
                else
                        flags = MAY_READ;
-               if ((status = nfs4_new_open(rqstp, &stp, current_fh, flags)))
+               status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags);
+               if (status)
                        goto out;
                init_stateid(stp, fp, open);
                status = nfsd4_truncate(rqstp, current_fh, open);
@@ -1759,10 +1854,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
                    stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid,
                    stp->st_stateid.si_fileid, stp->st_stateid.si_generation);
 out:
-       /* take the opportunity to clean up unused state */
-       if (fp && list_empty(&fp->fi_perfile) && list_empty(&fp->fi_del_perfile))
-               release_file(fp);
-
+       if (fp)
+               put_nfs4_file(fp);
        /* CLAIM_PREVIOUS has different error returns */
        nfs4_set_claim_prev(open, &status);
        /*
@@ -1775,6 +1868,7 @@ out:
        return status;
 }
 
+static struct workqueue_struct *laundry_wq;
 static struct work_struct laundromat_work;
 static void laundromat_main(void *);
 static DECLARE_WORK(laundromat_work, laundromat_main, NULL);
@@ -1800,7 +1894,7 @@ nfsd4_renew(clientid_t *clid)
        }
        renew_client(clp);
        status = nfserr_cb_path_down;
-       if (!list_empty(&clp->cl_del_perclnt)
+       if (!list_empty(&clp->cl_delegations)
                        && !atomic_read(&clp->cl_callback.cb_set))
                goto out;
        status = nfs_ok;
@@ -1809,7 +1903,15 @@ out:
        return status;
 }
 
-time_t
+static void
+end_grace(void)
+{
+       dprintk("NFSD: end of grace period\n");
+       nfsd4_recdir_purge_old();
+       in_grace = 0;
+}
+
+static time_t
 nfs4_laundromat(void)
 {
        struct nfs4_client *clp;
@@ -1823,6 +1925,8 @@ nfs4_laundromat(void)
        nfs4_lock_state();
 
        dprintk("NFSD: laundromat service - starting\n");
+       if (in_grace)
+               end_grace();
        list_for_each_safe(pos, next, &client_lru) {
                clp = list_entry(pos, struct nfs4_client, cl_lru);
                if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
@@ -1833,6 +1937,7 @@ nfs4_laundromat(void)
                }
                dprintk("NFSD: purging unused client (clientid %08x)\n",
                        clp->cl_clientid.cl_id);
+               nfsd4_remove_clid_dir(clp);
                expire_client(clp);
        }
        INIT_LIST_HEAD(&reaplist);
@@ -1882,13 +1987,13 @@ laundromat_main(void *not_used)
 
        t = nfs4_laundromat();
        dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);
-       schedule_delayed_work(&laundromat_work, t*HZ);
+       queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
 }
 
 /* search ownerid_hashtbl[] and close_lru for stateid owner
  * (stateid->si_stateownerid)
  */
-struct nfs4_stateowner *
+static struct nfs4_stateowner *
 find_openstateowner_id(u32 st_id, int flags) {
        struct nfs4_stateowner *local = NULL;
 
@@ -1948,15 +2053,6 @@ out:
        return status;
 }
 
-static inline int
-nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
-{
-       if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
-               return nfserr_openmode;
-       else
-               return nfs_ok;
-}
-
 static inline int
 check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
 {
@@ -2071,7 +2167,7 @@ out:
 /* 
  * Checks for sequence id mutating operations. 
  */
-int
+static int
 nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid)
 {
        int status;
@@ -2230,6 +2326,8 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs
                         stp->st_stateid.si_stateownerid,
                         stp->st_stateid.si_fileid,
                         stp->st_stateid.si_generation);
+
+       nfsd4_create_clid_dir(sop->so_client);
 out:
        if (oc->oc_stateowner)
                nfs4_get_stateowner(oc->oc_stateowner);
@@ -2387,7 +2485,7 @@ static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];
 static struct list_head        lock_ownerstr_hashtbl[LOCK_HASH_SIZE];
 static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE];
 
-struct nfs4_stateid *
+static struct nfs4_stateid *
 find_stateid(stateid_t *stid, int flags)
 {
        struct nfs4_stateid *local = NULL;
@@ -2419,25 +2517,19 @@ find_stateid(stateid_t *stid, int flags)
 static struct nfs4_delegation *
 find_delegation_stateid(struct inode *ino, stateid_t *stid)
 {
-       struct nfs4_delegation *dp = NULL;
-       struct nfs4_file *fp = NULL;
-       u32 st_id;
+       struct nfs4_file *fp;
+       struct nfs4_delegation *dl;
 
        dprintk("NFSD:find_delegation_stateid stateid=(%08x/%08x/%08x/%08x)\n",
                     stid->si_boot, stid->si_stateownerid,
                     stid->si_fileid, stid->si_generation);
 
-       st_id = stid->si_stateownerid;
        fp = find_file(ino);
-       if (fp) {
-               list_for_each_entry(dp, &fp->fi_del_perfile, dl_del_perfile) {
-                       if(dp->dl_stateid.si_stateownerid == st_id) {
-                               dprintk("NFSD: find_delegation dp %p\n",dp);
-                               return dp;
-                       }
-               }
-       }
-       return NULL;
+       if (!fp)
+               return NULL;
+       dl = find_delegation_file(fp, stid);
+       put_nfs4_file(fp);
+       return dl;
 }
 
 /*
@@ -2457,7 +2549,7 @@ nfs4_transform_lock_offset(struct file_lock *lock)
                lock->fl_end = OFFSET_MAX;
 }
 
-int
+static int
 nfs4_verify_lock_stateowner(struct nfs4_stateowner *sop, unsigned int hashval)
 {
        struct nfs4_stateowner *local = NULL;
@@ -2497,22 +2589,6 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
                deny->ld_type = NFS4_WRITE_LT;
 }
 
-static struct nfs4_stateowner *
-find_lockstateowner(struct xdr_netobj *owner, clientid_t *clid)
-{
-       struct nfs4_stateowner *local = NULL;
-       int i;
-
-       for (i = 0; i < LOCK_HASH_SIZE; i++) {
-               list_for_each_entry(local, &lock_ownerid_hashtbl[i], so_idhash) {
-                       if (!cmp_owner_str(local, owner, clid))
-                               continue;
-                       return local;
-               }
-       }
-       return NULL;
-}
-
 static struct nfs4_stateowner *
 find_lockstateowner_str(struct inode *inode, clientid_t *clid,
                struct xdr_netobj *owner)
@@ -2548,13 +2624,13 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
        INIT_LIST_HEAD(&sop->so_idhash);
        INIT_LIST_HEAD(&sop->so_strhash);
        INIT_LIST_HEAD(&sop->so_perclient);
-       INIT_LIST_HEAD(&sop->so_perfilestate);
-       INIT_LIST_HEAD(&sop->so_perlockowner);
+       INIT_LIST_HEAD(&sop->so_stateids);
+       INIT_LIST_HEAD(&sop->so_perstateid);
        INIT_LIST_HEAD(&sop->so_close_lru); /* not used */
        sop->so_time = 0;
        list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]);
        list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]);
-       list_add(&sop->so_perlockowner, &open_stp->st_perlockowner);
+       list_add(&sop->so_perstateid, &open_stp->st_lockowners);
        sop->so_is_open_owner = 0;
        sop->so_id = current_ownerid++;
        sop->so_client = clp;
@@ -2567,24 +2643,24 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
        return sop;
 }
 
-struct nfs4_stateid *
+static struct nfs4_stateid *
 alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struct nfs4_stateid *open_stp)
 {
        struct nfs4_stateid *stp;
        unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);
 
-       if ((stp = kmalloc(sizeof(struct nfs4_stateid), 
-                                       GFP_KERNEL)) == NULL)
+       stp = nfs4_alloc_stateid();
+       if (stp == NULL)
                goto out;
        INIT_LIST_HEAD(&stp->st_hash);
        INIT_LIST_HEAD(&stp->st_perfile);
-       INIT_LIST_HEAD(&stp->st_perfilestate);
-       INIT_LIST_HEAD(&stp->st_perlockowner); /* not used */
+       INIT_LIST_HEAD(&stp->st_perstateowner);
+       INIT_LIST_HEAD(&stp->st_lockowners); /* not used */
        list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]);
-       list_add(&stp->st_perfile, &fp->fi_perfile);
-       list_add_perfile++;
-       list_add(&stp->st_perfilestate, &sop->so_perfilestate);
+       list_add(&stp->st_perfile, &fp->fi_stateids);
+       list_add(&stp->st_perstateowner, &sop->so_stateids);
        stp->st_stateowner = sop;
+       get_nfs4_file(fp);
        stp->st_file = fp;
        stp->st_stateid.si_boot = boot_time;
        stp->st_stateid.si_stateownerid = sop->so_id;
@@ -2598,7 +2674,7 @@ out:
        return stp;
 }
 
-int
+static int
 check_lock_length(u64 offset, u64 length)
 {
        return ((length == 0)  || ((length != ~(u64)0) &&
@@ -2611,7 +2687,7 @@ check_lock_length(u64 offset, u64 length)
 int
 nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock)
 {
-       struct nfs4_stateowner *lock_sop = NULL, *open_sop = NULL;
+       struct nfs4_stateowner *open_sop = NULL;
        struct nfs4_stateid *lock_stp;
        struct file *filp;
        struct file_lock file_lock;
@@ -2670,16 +2746,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
                strhashval = lock_ownerstr_hashval(fp->fi_inode, 
                                open_sop->so_client->cl_clientid.cl_id, 
                                &lock->v.new.owner);
-               /* 
-                * If we already have this lock owner, the client is in 
-                * error (or our bookeeping is wrong!) 
-                * for asking for a 'new lock'.
-                */
-               status = nfserr_bad_stateid;
-               lock_sop = find_lockstateowner(&lock->v.new.owner,
-                                               &lock->v.new.clientid);
-               if (lock_sop)
-                       goto out;
+               /* XXX: Do we need to check for duplicate stateowners on
+                * the same file, or should they just be allowed (and
+                * create new stateids)? */
                status = nfserr_resource;
                if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock)))
                        goto out;
@@ -2970,8 +3039,11 @@ int
 nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner)
 {
        clientid_t *clid = &rlockowner->rl_clientid;
-       struct nfs4_stateowner *local = NULL;
+       struct nfs4_stateowner *sop;
+       struct nfs4_stateid *stp;
        struct xdr_netobj *owner = &rlockowner->rl_owner;
+       struct list_head matches;
+       int i;
        int status;
 
        dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
@@ -2987,22 +3059,32 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *
 
        nfs4_lock_state();
 
-       status = nfs_ok;
-       local = find_lockstateowner(owner, clid);
-       if (local) {
-               struct nfs4_stateid *stp;
-
-               /* check for any locks held by any stateid
-                * associated with the (lock) stateowner */
-               status = nfserr_locks_held;
-               list_for_each_entry(stp, &local->so_perfilestate,
-                               st_perfilestate) {
-                       if (check_for_locks(stp->st_vfs_file, local))
-                               goto out;
+       status = nfserr_locks_held;
+       /* XXX: we're doing a linear search through all the lockowners.
+        * Yipes!  For now we'll just hope clients aren't really using
+        * release_lockowner much, but eventually we have to fix these
+        * data structures. */
+       INIT_LIST_HEAD(&matches);
+       for (i = 0; i < LOCK_HASH_SIZE; i++) {
+               list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) {
+                       if (!cmp_owner_str(sop, owner, clid))
+                               continue;
+                       list_for_each_entry(stp, &sop->so_stateids,
+                                       st_perstateowner) {
+                               if (check_for_locks(stp->st_vfs_file, sop))
+                                       goto out;
+                               /* Note: so_perclient unused for lockowners,
+                                * so it's OK to fool with here. */
+                               list_add(&sop->so_perclient, &matches);
+                       }
                }
-               /* no locks held by (lock) stateowner */
-               status = nfs_ok;
-               release_stateowner(local);
+       }
+       /* Clients probably won't expect us to return with some (but not all)
+        * of the lockowner state released; so don't release any until all
+        * have been checked. */
+       status = nfs_ok;
+       list_for_each_entry(sop, &matches, so_perclient) {
+               release_stateowner(sop);
        }
 out:
        nfs4_unlock_state();
@@ -3010,39 +3092,38 @@ out:
 }
 
 static inline struct nfs4_client_reclaim *
-alloc_reclaim(int namelen)
+alloc_reclaim(void)
 {
-       struct nfs4_client_reclaim *crp = NULL;
+       return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
+}
 
-       crp = kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
-       if (!crp)
-               return NULL;
-       crp->cr_name.data = kmalloc(namelen, GFP_KERNEL);
-       if (!crp->cr_name.data) {
-               kfree(crp);
-               return NULL;
-       }
-       return crp;
+int
+nfs4_has_reclaimed_state(const char *name)
+{
+       unsigned int strhashval = clientstr_hashval(name);
+       struct nfs4_client *clp;
+
+       clp = find_confirmed_client_by_str(name, strhashval);
+       return clp ? 1 : 0;
 }
 
 /*
  * failure => all reset bets are off, nfserr_no_grace...
  */
-static int
-nfs4_client_to_reclaim(char *name, int namlen)
+int
+nfs4_client_to_reclaim(const char *name)
 {
        unsigned int strhashval;
        struct nfs4_client_reclaim *crp = NULL;
 
-       dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", namlen, name);
-       crp = alloc_reclaim(namlen);
+       dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
+       crp = alloc_reclaim();
        if (!crp)
                return 0;
-       strhashval = clientstr_hashval(name, namlen);
+       strhashval = clientstr_hashval(name);
        INIT_LIST_HEAD(&crp->cr_strhash);
        list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]);
-       memcpy(crp->cr_name.data, name, namlen);
-       crp->cr_name.len = namlen;
+       memcpy(crp->cr_recdir, name, HEXDIR_LEN);
        reclaim_str_hashtbl_size++;
        return 1;
 }
@@ -3053,13 +3134,11 @@ nfs4_release_reclaim(void)
        struct nfs4_client_reclaim *crp = NULL;
        int i;
 
-       BUG_ON(!nfs4_reclaim_init);
        for (i = 0; i < CLIENT_HASH_SIZE; i++) {
                while (!list_empty(&reclaim_str_hashtbl[i])) {
                        crp = list_entry(reclaim_str_hashtbl[i].next,
                                        struct nfs4_client_reclaim, cr_strhash);
                        list_del(&crp->cr_strhash);
-                       kfree(crp->cr_name.data);
                        kfree(crp);
                        reclaim_str_hashtbl_size--;
                }
@@ -3069,7 +3148,7 @@ nfs4_release_reclaim(void)
 
 /*
  * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
-struct nfs4_client_reclaim *
+static struct nfs4_client_reclaim *
 nfs4_find_reclaim_client(clientid_t *clid)
 {
        unsigned int strhashval;
@@ -3082,13 +3161,14 @@ nfs4_find_reclaim_client(clientid_t *clid)
        if (clp == NULL)
                return NULL;
 
-       dprintk("NFSD: nfs4_find_reclaim_client for %.*s\n",
-                           clp->cl_name.len, clp->cl_name.data);
+       dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n",
+                           clp->cl_name.len, clp->cl_name.data,
+                           clp->cl_recdir);
 
        /* find clp->cl_name in reclaim_str_hashtbl */
-       strhashval = clientstr_hashval(clp->cl_name.data, clp->cl_name.len);
+       strhashval = clientstr_hashval(clp->cl_recdir);
        list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) {
-               if (cmp_name(&crp->cr_name, &clp->cl_name)) {
+               if (same_name(crp->cr_recdir, clp->cl_recdir)) {
                        return crp;
                }
        }
@@ -3101,30 +3181,16 @@ nfs4_find_reclaim_client(clientid_t *clid)
 int
 nfs4_check_open_reclaim(clientid_t *clid)
 {
-       struct nfs4_client_reclaim *crp;
-
-       if ((crp = nfs4_find_reclaim_client(clid)) == NULL)
-               return nfserr_reclaim_bad;
-       return nfs_ok;
+       return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad;
 }
 
+/* initialization to perform at module load time: */
 
-/* 
- * Start and stop routines
- */
-
-static void
-__nfs4_state_init(void)
+void
+nfs4_state_init(void)
 {
        int i;
-       time_t grace_time;
 
-       if (!nfs4_reclaim_init) {
-               for (i = 0; i < CLIENT_HASH_SIZE; i++)
-                       INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
-               reclaim_str_hashtbl_size = 0;
-               nfs4_reclaim_init = 1;
-       }
        for (i = 0; i < CLIENT_HASH_SIZE; i++) {
                INIT_LIST_HEAD(&conf_id_hashtbl[i]);
                INIT_LIST_HEAD(&conf_str_hashtbl[i]);
@@ -3146,26 +3212,46 @@ __nfs4_state_init(void)
                INIT_LIST_HEAD(&lock_ownerid_hashtbl[i]);
                INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]);
        }
-       memset(&zerostateid, 0, sizeof(stateid_t));
        memset(&onestateid, ~0, sizeof(stateid_t));
-
        INIT_LIST_HEAD(&close_lru);
        INIT_LIST_HEAD(&client_lru);
        INIT_LIST_HEAD(&del_recall_lru);
-       spin_lock_init(&recall_lock);
+       for (i = 0; i < CLIENT_HASH_SIZE; i++)
+               INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
+       reclaim_str_hashtbl_size = 0;
+}
+
+static void
+nfsd4_load_reboot_recovery_data(void)
+{
+       int status;
+
+       nfs4_lock_state();
+       nfsd4_init_recdir(user_recovery_dirname);
+       status = nfsd4_recdir_load();
+       nfs4_unlock_state();
+       if (status)
+               printk("NFSD: Failure reading reboot recovery data\n");
+}
+
+/* initialization to perform when the nfsd service is started: */
+
+static void
+__nfs4_state_start(void)
+{
+       time_t grace_time;
+
        boot_time = get_seconds();
-       grace_time = max(old_lease_time, lease_time);
-       if (reclaim_str_hashtbl_size == 0)
-               grace_time = 0;
-       if (grace_time)
-               printk("NFSD: starting %ld-second grace period\n", grace_time);
-       grace_end = boot_time + grace_time;
-       INIT_WORK(&laundromat_work,laundromat_main, NULL);
-       schedule_delayed_work(&laundromat_work, NFSD_LEASE_TIME*HZ);
+       grace_time = max(user_lease_time, lease_time);
+       lease_time = user_lease_time;
+       in_grace = 1;
+       printk("NFSD: starting %ld-second grace period\n", grace_time);
+       laundry_wq = create_singlethread_workqueue("nfsd4");
+       queue_delayed_work(laundry_wq, &laundromat_work, grace_time*HZ);
 }
 
 int
-nfs4_state_init(void)
+nfs4_state_start(void)
 {
        int status;
 
@@ -3174,7 +3260,8 @@ nfs4_state_init(void)
        status = nfsd4_init_slabs();
        if (status)
                return status;
-       __nfs4_state_init();
+       nfsd4_load_reboot_recovery_data();
+       __nfs4_state_start();
        nfs4_init = 1;
        return 0;
 }
@@ -3182,14 +3269,7 @@ nfs4_state_init(void)
 int
 nfs4_in_grace(void)
 {
-       return get_seconds() < grace_end;
-}
-
-void
-set_no_grace(void)
-{
-       printk("NFSD: ERROR in reboot recovery.  State reclaims will fail.\n");
-       grace_end = get_seconds();
+       return in_grace;
 }
 
 time_t
@@ -3236,21 +3316,11 @@ __nfs4_state_shutdown(void)
                unhash_delegation(dp);
        }
 
-       release_all_files();
        cancel_delayed_work(&laundromat_work);
-       flush_scheduled_work();
+       flush_workqueue(laundry_wq);
+       destroy_workqueue(laundry_wq);
+       nfsd4_shutdown_recdir();
        nfs4_init = 0;
-       dprintk("NFSD: list_add_perfile %d list_del_perfile %d\n",
-                       list_add_perfile, list_del_perfile);
-       dprintk("NFSD: add_perclient %d del_perclient %d\n",
-                       add_perclient, del_perclient);
-       dprintk("NFSD: alloc_file %d free_file %d\n",
-                       alloc_file, free_file);
-       dprintk("NFSD: vfsopen %d vfsclose %d\n",
-                       vfsopen, vfsclose);
-       dprintk("NFSD: alloc_delegation %d free_delegation %d\n",
-                       alloc_delegation, free_delegation);
-
 }
 
 void
@@ -3263,56 +3333,48 @@ nfs4_state_shutdown(void)
        nfs4_unlock_state();
 }
 
+static void
+nfs4_set_recdir(char *recdir)
+{
+       nfs4_lock_state();
+       strcpy(user_recovery_dirname, recdir);
+       nfs4_unlock_state();
+}
+
+/*
+ * Change the NFSv4 recovery directory to recdir.
+ */
+int
+nfs4_reset_recoverydir(char *recdir)
+{
+       int status;
+       struct nameidata nd;
+
+       status = path_lookup(recdir, LOOKUP_FOLLOW, &nd);
+       if (status)
+               return status;
+       status = -ENOTDIR;
+       if (S_ISDIR(nd.dentry->d_inode->i_mode)) {
+               nfs4_set_recdir(recdir);
+               status = 0;
+       }
+       path_release(&nd);
+       return status;
+}
+
 /*
  * Called when leasetime is changed.
  *
- * if nfsd is not started, simply set the global lease.
- *
- * if nfsd(s) are running, lease change requires nfsv4 state to be reset.
- * e.g: boot_time is reset, existing nfs4_client structs are
- * used to fill reclaim_str_hashtbl, then all state (except for the
- * reclaim_str_hashtbl) is re-initialized.
- *
- * if the old lease time is greater than the new lease time, the grace
- * period needs to be set to the old lease time to allow clients to reclaim
- * their state. XXX - we may want to set the grace period == lease time
- * after an initial grace period == old lease time
- *
- * if an error occurs in this process, the new lease is set, but the server
- * will not honor OPEN or LOCK reclaims, and will return nfserr_no_grace
- * which means OPEN/LOCK/READ/WRITE will fail during grace period.
- *
- * clients will attempt to reset all state with SETCLIENTID/CONFIRM, and
- * OPEN and LOCK reclaims.
+ * The only way the protocol gives us to handle on-the-fly lease changes is to
+ * simulate a reboot.  Instead of doing that, we just wait till the next time
+ * we start to register any changes in lease time.  If the administrator
+ * really wants to change the lease time *now*, they can go ahead and bring
+ * nfsd down and then back up again after changing the lease time.
  */
 void
 nfs4_reset_lease(time_t leasetime)
 {
-       struct nfs4_client *clp;
-       int i;
-
-       printk("NFSD: New leasetime %ld\n",leasetime);
-       if (!nfs4_init)
-               return;
-       nfs4_lock_state();
-       old_lease_time = lease_time;
-       lease_time = leasetime;
-
-       nfs4_release_reclaim();
-
-       /* populate reclaim_str_hashtbl with current confirmed nfs4_clientid */
-       for (i = 0; i < CLIENT_HASH_SIZE; i++) {
-               list_for_each_entry(clp, &conf_id_hashtbl[i], cl_idhash) {
-                       if (!nfs4_client_to_reclaim(clp->cl_name.data,
-                                               clp->cl_name.len)) {
-                               nfs4_release_reclaim();
-                               goto init_state;
-                       }
-               }
-       }
-init_state:
-       __nfs4_state_shutdown();
-       __nfs4_state_init();
-       nfs4_unlock_state();
+       lock_kernel();
+       user_lease_time = leasetime;
+       unlock_kernel();
 }
-
index 36a058a112d57e261e7eded168b01da0f6d7274c..91fb171d2aceee025712bc4783f2a04e2773255c 100644 (file)
@@ -136,7 +136,7 @@ xdr_error:                                  \
        }                                       \
 } while (0)
 
-u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
+static u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
 {
        /* We want more bytes than seem to be available.
         * Maybe we need a new page, maybe we have just run out
@@ -190,7 +190,7 @@ defer_free(struct nfsd4_compoundargs *argp,
        return 0;
 }
 
-char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
+static char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
 {
        void *new = NULL;
        if (p == argp->tmp) {
@@ -1366,7 +1366,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
        if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) {
                if ((buflen -= 4) < 0)
                        goto out_resource;
-               WRITE32( NFS4_FH_NOEXPIRE_WITH_OPEN | NFS4_FH_VOL_RENAME );
+               if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
+                       WRITE32(NFS4_FH_VOLATILE_ANY);
+               else
+                       WRITE32(NFS4_FH_VOLATILE_ANY|NFS4_FH_VOL_RENAME);
        }
        if (bmval0 & FATTR4_WORD0_CHANGE) {
                /*
@@ -1969,7 +1972,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open
        case NFS4_OPEN_DELEGATE_READ:
                RESERVE_SPACE(20 + sizeof(stateid_t));
                WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t));
-               WRITE32(0);
+               WRITE32(open->op_recall);
 
                /*
                 * TODO: ACE's in delegations
index 161afdcb8f7d911b81035e3a76f20a5aad05635e..841c562991e8fdb051b12d18a3a8c88c1f528e16 100644 (file)
@@ -51,6 +51,7 @@ enum {
        NFSD_Fh,
        NFSD_Threads,
        NFSD_Leasetime,
+       NFSD_RecoveryDir,
 };
 
 /*
@@ -66,6 +67,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size);
 static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
 static ssize_t write_threads(struct file *file, char *buf, size_t size);
 static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
+static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
 
 static ssize_t (*write_op[])(struct file *, char *, size_t) = {
        [NFSD_Svc] = write_svc,
@@ -78,6 +80,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
        [NFSD_Fh] = write_filehandle,
        [NFSD_Threads] = write_threads,
        [NFSD_Leasetime] = write_leasetime,
+       [NFSD_RecoveryDir] = write_recoverydir,
 };
 
 static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
@@ -349,6 +352,25 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
        return strlen(buf);
 }
 
+static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
+{
+       char *mesg = buf;
+       char *recdir;
+       int len, status;
+
+       if (size > PATH_MAX || buf[size-1] != '\n')
+               return -EINVAL;
+       buf[size-1] = 0;
+
+       recdir = mesg;
+       len = qword_get(&mesg, recdir, size);
+       if (len <= 0)
+               return -EINVAL;
+
+       status = nfs4_reset_recoverydir(recdir);
+       return strlen(buf);
+}
+
 /*----------------------------------------------------------------------------*/
 /*
  *     populating the filesystem.
@@ -369,6 +391,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
                [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
 #ifdef CONFIG_NFSD_V4
                [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
+               [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
 #endif
                /* last one */ {""}
        };
@@ -397,9 +420,8 @@ static int __init init_nfsd(void)
        nfsd_cache_init();      /* RPC reply cache */
        nfsd_export_init();     /* Exports table */
        nfsd_lockd_init();      /* lockd->nfsd callbacks */
-#ifdef CONFIG_NFSD_V4
+       nfs4_state_init();      /* NFSv4 locking state */
        nfsd_idmap_init();      /* Name to ID mapping */
-#endif /* CONFIG_NFSD_V4 */
        if (proc_mkdir("fs/nfs", NULL)) {
                struct proc_dir_entry *entry;
                entry = create_proc_entry("fs/nfs/exports", 0, NULL);
@@ -426,9 +448,7 @@ static void __exit exit_nfsd(void)
        remove_proc_entry("fs/nfs", NULL);
        nfsd_stat_shutdown();
        nfsd_lockd_shutdown();
-#ifdef CONFIG_NFSD_V4
        nfsd_idmap_shutdown();
-#endif /* CONFIG_NFSD_V4 */
        unregister_filesystem(&nfsd_fs_type);
 }
 
index 904df604e86b62933b71f14e57a0920cd9373d91..07b9a065e9daa75ebb35fcff48e5f441376cc6f8 100644 (file)
@@ -95,7 +95,7 @@ nfsd_svc(unsigned short port, int nrservs)
        error = nfsd_racache_init(2*nrservs);
        if (error<0)
                goto out;
-       error = nfs4_state_init();
+       error = nfs4_state_start();
        if (error<0)
                goto out;
        if (!nfsd_serv) {
index de340ffd33c3e1dcbc4c4156536021cb5274e169..be24ead89d94935298af52020262978136887d1f 100644 (file)
 #include <linux/nfsd/nfsfh.h>
 #include <linux/quotaops.h>
 #include <linux/dnotify.h>
-#include <linux/xattr_acl.h>
 #include <linux/posix_acl.h>
-#ifdef CONFIG_NFSD_V4
 #include <linux/posix_acl_xattr.h>
+#ifdef CONFIG_NFSD_V4
 #include <linux/xattr.h>
 #include <linux/nfs4.h>
 #include <linux/nfs4_acl.h>
@@ -1872,10 +1871,10 @@ nfsd_get_posix_acl(struct svc_fh *fhp, int type)
                return ERR_PTR(-EOPNOTSUPP);
        switch(type) {
                case ACL_TYPE_ACCESS:
-                       name = XATTR_NAME_ACL_ACCESS;
+                       name = POSIX_ACL_XATTR_ACCESS;
                        break;
                case ACL_TYPE_DEFAULT:
-                       name = XATTR_NAME_ACL_DEFAULT;
+                       name = POSIX_ACL_XATTR_DEFAULT;
                        break;
                default:
                        return ERR_PTR(-EOPNOTSUPP);
@@ -1919,17 +1918,17 @@ nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
                return -EOPNOTSUPP;
        switch(type) {
                case ACL_TYPE_ACCESS:
-                       name = XATTR_NAME_ACL_ACCESS;
+                       name = POSIX_ACL_XATTR_ACCESS;
                        break;
                case ACL_TYPE_DEFAULT:
-                       name = XATTR_NAME_ACL_DEFAULT;
+                       name = POSIX_ACL_XATTR_DEFAULT;
                        break;
                default:
                        return -EOPNOTSUPP;
        }
 
        if (acl && acl->a_count) {
-               size = xattr_acl_size(acl->a_count);
+               size = posix_acl_xattr_size(acl->a_count);
                value = kmalloc(size, GFP_KERNEL);
                if (!value)
                        return -ENOMEM;
index 8ec63f735918d691d471bfc55bdb03c235b939b9..3f4a4286fdc4d7361c3f46d57b435863a0250494 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -808,7 +808,9 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
 
        /* NB: we're sure to have correct a_ops only after f_op->open */
        if (f->f_flags & O_DIRECT) {
-               if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO) {
+               if (!f->f_mapping->a_ops ||
+                   ((!f->f_mapping->a_ops->direct_IO) &&
+                   (!f->f_mapping->a_ops->get_xip_page))) {
                        fput(f);
                        f = ERR_PTR(-EINVAL);
                }
index 4c83c17969e12505248dc0767985af06b568062e..66d5cc26fafbf65bfcdf4b18a0ee49c5e48ebbc7 100644 (file)
@@ -17,4 +17,3 @@ obj-$(CONFIG_SUN_PARTITION) += sun.o
 obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o
 obj-$(CONFIG_IBM_PARTITION) += ibm.o
 obj-$(CONFIG_EFI_PARTITION) += efi.o
-obj-$(CONFIG_NEC98_PARTITION) += nec98.o msdos.o
index 2cab98a9a621ce12a2f402688acb976b6a5ef9e8..77e178f13162abef0305852554dbfa73d2a99ff0 100644 (file)
@@ -79,9 +79,6 @@ static int (*check_part[])(struct parsed_partitions *, struct block_device *) =
 #ifdef CONFIG_LDM_PARTITION
        ldm_partition,          /* this must come before msdos */
 #endif
-#ifdef CONFIG_NEC98_PARTITION
-       nec98_partition,        /* must be come before `msdos_partition' */
-#endif
 #ifdef CONFIG_MSDOS_PARTITION
        msdos_partition,
 #endif
index 43adcc68e47197c8bcc86dca3ae7327e2c5c43e9..17ae8ecd9e8b60afae6a8538d850ed7032477a4f 100644 (file)
@@ -30,7 +30,3 @@ put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size)
 
 extern int warn_no_part;
 
-extern void parse_bsd(struct parsed_partitions *state,
-                       struct block_device *bdev, u32 offset, u32 size,
-                       int origin, char *flavour, int max_partitions);
-
index 584a27b2bbd5a5cfc4317356a28efb3b42ef427f..9935d254186ef10276781815193995895b3dab8b 100644 (file)
@@ -202,12 +202,12 @@ parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev,
 #endif
 }
 
-#if defined(CONFIG_BSD_DISKLABEL) || defined(CONFIG_NEC98_PARTITION)
+#if defined(CONFIG_BSD_DISKLABEL)
 /* 
  * Create devices for BSD partitions listed in a disklabel, under a
  * dos-like partition. See parse_extended() for more information.
  */
-void
+static void
 parse_bsd(struct parsed_partitions *state, struct block_device *bdev,
                u32 offset, u32 size, int origin, char *flavour,
                int max_partitions)
index 738b9b602932b9b61eb0ced4841a4cbc1f88b312..7431d7ba2d097981e1e87a191dc0ab81a2684537 100644 (file)
@@ -11,4 +11,5 @@ proc-y       += inode.o root.o base.o generic.o array.o \
                kmsg.o proc_tty.o proc_misc.o
 
 proc-$(CONFIG_PROC_KCORE)      += kcore.o
+proc-$(CONFIG_PROC_VMCORE)     += vmcore.o
 proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o
index 94b570ad037d7e76cd00ebbb5999d42f2df8a0b4..a3453555a94e76ca4e84952a993049faa257f2b4 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/jiffies.h>
 #include <linux/sysrq.h>
 #include <linux/vmalloc.h>
+#include <linux/crash_dump.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
@@ -618,6 +619,11 @@ void __init proc_misc_init(void)
                                (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE;
        }
 #endif
+#ifdef CONFIG_PROC_VMCORE
+       proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL);
+       if (proc_vmcore)
+               proc_vmcore->proc_fops = &proc_vmcore_operations;
+#endif
 #ifdef CONFIG_MAGIC_SYSRQ
        entry = create_proc_entry("sysrq-trigger", S_IWUSR, NULL);
        if (entry)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
new file mode 100644 (file)
index 0000000..3b2e7b6
--- /dev/null
@@ -0,0 +1,669 @@
+/*
+ *     fs/proc/vmcore.c Interface for accessing the crash
+ *                              dump from the system's previous life.
+ *     Heavily borrowed from fs/proc/kcore.c
+ *     Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
+ *     Copyright (C) IBM Corporation, 2004. All rights reserved
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/elf.h>
+#include <linux/elfcore.h>
+#include <linux/proc_fs.h>
+#include <linux/highmem.h>
+#include <linux/bootmem.h>
+#include <linux/init.h>
+#include <linux/crash_dump.h>
+#include <linux/list.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* List representing chunks of contiguous memory areas and their offsets in
+ * vmcore file.
+ */
+static LIST_HEAD(vmcore_list);
+
+/* Stores the pointer to the buffer containing kernel elf core headers. */
+static char *elfcorebuf;
+static size_t elfcorebuf_sz;
+
+/* Total size of vmcore file. */
+static u64 vmcore_size;
+
+struct proc_dir_entry *proc_vmcore = NULL;
+
+/* Reads a page from the oldmem device from given offset. */
+static ssize_t read_from_oldmem(char *buf, size_t count,
+                            loff_t *ppos, int userbuf)
+{
+       unsigned long pfn, offset;
+       size_t nr_bytes;
+       ssize_t read = 0, tmp;
+
+       if (!count)
+               return 0;
+
+       offset = (unsigned long)(*ppos % PAGE_SIZE);
+       pfn = (unsigned long)(*ppos / PAGE_SIZE);
+       if (pfn > saved_max_pfn)
+               return -EINVAL;
+
+       do {
+               if (count > (PAGE_SIZE - offset))
+                       nr_bytes = PAGE_SIZE - offset;
+               else
+                       nr_bytes = count;
+
+               tmp = copy_oldmem_page(pfn, buf, nr_bytes, offset, userbuf);
+               if (tmp < 0)
+                       return tmp;
+               *ppos += nr_bytes;
+               count -= nr_bytes;
+               buf += nr_bytes;
+               read += nr_bytes;
+               ++pfn;
+               offset = 0;
+       } while (count);
+
+       return read;
+}
+
+/* Maps vmcore file offset to respective physical address in memroy. */
+static u64 map_offset_to_paddr(loff_t offset, struct list_head *vc_list,
+                                       struct vmcore **m_ptr)
+{
+       struct vmcore *m;
+       u64 paddr;
+
+       list_for_each_entry(m, vc_list, list) {
+               u64 start, end;
+               start = m->offset;
+               end = m->offset + m->size - 1;
+               if (offset >= start && offset <= end) {
+                       paddr = m->paddr + offset - start;
+                       *m_ptr = m;
+                       return paddr;
+               }
+       }
+       *m_ptr = NULL;
+       return 0;
+}
+
+/* Read from the ELF header and then the crash dump. On error, negative value is
+ * returned otherwise number of bytes read are returned.
+ */
+static ssize_t read_vmcore(struct file *file, char __user *buffer,
+                               size_t buflen, loff_t *fpos)
+{
+       ssize_t acc = 0, tmp;
+       size_t tsz, nr_bytes;
+       u64 start;
+       struct vmcore *curr_m = NULL;
+
+       if (buflen == 0 || *fpos >= vmcore_size)
+               return 0;
+
+       /* trim buflen to not go beyond EOF */
+       if (buflen > vmcore_size - *fpos)
+               buflen = vmcore_size - *fpos;
+
+       /* Read ELF core header */
+       if (*fpos < elfcorebuf_sz) {
+               tsz = elfcorebuf_sz - *fpos;
+               if (buflen < tsz)
+                       tsz = buflen;
+               if (copy_to_user(buffer, elfcorebuf + *fpos, tsz))
+                       return -EFAULT;
+               buflen -= tsz;
+               *fpos += tsz;
+               buffer += tsz;
+               acc += tsz;
+
+               /* leave now if filled buffer already */
+               if (buflen == 0)
+                       return acc;
+       }
+
+       start = map_offset_to_paddr(*fpos, &vmcore_list, &curr_m);
+       if (!curr_m)
+               return -EINVAL;
+       if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
+               tsz = buflen;
+
+       /* Calculate left bytes in current memory segment. */
+       nr_bytes = (curr_m->size - (start - curr_m->paddr));
+       if (tsz > nr_bytes)
+               tsz = nr_bytes;
+
+       while (buflen) {
+               tmp = read_from_oldmem(buffer, tsz, &start, 1);
+               if (tmp < 0)
+                       return tmp;
+               buflen -= tsz;
+               *fpos += tsz;
+               buffer += tsz;
+               acc += tsz;
+               if (start >= (curr_m->paddr + curr_m->size)) {
+                       if (curr_m->list.next == &vmcore_list)
+                               return acc;     /*EOF*/
+                       curr_m = list_entry(curr_m->list.next,
+                                               struct vmcore, list);
+                       start = curr_m->paddr;
+               }
+               if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
+                       tsz = buflen;
+               /* Calculate left bytes in current memory segment. */
+               nr_bytes = (curr_m->size - (start - curr_m->paddr));
+               if (tsz > nr_bytes)
+                       tsz = nr_bytes;
+       }
+       return acc;
+}
+
+static int open_vmcore(struct inode *inode, struct file *filp)
+{
+       return 0;
+}
+
+struct file_operations proc_vmcore_operations = {
+       .read           = read_vmcore,
+       .open           = open_vmcore,
+};
+
+static struct vmcore* __init get_new_element(void)
+{
+       struct vmcore *p;
+
+       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       if (p)
+               memset(p, 0, sizeof(*p));
+       return p;
+}
+
+static u64 __init get_vmcore_size_elf64(char *elfptr)
+{
+       int i;
+       u64 size;
+       Elf64_Ehdr *ehdr_ptr;
+       Elf64_Phdr *phdr_ptr;
+
+       ehdr_ptr = (Elf64_Ehdr *)elfptr;
+       phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
+       size = sizeof(Elf64_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr));
+       for (i = 0; i < ehdr_ptr->e_phnum; i++) {
+               size += phdr_ptr->p_memsz;
+               phdr_ptr++;
+       }
+       return size;
+}
+
+static u64 __init get_vmcore_size_elf32(char *elfptr)
+{
+       int i;
+       u64 size;
+       Elf32_Ehdr *ehdr_ptr;
+       Elf32_Phdr *phdr_ptr;
+
+       ehdr_ptr = (Elf32_Ehdr *)elfptr;
+       phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
+       size = sizeof(Elf32_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr));
+       for (i = 0; i < ehdr_ptr->e_phnum; i++) {
+               size += phdr_ptr->p_memsz;
+               phdr_ptr++;
+       }
+       return size;
+}
+
+/* Merges all the PT_NOTE headers into one. */
+static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
+                                               struct list_head *vc_list)
+{
+       int i, nr_ptnote=0, rc=0;
+       char *tmp;
+       Elf64_Ehdr *ehdr_ptr;
+       Elf64_Phdr phdr, *phdr_ptr;
+       Elf64_Nhdr *nhdr_ptr;
+       u64 phdr_sz = 0, note_off;
+
+       ehdr_ptr = (Elf64_Ehdr *)elfptr;
+       phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
+       for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+               int j;
+               void *notes_section;
+               struct vmcore *new;
+               u64 offset, max_sz, sz, real_sz = 0;
+               if (phdr_ptr->p_type != PT_NOTE)
+                       continue;
+               nr_ptnote++;
+               max_sz = phdr_ptr->p_memsz;
+               offset = phdr_ptr->p_offset;
+               notes_section = kmalloc(max_sz, GFP_KERNEL);
+               if (!notes_section)
+                       return -ENOMEM;
+               rc = read_from_oldmem(notes_section, max_sz, &offset, 0);
+               if (rc < 0) {
+                       kfree(notes_section);
+                       return rc;
+               }
+               nhdr_ptr = notes_section;
+               for (j = 0; j < max_sz; j += sz) {
+                       if (nhdr_ptr->n_namesz == 0)
+                               break;
+                       sz = sizeof(Elf64_Nhdr) +
+                               ((nhdr_ptr->n_namesz + 3) & ~3) +
+                               ((nhdr_ptr->n_descsz + 3) & ~3);
+                       real_sz += sz;
+                       nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz);
+               }
+
+               /* Add this contiguous chunk of notes section to vmcore list.*/
+               new = get_new_element();
+               if (!new) {
+                       kfree(notes_section);
+                       return -ENOMEM;
+               }
+               new->paddr = phdr_ptr->p_offset;
+               new->size = real_sz;
+               list_add_tail(&new->list, vc_list);
+               phdr_sz += real_sz;
+               kfree(notes_section);
+       }
+
+       /* Prepare merged PT_NOTE program header. */
+       phdr.p_type    = PT_NOTE;
+       phdr.p_flags   = 0;
+       note_off = sizeof(Elf64_Ehdr) +
+                       (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf64_Phdr);
+       phdr.p_offset  = note_off;
+       phdr.p_vaddr   = phdr.p_paddr = 0;
+       phdr.p_filesz  = phdr.p_memsz = phdr_sz;
+       phdr.p_align   = 0;
+
+       /* Add merged PT_NOTE program header*/
+       tmp = elfptr + sizeof(Elf64_Ehdr);
+       memcpy(tmp, &phdr, sizeof(phdr));
+       tmp += sizeof(phdr);
+
+       /* Remove unwanted PT_NOTE program headers. */
+       i = (nr_ptnote - 1) * sizeof(Elf64_Phdr);
+       *elfsz = *elfsz - i;
+       memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf64_Ehdr)-sizeof(Elf64_Phdr)));
+
+       /* Modify e_phnum to reflect merged headers. */
+       ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
+
+       return 0;
+}
+
+/* Merges all the PT_NOTE headers into one. */
+static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
+                                               struct list_head *vc_list)
+{
+       int i, nr_ptnote=0, rc=0;
+       char *tmp;
+       Elf32_Ehdr *ehdr_ptr;
+       Elf32_Phdr phdr, *phdr_ptr;
+       Elf32_Nhdr *nhdr_ptr;
+       u64 phdr_sz = 0, note_off;
+
+       ehdr_ptr = (Elf32_Ehdr *)elfptr;
+       phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
+       for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+               int j;
+               void *notes_section;
+               struct vmcore *new;
+               u64 offset, max_sz, sz, real_sz = 0;
+               if (phdr_ptr->p_type != PT_NOTE)
+                       continue;
+               nr_ptnote++;
+               max_sz = phdr_ptr->p_memsz;
+               offset = phdr_ptr->p_offset;
+               notes_section = kmalloc(max_sz, GFP_KERNEL);
+               if (!notes_section)
+                       return -ENOMEM;
+               rc = read_from_oldmem(notes_section, max_sz, &offset, 0);
+               if (rc < 0) {
+                       kfree(notes_section);
+                       return rc;
+               }
+               nhdr_ptr = notes_section;
+               for (j = 0; j < max_sz; j += sz) {
+                       if (nhdr_ptr->n_namesz == 0)
+                               break;
+                       sz = sizeof(Elf32_Nhdr) +
+                               ((nhdr_ptr->n_namesz + 3) & ~3) +
+                               ((nhdr_ptr->n_descsz + 3) & ~3);
+                       real_sz += sz;
+                       nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz);
+               }
+
+               /* Add this contiguous chunk of notes section to vmcore list.*/
+               new = get_new_element();
+               if (!new) {
+                       kfree(notes_section);
+                       return -ENOMEM;
+               }
+               new->paddr = phdr_ptr->p_offset;
+               new->size = real_sz;
+               list_add_tail(&new->list, vc_list);
+               phdr_sz += real_sz;
+               kfree(notes_section);
+       }
+
+       /* Prepare merged PT_NOTE program header. */
+       phdr.p_type    = PT_NOTE;
+       phdr.p_flags   = 0;
+       note_off = sizeof(Elf32_Ehdr) +
+                       (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf32_Phdr);
+       phdr.p_offset  = note_off;
+       phdr.p_vaddr   = phdr.p_paddr = 0;
+       phdr.p_filesz  = phdr.p_memsz = phdr_sz;
+       phdr.p_align   = 0;
+
+       /* Add merged PT_NOTE program header*/
+       tmp = elfptr + sizeof(Elf32_Ehdr);
+       memcpy(tmp, &phdr, sizeof(phdr));
+       tmp += sizeof(phdr);
+
+       /* Remove unwanted PT_NOTE program headers. */
+       i = (nr_ptnote - 1) * sizeof(Elf32_Phdr);
+       *elfsz = *elfsz - i;
+       memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf32_Ehdr)-sizeof(Elf32_Phdr)));
+
+       /* Modify e_phnum to reflect merged headers. */
+       ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
+
+       return 0;
+}
+
+/* Add memory chunks represented by program headers to vmcore list. Also update
+ * the new offset fields of exported program headers. */
+static int __init process_ptload_program_headers_elf64(char *elfptr,
+                                               size_t elfsz,
+                                               struct list_head *vc_list)
+{
+       int i;
+       Elf64_Ehdr *ehdr_ptr;
+       Elf64_Phdr *phdr_ptr;
+       loff_t vmcore_off;
+       struct vmcore *new;
+
+       ehdr_ptr = (Elf64_Ehdr *)elfptr;
+       phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */
+
+       /* First program header is PT_NOTE header. */
+       vmcore_off = sizeof(Elf64_Ehdr) +
+                       (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr) +
+                       phdr_ptr->p_memsz; /* Note sections */
+
+       for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+               if (phdr_ptr->p_type != PT_LOAD)
+                       continue;
+
+               /* Add this contiguous chunk of memory to vmcore list.*/
+               new = get_new_element();
+               if (!new)
+                       return -ENOMEM;
+               new->paddr = phdr_ptr->p_offset;
+               new->size = phdr_ptr->p_memsz;
+               list_add_tail(&new->list, vc_list);
+
+               /* Update the program header offset. */
+               phdr_ptr->p_offset = vmcore_off;
+               vmcore_off = vmcore_off + phdr_ptr->p_memsz;
+       }
+       return 0;
+}
+
+static int __init process_ptload_program_headers_elf32(char *elfptr,
+                                               size_t elfsz,
+                                               struct list_head *vc_list)
+{
+       int i;
+       Elf32_Ehdr *ehdr_ptr;
+       Elf32_Phdr *phdr_ptr;
+       loff_t vmcore_off;
+       struct vmcore *new;
+
+       ehdr_ptr = (Elf32_Ehdr *)elfptr;
+       phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */
+
+       /* First program header is PT_NOTE header. */
+       vmcore_off = sizeof(Elf32_Ehdr) +
+                       (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr) +
+                       phdr_ptr->p_memsz; /* Note sections */
+
+       for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+               if (phdr_ptr->p_type != PT_LOAD)
+                       continue;
+
+               /* Add this contiguous chunk of memory to vmcore list.*/
+               new = get_new_element();
+               if (!new)
+                       return -ENOMEM;
+               new->paddr = phdr_ptr->p_offset;
+               new->size = phdr_ptr->p_memsz;
+               list_add_tail(&new->list, vc_list);
+
+               /* Update the program header offset */
+               phdr_ptr->p_offset = vmcore_off;
+               vmcore_off = vmcore_off + phdr_ptr->p_memsz;
+       }
+       return 0;
+}
+
+/* Sets offset fields of vmcore elements. */
+static void __init set_vmcore_list_offsets_elf64(char *elfptr,
+                                               struct list_head *vc_list)
+{
+       loff_t vmcore_off;
+       Elf64_Ehdr *ehdr_ptr;
+       struct vmcore *m;
+
+       ehdr_ptr = (Elf64_Ehdr *)elfptr;
+
+       /* Skip Elf header and program headers. */
+       vmcore_off = sizeof(Elf64_Ehdr) +
+                       (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr);
+
+       list_for_each_entry(m, vc_list, list) {
+               m->offset = vmcore_off;
+               vmcore_off += m->size;
+       }
+}
+
+/* Sets offset fields of vmcore elements. */
+static void __init set_vmcore_list_offsets_elf32(char *elfptr,
+                                               struct list_head *vc_list)
+{
+       loff_t vmcore_off;
+       Elf32_Ehdr *ehdr_ptr;
+       struct vmcore *m;
+
+       ehdr_ptr = (Elf32_Ehdr *)elfptr;
+
+       /* Skip Elf header and program headers. */
+       vmcore_off = sizeof(Elf32_Ehdr) +
+                       (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr);
+
+       list_for_each_entry(m, vc_list, list) {
+               m->offset = vmcore_off;
+               vmcore_off += m->size;
+       }
+}
+
+static int __init parse_crash_elf64_headers(void)
+{
+       int rc=0;
+       Elf64_Ehdr ehdr;
+       u64 addr;
+
+       addr = elfcorehdr_addr;
+
+       /* Read Elf header */
+       rc = read_from_oldmem((char*)&ehdr, sizeof(Elf64_Ehdr), &addr, 0);
+       if (rc < 0)
+               return rc;
+
+       /* Do some basic Verification. */
+       if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
+               (ehdr.e_type != ET_CORE) ||
+               !elf_check_arch(&ehdr) ||
+               ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
+               ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
+               ehdr.e_version != EV_CURRENT ||
+               ehdr.e_ehsize != sizeof(Elf64_Ehdr) ||
+               ehdr.e_phentsize != sizeof(Elf64_Phdr) ||
+               ehdr.e_phnum == 0) {
+               printk(KERN_WARNING "Warning: Core image elf header is not"
+                                       "sane\n");
+               return -EINVAL;
+       }
+
+       /* Read in all elf headers. */
+       elfcorebuf_sz = sizeof(Elf64_Ehdr) + ehdr.e_phnum * sizeof(Elf64_Phdr);
+       elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL);
+       if (!elfcorebuf)
+               return -ENOMEM;
+       addr = elfcorehdr_addr;
+       rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0);
+       if (rc < 0) {
+               kfree(elfcorebuf);
+               return rc;
+       }
+
+       /* Merge all PT_NOTE headers into one. */
+       rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz, &vmcore_list);
+       if (rc) {
+               kfree(elfcorebuf);
+               return rc;
+       }
+       rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz,
+                                                       &vmcore_list);
+       if (rc) {
+               kfree(elfcorebuf);
+               return rc;
+       }
+       set_vmcore_list_offsets_elf64(elfcorebuf, &vmcore_list);
+       return 0;
+}
+
+static int __init parse_crash_elf32_headers(void)
+{
+       int rc=0;
+       Elf32_Ehdr ehdr;
+       u64 addr;
+
+       addr = elfcorehdr_addr;
+
+       /* Read Elf header */
+       rc = read_from_oldmem((char*)&ehdr, sizeof(Elf32_Ehdr), &addr, 0);
+       if (rc < 0)
+               return rc;
+
+       /* Do some basic Verification. */
+       if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
+               (ehdr.e_type != ET_CORE) ||
+               !elf_check_arch(&ehdr) ||
+               ehdr.e_ident[EI_CLASS] != ELFCLASS32||
+               ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
+               ehdr.e_version != EV_CURRENT ||
+               ehdr.e_ehsize != sizeof(Elf32_Ehdr) ||
+               ehdr.e_phentsize != sizeof(Elf32_Phdr) ||
+               ehdr.e_phnum == 0) {
+               printk(KERN_WARNING "Warning: Core image elf header is not"
+                                       "sane\n");
+               return -EINVAL;
+       }
+
+       /* Read in all elf headers. */
+       elfcorebuf_sz = sizeof(Elf32_Ehdr) + ehdr.e_phnum * sizeof(Elf32_Phdr);
+       elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL);
+       if (!elfcorebuf)
+               return -ENOMEM;
+       addr = elfcorehdr_addr;
+       rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0);
+       if (rc < 0) {
+               kfree(elfcorebuf);
+               return rc;
+       }
+
+       /* Merge all PT_NOTE headers into one. */
+       rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz, &vmcore_list);
+       if (rc) {
+               kfree(elfcorebuf);
+               return rc;
+       }
+       rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz,
+                                                               &vmcore_list);
+       if (rc) {
+               kfree(elfcorebuf);
+               return rc;
+       }
+       set_vmcore_list_offsets_elf32(elfcorebuf, &vmcore_list);
+       return 0;
+}
+
+static int __init parse_crash_elf_headers(void)
+{
+       unsigned char e_ident[EI_NIDENT];
+       u64 addr;
+       int rc=0;
+
+       addr = elfcorehdr_addr;
+       rc = read_from_oldmem(e_ident, EI_NIDENT, &addr, 0);
+       if (rc < 0)
+               return rc;
+       if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
+               printk(KERN_WARNING "Warning: Core image elf header"
+                                       " not found\n");
+               return -EINVAL;
+       }
+
+       if (e_ident[EI_CLASS] == ELFCLASS64) {
+               rc = parse_crash_elf64_headers();
+               if (rc)
+                       return rc;
+
+               /* Determine vmcore size. */
+               vmcore_size = get_vmcore_size_elf64(elfcorebuf);
+       } else if (e_ident[EI_CLASS] == ELFCLASS32) {
+               rc = parse_crash_elf32_headers();
+               if (rc)
+                       return rc;
+
+               /* Determine vmcore size. */
+               vmcore_size = get_vmcore_size_elf32(elfcorebuf);
+       } else {
+               printk(KERN_WARNING "Warning: Core image elf header is not"
+                                       " sane\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* Init function for vmcore module. */
+static int __init vmcore_init(void)
+{
+       int rc = 0;
+
+       /* If elfcorehdr= has been passed in cmdline, then capture the dump.*/
+       if (!(elfcorehdr_addr < ELFCORE_ADDR_MAX))
+               return rc;
+       rc = parse_crash_elf_headers();
+       if (rc) {
+               printk(KERN_WARNING "Kdump: vmcore not initialized\n");
+               return rc;
+       }
+
+       /* Initialize /proc/vmcore size if proc is already up. */
+       if (proc_vmcore)
+               proc_vmcore->size = vmcore_size;
+       return 0;
+}
+module_init(vmcore_init)
index cd66147cca04c902331f6807b25b6989b8a6b3fb..7a8f5595c26fea5898f1dfe246c8b86025b3e72a 100644 (file)
@@ -61,7 +61,7 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
                                                ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1;
                                        else {
                                                le  = (struct qnx4_link_info*)de;
-                                               ino = ( le->dl_inode_blk - 1 ) *
+                                               ino = ( le32_to_cpu(le->dl_inode_blk) - 1 ) *
                                                        QNX4_INODES_PER_BLOCK +
                                                        le->dl_inode_ndx;
                                        }
index aa92d6b76a9af185e2f6a375d8140cfab7a77bfc..b79162a35478ce46fae25af21067844b0fabfd4b 100644 (file)
@@ -236,7 +236,7 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
        struct buffer_head *bh = NULL;
        struct qnx4_xblk *xblk = NULL;
        struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode);
-       qnx4_nxtnt_t nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts);
+       u16 nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts);
 
        if ( iblock < le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size) ) {
                // iblock is in the first extent. This is easy.
@@ -372,7 +372,7 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
                printk("qnx4: unable to read the superblock\n");
                goto outnobh;
        }
-       if ( le32_to_cpu( *(__u32*)bh->b_data ) != QNX4_SUPER_MAGIC ) {
+       if ( le32_to_cpup((__le32*) bh->b_data) != QNX4_SUPER_MAGIC ) {
                if (!silent)
                        printk("qnx4: wrong fsid in superblock.\n");
                goto out;
index 2230afff18700c70df387ab4e3878ae43dfcbe4d..12e91209544ea1dc3fc7bc5b205d72312ef29c17 100644 (file)
@@ -201,7 +201,7 @@ static int reiserfs_allocate_blocks_for_region(
     /* If we came here, it means we absolutely need to open a transaction,
        since we need to allocate some blocks */
     reiserfs_write_lock(inode->i_sb); // Journaling stuff and we need that.
-    res = journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS); // Wish I know if this number enough
+    res = journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb)); // Wish I know if this number enough
     if (res)
         goto error_exit;
     reiserfs_update_inode_transaction(inode) ;
@@ -576,7 +576,7 @@ error_exit:
         int err;
         // update any changes we made to blk count
         reiserfs_update_sd(th, inode);
-        err = journal_end(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS);
+        err = journal_end(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb));
         if (err)
             res = err;
     }
index 2711dff1b7b40aaed153785d34e43f46816a4bca..289d864fe73189947416e1f6bc965da948554000 100644 (file)
@@ -28,7 +28,7 @@ static int reiserfs_prepare_write(struct file *f, struct page *page,
 void reiserfs_delete_inode (struct inode * inode)
 {
     /* We need blocks for transaction + (user+group) quota update (possibly delete) */
-    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * REISERFS_QUOTA_INIT_BLOCKS;
+    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb);
     struct reiserfs_transaction_handle th ;
   
     reiserfs_write_lock(inode->i_sb);
@@ -254,6 +254,7 @@ static int _get_block_create_0 (struct inode * inode, long block,
     char * p = NULL;
     int chars;
     int ret ;
+    int result ;
     int done = 0 ;
     unsigned long offset ;
 
@@ -262,10 +263,13 @@ static int _get_block_create_0 (struct inode * inode, long block,
                  (loff_t)block * inode->i_sb->s_blocksize + 1, TYPE_ANY, 3);
 
 research:
-    if (search_for_position_by_key (inode->i_sb, &key, &path) != POSITION_FOUND) {
+    result = search_for_position_by_key (inode->i_sb, &key, &path) ;
+    if (result != POSITION_FOUND) {
        pathrelse (&path);
         if (p)
             kunmap(bh_result->b_page) ;
+       if (result == IO_ERROR)
+           return -EIO;
        // We do not return -ENOENT if there is a hole but page is uptodate, because it means
        // That there is some MMAPED data associated with it that is yet to be written to disk.
        if ((args & GET_BLOCK_NO_HOLE) && !PageUptodate(bh_result->b_page) ) {
@@ -382,8 +386,9 @@ research:
 
        // update key to look for the next piece
        set_cpu_key_k_offset (&key, cpu_key_k_offset (&key) + chars);
-       if (search_for_position_by_key (inode->i_sb, &key, &path) != POSITION_FOUND)
-           // we read something from tail, even if now we got IO_ERROR
+       result = search_for_position_by_key (inode->i_sb, &key, &path);
+       if (result != POSITION_FOUND)
+           // i/o error most likely
            break;
        bh = get_last_bh (&path);
        ih = get_ih (&path);
@@ -394,6 +399,10 @@ research:
 
 finished:
     pathrelse (&path);
+
+    if (result == IO_ERROR)
+       return -EIO;
+
     /* this buffer has valid data, but isn't valid for io.  mapping it to
      * block #0 tells the rest of reiserfs it just has a tail in it
      */
@@ -591,7 +600,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
        XXX in practically impossible worst case direct2indirect()
        can incur (much) more than 3 balancings.
        quota update for user, group */
-    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS;
+    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb);
     int version;
     int dangle = 1;
     loff_t new_offset = (((loff_t)block) << inode->i_sb->s_blocksize_bits) + 1 ;
@@ -2796,12 +2805,15 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) {
 
                 if (!error) {
                    struct reiserfs_transaction_handle th;
+                   int jbegin_count = 2*(REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb)+REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb))+2;
 
                    /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */
-                   journal_begin(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2);
+                   error = journal_begin(&th, inode->i_sb, jbegin_count);
+                   if (error)
+                       goto out;
                     error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
                    if (error) {
-                       journal_end(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2);
+                       journal_end(&th, inode->i_sb, jbegin_count);
                        goto out;
                    }
                    /* Update corresponding info in inode so that everything is in
@@ -2811,7 +2823,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) {
                    if (attr->ia_valid & ATTR_GID)
                        inode->i_gid = attr->ia_gid;
                    mark_inode_dirty(inode);
-                   journal_end(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2);
+                   error = journal_end(&th, inode->i_sb, jbegin_count);
                }
         }
         if (!error)
index 94dc42475a0462cfa7997ec68fa20383658d96e3..76caedf737f260a7b1212c9681ff90188b472378 100644 (file)
@@ -36,10 +36,16 @@ int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
        /* following two cases are taken from fs/ext2/ioctl.c by Remy
           Card (card@masi.ibp.fr) */
        case REISERFS_IOC_GETFLAGS:
+               if (!reiserfs_attrs (inode->i_sb))
+                       return -ENOTTY;
+
                flags = REISERFS_I(inode) -> i_attrs;
                i_attrs_to_sd_attrs( inode, ( __u16 * ) &flags );
                return put_user(flags, (int __user *) arg);
        case REISERFS_IOC_SETFLAGS: {
+               if (!reiserfs_attrs (inode->i_sb))
+                       return -ENOTTY;
+
                if (IS_RDONLY(inode))
                        return -EROFS;
 
index 3072cfdee9598f3d44d91703c2ad92ef48a1af34..d1bcf0da6728abf99fb37e456f7b95475b1e2b48 100644 (file)
@@ -645,18 +645,22 @@ struct buffer_chunk {
 
 static void write_chunk(struct buffer_chunk *chunk) {
     int i;
+    get_fs_excl();
     for (i = 0; i < chunk->nr ; i++) {
        submit_logged_buffer(chunk->bh[i]) ;
     }
     chunk->nr = 0;
+    put_fs_excl();
 }
 
 static void write_ordered_chunk(struct buffer_chunk *chunk) {
     int i;
+    get_fs_excl();
     for (i = 0; i < chunk->nr ; i++) {
        submit_ordered_buffer(chunk->bh[i]) ;
     }
     chunk->nr = 0;
+    put_fs_excl();
 }
 
 static int add_to_chunk(struct buffer_chunk *chunk, struct buffer_head *bh,
@@ -918,6 +922,8 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list
     return 0 ;
   }
 
+  get_fs_excl();
+
   /* before we can put our commit blocks on disk, we have to make sure everyone older than
   ** us is on disk too
   */
@@ -1055,6 +1061,7 @@ put_jl:
 
   if (retval)
     reiserfs_abort (s, retval, "Journal write error in %s", __FUNCTION__);
+  put_fs_excl();
   return retval;
 }
 
@@ -1251,6 +1258,8 @@ static int flush_journal_list(struct super_block *s,
     return 0 ;
   }
 
+  get_fs_excl();
+
   /* if all the work is already done, get out of here */
   if (atomic_read(&(jl->j_nonzerolen)) <= 0 && 
       atomic_read(&(jl->j_commit_left)) <= 0) {
@@ -1450,6 +1459,7 @@ flush_older_and_return:
   put_journal_list(s, jl);
   if (flushall)
     up(&journal->j_flush_sem);
+  put_fs_excl();
   return err ;
 } 
 
@@ -2631,6 +2641,8 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, struct sup
   int retval;
 
   reiserfs_check_lock_depth(p_s_sb, "journal_begin") ;
+  if (nblocks > journal->j_trans_max)
+       BUG();
 
   PROC_INFO_INC( p_s_sb, journal.journal_being );
   /* set here for journal_join */
@@ -2717,6 +2729,7 @@ relock:
   th->t_trans_id = journal->j_trans_id ;
   unlock_journal(p_s_sb) ;
   INIT_LIST_HEAD (&th->t_list);
+  get_fs_excl();
   return 0 ;
 
 out_fail:
@@ -3524,6 +3537,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, struct super_b
   BUG_ON (th->t_refcount > 1);
   BUG_ON (!th->t_trans_id);
 
+  put_fs_excl();
   current->journal_info = th->t_handle_save;
   reiserfs_check_lock_depth(p_s_sb, "journal end");
   if (journal->j_len == 0) {
index 7d4dc5f5aa8b698e7e88c978cfd4978247e3dc38..4a333255f27abaf7d3292faf7636ed856299955d 100644 (file)
@@ -586,7 +586,7 @@ static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode,
     int retval;
     struct inode * inode;
     /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
-    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS);
+    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb)+REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb));
     struct reiserfs_transaction_handle th ;
     int locked;
 
@@ -653,7 +653,7 @@ static int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode,
     struct inode * inode;
     struct reiserfs_transaction_handle th ;
     /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
-    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS);
+    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb)+REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb));
     int locked;
 
     if (!new_valid_dev(rdev))
@@ -727,7 +727,7 @@ static int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode)
     struct inode * inode;
     struct reiserfs_transaction_handle th ;
     /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
-    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS);
+    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb)+REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb));
     int locked;
 
 #ifdef DISPLACE_NEW_PACKING_LOCALITIES
@@ -829,8 +829,10 @@ static int reiserfs_rmdir (struct inode * dir, struct dentry *dentry)
 
 
     /* we will be doing 2 balancings and update 2 stat data, we change quotas
-     * of the owner of the directory and of the owner of the parent directory */
-    jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS);
+     * of the owner of the directory and of the owner of the parent directory.
+     * The quota structure is possibly deleted only on last iput => outside
+     * of this transaction */
+    jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb);
 
     reiserfs_write_lock(dir->i_sb);
     retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
@@ -913,9 +915,10 @@ static int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
     inode = dentry->d_inode;
 
     /* in this transaction we can be doing at max two balancings and update
-       two stat datas, we change quotas of the owner of the directory and of
-       the owner of the parent directory */
-    jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS);
+     * two stat datas, we change quotas of the owner of the directory and of
+     * the owner of the parent directory. The quota structure is possibly
+     * deleted only on iput => outside of this transaction */
+    jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb);
 
     reiserfs_write_lock(dir->i_sb);
     retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
@@ -1000,7 +1003,7 @@ static int reiserfs_symlink (struct inode * parent_dir,
     struct reiserfs_transaction_handle th ;
     int mode = S_IFLNK | S_IRWXUGO;
     /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
-    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS);
+    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(parent_dir->i_sb)+REISERFS_QUOTA_TRANS_BLOCKS(parent_dir->i_sb));
 
     if (!(inode = new_inode(parent_dir->i_sb))) {
        return -ENOMEM ;
@@ -1076,7 +1079,7 @@ static int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct
     struct inode *inode = old_dentry->d_inode;
     struct reiserfs_transaction_handle th ;
     /* We need blocks for transaction + update of quotas for the owners of the directory */
-    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * REISERFS_QUOTA_TRANS_BLOCKS;
+    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb);
 
     reiserfs_write_lock(dir->i_sb);
     if (inode->i_nlink >= REISERFS_LINK_MAX) {
@@ -1196,7 +1199,7 @@ static int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry,
        pointed initially and (5) maybe block containing ".." of
        renamed directory
        quota updates: two parent directories */
-    jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 5 + 4 * REISERFS_QUOTA_TRANS_BLOCKS;
+    jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 5 + 4 * REISERFS_QUOTA_TRANS_BLOCKS(old_dir->i_sb);
 
     old_inode = old_dentry->d_inode;
     new_dentry_inode = new_dentry->d_inode;
index c47f8fd31a2d069e650b17866ab816b3a273b046..63158491e152c435b725543ce31c4c64ca18dee0 100644 (file)
@@ -223,7 +223,7 @@ extern struct tree_balance * cur_tb;
 const struct reiserfs_key  MIN_KEY = {0, 0, {{0, 0},}};
 
 /* Maximal possible key. It is never in the tree. */
-const struct reiserfs_key  MAX_KEY = {
+static const struct reiserfs_key  MAX_KEY = {
        __constant_cpu_to_le32(0xffffffff),
        __constant_cpu_to_le32(0xffffffff),
        {{__constant_cpu_to_le32(0xffffffff),
index aae0779ed5b4ccd2de0284032a43b26e7cf61845..4b80ab95d3385166c70020dc39fc9dbf1a78466b 100644 (file)
@@ -866,8 +866,9 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st
        {"jdev",        .arg_required = 'j', .values = NULL},
        {"nolargeio",   .arg_required = 'w', .values = NULL},
        {"commit",      .arg_required = 'c', .values = NULL},
-       {"usrquota",},
-       {"grpquota",},
+       {"usrquota",    .setmask = 1<<REISERFS_QUOTA},
+       {"grpquota",    .setmask = 1<<REISERFS_QUOTA},
+       {"noquota",     .clrmask = 1<<REISERFS_QUOTA},
        {"errors",      .arg_required = 'e', .values = error_actions},
        {"usrjquota",   .arg_required = 'u'|(1<<REISERFS_OPT_ALLOWEMPTY), .values = NULL},
        {"grpjquota",   .arg_required = 'g'|(1<<REISERFS_OPT_ALLOWEMPTY), .values = NULL},
@@ -964,6 +965,7 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st
                    return 0;
                }
                strcpy(REISERFS_SB(s)->s_qf_names[qtype], arg);
+               *mount_options |= 1<<REISERFS_QUOTA;
            }
            else {
                if (REISERFS_SB(s)->s_qf_names[qtype]) {
@@ -995,7 +997,13 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st
        reiserfs_warning(s, "reiserfs_parse_options: journalled quota format not specified.");
        return 0;
     }
+    /* This checking is not precise wrt the quota type but for our purposes it is sufficient */
+    if (!(*mount_options & (1<<REISERFS_QUOTA)) && sb_any_quota_enabled(s)) {
+       reiserfs_warning(s, "reiserfs_parse_options: quota options must be present when quota is turned on.");
+       return 0;
+    }
 #endif
+
     return 1;
 }
 
@@ -1045,10 +1053,9 @@ static void handle_barrier_mode(struct super_block *s, unsigned long bits) {
 
 static void handle_attrs( struct super_block *s )
 {
-       struct reiserfs_super_block * rs;
+       struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
 
        if( reiserfs_attrs( s ) ) {
-               rs = SB_DISK_SUPER_BLOCK (s);
                if( old_format_only(s) ) {
                        reiserfs_warning(s, "reiserfs: cannot support attributes on 3.5.x disk format" );
                        REISERFS_SB(s) -> s_mount_opt &= ~ ( 1 << REISERFS_ATTRS );
@@ -1058,6 +1065,8 @@ static void handle_attrs( struct super_block *s )
                                reiserfs_warning(s, "reiserfs: cannot support attributes until flag is set in super-block" );
                                REISERFS_SB(s) -> s_mount_opt &= ~ ( 1 << REISERFS_ATTRS );
                }
+       } else if (le32_to_cpu( rs -> s_flags ) & reiserfs_attrs_cleared) {
+               REISERFS_SB(s)->s_mount_opt |= REISERFS_ATTRS;
        }
 }
 
@@ -1105,6 +1114,7 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
   safe_mask |= 1 << REISERFS_ERROR_RO;
   safe_mask |= 1 << REISERFS_ERROR_CONTINUE;
   safe_mask |= 1 << REISERFS_ERROR_PANIC;
+  safe_mask |= 1 << REISERFS_QUOTA;
 
   /* Update the bitmask, taking care to keep
    * the bits we're not allowed to change here */
@@ -1841,13 +1851,18 @@ static int reiserfs_statfs (struct super_block * s, struct kstatfs * buf)
 static int reiserfs_dquot_initialize(struct inode *inode, int type)
 {
     struct reiserfs_transaction_handle th;
-    int ret;
+    int ret, err;
 
     /* We may create quota structure so we need to reserve enough blocks */
     reiserfs_write_lock(inode->i_sb);
-    journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS);
+    ret = journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb));
+    if (ret)
+       goto out;
     ret = dquot_initialize(inode, type);
-    journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS);
+    err = journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb));
+    if (!ret && err)
+       ret = err;
+out:
     reiserfs_write_unlock(inode->i_sb);
     return ret;
 }
@@ -1855,13 +1870,18 @@ static int reiserfs_dquot_initialize(struct inode *inode, int type)
 static int reiserfs_dquot_drop(struct inode *inode)
 {
     struct reiserfs_transaction_handle th;
-    int ret;
+    int ret, err;
 
     /* We may delete quota structure so we need to reserve enough blocks */
     reiserfs_write_lock(inode->i_sb);
-    journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS);
+    ret = journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb));
+    if (ret)
+       goto out;
     ret = dquot_drop(inode);
-    journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS);
+    err = journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb));
+    if (!ret && err)
+       ret = err;
+out:
     reiserfs_write_unlock(inode->i_sb);
     return ret;
 }
@@ -1869,12 +1889,17 @@ static int reiserfs_dquot_drop(struct inode *inode)
 static int reiserfs_write_dquot(struct dquot *dquot)
 {
     struct reiserfs_transaction_handle th;
-    int ret;
+    int ret, err;
 
     reiserfs_write_lock(dquot->dq_sb);
-    journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS);
+    ret = journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
+    if (ret)
+       goto out;
     ret = dquot_commit(dquot);
-    journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS);
+    err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
+    if (!ret && err)
+       ret = err;
+out:
     reiserfs_write_unlock(dquot->dq_sb);
     return ret;
 }
@@ -1882,12 +1907,17 @@ static int reiserfs_write_dquot(struct dquot *dquot)
 static int reiserfs_acquire_dquot(struct dquot *dquot)
 {
     struct reiserfs_transaction_handle th;
-    int ret;
+    int ret, err;
 
     reiserfs_write_lock(dquot->dq_sb);
-    journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS);
+    ret = journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb));
+    if (ret)
+       goto out;
     ret = dquot_acquire(dquot);
-    journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS);
+    err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb));
+    if (!ret && err)
+       ret = err;
+out:
     reiserfs_write_unlock(dquot->dq_sb);
     return ret;
 }
@@ -1895,12 +1925,17 @@ static int reiserfs_acquire_dquot(struct dquot *dquot)
 static int reiserfs_release_dquot(struct dquot *dquot)
 {
     struct reiserfs_transaction_handle th;
-    int ret;
+    int ret, err;
 
     reiserfs_write_lock(dquot->dq_sb);
-    journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS);
+    ret = journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb));
+    if (ret)
+       goto out;
     ret = dquot_release(dquot);
-    journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS);
+    err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb));
+    if (!ret && err)
+       ret = err;
+out:
     reiserfs_write_unlock(dquot->dq_sb);
     return ret;
 }
@@ -1920,13 +1955,18 @@ static int reiserfs_mark_dquot_dirty(struct dquot *dquot)
 static int reiserfs_write_info(struct super_block *sb, int type)
 {
     struct reiserfs_transaction_handle th;
-    int ret;
+    int ret, err;
 
     /* Data block + inode block */
     reiserfs_write_lock(sb);
-    journal_begin(&th, sb, 2);
+    ret = journal_begin(&th, sb, 2);
+    if (ret)
+       goto out;
     ret = dquot_commit_info(sb, type);
-    journal_end(&th, sb, 2);
+    err = journal_end(&th, sb, 2);
+    if (!ret && err)
+       ret = err;
+out:
     reiserfs_write_unlock(sb);
     return ret;
 }
@@ -1948,6 +1988,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, ch
     int err;
     struct nameidata nd;
 
+    if (!(REISERFS_SB(sb)->s_mount_opt & (1<<REISERFS_QUOTA)))
+       return -EINVAL;
     err = path_lookup(path, LOOKUP_FOLLOW, &nd);
     if (err)
         return err;
index e9cfa39f409918b80c463199e7a8ab635f605027..d72c1ce485598600c13ff7d484306c0a3aad85e7 100644 (file)
@@ -14,7 +14,7 @@
 #define to_subsys(k) container_of(k,struct subsystem,kset.kobj)
 #define to_sattr(a) container_of(a,struct subsys_attribute,attr)
 
-/**
+/*
  * Subsystem file operations.
  * These operations allow subsystems to have files that can be 
  * read/written. 
@@ -192,8 +192,9 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t
 
 /**
  *     flush_write_buffer - push buffer to kobject.
- *     @file:          file pointer.
+ *     @dentry:        dentry to the attribute
  *     @buffer:        data buffer for file.
+ *     @count:         number of bytes
  *
  *     Get the correct pointers for the kobject and the attribute we're
  *     dealing with, then call the store() method for the attribute, 
index 3f6dc7112bc6c4543bb261d7bf5c12861fc272fc..ac191ed7df0ac74cf57ca06152fd2b5fcd6367f5 100644 (file)
@@ -159,14 +159,12 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
        char *nameptr;
        uint8_t lfi;
        uint16_t liu;
-       loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
+       loff_t size;
        kernel_lb_addr bloc, eloc;
        uint32_t extoffset, elen, offset;
        struct buffer_head *bh = NULL;
 
-       if (!dir)
-               return NULL;
-
+       size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
        f_pos = (udf_ext0_offset(dir) >> 2);
 
        fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
index 93ce257cd1495cbffdb8cebfda51cd6d9c6431c6..a3a4b5aaf5d985020672a47e0c6858a21b190ad4 100644 (file)
@@ -149,11 +149,12 @@ linvfs_unwritten_convert(
  */
 STATIC void
 linvfs_unwritten_convert_direct(
-       struct inode    *inode,
+       struct kiocb    *iocb,
        loff_t          offset,
        ssize_t         size,
        void            *private)
 {
+       struct inode    *inode = iocb->ki_filp->f_dentry->d_inode;
        ASSERT(!private || inode == (struct inode *)private);
 
        /* private indicates an unwritten extent lay beneath this IO */
index c60e69431e11d746abc9b41d3c525c0ac65116d7..df0cba239dd589b2ac7b9fbb90aa0909190a5ac3 100644 (file)
@@ -1771,9 +1771,9 @@ xfsbufd(
 
        INIT_LIST_HEAD(&tmp);
        do {
-               if (unlikely(current->flags & PF_FREEZE)) {
+               if (unlikely(freezing(current))) {
                        xfsbufd_force_sleep = 1;
-                       refrigerator(PF_FREEZE);
+                       refrigerator();
                } else {
                        xfsbufd_force_sleep = 0;
                }
index 5fe9af38aa2063ac56c23ef7faa39a539b4161d1..f6dd7de2592748c95dee026e0f865ec37d5ca89b 100644 (file)
@@ -483,7 +483,7 @@ xfssyncd(
                set_current_state(TASK_INTERRUPTIBLE);
                timeleft = schedule_timeout(timeleft);
                /* swsusp */
-               try_to_freeze(PF_FREEZE);
+               try_to_freeze();
                if (vfsp->vfs_flag & VFS_UMOUNT)
                        break;
 
index c627bc408a6b11f876c7a8a0d392a5f7e5056b4a..9ad142476f3301eeb9961acf5e0dece7c8deddc5 100644 (file)
@@ -108,6 +108,21 @@ typedef int (*acpi_op_unbind)      (struct acpi_device *device);
 typedef int (*acpi_op_match)   (struct acpi_device *device,
                                 struct acpi_driver *driver);
 
+struct acpi_bus_ops {
+       u32                     acpi_op_add:1;
+       u32                     acpi_op_remove:1;
+       u32                     acpi_op_lock:1;
+       u32                     acpi_op_start:1;
+       u32                     acpi_op_stop:1;
+       u32                     acpi_op_suspend:1;
+       u32                     acpi_op_resume:1;
+       u32                     acpi_op_scan:1;
+       u32                     acpi_op_bind:1;
+       u32                     acpi_op_unbind:1;
+       u32                     acpi_op_match:1;
+       u32                     reserved:21;
+};
+
 struct acpi_device_ops {
        acpi_op_add             add;
        acpi_op_remove          remove;
@@ -327,9 +342,9 @@ int acpi_bus_generate_event (struct acpi_device *device, u8 type, int data);
 int acpi_bus_receive_event (struct acpi_bus_event *event);
 int acpi_bus_register_driver (struct acpi_driver *driver);
 int acpi_bus_unregister_driver (struct acpi_driver *driver);
-int acpi_bus_scan (struct acpi_device *start);
 int acpi_bus_add (struct acpi_device **child, struct acpi_device *parent,
                acpi_handle handle, int type);
+int acpi_bus_start (struct acpi_device *device);
 
 
 int acpi_match_ids (struct acpi_device *device, char   *ids);
index c62e92ec43b2893b120ef8087b9dfdc7e8c09545..4ec722d73381f5c31832fb19b5eb6b84ea3b6d10 100644 (file)
@@ -68,6 +68,7 @@ void acpi_pci_irq_del_prt (int segment, int bus);
 
 struct pci_bus;
 
+acpi_status acpi_get_pci_id (acpi_handle handle, struct acpi_pci_id *id);
 int acpi_pci_bind (struct acpi_device *device);
 int acpi_pci_unbind (struct acpi_device *device);
 int acpi_pci_bind_root (struct acpi_device *device, struct acpi_pci_id *id, struct pci_bus *bus);
index 0c7b57bc043a69719386d5ce290210fd8f9ff6be..b7806aa3785c0c753547acc8dedfe029765ddf5f 100644 (file)
@@ -223,6 +223,25 @@ pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr,
        /* Nothing to do. */
 }
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       unsigned long cacheline_size;
+       u8 byte;
+
+       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+       if (byte == 0)
+               cacheline_size = 1024;
+       else
+               cacheline_size = (int) byte * 4;
+
+       *strat = PCI_DMA_BURST_BOUNDARY;
+       *strategy_parameter = cacheline_size;
+}
+#endif
+
 /* TODO: integrate with include/asm-generic/pci.h ? */
 static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 {
index 7b2d9ee95a44683b0546b43cc149d37de0c1a4e2..7e4b2987d453dfc3de77184cb7306be68a94010a 100644 (file)
 #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
 #endif
 
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#endif
-       
-#define STD_SERIAL_PORT_DEFNS                  \
+#define SERIAL_PORT_DFNS                       \
        /* UART CLK   PORT IRQ     FLAGS        */                      \
        { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },      /* ttyS0 */     \
        { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },      /* ttyS1 */     \
        { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },      /* ttyS2 */     \
        { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },     /* ttyS3 */
-
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS                        \
-       { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS },     /* ttyS4 */     \
-       { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },     /* ttyS5 */     \
-       { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },     /* ttyS6 */     \
-       { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },     /* ttyS7 */     \
-       { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },     /* ttyS8 */     \
-       { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },     /* ttyS9 */     \
-       { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },     /* ttyS10 */    \
-       { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },     /* ttyS11 */    \
-       { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },       /* ttyS12 */    \
-       { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },       /* ttyS13 */    \
-       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS14 (spare) */            \
-       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS15 (spare) */            \
-       { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },        /* ttyS16 */    \
-       { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },        /* ttyS17 */    \
-       { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },        /* ttyS18 */    \
-       { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },        /* ttyS19 */    \
-       { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },        /* ttyS20 */    \
-       { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },        /* ttyS21 */    \
-       { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },        /* ttyS22 */    \
-       { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },        /* ttyS23 */    \
-       { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },        /* ttyS24 */    \
-       { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },        /* ttyS25 */    \
-       { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },        /* ttyS26 */    \
-       { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },        /* ttyS27 */    \
-       { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },        /* ttyS28 */    \
-       { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },        /* ttyS29 */    \
-       { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },        /* ttyS30 */    \
-       { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },        /* ttyS31 */
-#else
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif
-
-#define SERIAL_PORT_DFNS               \
-       STD_SERIAL_PORT_DEFNS           \
-       EXTRA_SERIAL_PORT_DEFNS
index 84634af5cc644ff1ef8d40ba298e17d6746eee17..03cbbe1fd9d8fe0f47874af3f9e43ffc935feb7a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * include/asm-arm/arch-ixp2000/ixp2000-gpio.h
+ * include/asm-arm/arch-ixp2000/gpio.h
  *
  * Copyright (C) 2002 Intel Corporation.
  *
  * Use this instead of directly setting the GPIO registers.
  * GPIOs may also be used as GPIOs (e.g. for emulating i2c/smb)
  */
-#ifndef _ASM_ARCH_IXP2000_GPIO_H_
-#define _ASM_ARCH_IXP2000_GPIO_H_
+#ifndef __ASM_ARCH_GPIO_H
+#define __ASM_ARCH_GPIO_H
 
 #ifndef __ASSEMBLY__
-#define GPIO_OUT                       0x0
-#define GPIO_IN                                0x80
+
+#define GPIO_IN                                0
+#define GPIO_OUT                       1
 
 #define IXP2000_GPIO_LOW               0
 #define IXP2000_GPIO_HIGH              1
 
-#define GPIO_NO_EDGES                  0
-#define GPIO_FALLING_EDGE              1
-#define GPIO_RISING_EDGE               2
-#define GPIO_BOTH_EDGES                3
-#define GPIO_LEVEL_LOW                 4
-#define GPIO_LEVEL_HIGH                8
-
-extern void set_GPIO_IRQ_edge(int gpio_nr, int edge);
-extern void set_GPIO_IRQ_level(int gpio_nr, int level);
-extern void gpio_line_config(int line, int style);
+extern void gpio_line_config(int line, int direction);
 
 static inline int gpio_line_get(int line)
 {
@@ -45,11 +37,12 @@ static inline int gpio_line_get(int line)
 static inline void gpio_line_set(int line, int value)
 {
        if (value == IXP2000_GPIO_HIGH) {
-               ixp_reg_write(IXP2000_GPIO_POSR, BIT(line));
-       } else if (value == IXP2000_GPIO_LOW)
-               ixp_reg_write(IXP2000_GPIO_POCR, BIT(line));
+               ixp2000_reg_write(IXP2000_GPIO_POSR, 1 << line);
+       } else if (value == IXP2000_GPIO_LOW) {
+               ixp2000_reg_write(IXP2000_GPIO_POCR, 1 << line);
+       }
 }
 
 #endif /* !__ASSEMBLY__ */
-#endif /* ASM_ARCH_IXP2000_GPIO_H_ */
 
+#endif /* ASM_ARCH_IXP2000_GPIO_H_ */
index 083462668e184a8953ef49ed8eb9753c38d35d24..3241cd6f0778e0384e188a945a8747f705f68750 100644 (file)
 
 #define IO_SPACE_LIMIT         0xffffffff
 #define __mem_pci(a)           (a)
-#define ___io(p)               ((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE))
 
 /*
- * The IXP2400 before revision B0 asserts byte lanes for PCI I/O
+ * The A? revisions of the IXP2000s assert byte lanes for PCI I/O
  * transactions the other way round (MEM transactions don't have this
- * issue), so we need to override the standard functions.  B0 and later
- * have a bit that can be set to 1 to get the 'proper' behavior, but
- * since that isn't available on the A? revisions we just keep doing
- * things manually.
+ * issue), so if we want to support those models, we need to override
+ * the standard I/O functions.
+ *
+ * B0 and later have a bit that can be set to 1 to get the proper
+ * behavior for I/O transactions, which then allows us to use the
+ * standard I/O functions.  This is what we do if the user does not
+ * explicitly ask for support for pre-B0.
  */
-#define alignb(addr)           (void __iomem *)((unsigned long)addr ^ 3)
-#define alignw(addr)           (void __iomem *)((unsigned long)addr ^ 2)
+#ifdef CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO
+#define ___io(p)               ((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE))
+
+#define alignb(addr)           (void __iomem *)((unsigned long)(addr) ^ 3)
+#define alignw(addr)           (void __iomem *)((unsigned long)(addr) ^ 2)
 
 #define outb(v,p)              __raw_writeb((v),alignb(___io(p)))
 #define outw(v,p)              __raw_writew((v),alignw(___io(p)))
 #define insw(p,d,l)            __raw_readsw(alignw(___io(p)),d,l)
 #define insl(p,d,l)            __raw_readsl(___io(p),d,l)
 
+#define __is_io_address(p)     ((((unsigned long)(p)) & ~(IXP2000_PCI_IO_SIZE - 1)) == IXP2000_PCI_IO_VIRT_BASE)
+
+#define ioread8(p)                                             \
+       ({                                                      \
+               unsigned int __v;                               \
+                                                               \
+               if (__is_io_address(p)) {                       \
+                       __v = __raw_readb(alignb(p));           \
+               } else {                                        \
+                       __v = __raw_readb(p);                   \
+               }                                               \
+                                                               \
+               __v;                                            \
+       })                                                      \
+
+#define ioread16(p)                                            \
+       ({                                                      \
+               unsigned int __v;                               \
+                                                               \
+               if (__is_io_address(p)) {                       \
+                       __v = __raw_readw(alignw(p));           \
+               } else {                                        \
+                       __v = le16_to_cpu(__raw_readw(p));      \
+               }                                               \
+                                                               \
+               __v;                                            \
+       })
+
+#define ioread32(p)                                            \
+       ({                                                      \
+               unsigned int __v;                               \
+                                                               \
+               if (__is_io_address(p)) {                       \
+                       __v = __raw_readl(p);                   \
+               } else {                                        \
+                       __v = le32_to_cpu(__raw_readl(p));      \
+               }                                               \
+                                                               \
+                __v;                                           \
+       })
+
+#define iowrite8(v,p)                                          \
+       ({                                                      \
+               if (__is_io_address(p)) {                       \
+                       __raw_writeb((v), alignb(p));           \
+               } else {                                        \
+                       __raw_writeb((v), p);                   \
+               }                                               \
+       })
+
+#define iowrite16(v,p)                                         \
+       ({                                                      \
+               if (__is_io_address(p)) {                       \
+                       __raw_writew((v), alignw(p));           \
+               } else {                                        \
+                       __raw_writew(cpu_to_le16(v), p);        \
+               }                                               \
+       })
+
+#define iowrite32(v,p)                                         \
+       ({                                                      \
+               if (__is_io_address(p)) {                       \
+                       __raw_writel((v), p);                   \
+               } else {                                        \
+                       __raw_writel(cpu_to_le32(v), p);        \
+               }                                               \
+       })
+
+#define ioport_map(port, nr)   ___io(port)
+
+#define ioport_unmap(addr)
+#else
+#define __io(p)                        ((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE))
+#endif
+
 
 #ifdef CONFIG_ARCH_IXDP2X01
 /*
index 3a398dfbf125c039a3c52a0871d09d2cfc2fee29..229381c64283ae7c0605d0138c03dc12ee1789e8 100644 (file)
@@ -21,8 +21,8 @@
  * On board CPLD memory map
  */
 #define IXDP2X00_PHYS_CPLD_BASE                0xc7000000
-#define IXDP2X00_VIRT_CPLD_BASE                0xfafff000
-#define IXDP2X00_CPLD_SIZE             0x00001000
+#define IXDP2X00_VIRT_CPLD_BASE                0xfe000000
+#define IXDP2X00_CPLD_SIZE             0x00100000
 
 
 #define IXDP2X00_CPLD_REG(x)   \
index b3a1bcda8d01068f6d02fcd5317935be2f8a23bf..b768009c3a519da19ea228e864cd6cb2551794ba 100644 (file)
@@ -18,8 +18,8 @@
 #define __IXDP2X01_H__
 
 #define        IXDP2X01_PHYS_CPLD_BASE         0xc6024000
-#define        IXDP2X01_VIRT_CPLD_BASE         0xfafff000
-#define        IXDP2X01_CPLD_REGION_SIZE       0x00001000
+#define        IXDP2X01_VIRT_CPLD_BASE         0xfe000000
+#define        IXDP2X01_CPLD_REGION_SIZE       0x00100000
 
 #define IXDP2X01_CPLD_VIRT_REG(reg) (volatile unsigned long*)(IXDP2X01_VIRT_CPLD_BASE | reg)
 #define IXDP2X01_CPLD_PHYS_REG(reg) (volatile u32*)(IXDP2X01_PHYS_CPLD_BASE | reg)
index a1d9e181b10f1c1d579cf4b3fa4d30db1a39b9a5..75623f81ef75492801108bb895f745fdbdb962e4 100644 (file)
 #ifndef _IXP2000_REGS_H_
 #define _IXP2000_REGS_H_
 
+/*
+ * IXP2000 linux memory map:
+ *
+ * virt                phys            size
+ * fb000000    db000000        16M             PCI CFG1
+ * fc000000    da000000        16M             PCI CFG0
+ * fd000000    d8000000        16M             PCI I/O
+ * fe[0-7]00000                        8M              per-platform mappings
+ * feb00000    c8000000        1M              MSF
+ * fec00000    df000000        1M              PCI CSRs
+ * fed00000    de000000        1M              PCI CREG
+ * fee00000    d6000000        1M              INTCTL
+ * fef00000    c0000000        1M              CAP
+ */
+
 /* 
  * Static I/O regions.
  *
 #define        IXP2000_PCI_CSR_VIRT_BASE       0xfec00000
 #define        IXP2000_PCI_CSR_SIZE            0x00100000
 
+#define IXP2000_MSF_PHYS_BASE          0xc8000000
+#define IXP2000_MSF_VIRT_BASE          0xfeb00000
+#define IXP2000_MSF_SIZE               0x00100000
+
 #define IXP2000_PCI_IO_PHYS_BASE       0xd8000000
 #define        IXP2000_PCI_IO_VIRT_BASE        0xfd000000
 #define IXP2000_PCI_IO_SIZE            0x01000000
 #define PCI_CONTROL_BE_DEI             (1 << 21)       /* Big Endian Data Enable In  */
 #define PCI_CONTROL_BE_BEO             (1 << 20)       /* Big Endian Byte Enable Out */
 #define PCI_CONTROL_BE_BEI             (1 << 19)       /* Big Endian Byte Enable In  */
-#define PCI_CONTROL_PNR                        (1 << 17)       /* PCI Not Reset bit */
+#define PCI_CONTROL_IEE                        (1 << 17)       /* I/O cycle Endian swap Enable */
 
 #define IXP2000_PCI_RST_REL            (1 << 2)
 #define CFG_RST_DIR                    (*IXP2000_PCI_CONTROL & IXP2000_PCICNTL_PCF)
index 901bba6d02b47bd3d2891b3a39804cbc31182d08..52ded516ea5caed2d85aff56000d2985af06daf8 100644 (file)
@@ -138,30 +138,10 @@ struct ixp2000_flash_data {
        unsigned long (*bank_setup)(unsigned long);
 };
 
-/*
- * GPIO helper functions
- */
-#define        GPIO_IN         0
-#define        GPIO_OUT        1
-
-extern void gpio_line_config(int line, int style);
-
-static inline int gpio_line_get(int line)
-{
-       return (((*IXP2000_GPIO_PLR) >> line) & 1);
-}
-
-static inline void gpio_line_set(int line, int value)
-{
-       if (value) 
-               ixp2000_reg_write(IXP2000_GPIO_POSR, (1 << line));
-       else 
-               ixp2000_reg_write(IXP2000_GPIO_POCR, (1 << line));
-}
-
 struct ixp2000_i2c_pins {
        unsigned long sda_pin;
        unsigned long scl_pin;
 };
 
+
 #endif /*  !__ASSEMBLY__ */
index 473dff4ec5616cbf2795aaf9144db06185d2f421..275136963a0ccfbe1a0385a3809370c5494f5d26 100644 (file)
@@ -17,4 +17,4 @@
  * The vmalloc() routines leaves a hole of 4kB between each vmalloced
  * area for the same reason. ;)
  */
-#define VMALLOC_END        0xfaffefff
+#define VMALLOC_END        0xfb000000
index 4499ae8e4b448c2f5bf9d729770cc7a51ee554bb..2e23651e217fc554a073a8ac77337dd795460f52 100644 (file)
@@ -15,6 +15,7 @@
                 tst     \rx, #1                 @ MMU enabled?
                 moveq   \rx, #0xc8000000
                 movne   \rx, #0xff000000
+               orrne   \rx, \rx, #0x00b00000
                 add     \rx,\rx,#3              @ Uart regs are at off set of 3 if
                                                @ byte writes used - Big Endian.
                 .endm
index 8eeb1db6309df154ad8ee44afa2ea2ebda87aee4..004696a95bdb70ef475b2425154332f24a1386ea 100644 (file)
 #define IXP4XX_PERIPHERAL_BASE_VIRT    (0xFFBF2000)
 #define IXP4XX_PERIPHERAL_REGION_SIZE  (0x0000C000)
 
+/*
+ * Debug UART
+ *
+ * This is basically a remap of UART1 into a region that is section
+ * aligned so that it * can be used with the low-level debug code.
+ */
+#define        IXP4XX_DEBUG_UART_BASE_PHYS     (0xC8000000)
+#define        IXP4XX_DEBUG_UART_BASE_VIRT     (0xffb00000)
+#define        IXP4XX_DEBUG_UART_REGION_SIZE   (0x00001000)
+
 #define IXP4XX_EXP_CS0_OFFSET  0x00
 #define IXP4XX_EXP_CS1_OFFSET   0x04
 #define IXP4XX_EXP_CS2_OFFSET   0x08
index 1438c6cef0caa1bd9bf5fb7ba39b769e96c75fe6..054fb9a8e0c684052ec4046be5c887c61538582b 100644 (file)
 #      define   HMC_TLLATTACH          (1 << 6)
 #      define   OTG_HMC(w)             (((w)>>0)&0x3f)
 #define OTG_CTRL_REG                   OTG_REG32(0x0c)
+#      define   OTG_USB2_EN            (1 << 29)
+#      define   OTG_USB2_DP            (1 << 28)
+#      define   OTG_USB2_DM            (1 << 27)
+#      define   OTG_USB1_EN            (1 << 26)
+#      define   OTG_USB1_DP            (1 << 25)
+#      define   OTG_USB1_DM            (1 << 24)
+#      define   OTG_USB0_EN            (1 << 23)
+#      define   OTG_USB0_DP            (1 << 22)
+#      define   OTG_USB0_DM            (1 << 21)
 #      define   OTG_ASESSVLD           (1 << 20)
 #      define   OTG_BSESSEND           (1 << 19)
 #      define   OTG_BSESSVLD           (1 << 18)
index f288e74b67c2307bdc2587fa66ec724608bbf334..b6ec68879176158e1f6e4dfbf46e4091d8d4aaa9 100644 (file)
@@ -11,6 +11,8 @@
  *
 */
 
+#include "hardware.h"
+
                .macro  addruart,rx
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
diff --git a/include/asm-arm/arch-s3c2410/audio.h b/include/asm-arm/arch-s3c2410/audio.h
new file mode 100644 (file)
index 0000000..0d276e6
--- /dev/null
@@ -0,0 +1,49 @@
+/* linux/include/asm-arm/arch-s3c2410/audio.h
+ *
+ * (c) 2004-2005 Simtec Electronics
+ *     http://www.simtec.co.uk/products/SWLINUX/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX - Audio platfrom_device info
+ *
+ * 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.
+ *
+ * Changelog:
+ *     20-Nov-2004 BJD  Created file
+ *     07-Mar-2005 BJD  Added suspend/resume calls
+*/
+
+#ifndef __ASM_ARCH_AUDIO_H
+#define __ASM_ARCH_AUDIO_H __FILE__
+
+/* struct s3c24xx_iis_ops
+ *
+ * called from the s3c24xx audio core to deal with the architecture
+ * or the codec's setup and control.
+ *
+ * the pointer to itself is passed through in case the caller wants to
+ * embed this in an larger structure for easy reference to it's context.
+*/
+
+struct s3c24xx_iis_ops {
+       struct module *owner;
+
+       int     (*startup)(struct s3c24xx_iis_ops *me);
+       void    (*shutdown)(struct s3c24xx_iis_ops *me);
+       int     (*suspend)(struct s3c24xx_iis_ops *me);
+       int     (*resume)(struct s3c24xx_iis_ops *me);
+
+       int     (*open)(struct s3c24xx_iis_ops *me, snd_pcm_substream_t *strm);
+       int     (*close)(struct s3c24xx_iis_ops *me, snd_pcm_substream_t *strm);
+       int     (*prepare)(struct s3c24xx_iis_ops *me, snd_pcm_substream_t *strm, snd_pcm_runtime_t *rt);
+};
+
+struct s3c24xx_platdata_iis {
+       const char              *codec_clk;
+       struct s3c24xx_iis_ops  *ops;
+       int                     (*match_dev)(struct device *dev);
+};
+
+#endif /* __ASM_ARCH_AUDIO_H */
diff --git a/include/asm-arm/hardware/arm_timer.h b/include/asm-arm/hardware/arm_timer.h
new file mode 100644 (file)
index 0000000..04be3bd
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __ASM_ARM_HARDWARE_ARM_TIMER_H
+#define __ASM_ARM_HARDWARE_ARM_TIMER_H
+
+#define TIMER_LOAD     0x00
+#define TIMER_VALUE    0x04
+#define TIMER_CTRL     0x08
+#define TIMER_CTRL_ONESHOT     (1 << 0)
+#define TIMER_CTRL_32BIT       (1 << 1)
+#define TIMER_CTRL_DIV1                (0 << 2)
+#define TIMER_CTRL_DIV16       (1 << 2)
+#define TIMER_CTRL_DIV256      (2 << 2)
+#define TIMER_CTRL_IE          (1 << 5)        /* Interrupt Enable (versatile only) */
+#define TIMER_CTRL_PERIODIC    (1 << 6)
+#define TIMER_CTRL_ENABLE      (1 << 7)
+
+#define TIMER_INTCLR   0x0c
+#define TIMER_RIS      0x10
+#define TIMER_MIS      0x14
+#define TIMER_BGLOAD   0x18
+
+#endif
index 2114acb3d2374c10a04aa3278ff095ea269b621d..4f68c8a5a1998cd9f222c32831875e0f8a1ea97a 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 /*
- *  This file contains the i386 architecture specific IDE code.
+ *  This file contains the ARM architecture specific IDE code.
  */
 
 #ifndef __ASMARM_IDE_H
index 08a46302d26556053e4cdbce8bcc60a164a51011..cfa71a0dffb655764153153f6ee7a5ddc338f016 100644 (file)
@@ -82,7 +82,7 @@ extern void __readwrite_bug(const char *fn);
  * only.  Their primary purpose is to access PCI and ISA peripherals.
  *
  * Note that for a big endian machine, this implies that the following
- * big endian mode connectivity is in place, as described by numerious
+ * big endian mode connectivity is in place, as described by numerous
  * ARM documents:
  *
  *    PCI:  D0-D7   D8-D15 D16-D23 D24-D31
@@ -275,6 +275,7 @@ extern void __iounmap(void __iomem *addr);
 /*
  * io{read,write}{8,16,32} macros
  */
+#ifndef ioread8
 #define ioread8(p)     ({ unsigned int __v = __raw_readb(p); __v; })
 #define ioread16(p)    ({ unsigned int __v = le16_to_cpu(__raw_readw(p)); __v; })
 #define ioread32(p)    ({ unsigned int __v = le32_to_cpu(__raw_readl(p)); __v; })
@@ -293,6 +294,7 @@ extern void __iounmap(void __iomem *addr);
 
 extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
 extern void ioport_unmap(void __iomem *addr);
+#endif
 
 struct pci_dev;
 
index 5cf4fd659fd54d4b64e2c4dbd9faa1690da22f72..2cf279a4401773e009cb163ecb32ea1cb477ecad 100644 (file)
@@ -39,8 +39,31 @@ struct sys_timer {
        void                    (*suspend)(void);
        void                    (*resume)(void);
        unsigned long           (*offset)(void);
+
+#ifdef CONFIG_NO_IDLE_HZ
+       struct dyn_tick_timer   *dyn_tick;
+#endif
+};
+
+#ifdef CONFIG_NO_IDLE_HZ
+
+#define DYN_TICK_SKIPPING      (1 << 2)
+#define DYN_TICK_ENABLED       (1 << 1)
+#define DYN_TICK_SUITABLE      (1 << 0)
+
+struct dyn_tick_timer {
+       unsigned int    state;                  /* Current state */
+       int             (*enable)(void);        /* Enables dynamic tick */
+       int             (*disable)(void);       /* Disables dynamic tick */
+       void            (*reprogram)(unsigned long); /* Reprograms the timer */
+       int             (*handler)(int, void *, struct pt_regs *);
 };
 
+void timer_dyn_reprogram(void);
+#else
+#define timer_dyn_reprogram()  do { } while (0)
+#endif
+
 extern struct sys_timer *system_timer;
 extern void timer_tick(struct pt_regs *);
 
index 40ffaefbeb1a7eca0f2da3dc4c34c0220f1ea524..e300646fe650dcf920ea4d4fc6aa23d72c7e39e2 100644 (file)
@@ -42,6 +42,16 @@ static inline void pcibios_penalize_isa_irq(int irq)
 #define pci_unmap_len(PTR, LEN_NAME)           ((PTR)->LEN_NAME)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)  (((PTR)->LEN_NAME) = (VAL))
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+#endif
+
 #define HAVE_PCI_MMAP
 extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                                enum pci_mmap_state mmap_state, int write_combine);
index 46e69ae395af53a9d2c7db10be7479ec12836678..760f6e65af05583c2faea5b1997989d8435c5c3b 100644 (file)
@@ -114,6 +114,7 @@ typedef unsigned long sigset_t;
 #define SIGSTKSZ       8192
 
 #ifdef __KERNEL__
+#define SA_TIMER               0x40000000
 #define SA_IRQNOMASK           0x08000000
 #endif
 
index 39dd7008013c839a102bc49f53ba4ba5691ab864..cdf49f442fd220db66c2864e3fd6c14168b470ce 100644 (file)
@@ -145,34 +145,12 @@ extern unsigned int user_debug;
 #define set_wmb(var, value) do { var = value; wmb(); } while (0)
 #define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
 
-#ifdef CONFIG_SMP
 /*
- * Define our own context switch locking.  This allows us to enable
- * interrupts over the context switch, otherwise we end up with high
- * interrupt latency.  The real problem area is switch_mm() which may
- * do a full cache flush.
+ * switch_mm() may do a full cache flush over the context switch,
+ * so enable interrupts over the context switch to avoid high
+ * latency.
  */
-#define prepare_arch_switch(rq,next)                                   \
-do {                                                                   \
-       spin_lock(&(next)->switch_lock);                                \
-       spin_unlock_irq(&(rq)->lock);                                   \
-} while (0)
-
-#define finish_arch_switch(rq,prev)                                    \
-       spin_unlock(&(prev)->switch_lock)
-
-#define task_running(rq,p)                                             \
-       ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock))
-#else
-/*
- * Our UP-case is more simple, but we assume knowledge of how
- * spin_unlock_irq() and friends are implemented.  This avoids
- * us needlessly decrementing and incrementing the preempt count.
- */
-#define prepare_arch_switch(rq,next)   local_irq_enable()
-#define finish_arch_switch(rq,prev)    spin_unlock(&(rq)->lock)
-#define task_running(rq,p)             ((rq)->curr == (p))
-#endif
+#define __ARCH_WANT_INTERRUPTS_ON_CTXSW
 
 /*
  * switch_to(prev, next) should switch from task `prev' to `next'
@@ -312,7 +290,6 @@ do {                                                                        \
 })
 
 #ifdef CONFIG_SMP
-#error SMP not supported
 
 #define smp_mb()               mb()
 #define smp_rmb()              rmb()
@@ -326,6 +303,8 @@ do {                                                                        \
 #define smp_wmb()              barrier()
 #define smp_read_barrier_depends()             do { } while(0)
 
+#endif /* CONFIG_SMP */
+
 #if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110)
 /*
  * On the StrongARM, "swp" is terminally broken since it bypasses the
@@ -338,9 +317,16 @@ do {                                                                       \
  *
  * We choose (1) since its the "easiest" to achieve here and is not
  * dependent on the processor type.
+ *
+ * NOTE that this solution won't work on an SMP system, so explcitly
+ * forbid it here.
  */
+#ifdef CONFIG_SMP
+#error SMP is not supported on SA1100/SA110
+#else
 #define swp_is_buggy
 #endif
+#endif
 
 static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
 {
@@ -383,8 +369,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
        return ret;
 }
 
-#endif /* CONFIG_SMP */
-
 #endif /* __ASSEMBLY__ */
 
 #define arch_align_stack(x) (x)
index 8a864b11856933418b723a0462db44b6a166b707..9387a5e1ffe007ef5ed62c4ad79308f651749118 100644 (file)
@@ -235,7 +235,7 @@ extern struct cpu_tlb_fns cpu_tlb;
 
 #define tlb_flag(f)    ((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f)))
 
-static inline void flush_tlb_all(void)
+static inline void local_flush_tlb_all(void)
 {
        const int zero = 0;
        const unsigned int __tlb_flag = __cpu_tlb_flags;
@@ -253,7 +253,7 @@ static inline void flush_tlb_all(void)
                asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
 }
 
-static inline void flush_tlb_mm(struct mm_struct *mm)
+static inline void local_flush_tlb_mm(struct mm_struct *mm)
 {
        const int zero = 0;
        const int asid = ASID(mm);
@@ -282,7 +282,7 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
 }
 
 static inline void
-flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
+local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
 {
        const int zero = 0;
        const unsigned int __tlb_flag = __cpu_tlb_flags;
@@ -313,7 +313,7 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
                asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (uaddr));
 }
 
-static inline void flush_tlb_kernel_page(unsigned long kaddr)
+static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
 {
        const int zero = 0;
        const unsigned int __tlb_flag = __cpu_tlb_flags;
@@ -384,8 +384,24 @@ static inline void clean_pmd_entry(pmd_t *pmd)
 /*
  * Convert calls to our calling convention.
  */
-#define flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma)
-#define flush_tlb_kernel_range(s,e)    __cpu_flush_kern_tlb_range(s,e)
+#define local_flush_tlb_range(vma,start,end)   __cpu_flush_user_tlb_range(start,end,vma)
+#define local_flush_tlb_kernel_range(s,e)      __cpu_flush_kern_tlb_range(s,e)
+
+#ifndef CONFIG_SMP
+#define flush_tlb_all          local_flush_tlb_all
+#define flush_tlb_mm           local_flush_tlb_mm
+#define flush_tlb_page         local_flush_tlb_page
+#define flush_tlb_kernel_page  local_flush_tlb_kernel_page
+#define flush_tlb_range                local_flush_tlb_range
+#define flush_tlb_kernel_range local_flush_tlb_kernel_range
+#else
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr);
+extern void flush_tlb_kernel_page(unsigned long kaddr);
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
+extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+#endif
 
 /*
  * if PG_dcache_dirty is set for the page, we need to ensure that any
index 21e1df31f086f6c6651af9a9e4187ea4445199c6..5fc747d1b501f74c62b5f4f4ebb5e3474a5c0998 100644 (file)
 #if defined(CONFIG_ARCH_A5K)
      /* UART CLK        PORT  IRQ     FLAGS        */
 
-#define STD_SERIAL_PORT_DEFNS                                           \
+#define SERIAL_PORT_DFNS                                                \
         { 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS },     /* ttyS0 */     \
         { 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS },     /* ttyS1 */
 
 #else
 
-#define STD_SERIAL_PORT_DEFNS                                           \
+#define SERIAL_PORT_DFNS                                                \
         { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS0 */     \
         { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS1 */
 
 #endif
 
-#define EXTRA_SERIAL_PORT_DEFNS \
-        { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS2 */     \
-        { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS3 */     \
-        { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS4 */     \
-        { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS5 */     \
-        { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS6 */     \
-        { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS7 */     \
-        { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS8 */     \
-        { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS9 */     \
-        { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS10 */    \
-        { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS11 */    \
-        { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS12 */    \
-        { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS13 */
-
-#define SERIAL_PORT_DFNS               \
-       STD_SERIAL_PORT_DEFNS           \
-       EXTRA_SERIAL_PORT_DEFNS
-
 #endif
index a6a469231f6270e67475f99f3fe4298c600cbef2..b4efe5e3591a5b22a7f511b606c13c4d3cf4b0ce 100644 (file)
@@ -57,6 +57,16 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
  */
 #define PCI_DMA_BUS_IS_PHYS    (1)
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+#endif
+
 /*
  *     These are pretty much arbitary with the CoMEM implementation.
  *     We have the whole address space to ourselves.
index 99cef06a364a6cdc3a3fc4756cb29646cbeb7925..b3bb326ae5b618a74cc3ca79d158f6d8b92c5743 100644 (file)
@@ -73,7 +73,7 @@
        }
 
 #define SECURITY_INIT                                                  \
-       .security_initcall.init : {                                     \
+       .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \
                VMLINUX_SYMBOL(__security_initcall_start) = .;          \
                *(.security_initcall.init)                              \
                VMLINUX_SYMBOL(__security_initcall_end) = .;            \
index a5810cf7b5783b9c156a33af77b1d1f0e960246e..6a1b1882285c004a1c5f80b109c046fe483c8bee 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/pm.h>
 #include <asm/fixmap.h>
 #include <asm/apicdef.h>
+#include <asm/processor.h>
 #include <asm/system.h>
 
 #define Dprintk(x...)
 #define APIC_VERBOSE 1
 #define APIC_DEBUG   2
 
+extern int enable_local_apic;
 extern int apic_verbosity;
 
+static inline void lapic_disable(void)
+{
+       enable_local_apic = -1;
+       clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
+}
+
+static inline void lapic_enable(void)
+{
+       enable_local_apic = 1;
+}
+
 /*
  * Define the default level of output to be very little
  * This can be turned up by using apic=verbose for more
@@ -87,7 +100,7 @@ extern void (*wait_timer_tick)(void);
 extern int get_maxlvt(void);
 extern void clear_local_APIC(void);
 extern void connect_bsp_APIC (void);
-extern void disconnect_bsp_APIC (void);
+extern void disconnect_bsp_APIC (int virt_wire_setup);
 extern void disable_local_APIC (void);
 extern void lapic_shutdown (void);
 extern int verify_local_APIC (void);
index c689554ad5b98a9db353e427ed58018c1b09b767..0fed5e3c699c738009d3113edcc2c7436433f6c0 100644 (file)
 #define                        APIC_LVT_REMOTE_IRR             (1<<14)
 #define                        APIC_INPUT_POLARITY             (1<<13)
 #define                        APIC_SEND_PENDING               (1<<12)
+#define                        APIC_MODE_MASK                  0x700
 #define                        GET_APIC_DELIVERY_MODE(x)       (((x)>>8)&0x7)
 #define                        SET_APIC_DELIVERY_MODE(x,y)     (((x)&~0x700)|((y)<<8))
 #define                                APIC_MODE_FIXED         0x0
 #define                                APIC_MODE_NMI           0x4
-#define                                APIC_MODE_EXINT         0x7
+#define                                APIC_MODE_EXTINT        0x7
 #define        APIC_LVT1       0x360
 #define                APIC_LVTERR     0x370
 #define                APIC_TMICT      0x380
index 002740b2195113799e2c7fe592f3f46e1b8e2a71..e7252c216ca81cc8d6543f51b51fa1f8a216d194 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/cpu.h>
 #include <linux/topology.h>
 #include <linux/nodemask.h>
+#include <linux/percpu.h>
 
 #include <asm/node.h>
 
@@ -16,4 +17,5 @@ extern int arch_register_cpu(int num);
 extern void arch_unregister_cpu(int);
 #endif
 
+DECLARE_PER_CPU(int, cpu_state);
 #endif /* _ASM_I386_CPU_H_ */
index 1df42bf347df6783e5d1d8bd7c6849505f7537d3..0fd331306b60115f9b889fe74313722ae28141ac 100644 (file)
@@ -70,6 +70,7 @@ void *kmap(struct page *page);
 void kunmap(struct page *page);
 void *kmap_atomic(struct page *page, enum km_type type);
 void kunmap_atomic(void *kvaddr, enum km_type type);
+void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
 struct page *kmap_atomic_to_page(void *ptr);
 
 #define flush_cache_kmaps()    do { } while (0)
diff --git a/include/asm-i386/i8253.h b/include/asm-i386/i8253.h
new file mode 100644 (file)
index 0000000..015d8df
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __ASM_I8253_H__
+#define __ASM_I8253_H__
+
+extern spinlock_t i8253_lock;
+
+#endif /* __ASM_I8253_H__ */
index 859ebf4da632cabe31276fb5d8ff6cb8121288bc..79dfab87135d5448673e92bc60d42fb5b096bf75 100644 (file)
@@ -41,13 +41,17 @@ static __inline__ int ide_default_irq(unsigned long base)
 
 static __inline__ unsigned long ide_default_io_base(int index)
 {
+       if (pci_find_device(PCI_ANY_ID, PCI_ANY_ID, NULL) == NULL) {
+               switch(index) {
+                       case 2: return 0x1e8;
+                       case 3: return 0x168;
+                       case 4: return 0x1e0;
+                       case 5: return 0x160;
+               }
+       }
        switch (index) {
                case 0: return 0x1f0;
                case 1: return 0x170;
-               case 2: return 0x1e8;
-               case 3: return 0x168;
-               case 4: return 0x1e0;
-               case 5: return 0x160;
                default:
                        return 0;
        }
index 05b9e61b0a7252c51ab218735160da67e39b0afc..270f1986b19f781ff7788a126d2d1486b5e5bfbc 100644 (file)
@@ -29,13 +29,19 @@ extern void release_vm86_irqs(struct task_struct *);
 
 #ifdef CONFIG_4KSTACKS
   extern void irq_ctx_init(int cpu);
+  extern void irq_ctx_exit(int cpu);
 # define __ARCH_HAS_DO_SOFTIRQ
 #else
 # define irq_ctx_init(cpu) do { } while (0)
+# define irq_ctx_exit(cpu) do { } while (0)
 #endif
 
 #ifdef CONFIG_IRQBALANCE
 extern int irqbalance_disable(char *str);
 #endif
 
+#ifdef CONFIG_HOTPLUG_CPU
+extern void fixup_irqs(cpumask_t map);
+#endif
+
 #endif /* _ASM_IRQ_H */
index de6498b0d49381e0d37cb0318ab245d6c28acdd4..b3f8d5f59d5d8fc02cc1c5f88bce01921c641496 100644 (file)
@@ -18,7 +18,7 @@ struct die_args {
 };
 
 /* Note - you should never unregister because that can race with NMIs.
-   If you really want to do it first unregister - then synchronize_kernel - then free.
+   If you really want to do it first unregister - then synchronize_sched - then free.
   */
 int register_die_notifier(struct notifier_block *nb);
 extern struct notifier_block *i386die_chain;
diff --git a/include/asm-i386/kexec.h b/include/asm-i386/kexec.h
new file mode 100644 (file)
index 0000000..6ed2a03
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _I386_KEXEC_H
+#define _I386_KEXEC_H
+
+#include <asm/fixmap.h>
+
+/*
+ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
+ * I.e. Maximum page that is mapped directly into kernel memory,
+ * and kmap is not required.
+ *
+ * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct
+ * calculation for the amount of memory directly mappable into the
+ * kernel memory space.
+ */
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
+/* Maximum address we can use for the control code buffer */
+#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE
+
+#define KEXEC_CONTROL_CODE_SIZE        4096
+
+/* The native architecture */
+#define KEXEC_ARCH KEXEC_ARCH_386
+
+#define MAX_NOTE_BYTES 1024
+typedef u32 note_buf_t[MAX_NOTE_BYTES/4];
+
+extern note_buf_t crash_notes[];
+
+#endif /* _I386_KEXEC_H */
index 03dd13a48a8cb4feee46e2b4559b8654ab22027f..56211414fc9595bc1aeb7a854e1133b6e5238036 100644 (file)
@@ -1,6 +1,7 @@
 /* defines for inline arch setup functions */
 
 #include <asm/apic.h>
+#include <asm/i8259.h>
 
 /**
  * do_timer_interrupt_hook - hook into timer tick
index 6f2b17a2008995d4939313982b165a8937ea6214..cc756a67cd63fee819143ff9994acf675de2de75 100644 (file)
@@ -4,11 +4,34 @@
 void send_IPI_mask_bitmask(cpumask_t mask, int vector);
 void __send_IPI_shortcut(unsigned int shortcut, int vector);
 
+extern int no_broadcast;
+
 static inline void send_IPI_mask(cpumask_t mask, int vector)
 {
        send_IPI_mask_bitmask(mask, vector);
 }
 
+static inline void __local_send_IPI_allbutself(int vector)
+{
+       if (no_broadcast) {
+               cpumask_t mask = cpu_online_map;
+               int this_cpu = get_cpu();
+
+               cpu_clear(this_cpu, mask);
+               send_IPI_mask(mask, vector);
+               put_cpu();
+       } else
+               __send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
+}
+
+static inline void __local_send_IPI_all(int vector)
+{
+       if (no_broadcast)
+               send_IPI_mask(cpu_online_map, vector);
+       else
+               __send_IPI_shortcut(APIC_DEST_ALLINC, vector);
+}
+
 static inline void send_IPI_allbutself(int vector)
 {
        /*
@@ -18,13 +41,13 @@ static inline void send_IPI_allbutself(int vector)
        if (!(num_online_cpus() > 1))
                return;
 
-       __send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
+       __local_send_IPI_allbutself(vector);
        return;
 }
 
 static inline void send_IPI_all(int vector)
 {
-       __send_IPI_shortcut(APIC_DEST_ALLINC, vector);
+       __local_send_IPI_all(vector);
 }
 
 #endif /* __ASM_MACH_IPI_H */
index dea8f8e6d86ed60dc5bcfdafd324fd16f9c421ef..8d93f732d72d0586dc1598542ffa354893351808 100644 (file)
@@ -126,9 +126,12 @@ extern int page_is_ram(unsigned long pagenr);
 
 #ifdef __ASSEMBLY__
 #define __PAGE_OFFSET          (0xC0000000)
+#define __PHYSICAL_START       CONFIG_PHYSICAL_START
 #else
 #define __PAGE_OFFSET          (0xC0000000UL)
+#define __PHYSICAL_START       ((unsigned long)CONFIG_PHYSICAL_START)
 #endif
+#define __KERNEL_START         (__PAGE_OFFSET + __PHYSICAL_START)
 
 
 #define PAGE_OFFSET            ((unsigned long)__PAGE_OFFSET)
index fb749b85a739675b804bc5a3baf07b7a4d574827..3561899eb826bee418bbca0f457398736dc6b90e 100644 (file)
@@ -99,6 +99,16 @@ static inline void pcibios_add_platform_entries(struct pci_dev *dev)
 {
 }
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+#endif
+
 #endif /* __KERNEL__ */
 
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
index c76c50e9622533caaeaf44f5e9ba35b9ff972a19..6f0f93d0d41741ea7f094a3975f7cae5843aa44f 100644 (file)
@@ -691,5 +691,7 @@ extern void select_idle_routine(const struct cpuinfo_x86 *c);
 #define cache_line_size() (boot_cpu_data.x86_cache_alignment)
 
 extern unsigned long boot_option_idle_override;
+extern void enable_sep_cpu(void);
+extern int sysenter_setup(void);
 
 #endif /* __ASM_I386_PROCESSOR_H */
index 21ddecc77c773fb374a234e2285627541b810adb..e1ecfccb743b7a16fc7934cab046ac2bdd8aaa51 100644 (file)
 #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
 #endif
 
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#define HUB6_FLAGS 0
-#endif
-
-#define MCA_COM_FLAGS  (STD_COM_FLAGS|ASYNC_BOOT_ONLYMCA)
-
-/*
- * The following define the access methods for the HUB6 card. All
- * access is through two ports for all 24 possible chips. The card is
- * selected through the high 2 bits, the port on that card with the
- * "middle" 3 bits, and the register on that port with the bottom
- * 3 bits.
- *
- * While the access port and interrupt is configurable, the default
- * port locations are 0x302 for the port control register, and 0x303
- * for the data read/write register. Normally, the interrupt is at irq3
- * but can be anything from 3 to 7 inclusive. Note that using 3 will
- * require disabling com2.
- */
-
-#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
-
-#define STD_SERIAL_PORT_DEFNS                  \
+#define SERIAL_PORT_DFNS                       \
        /* UART CLK   PORT IRQ     FLAGS        */                      \
        { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },      /* ttyS0 */     \
        { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },      /* ttyS1 */     \
        { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },      /* ttyS2 */     \
        { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },     /* ttyS3 */
-
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS                        \
-       { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS },     /* ttyS4 */     \
-       { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },     /* ttyS5 */     \
-       { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },     /* ttyS6 */     \
-       { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },     /* ttyS7 */     \
-       { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },     /* ttyS8 */     \
-       { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },     /* ttyS9 */     \
-       { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },     /* ttyS10 */    \
-       { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },     /* ttyS11 */    \
-       { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },       /* ttyS12 */    \
-       { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },       /* ttyS13 */    \
-       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS14 (spare) */            \
-       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS15 (spare) */            \
-       { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },        /* ttyS16 */    \
-       { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },        /* ttyS17 */    \
-       { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },        /* ttyS18 */    \
-       { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },        /* ttyS19 */    \
-       { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },        /* ttyS20 */    \
-       { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },        /* ttyS21 */    \
-       { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },        /* ttyS22 */    \
-       { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },        /* ttyS23 */    \
-       { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },        /* ttyS24 */    \
-       { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },        /* ttyS25 */    \
-       { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },        /* ttyS26 */    \
-       { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },        /* ttyS27 */    \
-       { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },        /* ttyS28 */    \
-       { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },        /* ttyS29 */    \
-       { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },        /* ttyS30 */    \
-       { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },        /* ttyS31 */
-#else
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif
-
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
- */
-#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
-#define HUB6_SERIAL_PORT_DFNS          \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) },  /* ttyS32 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) },  /* ttyS33 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) },  /* ttyS34 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) },  /* ttyS35 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) },  /* ttyS36 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) },  /* ttyS37 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) },  /* ttyS38 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) },  /* ttyS39 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) },  /* ttyS40 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) },  /* ttyS41 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) },  /* ttyS42 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) },  /* ttyS43 */
-#else
-#define HUB6_SERIAL_PORT_DFNS
-#endif
-
-#ifdef CONFIG_MCA
-#define MCA_SERIAL_PORT_DFNS                   \
-       { 0, BASE_BAUD, 0x3220, 3, MCA_COM_FLAGS },     \
-       { 0, BASE_BAUD, 0x3228, 3, MCA_COM_FLAGS },     \
-       { 0, BASE_BAUD, 0x4220, 3, MCA_COM_FLAGS },     \
-       { 0, BASE_BAUD, 0x4228, 3, MCA_COM_FLAGS },     \
-       { 0, BASE_BAUD, 0x5220, 3, MCA_COM_FLAGS },     \
-       { 0, BASE_BAUD, 0x5228, 3, MCA_COM_FLAGS },
-#else
-#define MCA_SERIAL_PORT_DFNS
-#endif
-
-#define SERIAL_PORT_DFNS               \
-       STD_SERIAL_PORT_DEFNS           \
-       EXTRA_SERIAL_PORT_DEFNS         \
-       HUB6_SERIAL_PORT_DFNS           \
-       MCA_SERIAL_PORT_DFNS
-
index 55ef31f66bbec2c7771a7571658dad9451dd4823..edad9b4712fafe5ffbc9fed0cd1d075bf6cc1a79 100644 (file)
@@ -42,10 +42,17 @@ extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
 extern void smp_invalidate_rcv(void);          /* Process an NMI */
 extern void (*mtrr_hook) (void);
 extern void zap_low_mappings (void);
+extern void lock_ipi_call_lock(void);
+extern void unlock_ipi_call_lock(void);
 
 #define MAX_APICID 256
 extern u8 x86_cpu_to_apicid[];
 
+#ifdef CONFIG_HOTPLUG_CPU
+extern void cpu_exit_clear(void);
+extern void cpu_uninit(void);
+#endif
+
 /*
  * This function is needed by all SMP systems. It must _always_ be valid
  * from the initial startup. We map APIC_BASE very early in page_setup(),
@@ -83,6 +90,9 @@ static __inline int logical_smp_processor_id(void)
 }
 
 #endif
+
+extern int __cpu_disable(void);
+extern void __cpu_die(unsigned int cpu);
 #endif /* !__ASSEMBLY__ */
 
 #define NO_PROC_ID             0xFF            /* No processor magic marker */
index 6a78ac58c19463e6f0a30e52a97b2bed8bd2c4c2..02c8f5d22065df19ec9adab857aabcd8a5627364 100644 (file)
@@ -116,7 +116,8 @@ __asm__ __volatile__(
        "orb $1,%%al\n"
        "3:"
        :"=a" (__res), "=&S" (d0), "=&D" (d1)
-                    :"1" (cs),"2" (ct));
+       :"1" (cs),"2" (ct)
+       :"memory");
 return __res;
 }
 
@@ -138,8 +139,9 @@ __asm__ __volatile__(
        "3:\tsbbl %%eax,%%eax\n\t"
        "orb $1,%%al\n"
        "4:"
-                    :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
-                    :"1" (cs),"2" (ct),"3" (count));
+       :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
+       :"1" (cs),"2" (ct),"3" (count)
+       :"memory");
 return __res;
 }
 
@@ -158,7 +160,9 @@ __asm__ __volatile__(
        "movl $1,%1\n"
        "2:\tmovl %1,%0\n\t"
        "decl %0"
-       :"=a" (__res), "=&S" (d0) : "1" (s),"0" (c));
+       :"=a" (__res), "=&S" (d0)
+       :"1" (s),"0" (c)
+       :"memory");
 return __res;
 }
 
@@ -175,7 +179,9 @@ __asm__ __volatile__(
        "leal -1(%%esi),%0\n"
        "2:\ttestb %%al,%%al\n\t"
        "jne 1b"
-       :"=g" (__res), "=&S" (d0), "=&a" (d1) :"0" (0),"1" (s),"2" (c));
+       :"=g" (__res), "=&S" (d0), "=&a" (d1)
+       :"0" (0),"1" (s),"2" (c)
+       :"memory");
 return __res;
 }
 
@@ -189,7 +195,9 @@ __asm__ __volatile__(
        "scasb\n\t"
        "notl %0\n\t"
        "decl %0"
-       :"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffffu));
+       :"=c" (__res), "=&D" (d0)
+       :"1" (s),"a" (0), "0" (0xffffffffu)
+       :"memory");
 return __res;
 }
 
@@ -333,7 +341,9 @@ __asm__ __volatile__(
        "je 1f\n\t"
        "movl $1,%0\n"
        "1:\tdecl %0"
-       :"=D" (__res), "=&c" (d0) : "a" (c),"0" (cs),"1" (count));
+       :"=D" (__res), "=&c" (d0)
+       :"a" (c),"0" (cs),"1" (count)
+       :"memory");
 return __res;
 }
 
@@ -369,7 +379,7 @@ __asm__ __volatile__(
        "je 2f\n\t"
        "stosb\n"
        "2:"
-       : "=&c" (d0), "=&D" (d1)
+       :"=&c" (d0), "=&D" (d1)
        :"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
        :"memory");
 return (s);    
@@ -392,7 +402,8 @@ __asm__ __volatile__(
        "jne 1b\n"
        "3:\tsubl %2,%0"
        :"=a" (__res), "=&d" (d0)
-       :"c" (s),"1" (count));
+       :"c" (s),"1" (count)
+       :"memory");
 return __res;
 }
 /* end of additional stuff */
@@ -473,7 +484,8 @@ static inline void * memscan(void * addr, int c, size_t size)
                "dec %%edi\n"
                "1:"
                : "=D" (addr), "=c" (size)
-               : "0" (addr), "1" (size), "a" (c));
+               : "0" (addr), "1" (size), "a" (c)
+               : "memory");
        return addr;
 }
 
index f22fab0cea26486bd323a0432a3c093e44ddec27..ab216e1370efb85fb3b6f73dab1ad588bf1382f7 100644 (file)
  */
 #define __flush_tlb_global()                                           \
        do {                                                            \
-               unsigned int tmpreg;                                    \
+               unsigned int tmpreg, cr4, cr4_orig;                     \
                                                                        \
                __asm__ __volatile__(                                   \
-                       "movl %1, %%cr4;  # turn off PGE     \n"        \
+                       "movl %%cr4, %2;  # turn off PGE     \n"        \
+                       "movl %2, %1;                        \n"        \
+                       "andl %3, %1;                        \n"        \
+                       "movl %1, %%cr4;                     \n"        \
                        "movl %%cr3, %0;                     \n"        \
                        "movl %0, %%cr3;  # flush TLB        \n"        \
                        "movl %2, %%cr4;  # turn PGE back on \n"        \
-                       : "=&r" (tmpreg)                                \
-                       : "r" (mmu_cr4_features & ~X86_CR4_PGE),        \
-                         "r" (mmu_cr4_features)                        \
+                       : "=&r" (tmpreg), "=&r" (cr4), "=&r" (cr4_orig) \
+                       : "i" (~X86_CR4_PGE)                            \
                        : "memory");                                    \
        } while (0)
 
index 6d0f67507b2101dcca96f484def09841fc82aa9c..2461b731781ebc182fd7b70c534b6dd87bb15e76 100644 (file)
@@ -74,11 +74,14 @@ static inline int node_to_first_cpu(int node)
        .imbalance_pct          = 125,                  \
        .cache_hot_time         = (10*1000000),         \
        .cache_nice_tries       = 1,                    \
+       .busy_idx               = 3,                    \
+       .idle_idx               = 1,                    \
+       .newidle_idx            = 2,                    \
+       .wake_idx               = 1,                    \
        .per_cpu_gain           = 100,                  \
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_EXEC       \
-                               | SD_BALANCE_NEWIDLE    \
-                               | SD_WAKE_IDLE          \
+                               | SD_BALANCE_FORK       \
                                | SD_WAKE_BALANCE,      \
        .last_balance           = jiffies,              \
        .balance_interval       = 1,                    \
index 176413fb9ae3b9922031e3ddf57197cbf4430fd1..e25e4c71a879a7687434a6f258a391a437fea81b 100644 (file)
 #define __NR_add_key           286
 #define __NR_request_key       287
 #define __NR_keyctl            288
+#define __NR_ioprio_set                289
+#define __NR_ioprio_get                290
 
-#define NR_syscalls 289
+#define NR_syscalls 291
 
 /*
  * user-visible error numbers are in the range -1 - -128: see
index 38a7a72791cc950c1db7eaf9b76d8fe263f20e0d..1093f35b3b906a32f4c9fa0a01df8ab1384a25fd 100644 (file)
@@ -71,8 +71,11 @@ static inline void iosapic_eoi(char __iomem *iosapic, u32 vector)
 }
 
 extern void __init iosapic_system_init (int pcat_compat);
-extern void __init iosapic_init (unsigned long address,
+extern int __devinit iosapic_init (unsigned long address,
                                    unsigned int gsi_base);
+#ifdef CONFIG_HOTPLUG
+extern int iosapic_remove (unsigned int gsi_base);
+#endif /* CONFIG_HOTPLUG */
 extern int gsi_to_vector (unsigned int gsi);
 extern int gsi_to_irq (unsigned int gsi);
 extern void iosapic_enable_intr (unsigned int vector);
@@ -94,11 +97,14 @@ extern unsigned int iosapic_version (char __iomem *addr);
 
 extern void iosapic_pci_fixup (int);
 #ifdef CONFIG_NUMA
-extern void __init map_iosapic_to_node (unsigned int, int);
+extern void __devinit map_iosapic_to_node (unsigned int, int);
 #endif
 #else
 #define iosapic_system_init(pcat_compat)                       do { } while (0)
-#define iosapic_init(address,gsi_base)                         do { } while (0)
+#define iosapic_init(address,gsi_base)                         (-EINVAL)
+#ifdef CONFIG_HOTPLUG
+#define iosapic_remove(gsi_base)                               (-ENODEV)
+#endif /* CONFIG_HOTPLUG */
 #define iosapic_register_intr(gsi,polarity,trigger)            (gsi)
 #define iosapic_unregister_intr(irq)                           do { } while (0)
 #define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger) do { } while (0)
index 7b700035e36de10211df784b66921d126f55a08e..bf36a32e37e4661dd4abaa944f55e7776c16ee65 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/ptrace.h>
 #include <asm/break.h>
 
+#define MAX_INSN_SIZE   16
 #define BREAK_INST     (long)(__IA64_BREAK_KPROBE << 6)
 
 typedef union cmp_inst {
@@ -63,6 +64,8 @@ typedef struct _bundle {
 
 #define JPROBE_ENTRY(pentry)   (kprobe_opcode_t *)pentry
 
+#define ARCH_SUPPORTS_KRETPROBES
+
 #define SLOT0_OPCODE_SHIFT     (37)
 #define SLOT1_p1_OPCODE_SHIFT  (37 - (64-46))
 #define SLOT2_OPCODE_SHIFT     (37)
@@ -93,11 +96,6 @@ struct arch_specific_insn {
        unsigned short target_br_reg;
 };
 
-/* ia64 does not need this */
-static inline void jprobe_return(void)
-{
-}
-
 /* ia64 does not need this */
 static inline void arch_copy_kprobe(struct kprobe *p)
 {
@@ -106,6 +104,12 @@ static inline void arch_copy_kprobe(struct kprobe *p)
 #ifdef CONFIG_KPROBES
 extern int kprobe_exceptions_notify(struct notifier_block *self,
                                    unsigned long val, void *data);
+
+/* ia64 does not need this */
+static inline void jprobe_return(void)
+{
+}
+
 #else                          /* !CONFIG_KPROBES */
 static inline int kprobe_exceptions_notify(struct notifier_block *self,
                                           unsigned long val, void *data)
index 0096e7e05012705baecbeaf4cbe654b76bbed767..e3e5fededb04c4c63301afd1e309c1f022d749b0 100644 (file)
@@ -132,6 +132,9 @@ reload_context (mm_context_t context)
        ia64_srlz_i();                  /* srlz.i implies srlz.d */
 }
 
+/*
+ * Must be called with preemption off
+ */
 static inline void
 activate_context (struct mm_struct *mm)
 {
index a8314ee4e7d2542d304ccb52f6ba0408ef2c83b9..0c4c5d801d3f8d3893ca02057d960f3fadc54c96 100644 (file)
@@ -82,6 +82,25 @@ extern int pcibios_prep_mwi (struct pci_dev *);
 #define sg_dma_len(sg)         ((sg)->dma_length)
 #define sg_dma_address(sg)     ((sg)->dma_address)
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       unsigned long cacheline_size;
+       u8 byte;
+
+       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+       if (byte == 0)
+               cacheline_size = 1024;
+       else
+               cacheline_size = (int) byte * 4;
+
+       *strat = PCI_DMA_BURST_MULTIPLE;
+       *strategy_parameter = cacheline_size;
+}
+#endif
+
 #define HAVE_PCI_MMAP
 extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
                                enum pci_mmap_state mmap_state, int write_combine);
index 8e3dbde1b429c167fe2a96af9966c7fb1fcb3ffb..e9eb7f62d32bb259f0ed8a52b836d8fa677e6b02 100644 (file)
@@ -17,6 +17,7 @@ extern char __start_gate_vtop_patchlist[], __end_gate_vtop_patchlist[];
 extern char __start_gate_fsyscall_patchlist[], __end_gate_fsyscall_patchlist[];
 extern char __start_gate_brl_fsys_bubble_down_patchlist[], __end_gate_brl_fsys_bubble_down_patchlist[];
 extern char __start_unwind[], __end_unwind[];
+extern char __start_ivt_text[], __end_ivt_text[];
 
 #endif /* _ASM_IA64_SECTIONS_H */
 
index 1bfdfb4d7b0110224b17f51a429f7d880c32c7a6..103d745dc5f2f9fc8eda359854310424cd63545c 100644 (file)
 #define TIO_SWIN_WIDGETNUM(x)          (((x)  >> TIO_SWIN_SIZE_BITS) & TIO_SWIN_WIDGET_MASK)
 
 
+#define TIO_IOSPACE_ADDR(n,x)                                  \
+       /* Move in the Chiplet ID for TIO Local Block MMR */    \
+       (REMOTE_ADDR(n,x) | 1UL << (NASID_SHIFT - 2))
+
 /*
  * The following macros produce the correct base virtual address for
  * the hub registers. The REMOTE_HUB_* macro produce
 #define REMOTE_HUB_ADDR(n,x)                                           \
        ((n & 1) ?                                                      \
        /* TIO: */                                                      \
-       ((volatile u64 *)(GLOBAL_MMR_ADDR(n,x)))                        \
-       : /* SHUB: */                                                   \
-       (((x) & BWIN_TOP) ? ((volatile u64 *)(GLOBAL_MMR_ADDR(n,x)))\
+       (is_shub2() ?                                                   \
+       /* TIO on Shub2 */                                              \
+       (volatile u64 *)(TIO_IOSPACE_ADDR(n,x))                         \
+       : /* TIO on shub1 */                                            \
+       (volatile u64 *)(GLOBAL_MMR_ADDR(n,x)))                         \
+                                                                       \
+       : /* SHUB1 and SHUB2 MMRs: */                                   \
+       (((x) & BWIN_TOP) ? ((volatile u64 *)(GLOBAL_MMR_ADDR(n,x)))    \
        : ((volatile u64 *)(NODE_SWIN_BASE(n,1) + 0x800000 + (x)))))
 
-
-
 #define HUB_L(x)                       (*((volatile typeof(*x) *)x))
 #define        HUB_S(x,d)                      (*((volatile typeof(*x) *)x) = (d))
 
index 08050d37b662563038abfb9b7cc9e93f77f83abc..2e5f0aa38889d8140fe5dbe61c6ee207f60c7625 100644 (file)
@@ -33,5 +33,6 @@
 #define L1_BRICKTYPE_PA                0x6a            /* j */
 #define L1_BRICKTYPE_IA                0x6b            /* k */
 #define L1_BRICKTYPE_ATHENA    0x2b            /* + */
+#define L1_BRICKTYPE_DAYTONA   0x7a            /* z */
 
 #endif /* _ASM_IA64_SN_L1_H */
index 323fa0cd8d83d671d04fb51977dd9963b18784de..7de1d1d4b71a9b7ccb67e10b09be4304fb047da8 100644 (file)
 /*                        Register "SH_IPI_INT"                         */
 /*               SHub Inter-Processor Interrupt Registers               */
 /* ==================================================================== */
-#define SH1_IPI_INT                               0x0000000110000380
-#define SH2_IPI_INT                               0x0000000010000380
+#define SH1_IPI_INT                    __IA64_UL_CONST(0x0000000110000380)
+#define SH2_IPI_INT                    __IA64_UL_CONST(0x0000000010000380)
 
 /*   SH_IPI_INT_TYPE                                                    */
 /*   Description:  Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT       */
-#define SH_IPI_INT_TYPE_SHFT                     0
-#define SH_IPI_INT_TYPE_MASK                     0x0000000000000007
+#define SH_IPI_INT_TYPE_SHFT                           0
+#define SH_IPI_INT_TYPE_MASK           __IA64_UL_CONST(0x0000000000000007)
 
 /*   SH_IPI_INT_AGT                                                     */
 /*   Description:  Agent, must be 0 for SHub                            */
-#define SH_IPI_INT_AGT_SHFT                      3
-#define SH_IPI_INT_AGT_MASK                      0x0000000000000008
+#define SH_IPI_INT_AGT_SHFT                            3
+#define SH_IPI_INT_AGT_MASK            __IA64_UL_CONST(0x0000000000000008)
 
 /*   SH_IPI_INT_PID                                                     */
 /*   Description:  Processor ID, same setting as on targeted McKinley  */
-#define SH_IPI_INT_PID_SHFT                      4
-#define SH_IPI_INT_PID_MASK                      0x00000000000ffff0
+#define SH_IPI_INT_PID_SHFT                            4
+#define SH_IPI_INT_PID_MASK            __IA64_UL_CONST(0x00000000000ffff0)
 
 /*   SH_IPI_INT_BASE                                                    */
 /*   Description:  Optional interrupt vector area, 2MB aligned          */
-#define SH_IPI_INT_BASE_SHFT                     21
-#define SH_IPI_INT_BASE_MASK                     0x0003ffffffe00000
+#define SH_IPI_INT_BASE_SHFT                           21
+#define SH_IPI_INT_BASE_MASK           __IA64_UL_CONST(0x0003ffffffe00000)
 
 /*   SH_IPI_INT_IDX                                                     */
 /*   Description:  Targeted McKinley interrupt vector                   */
-#define SH_IPI_INT_IDX_SHFT                      52
-#define SH_IPI_INT_IDX_MASK                      0x0ff0000000000000
+#define SH_IPI_INT_IDX_SHFT                            52
+#define SH_IPI_INT_IDX_MASK            __IA64_UL_CONST(0x0ff0000000000000)
 
 /*   SH_IPI_INT_SEND                                                    */
 /*   Description:  Send Interrupt Message to PI, This generates a puls  */
-#define SH_IPI_INT_SEND_SHFT                     63
-#define SH_IPI_INT_SEND_MASK                     0x8000000000000000
+#define SH_IPI_INT_SEND_SHFT                           63
+#define SH_IPI_INT_SEND_MASK           __IA64_UL_CONST(0x8000000000000000)
 
 /* ==================================================================== */
 /*                     Register "SH_EVENT_OCCURRED"                     */
 /*                    SHub Interrupt Event Occurred                     */
 /* ==================================================================== */
-#define SH1_EVENT_OCCURRED                        0x0000000110010000
-#define SH1_EVENT_OCCURRED_ALIAS                  0x0000000110010008
-#define SH2_EVENT_OCCURRED                        0x0000000010010000
-#define SH2_EVENT_OCCURRED_ALIAS                  0x0000000010010008
+#define SH1_EVENT_OCCURRED             __IA64_UL_CONST(0x0000000110010000)
+#define SH1_EVENT_OCCURRED_ALIAS       __IA64_UL_CONST(0x0000000110010008)
+#define SH2_EVENT_OCCURRED             __IA64_UL_CONST(0x0000000010010000)
+#define SH2_EVENT_OCCURRED_ALIAS       __IA64_UL_CONST(0x0000000010010008)
 
 /* ==================================================================== */
 /*                     Register "SH_PI_CAM_CONTROL"                     */
 /*                      CRB CAM MMR Access Control                      */
 /* ==================================================================== */
-#define SH1_PI_CAM_CONTROL                        0x0000000120050300
+#define SH1_PI_CAM_CONTROL             __IA64_UL_CONST(0x0000000120050300)
 
 /* ==================================================================== */
 /*                        Register "SH_SHUB_ID"                         */
 /*                            SHub ID Number                            */
 /* ==================================================================== */
-#define SH1_SHUB_ID                               0x0000000110060580
-#define SH1_SHUB_ID_REVISION_SHFT                 28
-#define SH1_SHUB_ID_REVISION_MASK                 0x00000000f0000000
+#define SH1_SHUB_ID                    __IA64_UL_CONST(0x0000000110060580)
+#define SH1_SHUB_ID_REVISION_SHFT                      28
+#define SH1_SHUB_ID_REVISION_MASK      __IA64_UL_CONST(0x00000000f0000000)
 
 /* ==================================================================== */
 /*                          Register "SH_RTC"                           */
 /*                           Real-time Clock                            */
 /* ==================================================================== */
-#define SH1_RTC                                   0x00000001101c0000
-#define SH2_RTC                                          0x00000002101c0000
-#define SH_RTC_MASK                               0x007fffffffffffff
+#define SH1_RTC                                __IA64_UL_CONST(0x00000001101c0000)
+#define SH2_RTC                                __IA64_UL_CONST(0x00000002101c0000)
+#define SH_RTC_MASK                    __IA64_UL_CONST(0x007fffffffffffff)
 
 /* ==================================================================== */
 /*                   Register "SH_PIO_WRITE_STATUS_0|1"                 */
 /*                      PIO Write Status for CPU 0 & 1                  */
 /* ==================================================================== */
-#define SH1_PIO_WRITE_STATUS_0                    0x0000000120070200
-#define SH1_PIO_WRITE_STATUS_1                    0x0000000120070280
-#define SH2_PIO_WRITE_STATUS_0                    0x0000000020070200
-#define SH2_PIO_WRITE_STATUS_1                    0x0000000020070280
-#define SH2_PIO_WRITE_STATUS_2                    0x0000000020070300
-#define SH2_PIO_WRITE_STATUS_3                    0x0000000020070380
+#define SH1_PIO_WRITE_STATUS_0         __IA64_UL_CONST(0x0000000120070200)
+#define SH1_PIO_WRITE_STATUS_1         __IA64_UL_CONST(0x0000000120070280)
+#define SH2_PIO_WRITE_STATUS_0         __IA64_UL_CONST(0x0000000020070200)
+#define SH2_PIO_WRITE_STATUS_1         __IA64_UL_CONST(0x0000000020070280)
+#define SH2_PIO_WRITE_STATUS_2         __IA64_UL_CONST(0x0000000020070300)
+#define SH2_PIO_WRITE_STATUS_3         __IA64_UL_CONST(0x0000000020070380)
 
 /*   SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK                               */
 /*   Description:  Deadlock response detected                           */
-#define SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT 1
-#define SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK 0x0000000000000002
+#define SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT                1
+#define SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK \
+                                       __IA64_UL_CONST(0x0000000000000002)
 
 /*   SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT                          */
 /*   Description:  Count of currently pending PIO writes                */
-#define SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_SHFT 56
-#define SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK 0x3f00000000000000
+#define SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_SHFT   56
+#define SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK \
+                                       __IA64_UL_CONST(0x3f00000000000000)
 
 /* ==================================================================== */
 /*                Register "SH_PIO_WRITE_STATUS_0_ALIAS"                */
 /* ==================================================================== */
-#define SH1_PIO_WRITE_STATUS_0_ALIAS              0x0000000120070208
-#define SH2_PIO_WRITE_STATUS_0_ALIAS              0x0000000020070208
+#define SH1_PIO_WRITE_STATUS_0_ALIAS   __IA64_UL_CONST(0x0000000120070208)
+#define SH2_PIO_WRITE_STATUS_0_ALIAS   __IA64_UL_CONST(0x0000000020070208)
 
 /* ==================================================================== */
 /*                     Register "SH_EVENT_OCCURRED"                     */
 /* ==================================================================== */
 /*   SH_EVENT_OCCURRED_UART_INT                                         */
 /*   Description:  Pending Junk Bus UART Interrupt                      */
-#define SH_EVENT_OCCURRED_UART_INT_SHFT          20
-#define SH_EVENT_OCCURRED_UART_INT_MASK          0x0000000000100000
+#define SH_EVENT_OCCURRED_UART_INT_SHFT                        20
+#define SH_EVENT_OCCURRED_UART_INT_MASK        __IA64_UL_CONST(0x0000000000100000)
 
 /*   SH_EVENT_OCCURRED_IPI_INT                                          */
 /*   Description:  Pending IPI Interrupt                                */
-#define SH_EVENT_OCCURRED_IPI_INT_SHFT           28
-#define SH_EVENT_OCCURRED_IPI_INT_MASK           0x0000000010000000
+#define SH_EVENT_OCCURRED_IPI_INT_SHFT                 28
+#define SH_EVENT_OCCURRED_IPI_INT_MASK __IA64_UL_CONST(0x0000000010000000)
 
 /*   SH_EVENT_OCCURRED_II_INT0                                          */
 /*   Description:  Pending II 0 Interrupt                               */
-#define SH_EVENT_OCCURRED_II_INT0_SHFT           29
-#define SH_EVENT_OCCURRED_II_INT0_MASK           0x0000000020000000
+#define SH_EVENT_OCCURRED_II_INT0_SHFT                 29
+#define SH_EVENT_OCCURRED_II_INT0_MASK __IA64_UL_CONST(0x0000000020000000)
 
 /*   SH_EVENT_OCCURRED_II_INT1                                          */
 /*   Description:  Pending II 1 Interrupt                               */
-#define SH_EVENT_OCCURRED_II_INT1_SHFT           30
-#define SH_EVENT_OCCURRED_II_INT1_MASK           0x0000000040000000
+#define SH_EVENT_OCCURRED_II_INT1_SHFT                 30
+#define SH_EVENT_OCCURRED_II_INT1_MASK __IA64_UL_CONST(0x0000000040000000)
 
 /*   SH2_EVENT_OCCURRED_EXTIO_INT2                                      */
 /*   Description:  Pending SHUB 2 EXT IO INT2                           */
-#define SH2_EVENT_OCCURRED_EXTIO_INT2_SHFT       33
-#define SH2_EVENT_OCCURRED_EXTIO_INT2_MASK       0x0000000200000000
+#define SH2_EVENT_OCCURRED_EXTIO_INT2_SHFT             33
+#define SH2_EVENT_OCCURRED_EXTIO_INT2_MASK __IA64_UL_CONST(0x0000000200000000)
 
 /*   SH2_EVENT_OCCURRED_EXTIO_INT3                                      */
 /*   Description:  Pending SHUB 2 EXT IO INT3                           */
-#define SH2_EVENT_OCCURRED_EXTIO_INT3_SHFT       34
-#define SH2_EVENT_OCCURRED_EXTIO_INT3_MASK       0x0000000400000000
+#define SH2_EVENT_OCCURRED_EXTIO_INT3_SHFT             34
+#define SH2_EVENT_OCCURRED_EXTIO_INT3_MASK __IA64_UL_CONST(0x0000000400000000)
 
 #define SH_ALL_INT_MASK \
        (SH_EVENT_OCCURRED_UART_INT_MASK | SH_EVENT_OCCURRED_IPI_INT_MASK | \
 /* ==================================================================== */
 /*                         LEDS                                         */
 /* ==================================================================== */
-#define SH1_REAL_JUNK_BUS_LED0                  0x7fed00000UL
-#define SH1_REAL_JUNK_BUS_LED1                  0x7fed10000UL
-#define SH1_REAL_JUNK_BUS_LED2                  0x7fed20000UL
-#define SH1_REAL_JUNK_BUS_LED3                  0x7fed30000UL
+#define SH1_REAL_JUNK_BUS_LED0                 0x7fed00000UL
+#define SH1_REAL_JUNK_BUS_LED1                 0x7fed10000UL
+#define SH1_REAL_JUNK_BUS_LED2                 0x7fed20000UL
+#define SH1_REAL_JUNK_BUS_LED3                 0x7fed30000UL
 
-#define SH2_REAL_JUNK_BUS_LED0                  0xf0000000UL
-#define SH2_REAL_JUNK_BUS_LED1                  0xf0010000UL
-#define SH2_REAL_JUNK_BUS_LED2                  0xf0020000UL
-#define SH2_REAL_JUNK_BUS_LED3                  0xf0030000UL
+#define SH2_REAL_JUNK_BUS_LED0                 0xf0000000UL
+#define SH2_REAL_JUNK_BUS_LED1                 0xf0010000UL
+#define SH2_REAL_JUNK_BUS_LED2                 0xf0020000UL
+#define SH2_REAL_JUNK_BUS_LED3                 0xf0030000UL
 
 /* ==================================================================== */
 /*                         Register "SH1_PTC_0"                         */
 /*       Puge Translation Cache Message Configuration Information       */
 /* ==================================================================== */
-#define SH1_PTC_0                                 0x00000001101a0000
+#define SH1_PTC_0                      __IA64_UL_CONST(0x00000001101a0000)
 
 /*   SH1_PTC_0_A                                                        */
 /*   Description:  Type                                                 */
-#define SH1_PTC_0_A_SHFT                          0
+#define SH1_PTC_0_A_SHFT                               0
 
 /*   SH1_PTC_0_PS                                                       */
 /*   Description:  Page Size                                            */
-#define SH1_PTC_0_PS_SHFT                         2
+#define SH1_PTC_0_PS_SHFT                              2
 
 /*   SH1_PTC_0_RID                                                      */
 /*   Description:  Region ID                                            */
-#define SH1_PTC_0_RID_SHFT                        8
+#define SH1_PTC_0_RID_SHFT                             8
 
 /*   SH1_PTC_0_START                                                    */
 /*   Description:  Start                                                */
-#define SH1_PTC_0_START_SHFT                      63
+#define SH1_PTC_0_START_SHFT                           63
 
 /* ==================================================================== */
 /*                         Register "SH1_PTC_1"                         */
 /*       Puge Translation Cache Message Configuration Information       */
 /* ==================================================================== */
-#define SH1_PTC_1                                 0x00000001101a0080
+#define SH1_PTC_1                      __IA64_UL_CONST(0x00000001101a0080)
 
 /*   SH1_PTC_1_START                                                    */
 /*   Description:  PTC_1 Start                                          */
-#define SH1_PTC_1_START_SHFT                      63
-
+#define SH1_PTC_1_START_SHFT                           63
 
 /* ==================================================================== */
 /*                         Register "SH2_PTC"                           */
 /*       Puge Translation Cache Message Configuration Information       */
 /* ==================================================================== */
-#define SH2_PTC                                   0x0000000170000000
+#define SH2_PTC                                __IA64_UL_CONST(0x0000000170000000)
 
 /*   SH2_PTC_A                                                          */
 /*   Description:  Type                                                 */
-#define SH2_PTC_A_SHFT                            0
+#define SH2_PTC_A_SHFT                                 0
 
 /*   SH2_PTC_PS                                                         */
 /*   Description:  Page Size                                            */
-#define SH2_PTC_PS_SHFT                           2
+#define SH2_PTC_PS_SHFT                                        2
 
 /*   SH2_PTC_RID                                                      */
 /*   Description:  Region ID                                            */
-#define SH2_PTC_RID_SHFT                          4
+#define SH2_PTC_RID_SHFT                               4
 
 /*   SH2_PTC_START                                                      */
 /*   Description:  Start                                                */
-#define SH2_PTC_START_SHFT                        63
+#define SH2_PTC_START_SHFT                             63
 
 /*   SH2_PTC_ADDR_RID                                                   */
 /*   Description:  Region ID                                            */
-#define SH2_PTC_ADDR_SHFT                         4
-#define SH2_PTC_ADDR_MASK                         0x1ffffffffffff000
+#define SH2_PTC_ADDR_SHFT                              4
+#define SH2_PTC_ADDR_MASK              __IA64_UL_CONST(0x1ffffffffffff000)
 
 /* ==================================================================== */
 /*                    Register "SH_RTC1_INT_CONFIG"                     */
 /*                SHub RTC 1 Interrupt Config Registers                 */
 /* ==================================================================== */
 
-#define SH1_RTC1_INT_CONFIG                      0x0000000110001480
-#define SH2_RTC1_INT_CONFIG                      0x0000000010001480
-#define SH_RTC1_INT_CONFIG_MASK                  0x0ff3ffffffefffff
-#define SH_RTC1_INT_CONFIG_INIT                  0x0000000000000000
+#define SH1_RTC1_INT_CONFIG            __IA64_UL_CONST(0x0000000110001480)
+#define SH2_RTC1_INT_CONFIG            __IA64_UL_CONST(0x0000000010001480)
+#define SH_RTC1_INT_CONFIG_MASK                __IA64_UL_CONST(0x0ff3ffffffefffff)
+#define SH_RTC1_INT_CONFIG_INIT                __IA64_UL_CONST(0x0000000000000000)
 
 /*   SH_RTC1_INT_CONFIG_TYPE                                            */
 /*   Description:  Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT       */
-#define SH_RTC1_INT_CONFIG_TYPE_SHFT             0
-#define SH_RTC1_INT_CONFIG_TYPE_MASK             0x0000000000000007
+#define SH_RTC1_INT_CONFIG_TYPE_SHFT                   0
+#define SH_RTC1_INT_CONFIG_TYPE_MASK   __IA64_UL_CONST(0x0000000000000007)
 
 /*   SH_RTC1_INT_CONFIG_AGT                                             */
 /*   Description:  Agent, must be 0 for SHub                            */
-#define SH_RTC1_INT_CONFIG_AGT_SHFT              3
-#define SH_RTC1_INT_CONFIG_AGT_MASK              0x0000000000000008
+#define SH_RTC1_INT_CONFIG_AGT_SHFT                    3
+#define SH_RTC1_INT_CONFIG_AGT_MASK    __IA64_UL_CONST(0x0000000000000008)
 
 /*   SH_RTC1_INT_CONFIG_PID                                             */
 /*   Description:  Processor ID, same setting as on targeted McKinley  */
-#define SH_RTC1_INT_CONFIG_PID_SHFT              4
-#define SH_RTC1_INT_CONFIG_PID_MASK              0x00000000000ffff0
+#define SH_RTC1_INT_CONFIG_PID_SHFT                    4
+#define SH_RTC1_INT_CONFIG_PID_MASK    __IA64_UL_CONST(0x00000000000ffff0)
 
 /*   SH_RTC1_INT_CONFIG_BASE                                            */
 /*   Description:  Optional interrupt vector area, 2MB aligned          */
-#define SH_RTC1_INT_CONFIG_BASE_SHFT             21
-#define SH_RTC1_INT_CONFIG_BASE_MASK             0x0003ffffffe00000
+#define SH_RTC1_INT_CONFIG_BASE_SHFT                   21
+#define SH_RTC1_INT_CONFIG_BASE_MASK   __IA64_UL_CONST(0x0003ffffffe00000)
 
 /*   SH_RTC1_INT_CONFIG_IDX                                             */
 /*   Description:  Targeted McKinley interrupt vector                   */
-#define SH_RTC1_INT_CONFIG_IDX_SHFT              52
-#define SH_RTC1_INT_CONFIG_IDX_MASK              0x0ff0000000000000
+#define SH_RTC1_INT_CONFIG_IDX_SHFT                    52
+#define SH_RTC1_INT_CONFIG_IDX_MASK    __IA64_UL_CONST(0x0ff0000000000000)
 
 /* ==================================================================== */
 /*                    Register "SH_RTC1_INT_ENABLE"                     */
 /*                SHub RTC 1 Interrupt Enable Registers                 */
 /* ==================================================================== */
 
-#define SH1_RTC1_INT_ENABLE                      0x0000000110001500
-#define SH2_RTC1_INT_ENABLE                      0x0000000010001500
-#define SH_RTC1_INT_ENABLE_MASK                  0x0000000000000001
-#define SH_RTC1_INT_ENABLE_INIT                  0x0000000000000000
+#define SH1_RTC1_INT_ENABLE            __IA64_UL_CONST(0x0000000110001500)
+#define SH2_RTC1_INT_ENABLE            __IA64_UL_CONST(0x0000000010001500)
+#define SH_RTC1_INT_ENABLE_MASK                __IA64_UL_CONST(0x0000000000000001)
+#define SH_RTC1_INT_ENABLE_INIT                __IA64_UL_CONST(0x0000000000000000)
 
 /*   SH_RTC1_INT_ENABLE_RTC1_ENABLE                                     */
 /*   Description:  Enable RTC 1 Interrupt                               */
-#define SH_RTC1_INT_ENABLE_RTC1_ENABLE_SHFT      0
-#define SH_RTC1_INT_ENABLE_RTC1_ENABLE_MASK      0x0000000000000001
+#define SH_RTC1_INT_ENABLE_RTC1_ENABLE_SHFT            0
+#define SH_RTC1_INT_ENABLE_RTC1_ENABLE_MASK \
+                                       __IA64_UL_CONST(0x0000000000000001)
 
 /* ==================================================================== */
 /*                    Register "SH_RTC2_INT_CONFIG"                     */
 /*                SHub RTC 2 Interrupt Config Registers                 */
 /* ==================================================================== */
 
-#define SH1_RTC2_INT_CONFIG                      0x0000000110001580
-#define SH2_RTC2_INT_CONFIG                      0x0000000010001580
-#define SH_RTC2_INT_CONFIG_MASK                  0x0ff3ffffffefffff
-#define SH_RTC2_INT_CONFIG_INIT                  0x0000000000000000
+#define SH1_RTC2_INT_CONFIG            __IA64_UL_CONST(0x0000000110001580)
+#define SH2_RTC2_INT_CONFIG            __IA64_UL_CONST(0x0000000010001580)
+#define SH_RTC2_INT_CONFIG_MASK                __IA64_UL_CONST(0x0ff3ffffffefffff)
+#define SH_RTC2_INT_CONFIG_INIT                __IA64_UL_CONST(0x0000000000000000)
 
 /*   SH_RTC2_INT_CONFIG_TYPE                                            */
 /*   Description:  Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT       */
-#define SH_RTC2_INT_CONFIG_TYPE_SHFT             0
-#define SH_RTC2_INT_CONFIG_TYPE_MASK             0x0000000000000007
+#define SH_RTC2_INT_CONFIG_TYPE_SHFT                   0
+#define SH_RTC2_INT_CONFIG_TYPE_MASK   __IA64_UL_CONST(0x0000000000000007)
 
 /*   SH_RTC2_INT_CONFIG_AGT                                             */
 /*   Description:  Agent, must be 0 for SHub                            */
-#define SH_RTC2_INT_CONFIG_AGT_SHFT              3
-#define SH_RTC2_INT_CONFIG_AGT_MASK              0x0000000000000008
+#define SH_RTC2_INT_CONFIG_AGT_SHFT                    3
+#define SH_RTC2_INT_CONFIG_AGT_MASK    __IA64_UL_CONST(0x0000000000000008)
 
 /*   SH_RTC2_INT_CONFIG_PID                                             */
 /*   Description:  Processor ID, same setting as on targeted McKinley  */
-#define SH_RTC2_INT_CONFIG_PID_SHFT              4
-#define SH_RTC2_INT_CONFIG_PID_MASK              0x00000000000ffff0
+#define SH_RTC2_INT_CONFIG_PID_SHFT                    4
+#define SH_RTC2_INT_CONFIG_PID_MASK    __IA64_UL_CONST(0x00000000000ffff0)
 
 /*   SH_RTC2_INT_CONFIG_BASE                                            */
 /*   Description:  Optional interrupt vector area, 2MB aligned          */
-#define SH_RTC2_INT_CONFIG_BASE_SHFT             21
-#define SH_RTC2_INT_CONFIG_BASE_MASK             0x0003ffffffe00000
+#define SH_RTC2_INT_CONFIG_BASE_SHFT                   21
+#define SH_RTC2_INT_CONFIG_BASE_MASK   __IA64_UL_CONST(0x0003ffffffe00000)
 
 /*   SH_RTC2_INT_CONFIG_IDX                                             */
 /*   Description:  Targeted McKinley interrupt vector                   */
-#define SH_RTC2_INT_CONFIG_IDX_SHFT              52
-#define SH_RTC2_INT_CONFIG_IDX_MASK              0x0ff0000000000000
+#define SH_RTC2_INT_CONFIG_IDX_SHFT                    52
+#define SH_RTC2_INT_CONFIG_IDX_MASK    __IA64_UL_CONST(0x0ff0000000000000)
 
 /* ==================================================================== */
 /*                    Register "SH_RTC2_INT_ENABLE"                     */
 /*                SHub RTC 2 Interrupt Enable Registers                 */
 /* ==================================================================== */
 
-#define SH1_RTC2_INT_ENABLE                      0x0000000110001600
-#define SH2_RTC2_INT_ENABLE                      0x0000000010001600
-#define SH_RTC2_INT_ENABLE_MASK                  0x0000000000000001
-#define SH_RTC2_INT_ENABLE_INIT                  0x0000000000000000
+#define SH1_RTC2_INT_ENABLE            __IA64_UL_CONST(0x0000000110001600)
+#define SH2_RTC2_INT_ENABLE            __IA64_UL_CONST(0x0000000010001600)
+#define SH_RTC2_INT_ENABLE_MASK                __IA64_UL_CONST(0x0000000000000001)
+#define SH_RTC2_INT_ENABLE_INIT                __IA64_UL_CONST(0x0000000000000000)
 
 /*   SH_RTC2_INT_ENABLE_RTC2_ENABLE                                     */
 /*   Description:  Enable RTC 2 Interrupt                               */
-#define SH_RTC2_INT_ENABLE_RTC2_ENABLE_SHFT      0
-#define SH_RTC2_INT_ENABLE_RTC2_ENABLE_MASK      0x0000000000000001
+#define SH_RTC2_INT_ENABLE_RTC2_ENABLE_SHFT            0
+#define SH_RTC2_INT_ENABLE_RTC2_ENABLE_MASK \
+                                       __IA64_UL_CONST(0x0000000000000001)
 
 /* ==================================================================== */
 /*                    Register "SH_RTC3_INT_CONFIG"                     */
 /*                SHub RTC 3 Interrupt Config Registers                 */
 /* ==================================================================== */
 
-#define SH1_RTC3_INT_CONFIG                      0x0000000110001680
-#define SH2_RTC3_INT_CONFIG                      0x0000000010001680
-#define SH_RTC3_INT_CONFIG_MASK                  0x0ff3ffffffefffff
-#define SH_RTC3_INT_CONFIG_INIT                  0x0000000000000000
+#define SH1_RTC3_INT_CONFIG            __IA64_UL_CONST(0x0000000110001680)
+#define SH2_RTC3_INT_CONFIG            __IA64_UL_CONST(0x0000000010001680)
+#define SH_RTC3_INT_CONFIG_MASK                __IA64_UL_CONST(0x0ff3ffffffefffff)
+#define SH_RTC3_INT_CONFIG_INIT                __IA64_UL_CONST(0x0000000000000000)
 
 /*   SH_RTC3_INT_CONFIG_TYPE                                            */
 /*   Description:  Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT       */
-#define SH_RTC3_INT_CONFIG_TYPE_SHFT             0
-#define SH_RTC3_INT_CONFIG_TYPE_MASK             0x0000000000000007
+#define SH_RTC3_INT_CONFIG_TYPE_SHFT                   0
+#define SH_RTC3_INT_CONFIG_TYPE_MASK   __IA64_UL_CONST(0x0000000000000007)
 
 /*   SH_RTC3_INT_CONFIG_AGT                                             */
 /*   Description:  Agent, must be 0 for SHub                            */
-#define SH_RTC3_INT_CONFIG_AGT_SHFT              3
-#define SH_RTC3_INT_CONFIG_AGT_MASK              0x0000000000000008
+#define SH_RTC3_INT_CONFIG_AGT_SHFT                    3
+#define SH_RTC3_INT_CONFIG_AGT_MASK    __IA64_UL_CONST(0x0000000000000008)
 
 /*   SH_RTC3_INT_CONFIG_PID                                             */
 /*   Description:  Processor ID, same setting as on targeted McKinley  */
-#define SH_RTC3_INT_CONFIG_PID_SHFT              4
-#define SH_RTC3_INT_CONFIG_PID_MASK              0x00000000000ffff0
+#define SH_RTC3_INT_CONFIG_PID_SHFT                    4
+#define SH_RTC3_INT_CONFIG_PID_MASK    __IA64_UL_CONST(0x00000000000ffff0)
 
 /*   SH_RTC3_INT_CONFIG_BASE                                            */
 /*   Description:  Optional interrupt vector area, 2MB aligned          */
-#define SH_RTC3_INT_CONFIG_BASE_SHFT             21
-#define SH_RTC3_INT_CONFIG_BASE_MASK             0x0003ffffffe00000
+#define SH_RTC3_INT_CONFIG_BASE_SHFT                   21
+#define SH_RTC3_INT_CONFIG_BASE_MASK   __IA64_UL_CONST(0x0003ffffffe00000)
 
 /*   SH_RTC3_INT_CONFIG_IDX                                             */
 /*   Description:  Targeted McKinley interrupt vector                   */
-#define SH_RTC3_INT_CONFIG_IDX_SHFT              52
-#define SH_RTC3_INT_CONFIG_IDX_MASK              0x0ff0000000000000
+#define SH_RTC3_INT_CONFIG_IDX_SHFT                    52
+#define SH_RTC3_INT_CONFIG_IDX_MASK    __IA64_UL_CONST(0x0ff0000000000000)
 
 /* ==================================================================== */
 /*                    Register "SH_RTC3_INT_ENABLE"                     */
 /*                SHub RTC 3 Interrupt Enable Registers                 */
 /* ==================================================================== */
 
-#define SH1_RTC3_INT_ENABLE                      0x0000000110001700
-#define SH2_RTC3_INT_ENABLE                      0x0000000010001700
-#define SH_RTC3_INT_ENABLE_MASK                  0x0000000000000001
-#define SH_RTC3_INT_ENABLE_INIT                  0x0000000000000000
+#define SH1_RTC3_INT_ENABLE            __IA64_UL_CONST(0x0000000110001700)
+#define SH2_RTC3_INT_ENABLE            __IA64_UL_CONST(0x0000000010001700)
+#define SH_RTC3_INT_ENABLE_MASK                __IA64_UL_CONST(0x0000000000000001)
+#define SH_RTC3_INT_ENABLE_INIT                __IA64_UL_CONST(0x0000000000000000)
 
 /*   SH_RTC3_INT_ENABLE_RTC3_ENABLE                                     */
 /*   Description:  Enable RTC 3 Interrupt                               */
-#define SH_RTC3_INT_ENABLE_RTC3_ENABLE_SHFT      0
-#define SH_RTC3_INT_ENABLE_RTC3_ENABLE_MASK      0x0000000000000001
+#define SH_RTC3_INT_ENABLE_RTC3_ENABLE_SHFT            0
+#define SH_RTC3_INT_ENABLE_RTC3_ENABLE_MASK \
+                                       __IA64_UL_CONST(0x0000000000000001)
 
 /*   SH_EVENT_OCCURRED_RTC1_INT                                         */
 /*   Description:  Pending RTC 1 Interrupt                              */
-#define SH_EVENT_OCCURRED_RTC1_INT_SHFT          24
-#define SH_EVENT_OCCURRED_RTC1_INT_MASK          0x0000000001000000
+#define SH_EVENT_OCCURRED_RTC1_INT_SHFT                        24
+#define SH_EVENT_OCCURRED_RTC1_INT_MASK        __IA64_UL_CONST(0x0000000001000000)
 
 /*   SH_EVENT_OCCURRED_RTC2_INT                                         */
 /*   Description:  Pending RTC 2 Interrupt                              */
-#define SH_EVENT_OCCURRED_RTC2_INT_SHFT          25
-#define SH_EVENT_OCCURRED_RTC2_INT_MASK          0x0000000002000000
+#define SH_EVENT_OCCURRED_RTC2_INT_SHFT                        25
+#define SH_EVENT_OCCURRED_RTC2_INT_MASK        __IA64_UL_CONST(0x0000000002000000)
 
 /*   SH_EVENT_OCCURRED_RTC3_INT                                         */
 /*   Description:  Pending RTC 3 Interrupt                              */
-#define SH_EVENT_OCCURRED_RTC3_INT_SHFT          26
-#define SH_EVENT_OCCURRED_RTC3_INT_MASK          0x0000000004000000
+#define SH_EVENT_OCCURRED_RTC3_INT_SHFT                        26
+#define SH_EVENT_OCCURRED_RTC3_INT_MASK        __IA64_UL_CONST(0x0000000004000000)
 
 /* ==================================================================== */
 /*                       Register "SH_IPI_ACCESS"                       */
 /*                 CPU interrupt Access Permission Bits                 */
 /* ==================================================================== */
 
-#define SH1_IPI_ACCESS                           0x0000000110060480
-#define SH2_IPI_ACCESS0                          0x0000000010060c00
-#define SH2_IPI_ACCESS1                          0x0000000010060c80
-#define SH2_IPI_ACCESS2                          0x0000000010060d00
-#define SH2_IPI_ACCESS3                          0x0000000010060d80
+#define SH1_IPI_ACCESS                 __IA64_UL_CONST(0x0000000110060480)
+#define SH2_IPI_ACCESS0                        __IA64_UL_CONST(0x0000000010060c00)
+#define SH2_IPI_ACCESS1                        __IA64_UL_CONST(0x0000000010060c80)
+#define SH2_IPI_ACCESS2                        __IA64_UL_CONST(0x0000000010060d00)
+#define SH2_IPI_ACCESS3                        __IA64_UL_CONST(0x0000000010060d80)
 
 /* ==================================================================== */
 /*                        Register "SH_INT_CMPB"                        */
 /*                  RTC Compare Value for Processor B                   */
 /* ==================================================================== */
 
-#define SH1_INT_CMPB                             0x00000001101b0080
-#define SH2_INT_CMPB                             0x00000000101b0080
-#define SH_INT_CMPB_MASK                         0x007fffffffffffff
-#define SH_INT_CMPB_INIT                         0x0000000000000000
+#define SH1_INT_CMPB                   __IA64_UL_CONST(0x00000001101b0080)
+#define SH2_INT_CMPB                   __IA64_UL_CONST(0x00000000101b0080)
+#define SH_INT_CMPB_MASK               __IA64_UL_CONST(0x007fffffffffffff)
+#define SH_INT_CMPB_INIT               __IA64_UL_CONST(0x0000000000000000)
 
 /*   SH_INT_CMPB_REAL_TIME_CMPB                                         */
 /*   Description:  Real Time Clock Compare                              */
-#define SH_INT_CMPB_REAL_TIME_CMPB_SHFT          0
-#define SH_INT_CMPB_REAL_TIME_CMPB_MASK          0x007fffffffffffff
+#define SH_INT_CMPB_REAL_TIME_CMPB_SHFT                        0
+#define SH_INT_CMPB_REAL_TIME_CMPB_MASK        __IA64_UL_CONST(0x007fffffffffffff)
 
 /* ==================================================================== */
 /*                        Register "SH_INT_CMPC"                        */
 /*                  RTC Compare Value for Processor C                   */
 /* ==================================================================== */
 
-#define SH1_INT_CMPC                             0x00000001101b0100
-#define SH2_INT_CMPC                             0x00000000101b0100
-#define SH_INT_CMPC_MASK                         0x007fffffffffffff
-#define SH_INT_CMPC_INIT                         0x0000000000000000
+#define SH1_INT_CMPC                   __IA64_UL_CONST(0x00000001101b0100)
+#define SH2_INT_CMPC                   __IA64_UL_CONST(0x00000000101b0100)
+#define SH_INT_CMPC_MASK               __IA64_UL_CONST(0x007fffffffffffff)
+#define SH_INT_CMPC_INIT               __IA64_UL_CONST(0x0000000000000000)
 
 /*   SH_INT_CMPC_REAL_TIME_CMPC                                         */
 /*   Description:  Real Time Clock Compare                              */
-#define SH_INT_CMPC_REAL_TIME_CMPC_SHFT          0
-#define SH_INT_CMPC_REAL_TIME_CMPC_MASK          0x007fffffffffffff
+#define SH_INT_CMPC_REAL_TIME_CMPC_SHFT                        0
+#define SH_INT_CMPC_REAL_TIME_CMPC_MASK        __IA64_UL_CONST(0x007fffffffffffff)
 
 /* ==================================================================== */
 /*                        Register "SH_INT_CMPD"                        */
 /*                  RTC Compare Value for Processor D                   */
 /* ==================================================================== */
 
-#define SH1_INT_CMPD                             0x00000001101b0180
-#define SH2_INT_CMPD                             0x00000000101b0180
-#define SH_INT_CMPD_MASK                         0x007fffffffffffff
-#define SH_INT_CMPD_INIT                         0x0000000000000000
+#define SH1_INT_CMPD                   __IA64_UL_CONST(0x00000001101b0180)
+#define SH2_INT_CMPD                   __IA64_UL_CONST(0x00000000101b0180)
+#define SH_INT_CMPD_MASK               __IA64_UL_CONST(0x007fffffffffffff)
+#define SH_INT_CMPD_INIT               __IA64_UL_CONST(0x0000000000000000)
 
 /*   SH_INT_CMPD_REAL_TIME_CMPD                                         */
 /*   Description:  Real Time Clock Compare                              */
-#define SH_INT_CMPD_REAL_TIME_CMPD_SHFT          0
-#define SH_INT_CMPD_REAL_TIME_CMPD_MASK          0x007fffffffffffff
+#define SH_INT_CMPD_REAL_TIME_CMPD_SHFT                        0
+#define SH_INT_CMPD_REAL_TIME_CMPD_MASK        __IA64_UL_CONST(0x007fffffffffffff)
 
 /* ==================================================================== */
 /*                Register "SH_MD_DQLP_MMR_DIR_PRIVEC0"                 */
 /*                      privilege vector for acc=0                      */
 /* ==================================================================== */
-
-#define SH1_MD_DQLP_MMR_DIR_PRIVEC0              0x0000000100030300
+#define SH1_MD_DQLP_MMR_DIR_PRIVEC0    __IA64_UL_CONST(0x0000000100030300)
 
 /* ==================================================================== */
 /*                Register "SH_MD_DQRP_MMR_DIR_PRIVEC0"                 */
 /*                      privilege vector for acc=0                      */
 /* ==================================================================== */
-
-#define SH1_MD_DQRP_MMR_DIR_PRIVEC0              0x0000000100050300
+#define SH1_MD_DQRP_MMR_DIR_PRIVEC0    __IA64_UL_CONST(0x0000000100050300)
 
 /* ==================================================================== */
 /* Some MMRs are functionally identical (or close enough) on both SHUB1 */
 /*                    Engine 0 Control and Status Register                    */
 /* ========================================================================== */
 
-#define SH2_BT_ENG_CSR_0                         0x0000000030040000
-#define SH2_BT_ENG_SRC_ADDR_0                    0x0000000030040080
-#define SH2_BT_ENG_DEST_ADDR_0                   0x0000000030040100
-#define SH2_BT_ENG_NOTIF_ADDR_0                  0x0000000030040180
+#define SH2_BT_ENG_CSR_0               __IA64_UL_CONST(0x0000000030040000)
+#define SH2_BT_ENG_SRC_ADDR_0          __IA64_UL_CONST(0x0000000030040080)
+#define SH2_BT_ENG_DEST_ADDR_0         __IA64_UL_CONST(0x0000000030040100)
+#define SH2_BT_ENG_NOTIF_ADDR_0                __IA64_UL_CONST(0x0000000030040180)
 
 /* ========================================================================== */
 /*                       BTE interfaces 1-3                                   */
 /* ========================================================================== */
 
-#define SH2_BT_ENG_CSR_1                         0x0000000030050000
-#define SH2_BT_ENG_CSR_2                         0x0000000030060000
-#define SH2_BT_ENG_CSR_3                         0x0000000030070000
+#define SH2_BT_ENG_CSR_1               __IA64_UL_CONST(0x0000000030050000)
+#define SH2_BT_ENG_CSR_2               __IA64_UL_CONST(0x0000000030060000)
+#define SH2_BT_ENG_CSR_3               __IA64_UL_CONST(0x0000000030070000)
 
 #endif /* _ASM_IA64_SN_SHUB_MMR_H */
index 78eb4f869c8b202d632d81b2d596bafe52f40e28..cf770e246af5b69acf896d376ab703dcd2183a76 100644 (file)
 
 #include <linux/config.h>
 
-#ifdef CONFIG_IA64_SGI_SN_SIM
-
 #define SNMAGIC 0xaeeeeeee8badbeefL
-#define IS_RUNNING_ON_SIMULATOR() ({long sn; asm("mov %0=cpuid[%1]" : "=r"(sn) : "r"(2)); sn == SNMAGIC;})
-
-#define SIMULATOR_SLEEP()      asm("nop.i 0x8beef")
+#define IS_MEDUSA()                    ({long sn; asm("mov %0=cpuid[%1]" : "=r"(sn) : "r"(2)); sn == SNMAGIC;})
 
+#ifdef CONFIG_IA64_SGI_SN_SIM
+#define SIMULATOR_SLEEP()              asm("nop.i 0x8beef")
+#define IS_RUNNING_ON_SIMULATOR()      (sn_prom_type)
+#define IS_RUNNING_ON_FAKE_PROM()      (sn_prom_type == 2)
+extern int sn_prom_type;               /* 0=hardware, 1=medusa/realprom, 2=medusa/fakeprom */
 #else
-
 #define IS_RUNNING_ON_SIMULATOR()      (0)
+#define IS_RUNNING_ON_FAKE_PROM()      (0)
 #define SIMULATOR_SLEEP()
 
 #endif
index b0c4d6dd77baf396e59c51b48972fe663ee1ea22..df75f4c4aec3bfce3385f8f5cefe1eaafc3dd1d3 100644 (file)
@@ -223,4 +223,6 @@ struct sn_hwperf_ioctl_args {
 #define SN_HWPERF_OP_RECONFIGURE       253
 #define SN_HWPERF_OP_INVAL             254
 
+int sn_topology_open(struct inode *inode, struct file *file);
+int sn_topology_release(struct inode *inode, struct file *file);
 #endif                         /* SN_HWPERF_H */
index eb0395ad0d6a68c1a93e98d86ac045c76928ce51..1455375d2ce4e8429fd78fc565ffe30151b0fb2e 100644 (file)
 #define SALRET_INVALID_ARG     (-2)
 #define SALRET_ERROR           (-3)
 
+#define SN_SAL_FAKE_PROM                          0x02009999
+
 
 /**
  * sn_sal_rev_major - get the major SGI SAL revision number
@@ -1105,4 +1107,12 @@ ia64_sn_bte_recovery(nasid_t nasid)
        return (int) rv.status;
 }
 
+static inline int
+ia64_sn_is_fake_prom(void)
+{
+       struct ia64_sal_retval rv;
+       SAL_CALL_NOLOCK(rv, SN_SAL_FAKE_PROM, 0, 0, 0, 0, 0, 0, 0);
+       return (rv.status == 0);
+}
+
 #endif /* _ASM_IA64_SN_SN_SAL_H */
index b6acc22ab2395ba04dbef557311622333d5590ec..5ccec608d325ef273ba94e3418d3ce8f18dec4c6 100644 (file)
@@ -201,6 +201,7 @@ tioca_tlbflush(struct tioca_kernel *tioca_kernel)
 }
 
 extern uint32_t        tioca_gart_found;
+extern struct list_head tioca_list;
 extern int tioca_init_provider(void);
 extern void tioca_fastwrite_enable(struct tioca_kernel *tioca_kern);
 #endif /* _ASM_IA64_SN_TIO_CA_AGP_PROVIDER_H */
index 6f516e76d1f0cf0947d99fa6d429f01657343791..cd2cf76b2db1d77cb22a69f928f96c4a74d1c59c 100644 (file)
@@ -183,8 +183,6 @@ do {                                                                \
 
 #ifdef __KERNEL__
 
-#define prepare_to_switch()    do { } while(0)
-
 #ifdef CONFIG_IA32_SUPPORT
 # define IS_IA32_PROCESS(regs) (ia64_psr(regs)->is != 0)
 #else
@@ -274,13 +272,7 @@ extern void ia64_load_extra (struct task_struct *task);
  * of that CPU which will not be released, because there we wait for the
  * tasklist_lock to become available.
  */
-#define prepare_arch_switch(rq, next)          \
-do {                                           \
-       spin_lock(&(next)->switch_lock);        \
-       spin_unlock(&(rq)->lock);               \
-} while (0)
-#define finish_arch_switch(rq, prev)   spin_unlock_irq(&(prev)->switch_lock)
-#define task_running(rq, p)            ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock))
+#define __ARCH_WANT_UNLOCKED_CTXSW
 
 #define ia64_platform_is(x) (strcmp(x, platform_name) == 0)
 
index 21cf351fd05cce785e81aa3243c68b4848c804ff..4e64c2a6b36913a5f2a0da25c9c7195ff39d747f 100644 (file)
 
 void build_cpu_to_node_map(void);
 
+#define SD_CPU_INIT (struct sched_domain) {            \
+       .span                   = CPU_MASK_NONE,        \
+       .parent                 = NULL,                 \
+       .groups                 = NULL,                 \
+       .min_interval           = 1,                    \
+       .max_interval           = 4,                    \
+       .busy_factor            = 64,                   \
+       .imbalance_pct          = 125,                  \
+       .cache_hot_time         = (10*1000000),         \
+       .per_cpu_gain           = 100,                  \
+       .cache_nice_tries       = 2,                    \
+       .busy_idx               = 2,                    \
+       .idle_idx               = 1,                    \
+       .newidle_idx            = 2,                    \
+       .wake_idx               = 1,                    \
+       .forkexec_idx           = 1,                    \
+       .flags                  = SD_LOAD_BALANCE       \
+                               | SD_BALANCE_NEWIDLE    \
+                               | SD_BALANCE_EXEC       \
+                               | SD_WAKE_AFFINE,       \
+       .last_balance           = jiffies,              \
+       .balance_interval       = 1,                    \
+       .nr_balance_failed      = 0,                    \
+}
+
 /* sched_domains SD_NODE_INIT for IA64 NUMA machines */
 #define SD_NODE_INIT (struct sched_domain) {           \
        .span                   = CPU_MASK_NONE,        \
        .parent                 = NULL,                 \
        .groups                 = NULL,                 \
-       .min_interval           = 80,                   \
-       .max_interval           = 320,                  \
-       .busy_factor            = 320,                  \
+       .min_interval           = 8                   \
+       .max_interval           = 8*(min(num_online_cpus(), 32)), \
+       .busy_factor            = 64,                   \
        .imbalance_pct          = 125,                  \
        .cache_hot_time         = (10*1000000),         \
-       .cache_nice_tries       = 1,                    \
+       .cache_nice_tries       = 2,                    \
+       .busy_idx               = 3,                    \
+       .idle_idx               = 2,                    \
+       .newidle_idx            = 0, /* unused */       \
+       .wake_idx               = 1,                    \
+       .forkexec_idx           = 1,                    \
        .per_cpu_gain           = 100,                  \
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_EXEC       \
-                               | SD_BALANCE_NEWIDLE    \
-                               | SD_WAKE_IDLE          \
+                               | SD_BALANCE_FORK       \
                                | SD_WAKE_BALANCE,      \
        .last_balance           = jiffies,              \
-       .balance_interval       = 1,                    \
+       .balance_interval       = 64,                   \
        .nr_balance_failed      = 0,                    \
 }
 
@@ -69,17 +98,21 @@ void build_cpu_to_node_map(void);
        .span                   = CPU_MASK_NONE,        \
        .parent                 = NULL,                 \
        .groups                 = NULL,                 \
-       .min_interval           = 80,                   \
-       .max_interval           = 320,                  \
-       .busy_factor            = 320,                  \
-       .imbalance_pct          = 125,                  \
+       .min_interval           = 64,                   \
+       .max_interval           = 64*num_online_cpus(), \
+       .busy_factor            = 128,                  \
+       .imbalance_pct          = 133,                  \
        .cache_hot_time         = (10*1000000),         \
        .cache_nice_tries       = 1,                    \
+       .busy_idx               = 3,                    \
+       .idle_idx               = 3,                    \
+       .newidle_idx            = 0, /* unused */       \
+       .wake_idx               = 0, /* unused */       \
+       .forkexec_idx           = 0, /* unused */       \
        .per_cpu_gain           = 100,                  \
-       .flags                  = SD_LOAD_BALANCE       \
-                               | SD_BALANCE_EXEC,      \
+       .flags                  = SD_LOAD_BALANCE,      \
        .last_balance           = jiffies,              \
-       .balance_interval       = 100*(63+num_online_cpus())/64,   \
+       .balance_interval       = 64,                   \
        .nr_balance_failed      = 0,                    \
 }
 
index f7f43ec2483a604640e965a7feb39df031fe65e5..517f1649ee648ef8ede34cd3113186d231c64cd0 100644 (file)
 #define __NR_add_key                   1271
 #define __NR_request_key               1272
 #define __NR_keyctl                    1273
+#define __NR_ioprio_set                        1274
+#define __NR_ioprio_get                        1275
 #define __NR_set_zone_reclaim          1276
 
 #ifdef __KERNEL__
index 1f446d6841f69d5fc44670f1e6c400592da556f6..bc3349ffc5055e14fba1d60e7b3eef5ae65c88b3 100644 (file)
  * videoram directly without any black magic.
  */
 
-#define VGA_MAP_MEM(x) ((unsigned long) ioremap((x), 0))
+extern unsigned long vga_console_iobase;
+extern unsigned long vga_console_membase;
+
+#define VGA_MAP_MEM(x) ((unsigned long) ioremap(vga_console_membase + (x), 0))
 
 #define vga_readb(x)   (*(x))
 #define vga_writeb(x,y)        (*(y) = (x))
index 9f5bcdc105fceb9855b6225aa4100870266fe482..3fe29f8b01948aa5493906175914a14aef6d6e3e 100644 (file)
 #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
 #endif
 
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#endif
-
-#define STD_SERIAL_PORT_DEFNS                  \
+#define SERIAL_PORT_DFNS                       \
        /* UART CLK   PORT IRQ     FLAGS        */                      \
        { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },      /* ttyS0 */     \
        { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },      /* ttyS1 */     \
        { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },      /* ttyS2 */     \
        { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },     /* ttyS3 */
-
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS                        \
-       { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS },     /* ttyS4 */     \
-       { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },     /* ttyS5 */     \
-       { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },     /* ttyS6 */     \
-       { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },     /* ttyS7 */     \
-       { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },     /* ttyS8 */     \
-       { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },     /* ttyS9 */     \
-       { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },     /* ttyS10 */    \
-       { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },     /* ttyS11 */    \
-       { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },       /* ttyS12 */    \
-       { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },       /* ttyS13 */    \
-       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS14 (spare) */            \
-       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS15 (spare) */            \
-       { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },        /* ttyS16 */    \
-       { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },        /* ttyS17 */    \
-       { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },        /* ttyS18 */    \
-       { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },        /* ttyS19 */    \
-       { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },        /* ttyS20 */    \
-       { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },        /* ttyS21 */    \
-       { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },        /* ttyS22 */    \
-       { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },        /* ttyS23 */    \
-       { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },        /* ttyS24 */    \
-       { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },        /* ttyS25 */    \
-       { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },        /* ttyS26 */    \
-       { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },        /* ttyS27 */    \
-       { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },        /* ttyS28 */    \
-       { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },        /* ttyS29 */    \
-       { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },        /* ttyS30 */    \
-       { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },        /* ttyS31 */
-#else
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif
-
-#define SERIAL_PORT_DFNS               \
-       STD_SERIAL_PORT_DEFNS           \
-       EXTRA_SERIAL_PORT_DEFNS
index 29ee13be0b2ad28687ae2eb57edc546f5ca9fdf0..d721143dbd47596f4387c8ba72f9baa1153c4ef1 100644 (file)
@@ -8,6 +8,8 @@
 #include <asm/page.h>
 #include <mmzone.h>
 
+#ifdef CONFIG_DISCONTIGMEM
+
 #define kvaddr_to_nid(kvaddr)  pa_to_nid(__pa(kvaddr))
 #define pfn_to_nid(pfn)                pa_to_nid((pfn) << PAGE_SHIFT)
 
@@ -36,4 +38,6 @@
 /* XXX: FIXME -- wli */
 #define kern_addr_valid(addr)  (0)
 
+#endif /* CONFIG_DISCONTIGMEM */
+
 #endif /* _ASM_MMZONE_H_ */
index d1bf8240e73b258ff411918683ae7045cdf5493c..5cae35cd9ba923f76e49754d5a81757fdd2f83ad 100644 (file)
@@ -127,7 +127,7 @@ static __inline__ int get_order(unsigned long size)
 
 #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
 
-#ifndef CONFIG_DISCONTIGMEM
+#ifndef CONFIG_NEED_MULTIPLE_NODES
 #define pfn_to_page(pfn)       (mem_map + (pfn))
 #define page_to_pfn(page)      ((unsigned long)((page) - mem_map))
 #define pfn_valid(pfn)         ((pfn) < max_mapnr)
index c9c576b48556b933829594bae7fb4eb3e0bea296..2d323b6e147d135e45cb626c504cb548e81e12b5 100644 (file)
@@ -130,6 +130,16 @@ extern void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
 extern void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
        dma64_addr_t dma_addr, size_t len, int direction);
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+#endif
+
 extern void pcibios_resource_to_bus(struct pci_dev *dev,
        struct pci_bus_region *region, struct resource *res);
 
index 878843203d67aca6580f2aa2d997d39a6685b56e..e76ccd6e3a5dcc8ef9760d7a48bc62b2414af3d8 100644 (file)
@@ -350,7 +350,7 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
        __update_cache(vma, address, pte);
 }
 
-#ifndef CONFIG_DISCONTIGMEM
+#ifndef CONFIG_NEED_MULTIPLE_NODES
 #define kern_addr_valid(addr)  (1)
 #endif
 
index 8a70ff58f7603ebfc27c9422ba2df30546eec0e0..4eed8e2acdc39d348b67fe3743f859cbc8b1e2c3 100644 (file)
 #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
 #endif
 
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#define HUB6_FLAGS 0
-#define RS_TABLE_SIZE  64
-#else
-#define RS_TABLE_SIZE
-#endif
-
-/*
- * The following define the access methods for the HUB6 card. All
- * access is through two ports for all 24 possible chips. The card is
- * selected through the high 2 bits, the port on that card with the
- * "middle" 3 bits, and the register on that port with the bottom
- * 3 bits.
- *
- * While the access port and interrupt is configurable, the default
- * port locations are 0x302 for the port control register, and 0x303
- * for the data read/write register. Normally, the interrupt is at irq3
- * but can be anything from 3 to 7 inclusive. Note that using 3 will
- * require disabling com2.
- */
-
-#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
-
 #ifdef CONFIG_MACH_JAZZ
 #include <asm/jazz.h>
 
        { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },      /* ttyS2 */     \
        { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },     /* ttyS3 */
 
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS                        \
-       { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS },     /* ttyS4 */     \
-       { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },     /* ttyS5 */     \
-       { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },     /* ttyS6 */     \
-       { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },     /* ttyS7 */     \
-       { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },     /* ttyS8 */     \
-       { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },     /* ttyS9 */     \
-       { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },     /* ttyS10 */    \
-       { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },     /* ttyS11 */    \
-       { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },       /* ttyS12 */    \
-       { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },       /* ttyS13 */    \
-       { 0, BASE_BAUD, 0x000, 0, 0 },                  /* ttyS14 (spare) */ \
-       { 0, BASE_BAUD, 0x000, 0, 0 },                  /* ttyS15 (spare) */ \
-       { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },        /* ttyS16 */    \
-       { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },        /* ttyS17 */    \
-       { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },        /* ttyS18 */    \
-       { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },        /* ttyS19 */    \
-       { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },        /* ttyS20 */    \
-       { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },        /* ttyS21 */    \
-       { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },        /* ttyS22 */    \
-       { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },        /* ttyS23 */    \
-       { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },        /* ttyS24 */    \
-       { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },        /* ttyS25 */    \
-       { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },        /* ttyS26 */    \
-       { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },        /* ttyS27 */    \
-       { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },        /* ttyS28 */    \
-       { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },        /* ttyS29 */    \
-       { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },        /* ttyS30 */    \
-       { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },        /* ttyS31 */
-#else /* CONFIG_SERIAL_MANY_PORTS */
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif /* CONFIG_SERIAL_MANY_PORTS */
-
 #else /* CONFIG_HAVE_STD_PC_SERIAL_PORTS */
 #define STD_SERIAL_PORT_DEFNS
-#define EXTRA_SERIAL_PORT_DEFNS
 #endif /* CONFIG_HAVE_STD_PC_SERIAL_PORTS */
 
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
- */
-#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
-#define HUB6_SERIAL_PORT_DFNS          \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) },  /* ttyS32 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) },  /* ttyS33 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) },  /* ttyS34 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) },  /* ttyS35 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) },  /* ttyS36 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) },  /* ttyS37 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) },  /* ttyS38 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) },  /* ttyS39 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) },  /* ttyS40 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) },  /* ttyS41 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) },  /* ttyS42 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) },  /* ttyS43 */
-#else
-#define HUB6_SERIAL_PORT_DFNS
-#endif
-
 #ifdef CONFIG_MOMENCO_JAGUAR_ATX
 /* Ordinary NS16552 duart with a 20MHz crystal.  */
 #define JAGUAR_ATX_UART_CLK    20000000
        COBALT_SERIAL_PORT_DEFNS                        \
        DDB5477_SERIAL_PORT_DEFNS                       \
        EV96100_SERIAL_PORT_DEFNS                       \
-       EXTRA_SERIAL_PORT_DEFNS                         \
-       HUB6_SERIAL_PORT_DFNS                           \
        IP32_SERIAL_PORT_DEFNS                          \
        ITE_SERIAL_PORT_DEFNS                           \
        IVR_SERIAL_PORT_DEFNS                           \
index 888fd8908467210cc9344e3ce3050eabd28ee2de..169f3d4265b14fdeec80c30982572938bab81fc1 100644 (file)
@@ -422,16 +422,10 @@ extern void __die_if_kernel(const char *, struct pt_regs *, const char *file,
 extern int stop_a_enabled;
 
 /*
- * Taken from include/asm-ia64/system.h; prevents deadlock on SMP
+ * See include/asm-ia64/system.h; prevents deadlock on SMP
  * systems.
  */
-#define prepare_arch_switch(rq, next)          \
-do {                                           \
-       spin_lock(&(next)->switch_lock);        \
-       spin_unlock(&(rq)->lock);               \
-} while (0)
-#define finish_arch_switch(rq, prev)   spin_unlock_irq(&(prev)->switch_lock)
-#define task_running(rq, p)            ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock))
+#define __ARCH_WANT_UNLOCKED_CTXSW
 
 #define arch_align_stack(x) (x)
 
index 0763c2982fb085b2691893cc400d00f388119df7..ee741c150176a9f9fab30d503f5fcfd521012e92 100644 (file)
@@ -230,6 +230,25 @@ extern inline void pcibios_register_hba(struct pci_hba_data *x)
 /* export the pci_ DMA API in terms of the dma_ one */
 #include <asm-generic/pci-dma-compat.h>
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       unsigned long cacheline_size;
+       u8 byte;
+
+       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+       if (byte == 0)
+               cacheline_size = 1024;
+       else
+               cacheline_size = (int) byte * 4;
+
+       *strat = PCI_DMA_BURST_MULTIPLE;
+       *strategy_parameter = cacheline_size;
+}
+#endif
+
 extern void
 pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
                         struct resource *res);
index 239c5dcab7e6c8fa3787097dc61e67a57f5f46b7..82fd820d684f090137e5a6c53d7c1adfb7fea263 100644 (file)
  * A500 w/ PCI serial cards: 5 + 4 * card ~= 17
  */
  
-#define STD_SERIAL_PORT_DEFNS                  \
-       { 0, },         /* ttyS0 */     \
-       { 0, },         /* ttyS1 */     \
-       { 0, },         /* ttyS2 */     \
-       { 0, },         /* ttyS3 */     \
-       { 0, },         /* ttyS4 */     \
-       { 0, },         /* ttyS5 */     \
-       { 0, },         /* ttyS6 */     \
-       { 0, },         /* ttyS7 */     \
-       { 0, },         /* ttyS8 */
-
-
-#define SERIAL_PORT_DFNS               \
-       STD_SERIAL_PORT_DEFNS
-
+#define SERIAL_PORT_DFNS
diff --git a/include/asm-ppc/fsl_ocp.h b/include/asm-ppc/fsl_ocp.h
deleted file mode 100644 (file)
index 050fbba..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * include/asm-ppc/fsl_ocp.h
- *
- * Definitions for the on-chip peripherals on Freescale PPC processors
- *
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
- *
- * Copyright 2004 Freescale Semiconductor, Inc
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_FS_OCP_H__
-#define __ASM_FS_OCP_H__
-
-/* A table of information for supporting the Gianfar Ethernet Controller
- * This helps identify which enet controller we are dealing with,
- * and what type of enet controller it is
- */
-struct ocp_gfar_data {
-       uint interruptTransmit;
-       uint interruptError;
-       uint interruptReceive;
-       uint interruptPHY;
-       uint flags;
-       uint phyid;
-       uint phyregidx;
-       unsigned char mac_addr[6];
-};
-
-/* Flags in the flags field */
-#define GFAR_HAS_COALESCE              0x20
-#define GFAR_HAS_RMON                  0x10
-#define GFAR_HAS_MULTI_INTR            0x08
-#define GFAR_FIRM_SET_MACADDR          0x04
-#define GFAR_HAS_PHY_INTR              0x02    /* if not set use a timer */
-#define GFAR_HAS_GIGABIT               0x01
-
-/* Data structure for I2C support.  Just contains a couple flags
- * to distinguish various I2C implementations*/
-struct ocp_fs_i2c_data {
-       uint flags;
-};
-
-/* Flags for I2C */
-#define FS_I2C_SEPARATE_DFSRR  0x02
-#define FS_I2C_CLOCK_5200      0x01
-
-#endif /* __ASM_FS_OCP_H__ */
-#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/kexec.h b/include/asm-ppc/kexec.h
new file mode 100644 (file)
index 0000000..7319131
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _PPC_KEXEC_H
+#define _PPC_KEXEC_H
+
+#ifdef CONFIG_KEXEC
+
+/*
+ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
+ * I.e. Maximum page that is mapped directly into kernel memory,
+ * and kmap is not required.
+ *
+ * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct
+ * calculation for the amount of memory directly mappable into the
+ * kernel memory space.
+ */
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
+/* Maximum address we can use for the control code buffer */
+#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE
+
+#define KEXEC_CONTROL_CODE_SIZE        4096
+
+/* The native architecture */
+#define KEXEC_ARCH KEXEC_ARCH_PPC
+
+#ifndef __ASSEMBLY__
+
+struct kimage;
+
+extern void machine_kexec_simple(struct kimage *image);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* CONFIG_KEXEC */
+
+#endif /* _PPC_KEXEC_H */
index b78d40870c951ac1a41c7133ac3edcc0acad1532..1d4ab70a56f353eed0e22d06d3241983d9559d42 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/kexec.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
@@ -114,6 +115,36 @@ struct machdep_calls {
        /* functions for dealing with other cpus */
        struct smp_ops_t *smp_ops;
 #endif /* CONFIG_SMP */
+
+#ifdef CONFIG_KEXEC
+       /* Called to shutdown machine specific hardware not already controlled
+        * by other drivers.
+        * XXX Should we move this one out of kexec scope?
+        */
+       void (*machine_shutdown)(void);
+
+       /* Called to do the minimal shutdown needed to run a kexec'd kernel
+        * to run successfully.
+        * XXX Should we move this one out of kexec scope?
+        */
+       void (*machine_crash_shutdown)(void);
+
+       /* Called to do what every setup is needed on image and the
+        * reboot code buffer. Returns 0 on success.
+        * Provide your own (maybe dummy) implementation if your platform
+        * claims to support kexec.
+        */
+       int (*machine_kexec_prepare)(struct kimage *image);
+
+       /* Called to handle any machine specific cleanup on image */
+       void (*machine_kexec_cleanup)(struct kimage *image);
+
+       /* Called to perform the _real_ kexec.
+        * Do NOT allocate memory or fail here. We are past the point of
+        * no return.
+        */
+       void (*machine_kexec)(struct kimage *image);
+#endif /* CONFIG_KEXEC */
 };
 
 extern struct machdep_calls ppc_md;
index d465aee1c82ea6c554b986c9058e71e2af75b01c..9205db404c7a27fb9d8b7be620a083323a928588 100644 (file)
@@ -405,7 +405,7 @@ typedef struct _P601_BAT {
 
 #define MAS0_TLBSEL(x) ((x << 28) & 0x30000000)
 #define MAS0_ESEL(x)   ((x << 16) & 0x0FFF0000)
-#define MAS0_NV                0x00000FFF
+#define MAS0_NV(x)     ((x) & 0x00000FFF)
 
 #define MAS1_VALID     0x80000000
 #define MAS1_IPROT     0x40000000
index 9222fa6ca172337970970985870ceca2d9dabe84..ccabbce39d8538702683e0fd51e30680018607f7 100644 (file)
@@ -63,7 +63,7 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 #define LAST_CONTEXT           255
 #define FIRST_CONTEXT          1
 
-#elif defined(CONFIG_E500)
+#elif defined(CONFIG_E200) || defined(CONFIG_E500)
 #define NO_CONTEXT             256
 #define LAST_CONTEXT           255
 #define FIRST_CONTEXT          1
index c726f18451906536ea29f337251d633035b2f98e..983116f59d909f0e802c6f19c30a5d5a9a974e82 100644 (file)
@@ -202,10 +202,6 @@ static DEVICE_ATTR(name##_##field, S_IRUGO, show_##name##_##field, NULL);
 #include <asm/ibm_ocp.h>
 #endif
 
-#ifdef CONFIG_FSL_OCP
-#include <asm/fsl_ocp.h>
-#endif
-
 #endif                         /* CONFIG_PPC_OCP */
 #endif                         /* __OCP_H__ */
 #endif                         /* __KERNEL__ */
index dbe853319741e9e96049b7c6c6c9f089284e6ff6..7848aa610c05676ee8bb4f769718bdc1a852ffb4 100644 (file)
 #define OPENPIC_VEC_IPI                118     /* and up */
 #define OPENPIC_VEC_SPURIOUS   255
 
+/* Priorities */
+#define OPENPIC_PRIORITY_IPI_BASE      10
+#define OPENPIC_PRIORITY_DEFAULT       4
+#define OPENPIC_PRIORITY_NMI           9
+
 /* OpenPIC IRQ controller structure */
 extern struct hw_interrupt_type open_pic;
 
@@ -42,6 +47,7 @@ extern int epic_serial_mode;
 extern void openpic_set_sources(int first_irq, int num_irqs, void __iomem *isr);
 extern void openpic_init(int linux_irq_offset);
 extern void openpic_init_nmi_irq(u_int irq);
+extern void openpic_set_irq_priority(u_int irq, u_int pri);
 extern void openpic_hookup_cascade(u_int irq, char *name,
                                   int (*cascade_fn)(struct pt_regs *));
 extern u_int openpic_irq(void);
index fa9cbb67ce3e009a8ec4e67abfda7d6fcbad4aca..8f994f9f8857e70c2a6530247a668d12ca8f8f19 100644 (file)
 #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
 #endif
 
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#define HUB6_FLAGS 0
-#endif
-       
-/*
- * The following define the access methods for the HUB6 card. All
- * access is through two ports for all 24 possible chips. The card is
- * selected through the high 2 bits, the port on that card with the
- * "middle" 3 bits, and the register on that port with the bottom
- * 3 bits.
- *
- * While the access port and interrupt is configurable, the default
- * port locations are 0x302 for the port control register, and 0x303
- * for the data read/write register. Normally, the interrupt is at irq3
- * but can be anything from 3 to 7 inclusive. Note that using 3 will
- * require disabling com2.
- */
-
-#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
-
-#define STD_SERIAL_PORT_DEFNS                  \
+#define SERIAL_PORT_DFNS                       \
        /* UART CLK   PORT IRQ     FLAGS        */                      \
        { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },      /* ttyS0 */     \
        { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },      /* ttyS1 */     \
        { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },      /* ttyS2 */     \
        { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },     /* ttyS3 */
-
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS                        \
-       { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS },     /* ttyS4 */     \
-       { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },     /* ttyS5 */     \
-       { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },     /* ttyS6 */     \
-       { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },     /* ttyS7 */     \
-       { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },     /* ttyS8 */     \
-       { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },     /* ttyS9 */     \
-       { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },     /* ttyS10 */    \
-       { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },     /* ttyS11 */    \
-       { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },       /* ttyS12 */    \
-       { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },       /* ttyS13 */    \
-       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS14 (spare) */            \
-       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS15 (spare) */            \
-       { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },        /* ttyS16 */    \
-       { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },        /* ttyS17 */    \
-       { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },        /* ttyS18 */    \
-       { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },        /* ttyS19 */    \
-       { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },        /* ttyS20 */    \
-       { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },        /* ttyS21 */    \
-       { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },        /* ttyS22 */    \
-       { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },        /* ttyS23 */    \
-       { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },        /* ttyS24 */    \
-       { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },        /* ttyS25 */    \
-       { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },        /* ttyS26 */    \
-       { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },        /* ttyS27 */    \
-       { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },        /* ttyS28 */    \
-       { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },        /* ttyS29 */    \
-       { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },        /* ttyS30 */    \
-       { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },        /* ttyS31 */
-#else
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif
-
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
- */
-#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
-#define HUB6_SERIAL_PORT_DFNS          \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) },  /* ttyS32 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) },  /* ttyS33 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) },  /* ttyS34 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) },  /* ttyS35 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) },  /* ttyS36 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) },  /* ttyS37 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) },  /* ttyS38 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) },  /* ttyS39 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) },  /* ttyS40 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) },  /* ttyS41 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) },  /* ttyS42 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) },  /* ttyS43 */
-#else
-#define HUB6_SERIAL_PORT_DFNS
-#endif
-
-#define SERIAL_PORT_DFNS               \
-       STD_SERIAL_PORT_DEFNS           \
-       EXTRA_SERIAL_PORT_DEFNS         \
-       HUB6_SERIAL_PORT_DFNS
index ce5ae6d048f51b0246aad54fcd2de651ce2ccc93..db0a2a0ec74d9727ac724967271dd18ad7ab6cc1 100644 (file)
@@ -69,6 +69,16 @@ extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr);
 #define pci_unmap_len(PTR, LEN_NAME)           (0)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+#endif
+
 /*
  * At present there are very few 32-bit PPC machines that can have
  * memory above the 4GB point, and we don't support that.
@@ -103,6 +113,12 @@ extern pgprot_t    pci_phys_mem_access_prot(struct file *file,
                                         unsigned long size,
                                         pgprot_t prot);
 
+#define HAVE_ARCH_PCI_RESOURCE_TO_USER
+extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
+                                const struct resource *rsrc,
+                                u64 *start, u64 *end);
+
+
 #endif /* __KERNEL__ */
 
 #endif /* __PPC_PCI_H */
index 13fa8e7483c1c39319be4598ee67fc64e4345f72..f76221def484d3f8bffa45b0f9a71f9ee88a9cd4 100644 (file)
@@ -174,6 +174,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601)
 #define CLR_TOP32(r)
 #endif /* CONFIG_PPC64BRIDGE */
 
+#define RFCI           .long 0x4c000066        /* rfci instruction */
+#define RFDI           .long 0x4c00004e        /* rfdi instruction */
 #define RFMCI          .long 0x4c00004c        /* rfmci instruction */
 
 #ifdef CONFIG_IBM405_ERR77
index c418aab7cd346a7967581c150789cbb0480c2363..88b4222154d48517cb8ba5e7014a69d306929ccb 100644 (file)
 #define HID0_ICFI      (1<<11)         /* Instr. Cache Flash Invalidate */
 #define HID0_DCI       (1<<10)         /* Data Cache Invalidate */
 #define HID0_SPD       (1<<9)          /* Speculative disable */
+#define HID0_DAPUEN    (1<<8)          /* Debug APU enable */
 #define HID0_SGE       (1<<7)          /* Store Gathering Enable */
 #define HID0_SIED      (1<<7)          /* Serial Instr. Execution [Disable] */
 #define HID0_DFCA      (1<<6)          /* Data Cache Flush Assist */
index 45c5e6f2b7abfc41c22dedf2d4eec2ae8b95c47a..00ad9c754c789b580a05f07110f7f4fccae9202c 100644 (file)
@@ -165,6 +165,8 @@ do {                                                \
 #define SPRN_MCSRR1    0x23B   /* Machine Check Save and Restore Register 1 */
 #define SPRN_MCSR      0x23C   /* Machine Check Status Register */
 #define SPRN_MCAR      0x23D   /* Machine Check Address Register */
+#define SPRN_DSRR0     0x23E   /* Debug Save and Restore Register 0 */
+#define SPRN_DSRR1     0x23F   /* Debug Save and Restore Register 1 */
 #define SPRN_MAS0      0x270   /* MMU Assist Register 0 */
 #define SPRN_MAS1      0x271   /* MMU Assist Register 1 */
 #define SPRN_MAS2      0x272   /* MMU Assist Register 2 */
@@ -264,6 +266,17 @@ do {                                               \
 #define MCSR_BUS_IPERR         0x00000002UL /* Instruction parity Error */
 #define MCSR_BUS_RPERR         0x00000001UL /* Read parity Error */
 #endif
+#ifdef CONFIG_E200
+#define MCSR_MCP       0x80000000UL /* Machine Check Input Pin */
+#define MCSR_CP_PERR   0x20000000UL /* Cache Push Parity Error */
+#define MCSR_CPERR     0x10000000UL /* Cache Parity Error */
+#define MCSR_EXCP_ERR  0x08000000UL /* ISI, ITLB, or Bus Error on 1st insn
+                                       fetch for an exception handler */
+#define MCSR_BUS_IRERR         0x00000010UL /* Read Bus Error on instruction fetch*/
+#define MCSR_BUS_DRERR         0x00000008UL /* Read Bus Error on data load */
+#define MCSR_BUS_WRERR         0x00000004UL /* Write Bus Error on buffered
+                                       store or cache line push */
+#endif
 
 /* Bit definitions for the DBSR. */
 /*
@@ -311,6 +324,7 @@ do {                                                \
 #define ESR_ST         0x00800000      /* Store Operation */
 #define ESR_DLK                0x00200000      /* Data Cache Locking */
 #define ESR_ILK                0x00100000      /* Instr. Cache Locking */
+#define ESR_PUO                0x00040000      /* Unimplemented Operation exception */
 #define ESR_BO         0x00020000      /* Byte Ordering */
 
 /* Bit definitions related to the DBCR0. */
@@ -387,10 +401,12 @@ do {                                              \
 #define ICCR_CACHE     1               /* Cacheable */
 
 /* Bit definitions for L1CSR0. */
+#define L1CSR0_CLFC    0x00000100      /* Cache Lock Bits Flash Clear */
 #define L1CSR0_DCFI    0x00000002      /* Data Cache Flash Invalidate */
+#define L1CSR0_CFI     0x00000002      /* Cache Flash Invalidate */
 #define L1CSR0_DCE     0x00000001      /* Data Cache Enable */
 
-/* Bit definitions for L1CSR0. */
+/* Bit definitions for L1CSR1. */
 #define L1CSR1_ICLFR   0x00000100      /* Instr Cache Lock Bits Flash Reset */
 #define L1CSR1_ICFI    0x00000002      /* Instr Cache Flash Invalidate */
 #define L1CSR1_ICE     0x00000001      /* Instr Cache Enable */
index cc51e5c9acc2eb02ef9673ddc84c08c618ee8dfe..e8b79220b29c1687abb28a324ffc0ee010626cfd 100644 (file)
 #define __NR_request_key       270
 #define __NR_keyctl            271
 #define __NR_waitid            272
+#define __NR_ioprio_set                273
+#define __NR_ioprio_get                274
 
-#define __NR_syscalls          273
+#define __NR_syscalls          275
 
 #define __NR(n)        #n
 
index 80327532de64ecbdd13a819a9d85a39583c13146..8b57da62b674dd1ca5069c14dd93959b18a86809 100644 (file)
@@ -40,7 +40,6 @@ static __inline__ void st_le32(volatile __u32 *addr, const __u32 val)
        __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
 }
 
-#if 0
 static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 value)
 {
        __u16 result;
@@ -63,17 +62,8 @@ static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 value)
        return result;
 }
 
-static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 value)
-{
-       __u64 result;
-#error implement me
-}
-
 #define __arch__swab16(x) ___arch__swab16(x)
 #define __arch__swab32(x) ___arch__swab32(x)
-#define __arch__swab64(x) ___arch__swab64(x)
-
-#endif
 
 /* The same, but returns converted value from the location pointer by addr. */
 #define __arch__swab16p(addr) ld_le16(addr)
index 393299e04d7fcf713915815d74fcba66888f09f0..69b26ad74135fceef296dae507336a47991e1d95 100644 (file)
@@ -41,7 +41,7 @@ struct HvLpEvent;
 #define LpEventMaxSize         256
 #define LpEventAlign           64
 
-struct ItLpQueue {
+struct hvlpevent_queue {
 /*
  * The xSlicCurEventPtr is the pointer to the next event stack entry
  * that will become valid.  The OS must peek at this entry to determine
@@ -69,16 +69,13 @@ struct ItLpQueue {
        char    *xSlicEventStackPtr;    // 0x20
        u8      xIndex;                 // 0x28 unique sequential index.
        u8      xSlicRsvd[3];           // 0x29-2b
-       u32     xInUseWord;             // 0x2C
-       u64     xLpIntCount;            // 0x30 Total Lp Int msgs processed
-       u64     xLpIntCountByType[9];   // 0x38-0x7F Event counts by type
+       spinlock_t      lock;
 };
 
-extern struct ItLpQueue xItLpQueue;
+extern struct hvlpevent_queue hvlpevent_queue;
 
-extern struct HvLpEvent *ItLpQueue_getNextLpEvent(struct ItLpQueue *);
-extern int ItLpQueue_isLpIntPending(struct ItLpQueue *);
-extern unsigned ItLpQueue_process(struct ItLpQueue *, struct pt_regs *);
-extern void ItLpQueue_clearValid(struct HvLpEvent *);
+extern int hvlpevent_is_pending(void);
+extern void process_hvlpevents(struct pt_regs *);
+extern void setup_hvlpevent_queue(void);
 
 #endif /* _ITLPQUEUE_H */
index 488634258a722ee7da2319b61caae04ff877f1e4..d383d161cf8d9b24e28b1f230ae7dedec81cbfdd 100644 (file)
@@ -17,7 +17,7 @@ struct die_args {
 
 /*
    Note - you should never unregister because that can race with NMIs.
-   If you really want to do it first unregister - then synchronize_kernel -
+   If you really want to do it first unregister - then synchronize_sched -
    then free.
  */
 int register_die_notifier(struct notifier_block *nb);
diff --git a/include/asm-ppc64/kexec.h b/include/asm-ppc64/kexec.h
new file mode 100644 (file)
index 0000000..511908a
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _PPC64_KEXEC_H
+#define _PPC64_KEXEC_H
+
+/*
+ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
+ * I.e. Maximum page that is mapped directly into kernel memory,
+ * and kmap is not required.
+ */
+
+/* Maximum physical address we can use pages from */
+/* XXX: since we copy virt we can use any page we allocate */
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
+
+/* Maximum address we can reach in physical address mode */
+/* XXX: I want to allow initrd in highmem.  otherwise set to rmo on lpar */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
+
+/* Maximum address we can use for the control code buffer */
+/* XXX: unused today, ppc32 uses TASK_SIZE, probably left over from use_mm  */
+#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL)
+
+/* XXX: today we don't use this at all, althogh we have a static stack */
+#define KEXEC_CONTROL_CODE_SIZE 4096
+
+/* The native architecture */
+#define KEXEC_ARCH KEXEC_ARCH_PPC64
+
+#define MAX_NOTE_BYTES 1024
+
+#ifndef __ASSEMBLY__
+
+typedef u32 note_buf_t[MAX_NOTE_BYTES/4];
+
+extern note_buf_t crash_notes[];
+
+extern void kexec_smp_wait(void);      /* get and clear naca physid, wait for
+                                         master to copy new code to 0 */
+
+#endif /* __ASSEMBLY__ */
+#endif /* _PPC_KEXEC_H */
+
index 19b468bed0590d095f5ca121bc5829309fed1490..0802919c3235c1b5cc2debe8a0930558525e6615 100644 (file)
@@ -42,10 +42,13 @@ typedef unsigned int kprobe_opcode_t;
 
 #define JPROBE_ENTRY(pentry)   (kprobe_opcode_t *)((func_descr_t *)pentry)
 
+#define ARCH_SUPPORTS_KRETPROBES
+void kretprobe_trampoline(void);
+
 /* Architecture specific copy of original instruction */
 struct arch_specific_insn {
        /* copy of original instruction */
-       kprobe_opcode_t insn[MAX_INSN_SIZE];
+       kprobe_opcode_t *insn;
 };
 
 #ifdef CONFIG_KPROBES
index 553b2ea23bedfb324b56dc76347917794f1872b2..9cdad3ed1526c2a6a74dff7f9c7d0d2ca8ec85b4 100644 (file)
@@ -86,6 +86,7 @@ struct machdep_calls {
 
        void            (*init_IRQ)(void);
        int             (*get_irq)(struct pt_regs *);
+       void            (*cpu_irq_down)(void);
 
        /* PCI stuff */
        void            (*pcibios_fixup)(void);
index 9d03a98a4fa3009ea04496d117649a0203a68a16..f373de5e3dd900964fbf2ac5f3b52e751eeab3a3 100644 (file)
@@ -181,6 +181,28 @@ static inline void tlbiel(unsigned long va)
        asm volatile("ptesync": : :"memory");
 }
 
+static inline unsigned long slot2va(unsigned long avpn, unsigned long large,
+               unsigned long secondary, unsigned long slot)
+{
+       unsigned long va;
+
+       va = avpn << 23;
+
+       if (!large) {
+               unsigned long vpi, pteg;
+
+               pteg = slot / HPTES_PER_GROUP;
+               if (secondary)
+                       pteg = ~pteg;
+
+               vpi = ((va >> 28) ^ pteg) & htab_hash_mask;
+
+               va |= vpi << PAGE_SHIFT;
+       }
+
+       return va;
+}
+
 /*
  * Handle a fault by adding an HPTE. If the address can't be determined
  * to be valid via Linux page tables, return 1. If handled return 0
index ae76cae1483fad886c002fe33aec8166b2c1a5a7..2f0f36f73d38507d548a14ff221b96fe42ffce85 100644 (file)
@@ -20,7 +20,6 @@
 #include       <asm/types.h>
 #include       <asm/lppaca.h>
 #include       <asm/iSeries/ItLpRegSave.h>
-#include       <asm/iSeries/ItLpQueue.h>
 #include       <asm/mmu.h>
 
 register struct paca_struct *local_paca asm("r13");
@@ -62,7 +61,6 @@ struct paca_struct {
        u16 paca_index;                 /* Logical processor number */
 
        u32 default_decr;               /* Default decrementer value */
-       struct ItLpQueue *lpqueue_ptr;  /* LpQueue handled by this CPU */
        u64 kernel_toc;                 /* Kernel TOC address */
        u64 stab_real;                  /* Absolute address of segment table */
        u64 stab_addr;                  /* Virtual address of segment table */
@@ -91,7 +89,6 @@ struct paca_struct {
        u64 next_jiffy_update_tb;       /* TB value for next jiffy update */
        u64 saved_r1;                   /* r1 save for RTAS calls */
        u64 saved_msr;                  /* MSR saved here by enter_rtas */
-       u32 lpevent_count;              /* lpevents processed  */
        u8 proc_enabled;                /* irq soft-enable flag */
 
        /* not yet used */
index 6cd593f660a034eb9aec52e8c2928e03863b4445..d12dfce21e2069777eb7d5cff8db9c1ab49367d2 100644 (file)
@@ -78,6 +78,25 @@ static inline int pci_dac_dma_supported(struct pci_dev *hwdev,u64 mask)
        return 0;
 }
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       unsigned long cacheline_size;
+       u8 byte;
+
+       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+       if (byte == 0)
+               cacheline_size = 1024;
+       else
+               cacheline_size = (int) byte * 4;
+
+       *strat = PCI_DMA_BURST_MULTIPLE;
+       *strategy_parameter = cacheline_size;
+}
+#endif
+
 extern int pci_domain_nr(struct pci_bus *bus);
 
 /* Decide whether to display the domain number in /proc */
@@ -136,6 +155,13 @@ extern pgprot_t    pci_phys_mem_access_prot(struct file *file,
                                         unsigned long size,
                                         pgprot_t prot);
 
+#ifdef CONFIG_PPC_MULTIPLATFORM
+#define HAVE_ARCH_PCI_RESOURCE_TO_USER
+extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
+                                const struct resource *rsrc,
+                                u64 *start, u64 *end);
+#endif /* CONFIG_PPC_MULTIPLATFORM */
+
 
 #endif /* __KERNEL__ */
 
index fdec5e7a7af6cd177e324648bbeeb29da3fb8c4a..0c45e14e26ca66d219035da90519703b7dbdac09 100644 (file)
@@ -17,6 +17,7 @@
 void xics_init_IRQ(void);
 int xics_get_irq(struct pt_regs *);
 void xics_setup_cpu(void);
+void xics_teardown_cpu(void);
 void xics_cause_IPI(int cpu);
 void xics_request_IPIs(void);
 void xics_migrate_irqs_away(void);
index 1d33c5da083edaa5f933598498978e1985efc171..1fcf65be7a230cbc91caa153cb97dfe900ac1b82 100644 (file)
 #define __CPCMD__
 
 /*
+ * the lowlevel function for cpcmd
  * the caller of __cpcmd has to ensure that the response buffer is below 2 GB
  */
-extern void __cpcmd(char *cmd, char *response, int rlen);
+extern int __cpcmd(const char *cmd, char *response, int rlen, int *response_code);
 
 #ifndef __s390x__
 #define cpcmd __cpcmd
 #else
-extern void cpcmd(char *cmd, char *response, int rlen);
+/*
+ * cpcmd is the in-kernel interface for issuing CP commands
+ *
+ * cmd:                null-terminated command string, max 240 characters
+ * response:   response buffer for VM's textual response
+ * rlen:       size of the response buffer, cpcmd will not exceed this size
+ *             but will cap the output, if its too large. Everything that
+ *             did not fit into the buffer will be silently dropped
+ * response_code: return pointer for VM's error code
+ * return value: the size of the response. The caller can check if the buffer
+ *             was large enough by comparing the return value and rlen
+ * NOTE: If the response buffer is not below 2 GB, cpcmd can sleep
+ */
+extern int cpcmd(const char *cmd, char *response, int rlen, int *response_code);
 #endif /*__s390x__*/
 
 #endif
index 6bbcdea42a86079a25d981f40c80097773c8bd08..92360d90144bc698618f1dbf09da1dae22a202d7 100644 (file)
@@ -9,6 +9,8 @@
 #ifndef DEBUG_H
 #define DEBUG_H
 
+#include <linux/config.h>
+#include <linux/fs.h>
 #include <linux/string.h>
 
 /* Note:
@@ -31,19 +33,18 @@ struct __debug_entry{
 } __attribute__((packed));
 
 
-#define __DEBUG_FEATURE_VERSION      1  /* version of debug feature */
+#define __DEBUG_FEATURE_VERSION      2  /* version of debug feature */
 
 #ifdef __KERNEL__
 #include <linux/spinlock.h>
 #include <linux/kernel.h>
 #include <linux/time.h>
-#include <linux/proc_fs.h>
 
 #define DEBUG_MAX_LEVEL            6  /* debug levels range from 0 to 6 */
 #define DEBUG_OFF_LEVEL            -1 /* level where debug is switched off */
 #define DEBUG_FLUSH_ALL            -1 /* parameter to flush all areas */
 #define DEBUG_MAX_VIEWS            10 /* max number of views in proc fs */
-#define DEBUG_MAX_PROCF_LEN        64 /* max length for a proc file name */
+#define DEBUG_MAX_NAME_LEN         64 /* max length for a debugfs file name */
 #define DEBUG_DEFAULT_LEVEL        3  /* initial debug level */
 
 #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */
@@ -64,16 +65,17 @@ typedef struct debug_info {
        spinlock_t lock;                        
        int level;
        int nr_areas;
-       int page_order;
+       int pages_per_area;
        int buf_size;
        int entry_size; 
-       debug_entry_t** areas;
+       debug_entry_t*** areas;
        int active_area;
-       int *active_entry;
-       struct proc_dir_entry* proc_root_entry;
-       struct proc_dir_entry* proc_entries[DEBUG_MAX_VIEWS];
+       int *active_pages;
+       int *active_entries;
+       struct dentry* debugfs_root_entry;
+       struct dentry* debugfs_entries[DEBUG_MAX_VIEWS];
        struct debug_view* views[DEBUG_MAX_VIEWS];      
-       char name[DEBUG_MAX_PROCF_LEN];
+       char name[DEBUG_MAX_NAME_LEN];
 } debug_info_t;
 
 typedef int (debug_header_proc_t) (debug_info_t* id,
@@ -98,7 +100,7 @@ int debug_dflt_header_fn(debug_info_t* id, struct debug_view* view,
                         int area, debug_entry_t* entry, char* out_buf);                                                
                                
 struct debug_view {
-       char name[DEBUG_MAX_PROCF_LEN];
+       char name[DEBUG_MAX_NAME_LEN];
        debug_prolog_proc_t* prolog_proc;
        debug_header_proc_t* header_proc;
        debug_format_proc_t* format_proc;
@@ -120,7 +122,7 @@ debug_entry_t* debug_exception_common(debug_info_t* id, int level,
 
 /* Debug Feature API: */
 
-debug_info_t* debug_register(char* name, int pages_index, int nr_areas,
+debug_info_t* debug_register(char* name, int pages, int nr_areas,
                              int buf_size);
 
 void debug_unregister(debug_info_t* id);
@@ -132,7 +134,8 @@ void debug_stop_all(void);
 extern inline debug_entry_t* 
 debug_event(debug_info_t* id, int level, void* data, int length)
 {
-       if ((!id) || (level > id->level)) return NULL;
+       if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+               return NULL;
         return debug_event_common(id,level,data,length);
 }
 
@@ -140,7 +143,8 @@ extern inline debug_entry_t*
 debug_int_event(debug_info_t* id, int level, unsigned int tag)
 {
         unsigned int t=tag;
-       if ((!id) || (level > id->level)) return NULL;
+       if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+               return NULL;
         return debug_event_common(id,level,&t,sizeof(unsigned int));
 }
 
@@ -148,14 +152,16 @@ extern inline debug_entry_t *
 debug_long_event (debug_info_t* id, int level, unsigned long tag)
 {
         unsigned long t=tag;
-       if ((!id) || (level > id->level)) return NULL;
+       if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+               return NULL;
         return debug_event_common(id,level,&t,sizeof(unsigned long));
 }
 
 extern inline debug_entry_t* 
 debug_text_event(debug_info_t* id, int level, const char* txt)
 {
-       if ((!id) || (level > id->level)) return NULL;
+       if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+               return NULL;
         return debug_event_common(id,level,txt,strlen(txt));
 }
 
@@ -167,7 +173,8 @@ debug_sprintf_event(debug_info_t* id,int level,char *string,...)
 extern inline debug_entry_t* 
 debug_exception(debug_info_t* id, int level, void* data, int length)
 {
-       if ((!id) || (level > id->level)) return NULL;
+       if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+               return NULL;
         return debug_exception_common(id,level,data,length);
 }
 
@@ -175,7 +182,8 @@ extern inline debug_entry_t*
 debug_int_exception(debug_info_t* id, int level, unsigned int tag)
 {
         unsigned int t=tag;
-       if ((!id) || (level > id->level)) return NULL;
+       if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+               return NULL;
         return debug_exception_common(id,level,&t,sizeof(unsigned int));
 }
 
@@ -183,14 +191,16 @@ extern inline debug_entry_t *
 debug_long_exception (debug_info_t* id, int level, unsigned long tag)
 {
         unsigned long t=tag;
-       if ((!id) || (level > id->level)) return NULL;
+       if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+               return NULL;
         return debug_exception_common(id,level,&t,sizeof(unsigned long));
 }
 
 extern inline debug_entry_t* 
 debug_text_exception(debug_info_t* id, int level, const char* txt)
 {
-       if ((!id) || (level > id->level)) return NULL;
+       if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+               return NULL;
         return debug_exception_common(id,level,txt,strlen(txt));
 }
 
diff --git a/include/asm-s390/kexec.h b/include/asm-s390/kexec.h
new file mode 100644 (file)
index 0000000..54cf7d9
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * include/asm-s390/kexec.h
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *
+ */
+
+#ifndef _S390_KEXEC_H
+#define _S390_KEXEC_H
+
+#include <asm/page.h>
+#include <asm/processor.h>
+/*
+ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
+ * I.e. Maximum page that is mapped directly into kernel memory,
+ * and kmap is not required.
+ */
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
+
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
+
+/* Maximum address we can use for the control pages */
+/* Not more than 2GB */
+#define KEXEC_CONTROL_MEMORY_LIMIT (1<<31)
+
+/* Allocate one page for the pdp and the second for the code */
+#define KEXEC_CONTROL_CODE_SIZE 4096
+
+/* The native architecture */
+#define KEXEC_ARCH KEXEC_ARCH_S390
+
+#define MAX_NOTE_BYTES 1024
+typedef u32 note_buf_t[MAX_NOTE_BYTES/4];
+
+extern note_buf_t crash_notes[];
+
+#endif /*_S390_KEXEC_H */
index df5172fc589dc5c4debd62a924047c21bcf5be47..76b5b19c0ae2c1f4c7160d08337c92b4e93444ce 100644 (file)
 
 #ifndef __s390x__
 #define __LC_PFAULT_INTPARM             0x080
+#define __LC_CPU_TIMER_SAVE_AREA        0x0D8
 #define __LC_AREGS_SAVE_AREA            0x120
+#define __LC_GPREGS_SAVE_AREA           0x180
 #define __LC_CREGS_SAVE_AREA            0x1C0
 #else /* __s390x__ */
 #define __LC_PFAULT_INTPARM             0x11B8
+#define __LC_GPREGS_SAVE_AREA           0x1280
+#define __LC_CPU_TIMER_SAVE_AREA        0x1328
 #define __LC_AREGS_SAVE_AREA            0x1340
 #define __LC_CREGS_SAVE_AREA            0x1380
 #endif /* __s390x__ */
@@ -167,7 +171,8 @@ struct _lowcore
        __u16        subchannel_nr;            /* 0x0ba */
        __u32        io_int_parm;              /* 0x0bc */
        __u32        io_int_word;              /* 0x0c0 */
-        __u8         pad3[0xD8-0xC4];          /* 0x0c4 */
+        __u8         pad3[0xD4-0xC4];          /* 0x0c4 */
+       __u32        extended_save_area_addr;  /* 0x0d4 */
        __u32        cpu_timer_save_area[2];   /* 0x0d8 */
        __u32        clock_comp_save_area[2];  /* 0x0e0 */
        __u32        mcck_interruption_code[2]; /* 0x0e8 */
index fb46e9090b500bc2405ca4660dbfb6040188dceb..8bd14de69e35bf5cbbe5c1dcc5ab4a5cffc1b4a1 100644 (file)
@@ -206,6 +206,18 @@ unsigned long get_wchan(struct task_struct *p);
        asm volatile ("ex 0,%0" : : "i" (__LC_DIAG44_OPCODE) : "memory")
 #endif /* __s390x__ */
 
+/*
+ * Set PSW to specified value.
+ */
+static inline void __load_psw(psw_t psw)
+{
+#ifndef __s390x__
+       asm volatile ("lpsw  0(%0)" : : "a" (&psw), "m" (psw) : "cc" );
+#else
+       asm volatile ("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc" );
+#endif
+}
+
 /*
  * Set PSW mask to specified value, while leaving the
  * PSW addr pointing to the next instruction.
@@ -214,8 +226,8 @@ unsigned long get_wchan(struct task_struct *p);
 static inline void __load_psw_mask (unsigned long mask)
 {
        unsigned long addr;
-
        psw_t psw;
+
        psw.mask = mask;
 
 #ifndef __s390x__
@@ -241,30 +253,8 @@ static inline void __load_psw_mask (unsigned long mask)
  */
 static inline void enabled_wait(void)
 {
-       unsigned long reg;
-       psw_t wait_psw;
-
-       wait_psw.mask = PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT |
-               PSW_MASK_MCHECK | PSW_MASK_WAIT | PSW_DEFAULT_KEY;
-#ifndef __s390x__
-       asm volatile (
-               "    basr %0,0\n"
-               "0:  la   %0,1f-0b(%0)\n"
-               "    st   %0,4(%1)\n"
-               "    oi   4(%1),0x80\n"
-               "    lpsw 0(%1)\n"
-               "1:"
-               : "=&a" (reg) : "a" (&wait_psw), "m" (wait_psw)
-               : "memory", "cc" );
-#else /* __s390x__ */
-       asm volatile (
-               "    larl  %0,0f\n"
-               "    stg   %0,8(%1)\n"
-               "    lpswe 0(%1)\n"
-               "0:"
-               : "=&a" (reg) : "a" (&wait_psw), "m" (wait_psw)
-               : "memory", "cc" );
-#endif /* __s390x__ */
+       __load_psw_mask(PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT |
+                       PSW_MASK_MCHECK | PSW_MASK_WAIT | PSW_DEFAULT_KEY);
 }
 
 /*
@@ -273,13 +263,11 @@ static inline void enabled_wait(void)
 
 static inline void disabled_wait(unsigned long code)
 {
-        char psw_buffer[2*sizeof(psw_t)];
         unsigned long ctl_buf;
-        psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1)
-                                  & -sizeof(psw_t));
+        psw_t dw_psw;
 
-        dw_psw->mask = PSW_BASE_BITS | PSW_MASK_WAIT;
-        dw_psw->addr = code;
+        dw_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT;
+        dw_psw.addr = code;
         /* 
          * Store status and then load disabled wait psw,
          * the processor is dead afterwards
@@ -301,7 +289,7 @@ static inline void disabled_wait(unsigned long code)
                       "    oi    0x1c0,0x10\n" /* fake protection bit */
                       "    lpsw 0(%1)"
                       : "=m" (ctl_buf)
-                     : "a" (dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc" );
+                     : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc" );
 #else /* __s390x__ */
         asm volatile ("    stctg 0,0,0(%2)\n"
                       "    ni    4(%2),0xef\n" /* switch off protection */
@@ -333,7 +321,7 @@ static inline void disabled_wait(unsigned long code)
                       "    oi    0x384(1),0x10\n" /* fake protection bit */
                       "    lpswe 0(%1)"
                       : "=m" (ctl_buf)
-                     : "a" (dw_psw), "a" (&ctl_buf),
+                     : "a" (&dw_psw), "a" (&ctl_buf),
                        "m" (dw_psw) : "cc", "0", "1");
 #endif /* __s390x__ */
 }
index 4eff8f2e3bf1d636e78ccb9842bc519722387c7d..fc7c96edc697c5922f0377811b3531cc0d161cdb 100644 (file)
@@ -276,7 +276,7 @@ typedef struct
 #endif /* __s390x__ */
 
 #define PSW_KERNEL_BITS        (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | \
-                        PSW_DEFAULT_KEY)
+                        PSW_MASK_MCHECK | PSW_DEFAULT_KEY)
 #define PSW_USER_BITS  (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
                         PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
                         PSW_MASK_PSTATE | PSW_DEFAULT_KEY)
index 81514d76edcf3d1d498cfc5e53dfa14803c24fd3..864cae7e1fd66382ae919b96ebe781f05fd237e5 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/types.h>
 #include <asm/ptrace.h>
 #include <asm/setup.h>
+#include <asm/processor.h>
 
 #ifdef __KERNEL__
 
@@ -103,29 +104,16 @@ static inline void restore_access_regs(unsigned int *acrs)
        prev = __switch_to(prev,next);                                       \
 } while (0)
 
-#define prepare_arch_switch(rq, next)  do { } while(0)
-#define task_running(rq, p)            ((rq)->curr == (p))
-
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 extern void account_user_vtime(struct task_struct *);
 extern void account_system_vtime(struct task_struct *);
+#endif
 
-#define finish_arch_switch(rq, prev) do {                                   \
+#define finish_arch_switch(prev) do {                                       \
        set_fs(current->thread.mm_segment);                                  \
-       spin_unlock(&(rq)->lock);                                            \
        account_system_vtime(prev);                                          \
-       local_irq_enable();                                                  \
 } while (0)
 
-#else
-
-#define finish_arch_switch(rq, prev) do {                                   \
-       set_fs(current->thread.mm_segment);                                  \
-       spin_unlock_irq(&(rq)->lock);                                        \
-} while (0)
-
-#endif
-
 #define nop() __asm__ __volatile__ ("nop")
 
 #define xchg(ptr,x) \
@@ -331,9 +319,6 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
 
 #ifdef __s390x__
 
-#define __load_psw(psw) \
-        __asm__ __volatile__("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc" );
-
 #define __ctl_load(array, low, high) ({ \
        typedef struct { char _[sizeof(array)]; } addrtype; \
        __asm__ __volatile__ ( \
@@ -390,9 +375,6 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
 
 #else /* __s390x__ */
 
-#define __load_psw(psw) \
-       __asm__ __volatile__("lpsw 0(%0)" : : "a" (&psw) : "cc" );
-
 #define __ctl_load(array, low, high) ({ \
        typedef struct { char _[sizeof(array)]; } addrtype; \
        __asm__ __volatile__ ( \
@@ -451,6 +433,20 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
 /* For spinlocks etc */
 #define local_irq_save(x)      ((x) = local_irq_disable())
 
+/*
+ * Use to set psw mask except for the first byte which
+ * won't be changed by this function.
+ */
+static inline void
+__set_psw_mask(unsigned long mask)
+{
+       local_save_flags(mask);
+       __load_psw_mask(mask);
+}
+
+#define local_mcck_enable()  __set_psw_mask(PSW_KERNEL_BITS)
+#define local_mcck_disable() __set_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK)
+
 #ifdef CONFIG_SMP
 
 extern void smp_ctl_set_bit(int cr, int bit);
index fe101d41e849bfe9c35c08aa624e6e7cdb1fdc93..6c18a3f24316ad69defc3f680edefe695702fca7 100644 (file)
@@ -96,6 +96,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_RESTART_SVC                4       /* restart svc with new svc number */
 #define TIF_SYSCALL_AUDIT      5       /* syscall auditing active */
 #define TIF_SINGLE_STEP                6       /* deliver sigtrap on return to user */
+#define TIF_MCCK_PENDING       7       /* machine check handling is pending */
 #define TIF_USEDFPU            16      /* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG     17      /* true if poll_idle() is polling 
                                           TIF_NEED_RESCHED */
@@ -109,6 +110,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_RESTART_SVC       (1<<TIF_RESTART_SVC)
 #define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SINGLE_STEP       (1<<TIF_SINGLE_STEP)
+#define _TIF_MCCK_PENDING      (1<<TIF_MCCK_PENDING)
 #define _TIF_USEDFPU           (1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
 #define _TIF_31BIT             (1<<TIF_31BIT)
index f1a204f7c0f0b2559636a815d813766f89d71d1f..363db45f8d074314ed9603bc8c26466aeb270134 100644 (file)
 #define __NR_mq_timedreceive   274
 #define __NR_mq_notify         275
 #define __NR_mq_getsetattr     276
-/* Number 277 is reserved for new sys_kexec_load */
+#define __NR_kexec_load                277
 #define __NR_add_key           278
 #define __NR_request_key       279
 #define __NR_keyctl            280
index 540f12205923732c3fd280b61a12bd3cf0a45fb4..7233af42f75584d5d2c421396061d6541f35bcbe 100644 (file)
 #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
 
 
-#define STD_SERIAL_PORT_DEFNS                   \
+#define SERIAL_PORT_DFNS                   \
         /* UART CLK   PORT IRQ     FLAGS        */                      \
         { 0, BASE_BAUD, 0x3F8, HD64465_IRQ_UART, STD_COM_FLAGS } /* ttyS0 */ 
 
-
-#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS
-
 /* XXX: This should be moved ino irq.h */
 #define irq_cannonicalize(x) (x)
 
index f8eb16312ed9dde876e2fa2c4dc5b5dc1e26e8a3..cfe4d78ec1eea102b2975e33e9db908ac020f09b 100644 (file)
  * it's got the keyboard controller behind it so we can't really use it
  * (without moving the keyboard driver to userspace, which doesn't sound
  * like a very good idea) */
-#define STD_SERIAL_PORT_DEFNS                  \
+#define SERIAL_PORT_DFNS                       \
        /* UART CLK   PORT IRQ     FLAGS        */                      \
        { 0, BASE_BAUD, 0x11C00, EC3104_IRQBASE+7, STD_COM_FLAGS }, /* ttyS0 */ \
        { 0, BASE_BAUD, 0x12000, EC3104_IRQBASE+8, STD_COM_FLAGS }, /* ttyS1 */ \
        { 0, BASE_BAUD, 0x12400, EC3104_IRQBASE+9, STD_COM_FLAGS }, /* ttyS2 */
 
-#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS
-
 /* XXX: This should be moved ino irq.h */
 #define irq_cannonicalize(x) (x)
index 9c3b63d0105ef2ef1336822a6311e93773ec7f27..26044889c7700e6066fb3e5183810bca17ccaeba 100644 (file)
@@ -96,6 +96,16 @@ static inline void pcibios_penalize_isa_irq(int irq)
 #define sg_dma_address(sg)     (virt_to_bus((sg)->dma_address))
 #define sg_dma_len(sg)         ((sg)->length)
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+#endif
+
 /* Board-specific fixup routines. */
 extern void pcibios_fixup(void);
 extern void pcibios_fixup_irqs(void);
index 5474dbdbaa86fd925dffb20fa476982a6d98eb66..f51e232d5cd94f085fef8e3698c67c390b0edca1 100644 (file)
 #ifdef CONFIG_HD64465
 #include <asm/hd64465.h>
 
-#define STD_SERIAL_PORT_DEFNS                   \
+#define SERIAL_PORT_DFNS                   \
         /* UART CLK   PORT IRQ     FLAGS        */                      \
         { 0, BASE_BAUD, 0x3F8, HD64465_IRQ_UART, STD_COM_FLAGS }  /* ttyS0 */
 
 #else
 
-#define STD_SERIAL_PORT_DEFNS                  \
+#define SERIAL_PORT_DFNS                       \
        /* UART CLK   PORT IRQ     FLAGS        */                      \
        { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },      /* ttyS0 */     \
        { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }       /* ttyS1 */
 
 #endif
 
-#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS
-
 #endif
 #endif /* _ASM_SERIAL_H */
index 8cc14e139750d7833b00b134c4f03b1bfb7ffe62..c68870e02d9133ae269116917b35d91bb93e6f30 100644 (file)
@@ -86,6 +86,16 @@ static inline void pcibios_penalize_isa_irq(int irq)
 #define sg_dma_address(sg)     ((sg)->dma_address)
 #define sg_dma_len(sg)         ((sg)->length)
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+#endif
+
 /* Board-specific fixup routines. */
 extern void pcibios_fixup(void);
 extern void pcibios_fixup_irqs(void);
index 8e39b4e90c763c69017f1a6e97000d50023545d6..29c9be15112ba1fbca610958cd7c9a0cc71b33c9 100644 (file)
 
 #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
 
-#define STD_SERIAL_PORT_DEFNS                  \
+#define SERIAL_PORT_DFNS                       \
        /* UART CLK   PORT IRQ     FLAGS        */                      \
        { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },      /* ttyS0 */     \
        { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }       /* ttyS1 */
 
-#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS
-
 /* XXX: This should be moved ino irq.h */
 #define irq_cannonicalize(x) (x)
 
index d200a25a7373b77c58453a443c802882bf42962d..44bb38758c96964b51e9a925647d52e64b93a2fc 100644 (file)
@@ -144,6 +144,16 @@ extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 
 #define pci_dac_dma_supported(dev, mask)       (0)
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+#endif
+
 static inline void pcibios_add_platform_entries(struct pci_dev *dev)
 {
 }
index 80cf20cfaee1cdf1d6213fbd5b9a516a73c9a9ff..898562ebe94c6d8e7abfbc75d8d9f22e0ffd8dc1 100644 (file)
@@ -101,7 +101,7 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
  * SWITCH_ENTER and SWITH_DO_LAZY_FPU do not work yet (e.g. SMP does not work)
  * XXX WTF is the above comment? Found in late teen 2.4.x.
  */
-#define prepare_arch_switch(rq, next) do { \
+#define prepare_arch_switch(next) do { \
        __asm__ __volatile__( \
        ".globl\tflush_patch_switch\nflush_patch_switch:\n\t" \
        "save %sp, -0x40, %sp; save %sp, -0x40, %sp; save %sp, -0x40, %sp\n\t" \
@@ -109,8 +109,6 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
        "save %sp, -0x40, %sp\n\t" \
        "restore; restore; restore; restore; restore; restore; restore"); \
 } while(0)
-#define finish_arch_switch(rq, next)   spin_unlock_irq(&(rq)->lock)
-#define task_running(rq, p)            ((rq)->curr == (p))
 
        /* Much care has gone into this code, do not touch it.
         *
index 5eb01dd471507a2be701c4be03bd6499be82f431..81a590a50a1fa24ce38662c6586e30c4f2d26c89 100644 (file)
@@ -75,6 +75,8 @@
 
 #ifndef __ASSEMBLY__
 
+extern void __iomem *auxio_register;
+
 #define AUXIO_LTE_ON   1
 #define AUXIO_LTE_OFF  0
 
index e071b4b4edfd8ec8b92ceb4d3d8edcfc4cd644dc..49d49a285943d2654e3a59c50376d3bca384d353 100644 (file)
@@ -159,7 +159,7 @@ static void sun_82077_fd_outb(unsigned char value, unsigned long port)
  * underruns.  If non-zero, doing_pdma encodes the direction of
  * the transfer for debugging.  1=read 2=write
  */
-char *pdma_vaddr;
+unsigned char *pdma_vaddr;
 unsigned long pdma_size;
 volatile int doing_pdma = 0;
 
@@ -209,8 +209,7 @@ static void sun_fd_enable_dma(void)
        pdma_areasize = pdma_size;
 }
 
-/* Our low-level entry point in arch/sparc/kernel/entry.S */
-extern irqreturn_t floppy_hardint(int irq, void *unused, struct pt_regs *regs);
+extern irqreturn_t sparc_floppy_irq(int, void *, struct pt_regs *);
 
 static int sun_fd_request_irq(void)
 {
@@ -220,8 +219,8 @@ static int sun_fd_request_irq(void)
        if(!once) {
                once = 1;
 
-               error = request_fast_irq(FLOPPY_IRQ, floppy_hardint
-                                        SA_INTERRUPT, "floppy", NULL);
+               error = request_irq(FLOPPY_IRQ, sparc_floppy_irq
+                                   SA_INTERRUPT, "floppy", NULL);
 
                return ((error == 0) ? 0 : -1);
        }
@@ -615,7 +614,7 @@ static unsigned long __init sun_floppy_init(void)
                struct linux_ebus *ebus;
                struct linux_ebus_device *edev = NULL;
                unsigned long config = 0;
-               unsigned long auxio_reg;
+               void __iomem *auxio_reg;
 
                for_each_ebus(ebus) {
                        for_each_ebusdev(edev, ebus) {
@@ -642,7 +641,7 @@ static unsigned long __init sun_floppy_init(void)
                /* Make sure the high density bit is set, some systems
                 * (most notably Ultra5/Ultra10) come up with it clear.
                 */
-               auxio_reg = edev->resource[2].start;
+               auxio_reg = (void __iomem *) edev->resource[2].start;
                writel(readl(auxio_reg)|0x2, auxio_reg);
 
                sun_pci_ebus_dev = ebus->self;
@@ -650,7 +649,8 @@ static unsigned long __init sun_floppy_init(void)
                spin_lock_init(&sun_pci_fd_ebus_dma.lock);
 
                /* XXX ioremap */
-               sun_pci_fd_ebus_dma.regs = edev->resource[1].start;
+               sun_pci_fd_ebus_dma.regs = (void __iomem *)
+                       edev->resource[1].start;
                if (!sun_pci_fd_ebus_dma.regs)
                        return 0;
 
index 3aef0ca67750de82d5cade3fd37546a6115f322d..018e2e46082b9844b2a7c50738c3002c0a1103ff 100644 (file)
@@ -19,7 +19,7 @@
 /* You should not mess with this directly. That's the job of irq.c.
  *
  * If you make changes here, please update hand coded assembler of
- * SBUS/floppy interrupt handler in entry.S -DaveM
+ * the vectored interrupt trap handler in entry.S -DaveM
  *
  * This is currently one DCACHE line, two buckets per L2 cache
  * line.  Keep this in mind please.
@@ -122,11 +122,6 @@ extern void enable_irq(unsigned int);
 extern unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap);
 extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
 
-extern int request_fast_irq(unsigned int irq,
-                           irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                           unsigned long flags, __const__ char *devname,
-                           void *dev_id);
-
 static __inline__ void set_softint(unsigned long bits)
 {
        __asm__ __volatile__("wr        %0, 0x0, %%set_softint"
index f70d3dad01f9398166409397efbf2f5013959654..6321f5a0198d4811c3a7ed4a8bbf2efed4b86a37 100644 (file)
@@ -16,7 +16,7 @@ struct die_args {
 };
 
 /* Note - you should never unregister because that can race with NMIs.
- * If you really want to do it first unregister - then synchronize_kernel
+ * If you really want to do it first unregister - then synchronize_sched
  * - then free.
  */
 int register_die_notifier(struct notifier_block *nb);
index 2a0c85cd1c11de63ba0bb21ddb4424445e9f8722..84e41c1ef3f8e6e621215adcc9195e58c9928d59 100644 (file)
@@ -220,6 +220,25 @@ static inline int pci_dma_mapping_error(dma_addr_t dma_addr)
        return (dma_addr == PCI_DMA_ERROR_CODE);
 }
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       unsigned long cacheline_size;
+       u8 byte;
+
+       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+       if (byte == 0)
+               cacheline_size = 1024;
+       else
+               cacheline_size = (int) byte * 4;
+
+       *strat = PCI_DMA_BURST_BOUNDARY;
+       *strategy_parameter = cacheline_size;
+}
+#endif
+
 /* Return the index of the PCI controller for device PDEV. */
 
 extern int pci_domain_nr(struct pci_bus *bus);
index bf2ae90ed3df8ecef35fbb62444675e7ae8fea9e..a1cc94f95984039f4e416686ca5a427964a6bc95 100644 (file)
@@ -55,8 +55,9 @@ static __inline__ int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
                "add            %%g1, %1, %%g7\n\t"
                "cas            [%2], %%g1, %%g7\n\t"
                "cmp            %%g1, %%g7\n\t"
+               "membar         #StoreLoad | #StoreStore\n\t"
                "bne,pn         %%icc, 1b\n\t"
-               " membar        #StoreLoad | #StoreStore\n\t"
+               " nop\n\t"
                "mov            %%g7, %0\n\t"
                : "=&r" (tmp)
                : "0" (tmp), "r" (sem)
index db7581bdb53141a8493991dc02c8bb20af768f1d..9cb93a5c2b4feac61ab2245c9ca17cb74997ded0 100644 (file)
@@ -52,12 +52,14 @@ static inline void _raw_spin_lock(spinlock_t *lock)
 
        __asm__ __volatile__(
 "1:    ldstub          [%1], %0\n"
+"      membar          #StoreLoad | #StoreStore\n"
 "      brnz,pn         %0, 2f\n"
-"       membar         #StoreLoad | #StoreStore\n"
+"       nop\n"
 "      .subsection     2\n"
 "2:    ldub            [%1], %0\n"
+"      membar          #LoadLoad\n"
 "      brnz,pt         %0, 2b\n"
-"       membar         #LoadLoad\n"
+"       nop\n"
 "      ba,a,pt         %%xcc, 1b\n"
 "      .previous"
        : "=&r" (tmp)
@@ -95,16 +97,18 @@ static inline void _raw_spin_lock_flags(spinlock_t *lock, unsigned long flags)
 
        __asm__ __volatile__(
 "1:    ldstub          [%2], %0\n"
-"      brnz,pn         %0, 2f\n"
 "      membar          #StoreLoad | #StoreStore\n"
+"      brnz,pn         %0, 2f\n"
+"       nop\n"
 "      .subsection     2\n"
 "2:    rdpr            %%pil, %1\n"
 "      wrpr            %3, %%pil\n"
 "3:    ldub            [%2], %0\n"
-"      brnz,pt         %0, 3b\n"
 "      membar          #LoadLoad\n"
+"      brnz,pt         %0, 3b\n"
+"       nop\n"
 "      ba,pt           %%xcc, 1b\n"
-"      wrpr            %1, %%pil\n"
+"       wrpr           %1, %%pil\n"
 "      .previous"
        : "=&r" (tmp1), "=&r" (tmp2)
        : "r"(lock), "r"(flags)
@@ -162,12 +166,14 @@ static void inline __read_lock(rwlock_t *lock)
 "4:     add            %0, 1, %1\n"
 "      cas             [%2], %0, %1\n"
 "      cmp             %0, %1\n"
+"      membar          #StoreLoad | #StoreStore\n"
 "      bne,pn          %%icc, 1b\n"
-"       membar         #StoreLoad | #StoreStore\n"
+"       nop\n"
 "      .subsection     2\n"
 "2:    ldsw            [%2], %0\n"
+"      membar          #LoadLoad\n"
 "      brlz,pt         %0, 2b\n"
-"       membar         #LoadLoad\n"
+"       nop\n"
 "      ba,a,pt         %%xcc, 4b\n"
 "      .previous"
        : "=&r" (tmp1), "=&r" (tmp2)
@@ -204,12 +210,14 @@ static void inline __write_lock(rwlock_t *lock)
 "4:     or             %0, %3, %1\n"
 "      cas             [%2], %0, %1\n"
 "      cmp             %0, %1\n"
+"      membar          #StoreLoad | #StoreStore\n"
 "      bne,pn          %%icc, 1b\n"
-"       membar         #StoreLoad | #StoreStore\n"
+"       nop\n"
 "      .subsection     2\n"
 "2:    lduw            [%2], %0\n"
+"      membar          #LoadLoad\n"
 "      brnz,pt         %0, 2b\n"
-"       membar         #LoadLoad\n"
+"       nop\n"
 "      ba,a,pt         %%xcc, 4b\n"
 "      .previous"
        : "=&r" (tmp1), "=&r" (tmp2)
@@ -240,8 +248,9 @@ static int inline __write_trylock(rwlock_t *lock)
 "       or             %0, %4, %1\n"
 "      cas             [%3], %0, %1\n"
 "      cmp             %0, %1\n"
+"      membar          #StoreLoad | #StoreStore\n"
 "      bne,pn          %%icc, 1b\n"
-"       membar         #StoreLoad | #StoreStore\n"
+"       nop\n"
 "      mov             1, %2\n"
 "2:"
        : "=&r" (tmp1), "=&r" (tmp2), "=&r" (result)
index 9d7613eea8129a58dbbcca8dbaef05f2228f6d66..1aa932773af8464bd5ff779a4375026814165f4b 100644 (file)
@@ -111,7 +111,6 @@ static __inline__ void spitfire_put_dcache_tag(unsigned long addr, unsigned long
                             "membar    #Sync"
                             : /* No outputs */
                             : "r" (tag), "r" (addr), "i" (ASI_DCACHE_TAG));
-       __asm__ __volatile__ ("membar #Sync" : : : "memory");
 }
 
 /* The instruction cache lines are flushed with this, but note that
index fd12ca386f486047b141926aa41890f2d129d095..f9be2c5b4dc97360013fb5ddfe2d54c23aeaad90 100644 (file)
@@ -139,19 +139,13 @@ extern void __flushw_user(void);
 #define flush_user_windows flushw_user
 #define flush_register_windows flushw_all
 
-#define prepare_arch_switch(rq, next)          \
-do {   spin_lock(&(next)->switch_lock);        \
-       spin_unlock(&(rq)->lock);               \
+/* Don't hold the runqueue lock over context switch */
+#define __ARCH_WANT_UNLOCKED_CTXSW
+#define prepare_arch_switch(next)              \
+do {                                           \
        flushw_all();                           \
 } while (0)
 
-#define finish_arch_switch(rq, prev)           \
-do {   spin_unlock_irq(&(prev)->switch_lock);  \
-} while (0)
-
-#define task_running(rq, p) \
-       ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock))
-
        /* See what happens when you design the chip correctly?
         *
         * We tell gcc we clobber all non-fixed-usage registers except
index 8effce0da0878f054ec6b3514a3f34b00a385fa5..9777a9cca88aa900a68545fccb1e7939bcf51a81 100644 (file)
@@ -100,16 +100,17 @@ struct winsize {
 #define user_termio_to_kernel_termios(termios, termio) \
 ({ \
        unsigned short tmp; \
-       get_user(tmp, &(termio)->c_iflag); \
+       int err; \
+       err = get_user(tmp, &(termio)->c_iflag); \
        (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \
-       get_user(tmp, &(termio)->c_oflag); \
+       err |= get_user(tmp, &(termio)->c_oflag); \
        (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \
-       get_user(tmp, &(termio)->c_cflag); \
+       err |= get_user(tmp, &(termio)->c_cflag); \
        (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \
-       get_user(tmp, &(termio)->c_lflag); \
+       err |= get_user(tmp, &(termio)->c_lflag); \
        (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \
-       copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
-       0; \
+       err |= copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+       err; \
 })
 
 /*
@@ -119,53 +120,56 @@ struct winsize {
  */
 #define kernel_termios_to_user_termio(termio, termios) \
 ({ \
-       put_user((termios)->c_iflag, &(termio)->c_iflag); \
-       put_user((termios)->c_oflag, &(termio)->c_oflag); \
-       put_user((termios)->c_cflag, &(termio)->c_cflag); \
-       put_user((termios)->c_lflag, &(termio)->c_lflag); \
-       put_user((termios)->c_line,  &(termio)->c_line); \
-       copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+       int err; \
+       err  = put_user((termios)->c_iflag, &(termio)->c_iflag); \
+       err |= put_user((termios)->c_oflag, &(termio)->c_oflag); \
+       err |= put_user((termios)->c_cflag, &(termio)->c_cflag); \
+       err |= put_user((termios)->c_lflag, &(termio)->c_lflag); \
+       err |= put_user((termios)->c_line,  &(termio)->c_line); \
+       err |= copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
        if (!((termios)->c_lflag & ICANON)) { \
-               put_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \
-               put_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \
+               err |= put_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \
+               err |= put_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \
        } \
-       0; \
+       err; \
 })
 
 #define user_termios_to_kernel_termios(k, u) \
 ({ \
-       get_user((k)->c_iflag, &(u)->c_iflag); \
-       get_user((k)->c_oflag, &(u)->c_oflag); \
-       get_user((k)->c_cflag, &(u)->c_cflag); \
-       get_user((k)->c_lflag, &(u)->c_lflag); \
-       get_user((k)->c_line,  &(u)->c_line); \
-       copy_from_user((k)->c_cc, (u)->c_cc, NCCS); \
+       int err; \
+       err  = get_user((k)->c_iflag, &(u)->c_iflag); \
+       err |= get_user((k)->c_oflag, &(u)->c_oflag); \
+       err |= get_user((k)->c_cflag, &(u)->c_cflag); \
+       err |= get_user((k)->c_lflag, &(u)->c_lflag); \
+       err |= get_user((k)->c_line,  &(u)->c_line); \
+       err |= copy_from_user((k)->c_cc, (u)->c_cc, NCCS); \
        if((k)->c_lflag & ICANON) { \
-               get_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \
-               get_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \
+               err |= get_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \
+               err |= get_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \
        } else { \
-               get_user((k)->c_cc[VMIN],  &(u)->c_cc[_VMIN]); \
-               get_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \
+               err |= get_user((k)->c_cc[VMIN],  &(u)->c_cc[_VMIN]); \
+               err |= get_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \
        } \
-       0; \
+       err; \
 })
 
 #define kernel_termios_to_user_termios(u, k) \
 ({ \
-       put_user((k)->c_iflag, &(u)->c_iflag); \
-       put_user((k)->c_oflag, &(u)->c_oflag); \
-       put_user((k)->c_cflag, &(u)->c_cflag); \
-       put_user((k)->c_lflag, &(u)->c_lflag); \
-       put_user((k)->c_line, &(u)->c_line); \
-       copy_to_user((u)->c_cc, (k)->c_cc, NCCS); \
+       int err; \
+       err  = put_user((k)->c_iflag, &(u)->c_iflag); \
+       err |= put_user((k)->c_oflag, &(u)->c_oflag); \
+       err |= put_user((k)->c_cflag, &(u)->c_cflag); \
+       err |= put_user((k)->c_lflag, &(u)->c_lflag); \
+       err |= put_user((k)->c_line, &(u)->c_line); \
+       err |= copy_to_user((u)->c_cc, (k)->c_cc, NCCS); \
        if(!((k)->c_lflag & ICANON)) { \
-               put_user((k)->c_cc[VMIN],  &(u)->c_cc[_VMIN]); \
-               put_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \
+               err |= put_user((k)->c_cc[VMIN],  &(u)->c_cc[_VMIN]); \
+               err |= put_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \
        } else { \
-               put_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \
-               put_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \
+               err |= put_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \
+               err |= put_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \
        } \
-       0; \
+       err; \
 })
 
 #endif /* __KERNEL__ */
index 04222f35c43e2cd0a64b9b28e390be9953104ee6..fe882b9d917eb3d42d4fb73151a833271ef1c8e3 100644 (file)
 #define PT_REGS_SYSCALL_RET(r) PT_REGS_EAX(r)
 #define PT_FIX_EXEC_STACK(sp) do ; while(0)
 
+/* Cope with a conditional i386 definition. */
+#undef profile_pc
+#define profile_pc(regs) PT_REGS_IP(regs)
+
 #define user_mode(r) UPT_IS_USER(&(r)->regs)
 
 #endif
index e41941447b49210a103361c0d3dfe6ba30e8aef3..8e79be0fe99d89b342f303d23b9b81a17223c293 100644 (file)
@@ -81,6 +81,16 @@ extern void
 pci_free_consistent (struct pci_dev *pdev, size_t size, void *cpu_addr,
                     dma_addr_t dma_addr);
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+#endif
+
 static inline void pcibios_add_platform_entries(struct pci_dev *dev)
 {
 }
index e4b1017b8b2b1cbb7208abcd123b38e49d0d3e46..16ec82e16b21aa18e400e269f386b3d52b3d9ee0 100644 (file)
@@ -77,7 +77,7 @@ static inline void ack_APIC_irq(void)
 extern int get_maxlvt (void);
 extern void clear_local_APIC (void);
 extern void connect_bsp_APIC (void);
-extern void disconnect_bsp_APIC (void);
+extern void disconnect_bsp_APIC (int virt_wire_setup);
 extern void disable_local_APIC (void);
 extern int verify_local_APIC (void);
 extern void cache_APIC_registers (void);
index bfebdb6906547182cb1c328d208518a300f1eabf..9388062c4f6e52fd409ef099395ca55be862c21d 100644 (file)
@@ -94,7 +94,7 @@
 #define                        SET_APIC_DELIVERY_MODE(x,y)     (((x)&~0x700)|((y)<<8))
 #define                                APIC_MODE_FIXED         0x0
 #define                                APIC_MODE_NMI           0x4
-#define                                APIC_MODE_EXINT         0x7
+#define                                APIC_MODE_EXTINT        0x7
 #define        APIC_LVT1       0x360
 #define                APIC_LVTERR     0x370
 #define                APIC_TMICT      0x380
index 32573749004c7cbd2ea95ac37e78006d11ca9649..a8babd2bbe849c5197e96b908ffc7ded77e388e0 100644 (file)
@@ -217,4 +217,6 @@ extern int assign_irq_vector(int irq);
 
 void enable_NMI_through_LVT0 (void * dummy);
 
+extern spinlock_t i8259A_lock;
+
 #endif
index 3af50b3c3b05130a3044c37cb46bb89f2843a3d4..eb3b7aa9eb9f2c4ea0bc34b6a72522a36a8a1041 100644 (file)
@@ -52,4 +52,9 @@ struct irqaction;
 struct pt_regs;
 int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
 
+#ifdef CONFIG_HOTPLUG_CPU
+#include <linux/cpumask.h>
+extern void fixup_irqs(cpumask_t map);
+#endif
+
 #endif /* _ASM_IRQ_H */
index 6277f75cbb4b3f1a25330cf80280e9118f63f8a3..b90341994d80f6e78d18f685cca99e15baea8e37 100644 (file)
@@ -14,7 +14,7 @@ struct die_args {
 }; 
 
 /* Note - you should never unregister because that can race with NMIs.
-   If you really want to do it first unregister - then synchronize_kernel - then free. 
+   If you really want to do it first unregister - then synchronize_sched - then free.
   */
 int register_die_notifier(struct notifier_block *nb);
 extern struct notifier_block *die_chain;
diff --git a/include/asm-x86_64/kexec.h b/include/asm-x86_64/kexec.h
new file mode 100644 (file)
index 0000000..42d2ff1
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _X86_64_KEXEC_H
+#define _X86_64_KEXEC_H
+
+#include <asm/page.h>
+#include <asm/proto.h>
+
+/*
+ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
+ * I.e. Maximum page that is mapped directly into kernel memory,
+ * and kmap is not required.
+ *
+ * So far x86_64 is limited to 40 physical address bits.
+ */
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT      (0xFFFFFFFFFFUL)
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (0xFFFFFFFFFFUL)
+/* Maximum address we can use for the control pages */
+#define KEXEC_CONTROL_MEMORY_LIMIT     (0xFFFFFFFFFFUL)
+
+/* Allocate one page for the pdp and the second for the code */
+#define KEXEC_CONTROL_CODE_SIZE  (4096UL + 4096UL)
+
+/* The native architecture */
+#define KEXEC_ARCH KEXEC_ARCH_X86_64
+
+#define MAX_NOTE_BYTES 1024
+typedef u32 note_buf_t[MAX_NOTE_BYTES/4];
+
+extern note_buf_t crash_notes[];
+
+#endif /* _X86_64_KEXEC_H */
index 60130f4ca986b7855119ec0486c45a94e881191f..431318764af60da58dae27c150deed7379676198 100644 (file)
@@ -64,12 +64,14 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 #define __pgd(x) ((pgd_t) { (x) } )
 #define __pgprot(x)    ((pgprot_t) { (x) } )
 
-#define __START_KERNEL         0xffffffff80100000UL
+#define __PHYSICAL_START       ((unsigned long)CONFIG_PHYSICAL_START)
+#define __START_KERNEL         (__START_KERNEL_map + __PHYSICAL_START)
 #define __START_KERNEL_map     0xffffffff80000000UL
 #define __PAGE_OFFSET           0xffff810000000000UL
 
 #else
-#define __START_KERNEL         0xffffffff80100000
+#define __PHYSICAL_START       CONFIG_PHYSICAL_START
+#define __START_KERNEL         (__START_KERNEL_map + __PHYSICAL_START)
 #define __START_KERNEL_map     0xffffffff80000000
 #define __PAGE_OFFSET           0xffff810000000000
 #endif /* !__ASSEMBLY__ */
index 8712520ca47fc071b1c2eb672c02da70b4f616d3..c1961db88fac5f5fbcf779327f4c4b87584a3b9d 100644 (file)
@@ -123,6 +123,16 @@ pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr,
        flush_write_buffers();
 }
 
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+#endif
+
 #define HAVE_PCI_MMAP
 extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                               enum pci_mmap_state mmap_state, int write_combine);
index dbab232044cd64505f57a5698feb191b4f9fcd53..dc752eafa681e1f3dcd46045fb0cce9dd40bdfae 100644 (file)
 #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
 #endif
 
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#define HUB6_FLAGS 0
-#endif
-
-#define MCA_COM_FLAGS  (STD_COM_FLAGS|ASYNC_BOOT_ONLYMCA)
-
-/*
- * The following define the access methods for the HUB6 card. All
- * access is through two ports for all 24 possible chips. The card is
- * selected through the high 2 bits, the port on that card with the
- * "middle" 3 bits, and the register on that port with the bottom
- * 3 bits.
- *
- * While the access port and interrupt is configurable, the default
- * port locations are 0x302 for the port control register, and 0x303
- * for the data read/write register. Normally, the interrupt is at irq3
- * but can be anything from 3 to 7 inclusive. Note that using 3 will
- * require disabling com2.
- */
-
-#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
-
-#define STD_SERIAL_PORT_DEFNS                  \
+#define SERIAL_PORT_DFNS                       \
        /* UART CLK   PORT IRQ     FLAGS        */                      \
        { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },      /* ttyS0 */     \
        { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },      /* ttyS1 */     \
        { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },      /* ttyS2 */     \
        { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },     /* ttyS3 */
-
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS                        \
-       { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS },     /* ttyS4 */     \
-       { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },     /* ttyS5 */     \
-       { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },     /* ttyS6 */     \
-       { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },     /* ttyS7 */     \
-       { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },     /* ttyS8 */     \
-       { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },     /* ttyS9 */     \
-       { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },     /* ttyS10 */    \
-       { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },     /* ttyS11 */    \
-       { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },       /* ttyS12 */    \
-       { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },       /* ttyS13 */    \
-       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS14 (spare) */            \
-       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS15 (spare) */            \
-       { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },        /* ttyS16 */    \
-       { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },        /* ttyS17 */    \
-       { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },        /* ttyS18 */    \
-       { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },        /* ttyS19 */    \
-       { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },        /* ttyS20 */    \
-       { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },        /* ttyS21 */    \
-       { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },        /* ttyS22 */    \
-       { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },        /* ttyS23 */    \
-       { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },        /* ttyS24 */    \
-       { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },        /* ttyS25 */    \
-       { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },        /* ttyS26 */    \
-       { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },        /* ttyS27 */    \
-       { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },        /* ttyS28 */    \
-       { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },        /* ttyS29 */    \
-       { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },        /* ttyS30 */    \
-       { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },        /* ttyS31 */
-#else
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif
-
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
- */
-#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
-#define HUB6_SERIAL_PORT_DFNS          \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) },  /* ttyS32 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) },  /* ttyS33 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) },  /* ttyS34 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) },  /* ttyS35 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) },  /* ttyS36 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) },  /* ttyS37 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) },  /* ttyS38 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) },  /* ttyS39 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) },  /* ttyS40 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) },  /* ttyS41 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) },  /* ttyS42 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) },  /* ttyS43 */
-#else
-#define HUB6_SERIAL_PORT_DFNS
-#endif
-
-#ifdef CONFIG_MCA
-#define MCA_SERIAL_PORT_DFNS                   \
-       { 0, BASE_BAUD, 0x3220, 3, MCA_COM_FLAGS },     \
-       { 0, BASE_BAUD, 0x3228, 3, MCA_COM_FLAGS },     \
-       { 0, BASE_BAUD, 0x4220, 3, MCA_COM_FLAGS },     \
-       { 0, BASE_BAUD, 0x4228, 3, MCA_COM_FLAGS },     \
-       { 0, BASE_BAUD, 0x5220, 3, MCA_COM_FLAGS },     \
-       { 0, BASE_BAUD, 0x5228, 3, MCA_COM_FLAGS },
-#else
-#define MCA_SERIAL_PORT_DFNS
-#endif
-
-#define SERIAL_PORT_DFNS               \
-       STD_SERIAL_PORT_DEFNS           \
-       EXTRA_SERIAL_PORT_DEFNS         \
-       HUB6_SERIAL_PORT_DFNS           \
-       MCA_SERIAL_PORT_DFNS
-
index a7425aa5a3b72d369ef676c5f1fda8c5dec049b3..aeb1b73e21e117eb24a5ea341bdc2e1f80eb3774 100644 (file)
@@ -43,6 +43,8 @@ extern cpumask_t cpu_callout_map;
 extern void smp_alloc_memory(void);
 extern volatile unsigned long smp_invalidate_needed;
 extern int pic_mode;
+extern void lock_ipi_call_lock(void);
+extern void unlock_ipi_call_lock(void);
 extern int smp_num_siblings;
 extern void smp_flush_tlb(void);
 extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
@@ -77,6 +79,8 @@ extern __inline int hard_smp_processor_id(void)
 }
 
 extern int safe_smp_processor_id(void);
+extern int __cpu_disable(void);
+extern void __cpu_die(unsigned int cpu);
 
 #endif /* !ASSEMBLY */
 
index ec745807feae4892ec7d560e9fc930ca04591acb..bb9f40597d097dacf7e08ae8de2cc23dfbb2adab 100644 (file)
@@ -16,7 +16,7 @@ arch_prepare_suspend(void)
 struct saved_context {
        u16 ds, es, fs, gs, ss;
        unsigned long gs_base, gs_kernel_base, fs_base;
-       unsigned long cr0, cr2, cr3, cr4;
+       unsigned long cr0, cr2, cr3, cr4, cr8;
        u16 gdt_pad;
        u16 gdt_limit;
        unsigned long gdt_base;
index 2e811ac262af78062c2ffb661bfa9eef3815b824..061742382520ecfe4cf416a5be91cba6b8b51f18 100644 (file)
  */
 #define __flush_tlb_global()                                           \
        do {                                                            \
-               unsigned long tmpreg;                                   \
+               unsigned long tmpreg, cr4, cr4_orig;                    \
                                                                        \
                __asm__ __volatile__(                                   \
-                       "movq %1, %%cr4;  # turn off PGE     \n"        \
+                       "movq %%cr4, %2;  # turn off PGE     \n"        \
+                       "movq %2, %1;                        \n"        \
+                       "andq %3, %1;                        \n"        \
+                       "movq %1, %%cr4;                     \n"        \
                        "movq %%cr3, %0;  # flush TLB        \n"        \
                        "movq %0, %%cr3;                     \n"        \
                        "movq %2, %%cr4;  # turn PGE back on \n"        \
-                       : "=&r" (tmpreg)                                \
-                       : "r" (mmu_cr4_features & ~X86_CR4_PGE),        \
-                         "r" (mmu_cr4_features)                        \
+                       : "=&r" (tmpreg), "=&r" (cr4), "=&r" (cr4_orig) \
+                       : "i" (~X86_CR4_PGE)                            \
                        : "memory");                                    \
        } while (0)
 
index 8f77e9f6bc23c4ac810c304cc859316843e5faf4..c1bc3fad482ed4a4388412ff300a0395f86178a1 100644 (file)
@@ -39,12 +39,16 @@ extern int __node_distance(int, int);
        .busy_factor            = 32,                   \
        .imbalance_pct          = 125,                  \
        .cache_hot_time         = (10*1000000),         \
-       .cache_nice_tries       = 1,                    \
+       .cache_nice_tries       = 2,                    \
+       .busy_idx               = 3,                    \
+       .idle_idx               = 2,                    \
+       .newidle_idx            = 0,                    \
+       .wake_idx               = 1,                    \
+       .forkexec_idx           = 1,                    \
        .per_cpu_gain           = 100,                  \
        .flags                  = SD_LOAD_BALANCE       \
-                               | SD_BALANCE_NEWIDLE    \
+                               | SD_BALANCE_FORK       \
                                | SD_BALANCE_EXEC       \
-                               | SD_WAKE_IDLE          \
                                | SD_WAKE_BALANCE,      \
        .last_balance           = jiffies,              \
        .balance_interval       = 1,                    \
index 3c9af6fd433216fdfd26b60619dc6d3b9ce903b8..6560439a83e47b85fe1fad1287bb34f16d64e7f1 100644 (file)
@@ -552,7 +552,7 @@ __SYSCALL(__NR_mq_notify, sys_mq_notify)
 #define __NR_mq_getsetattr     245
 __SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr)
 #define __NR_kexec_load        246
-__SYSCALL(__NR_kexec_load, sys_ni_syscall)
+__SYSCALL(__NR_kexec_load, sys_kexec_load)
 #define __NR_waitid            247
 __SYSCALL(__NR_waitid, sys_waitid)
 #define __NR_add_key           248
@@ -561,8 +561,12 @@ __SYSCALL(__NR_add_key, sys_add_key)
 __SYSCALL(__NR_request_key, sys_request_key)
 #define __NR_keyctl            250
 __SYSCALL(__NR_keyctl, sys_keyctl)
+#define __NR_ioprio_set                251
+__SYSCALL(__NR_ioprio_set, sys_ioprio_set)
+#define __NR_ioprio_get                252
+__SYSCALL(__NR_ioprio_get, sys_ioprio_get)
 
-#define __NR_syscall_max __NR_keyctl
+#define __NR_syscall_max __NR_ioprio_get
 #ifndef __NO_STUBS
 
 /* user-visible error numbers are in the range -1 - -4095 */
diff --git a/include/asm-xtensa/a.out.h b/include/asm-xtensa/a.out.h
new file mode 100644 (file)
index 0000000..3be701d
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * include/asm-xtensa/addrspace.h
+ *
+ * Dummy a.out file. Xtensa does not support the a.out format, but the kernel
+ * seems to depend on it.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_A_OUT_H
+#define _XTENSA_A_OUT_H
+
+/* Note: the kernel needs the a.out definitions, even if only ELF is used. */
+
+#define STACK_TOP      TASK_SIZE
+
+struct exec
+{
+  unsigned long a_info;
+  unsigned a_text;
+  unsigned a_data;
+  unsigned a_bss;
+  unsigned a_syms;
+  unsigned a_entry;
+  unsigned a_trsize;
+  unsigned a_drsize;
+};
+
+#endif /* _XTENSA_A_OUT_H */
diff --git a/include/asm-xtensa/atomic.h b/include/asm-xtensa/atomic.h
new file mode 100644 (file)
index 0000000..d72bcb3
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * include/asm-xtensa/atomic.h
+ *
+ * Atomic operations that C can't guarantee us.  Useful for resource counting..
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_ATOMIC_H
+#define _XTENSA_ATOMIC_H
+
+#include <linux/config.h>
+#include <linux/stringify.h>
+
+typedef struct { volatile int counter; } atomic_t;
+
+#ifdef __KERNEL__
+#include <asm/processor.h>
+#include <asm/system.h>
+
+#define ATOMIC_INIT(i) ( (atomic_t) { (i) } )
+
+/*
+ * This Xtensa implementation assumes that the right mechanism
+ * for exclusion is for locking interrupts to level 1.
+ *
+ * Locking interrupts looks like this:
+ *
+ *    rsil a15, 1
+ *    <code>
+ *    wsr  a15, PS
+ *    rsync
+ *
+ * Note that a15 is used here because the register allocation
+ * done by the compiler is not guaranteed and a window overflow
+ * may not occur between the rsil and wsr instructions. By using
+ * a15 in the rsil, the machine is guaranteed to be in a state
+ * where no register reference will cause an overflow.
+ */
+
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically reads the value of @v.
+ */
+#define atomic_read(v)         ((v)->counter)
+
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i.
+ */
+#define atomic_set(v,i)                ((v)->counter = (i))
+
+/**
+ * atomic_add - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ *
+ * Atomically adds @i to @v.
+ */
+extern __inline__ void atomic_add(int i, atomic_t * v)
+{
+    unsigned int vval;
+
+    __asm__ __volatile__(
+       "rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
+       "l32i    %0, %2, 0              \n\t"
+       "add     %0, %0, %1             \n\t"
+       "s32i    %0, %2, 0              \n\t"
+       "wsr     a15, "__stringify(PS)"       \n\t"
+       "rsync                          \n"
+       : "=&a" (vval)
+       : "a" (i), "a" (v)
+       : "a15", "memory"
+       );
+}
+
+/**
+ * atomic_sub - subtract the atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v.
+ */
+extern __inline__ void atomic_sub(int i, atomic_t *v)
+{
+    unsigned int vval;
+
+    __asm__ __volatile__(
+       "rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
+       "l32i    %0, %2, 0              \n\t"
+       "sub     %0, %0, %1             \n\t"
+       "s32i    %0, %2, 0              \n\t"
+       "wsr     a15, "__stringify(PS)"       \n\t"
+       "rsync                          \n"
+       : "=&a" (vval)
+       : "a" (i), "a" (v)
+       : "a15", "memory"
+       );
+}
+
+/*
+ * We use atomic_{add|sub}_return to define other functions.
+ */
+
+extern __inline__ int atomic_add_return(int i, atomic_t * v)
+{
+     unsigned int vval;
+
+    __asm__ __volatile__(
+       "rsil    a15,"__stringify(LOCKLEVEL)"\n\t"
+       "l32i    %0, %2, 0             \n\t"
+       "add     %0, %0, %1            \n\t"
+       "s32i    %0, %2, 0             \n\t"
+       "wsr     a15, "__stringify(PS)"      \n\t"
+       "rsync                         \n"
+       : "=&a" (vval)
+       : "a" (i), "a" (v)
+       : "a15", "memory"
+       );
+
+    return vval;
+}
+
+extern __inline__ int atomic_sub_return(int i, atomic_t * v)
+{
+    unsigned int vval;
+
+    __asm__ __volatile__(
+       "rsil    a15,"__stringify(LOCKLEVEL)"\n\t"
+       "l32i    %0, %2, 0             \n\t"
+       "sub     %0, %0, %1            \n\t"
+       "s32i    %0, %2, 0             \n\t"
+       "wsr     a15, "__stringify(PS)"       \n\t"
+       "rsync                         \n"
+       : "=&a" (vval)
+       : "a" (i), "a" (v)
+       : "a15", "memory"
+       );
+
+    return vval;
+}
+
+/**
+ * atomic_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+#define atomic_sub_and_test(i,v) (atomic_sub_return((i),(v)) == 0)
+
+/**
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1.
+ */
+#define atomic_inc(v) atomic_add(1,(v))
+
+/**
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1.
+ */
+#define atomic_inc_return(v) atomic_add_return(1,(v))
+
+/**
+ * atomic_dec - decrement atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1.
+ */
+#define atomic_dec(v) atomic_sub(1,(v))
+
+/**
+ * atomic_dec_return - decrement atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1.
+ */
+#define atomic_dec_return(v) atomic_sub_return(1,(v))
+
+/**
+ * atomic_dec_and_test - decrement and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */
+#define atomic_dec_and_test(v) (atomic_sub_return(1,(v)) == 0)
+
+/**
+ * atomic_inc_and_test - increment and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+#define atomic_inc_and_test(v) (atomic_add_return(1,(v)) == 0)
+
+/**
+ * atomic_add_negative - add and test if negative
+ * @v: pointer of type atomic_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @v and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */
+#define atomic_add_negative(i,v) (atomic_add_return((i),(v)) < 0)
+
+
+extern __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v)
+{
+    unsigned int all_f = -1;
+    unsigned int vval;
+
+    __asm__ __volatile__(
+       "rsil    a15,"__stringify(LOCKLEVEL)"\n\t"
+       "l32i    %0, %2, 0             \n\t"
+       "xor     %1, %4, %3            \n\t"
+       "and     %0, %0, %4            \n\t"
+       "s32i    %0, %2, 0             \n\t"
+       "wsr     a15, "__stringify(PS)"      \n\t"
+       "rsync                         \n"
+       : "=&a" (vval), "=a" (mask)
+       : "a" (v), "a" (all_f), "1" (mask)
+       : "a15", "memory"
+       );
+}
+
+extern __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v)
+{
+    unsigned int vval;
+
+    __asm__ __volatile__(
+       "rsil    a15,"__stringify(LOCKLEVEL)"\n\t"
+       "l32i    %0, %2, 0             \n\t"
+       "or      %0, %0, %1            \n\t"
+       "s32i    %0, %2, 0             \n\t"
+       "wsr     a15, "__stringify(PS)"       \n\t"
+       "rsync                         \n"
+       : "=&a" (vval)
+       : "a" (mask), "a" (v)
+       : "a15", "memory"
+       );
+}
+
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec()    barrier()
+#define smp_mb__after_atomic_dec()     barrier()
+#define smp_mb__before_atomic_inc()    barrier()
+#define smp_mb__after_atomic_inc()     barrier()
+
+#endif /* __KERNEL__ */
+
+#endif /* _XTENSA_ATOMIC_H */
+
diff --git a/include/asm-xtensa/bitops.h b/include/asm-xtensa/bitops.h
new file mode 100644 (file)
index 0000000..d395ef2
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * include/asm-xtensa/bitops.h
+ *
+ * Atomic operations that C can't guarantee us.Useful for resource counting etc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_BITOPS_H
+#define _XTENSA_BITOPS_H
+
+#ifdef __KERNEL__
+
+#include <asm/processor.h>
+#include <asm/byteorder.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_SMP
+# error SMP not supported on this architecture
+#endif
+
+static __inline__ void set_bit(int nr, volatile void * addr)
+{
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+       unsigned long flags;
+
+       local_irq_save(flags);
+       *a |= mask;
+       local_irq_restore(flags);
+}
+
+static __inline__ void __set_bit(int nr, volatile unsigned long * addr)
+{
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+
+       *a |= mask;
+}
+
+static __inline__ void clear_bit(int nr, volatile void * addr)
+{
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+       unsigned long flags;
+
+       local_irq_save(flags);
+       *a &= ~mask;
+       local_irq_restore(flags);
+}
+
+static __inline__ void __clear_bit(int nr, volatile unsigned long *addr)
+{
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+
+       *a &= ~mask;
+}
+
+/*
+ * clear_bit() doesn't provide any barrier for the compiler.
+ */
+
+#define smp_mb__before_clear_bit()     barrier()
+#define smp_mb__after_clear_bit()      barrier()
+
+static __inline__ void change_bit(int nr, volatile void * addr)
+{
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+       unsigned long flags;
+
+       local_irq_save(flags);
+       *a ^= mask;
+       local_irq_restore(flags);
+}
+
+static __inline__ void __change_bit(int nr, volatile void * addr)
+{
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+
+       *a ^= mask;
+}
+
+static __inline__ int test_and_set_bit(int nr, volatile void * addr)
+{
+       unsigned long retval;
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+       unsigned long flags;
+
+       local_irq_save(flags);
+       retval = (mask & *a) != 0;
+       *a |= mask;
+       local_irq_restore(flags);
+
+       return retval;
+}
+
+static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
+{
+       unsigned long retval;
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+
+       retval = (mask & *a) != 0;
+       *a |= mask;
+
+       return retval;
+}
+
+static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
+{
+       unsigned long retval;
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+       unsigned long flags;
+
+       local_irq_save(flags);
+       retval = (mask & *a) != 0;
+       *a &= ~mask;
+       local_irq_restore(flags);
+
+       return retval;
+}
+
+static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
+{
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+       unsigned long old = *a;
+
+       *a = old & ~mask;
+       return (old & mask) != 0;
+}
+
+static __inline__ int test_and_change_bit(int nr, volatile void * addr)
+{
+       unsigned long retval;
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       retval = (mask & *a) != 0;
+       *a ^= mask;
+       local_irq_restore(flags);
+
+       return retval;
+}
+
+/*
+ * non-atomic version; can be reordered
+ */
+
+static __inline__ int __test_and_change_bit(int nr, volatile void *addr)
+{
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+       unsigned long old = *a;
+
+       *a = old ^ mask;
+       return (old & mask) != 0;
+}
+
+static __inline__ int test_bit(int nr, const volatile void *addr)
+{
+       return 1UL & (((const volatile unsigned int *)addr)[nr>>5] >> (nr&31));
+}
+
+#if XCHAL_HAVE_NSAU
+
+static __inline__ int __cntlz (unsigned long x)
+{
+       int lz;
+       asm ("nsau %0, %1" : "=r" (lz) : "r" (x));
+       return 31 - lz;
+}
+
+#else
+
+static __inline__ int __cntlz (unsigned long x)
+{
+       unsigned long sum, x1, x2, x4, x8, x16;
+       x1  = x & 0xAAAAAAAA;
+       x2  = x & 0xCCCCCCCC;
+       x4  = x & 0xF0F0F0F0;
+       x8  = x & 0xFF00FF00;
+       x16 = x & 0xFFFF0000;
+       sum = x2 ? 2 : 0;
+       sum += (x16 != 0) * 16;
+       sum += (x8 != 0) * 8;
+       sum += (x4 != 0) * 4;
+       sum += (x1 != 0);
+
+       return sum;
+}
+
+#endif
+
+/*
+ * ffz: Find first zero in word. Undefined if no zero exists.
+ * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
+ */
+
+static __inline__ int ffz(unsigned long x)
+{
+       if ((x = ~x) == 0)
+               return 32;
+       return __cntlz(x & -x);
+}
+
+/*
+ * __ffs: Find first bit set in word. Return 0 for bit 0
+ */
+
+static __inline__ int __ffs(unsigned long x)
+{
+       return __cntlz(x & -x);
+}
+
+/*
+ * ffs: Find first bit set in word. 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(unsigned long x)
+{
+       return __cntlz(x & -x) + 1;
+}
+
+/*
+ * fls: Find last (most-significant) bit set in word.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+
+static __inline__ int fls (unsigned int x)
+{
+       return __cntlz(x);
+}
+
+static __inline__ int
+find_next_bit(const unsigned long *addr, int size, int offset)
+{
+       const unsigned long *p = addr + (offset >> 5);
+       unsigned long result = offset & ~31UL;
+       unsigned long tmp;
+
+       if (offset >= size)
+               return size;
+       size -= result;
+       offset &= 31UL;
+       if (offset) {
+               tmp = *p++;
+               tmp &= ~0UL << offset;
+               if (size < 32)
+                       goto found_first;
+               if (tmp)
+                       goto found_middle;
+               size -= 32;
+               result += 32;
+       }
+       while (size >= 32) {
+               if ((tmp = *p++) != 0)
+                       goto found_middle;
+               result += 32;
+               size -= 32;
+       }
+       if (!size)
+               return result;
+       tmp = *p;
+
+found_first:
+       tmp &= ~0UL >> (32 - size);
+       if (tmp == 0UL) /* Are any bits set? */
+               return result + size;   /* Nope. */
+found_middle:
+       return result + __ffs(tmp);
+}
+
+/**
+ * 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.
+ */
+
+#define find_first_bit(addr, size) \
+        find_next_bit((addr), (size), 0)
+
+static __inline__ int
+find_next_zero_bit(const unsigned long *addr, int size, int offset)
+{
+       const unsigned long *p = addr + (offset >> 5);
+       unsigned long result = offset & ~31UL;
+       unsigned long tmp;
+
+       if (offset >= size)
+               return size;
+       size -= result;
+       offset &= 31UL;
+       if (offset) {
+               tmp = *p++;
+               tmp |= ~0UL >> (32-offset);
+               if (size < 32)
+                       goto found_first;
+               if (~tmp)
+                       goto found_middle;
+               size -= 32;
+               result += 32;
+       }
+       while (size & ~31UL) {
+               if (~(tmp = *p++))
+                       goto found_middle;
+               result += 32;
+               size -= 32;
+       }
+       if (!size)
+               return result;
+       tmp = *p;
+
+found_first:
+       tmp |= ~0UL << size;
+found_middle:
+       return result + ffz(tmp);
+}
+
+#define find_first_zero_bit(addr, size) \
+        find_next_zero_bit((addr), (size), 0)
+
+#ifdef __XTENSA_EL__
+# define ext2_set_bit(nr,addr) __test_and_set_bit((nr), (addr))
+# define ext2_set_bit_atomic(lock,nr,addr) test_and_set_bit((nr),(addr))
+# define ext2_clear_bit(nr,addr) __test_and_clear_bit((nr), (addr))
+# define ext2_clear_bit_atomic(lock,nr,addr) test_and_clear_bit((nr),(addr))
+# define ext2_test_bit(nr,addr) test_bit((nr), (addr))
+# define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr),(size))
+# define ext2_find_next_zero_bit(addr, size, offset) \
+                find_next_zero_bit((addr), (size), (offset))
+#elif defined(__XTENSA_EB__)
+# define ext2_set_bit(nr,addr) __test_and_set_bit((nr) ^ 0x18, (addr))
+# define ext2_set_bit_atomic(lock,nr,addr) test_and_set_bit((nr) ^ 0x18, (addr))
+# define ext2_clear_bit(nr,addr) __test_and_clear_bit((nr) ^ 18, (addr))
+# define ext2_clear_bit_atomic(lock,nr,addr) test_and_clear_bit((nr)^0x18,(addr))
+# define ext2_test_bit(nr,addr) test_bit((nr) ^ 0x18, (addr))
+# define ext2_find_first_zero_bit(addr, size) \
+        ext2_find_next_zero_bit((addr), (size), 0)
+
+static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+{
+       unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
+       unsigned long result = offset & ~31UL;
+       unsigned long tmp;
+
+       if (offset >= size)
+               return size;
+       size -= result;
+       offset &= 31UL;
+       if(offset) {
+               /* We hold the little endian value in tmp, but then the
+                * shift is illegal. So we could keep a big endian value
+                * in tmp, like this:
+                *
+                * tmp = __swab32(*(p++));
+                * tmp |= ~0UL >> (32-offset);
+                *
+                * but this would decrease preformance, so we change the
+                * shift:
+                */
+               tmp = *(p++);
+               tmp |= __swab32(~0UL >> (32-offset));
+               if(size < 32)
+                       goto found_first;
+               if(~tmp)
+                       goto found_middle;
+               size -= 32;
+               result += 32;
+       }
+       while(size & ~31UL) {
+               if(~(tmp = *(p++)))
+                       goto found_middle;
+               result += 32;
+               size -= 32;
+       }
+       if(!size)
+               return result;
+       tmp = *p;
+
+found_first:
+       /* tmp is little endian, so we would have to swab the shift,
+        * see above. But then we have to swab tmp below for ffz, so
+        * we might as well do this here.
+        */
+       return result + ffz(__swab32(tmp) | (~0UL << size));
+found_middle:
+       return result + ffz(__swab32(tmp));
+}
+
+#else
+# error processor byte order undefined!
+#endif
+
+
+#define hweight32(x)   generic_hweight32(x)
+#define hweight16(x)   generic_hweight16(x)
+#define hweight8(x)    generic_hweight8(x)
+
+/*
+ * Find the first bit set in a 140-bit bitmap.
+ * The first 100 bits are unlikely to be set.
+ */
+
+static inline int sched_find_first_bit(const unsigned long *b)
+{
+       if (unlikely(b[0]))
+               return __ffs(b[0]);
+       if (unlikely(b[1]))
+               return __ffs(b[1]) + 32;
+       if (unlikely(b[2]))
+               return __ffs(b[2]) + 64;
+       if (b[3])
+               return __ffs(b[3]) + 96;
+       return __ffs(b[4]) + 128;
+}
+
+
+/* Bitmap functions for the minix filesystem.  */
+
+#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
+#define minix_set_bit(nr,addr) set_bit(nr,addr)
+#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
+#define minix_test_bit(nr,addr) test_bit(nr,addr)
+#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
+
+#endif /* __KERNEL__ */
+
+#endif /* _XTENSA_BITOPS_H */
diff --git a/include/asm-xtensa/bootparam.h b/include/asm-xtensa/bootparam.h
new file mode 100644 (file)
index 0000000..9983f2c
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * include/asm-xtensa/bootparam.h
+ *
+ * Definition of the Linux/Xtensa boot parameter structure
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005  Tensilica Inc.
+ *
+ * (Concept borrowed from the 68K port)
+ */
+
+#ifndef _XTENSA_BOOTPARAM_H
+#define _XTENSA_BOOTPARAM_H
+
+#define BP_VERSION 0x0001
+
+#define BP_TAG_COMMAND_LINE    0x1001  /* command line (0-terminated string)*/
+#define BP_TAG_INITRD          0x1002  /* ramdisk addr and size (bp_meminfo) */
+#define BP_TAG_MEMORY          0x1003  /* memory addr and size (bp_meminfo) */
+#define BP_TAG_SERIAL_BAUSRATE 0x1004  /* baud rate of current console. */
+#define BP_TAG_SERIAL_PORT     0x1005  /* serial device of current console */
+
+#define BP_TAG_FIRST           0x7B0B  /* first tag with a version number */
+#define BP_TAG_LAST            0x7E0B  /* last tag */
+
+#ifndef __ASSEMBLY__
+
+/* All records are aligned to 4 bytes */
+
+typedef struct bp_tag {
+  unsigned short id;           /* tag id */
+  unsigned short size;         /* size of this record excluding the structure*/
+  unsigned long data[0];       /* data */
+} bp_tag_t;
+
+typedef struct meminfo {
+  unsigned long type;
+  unsigned long start;
+  unsigned long end;
+} meminfo_t;
+
+#define SYSMEM_BANKS_MAX 5
+
+#define MEMORY_TYPE_CONVENTIONAL       0x1000
+#define MEMORY_TYPE_NONE               0x2000
+
+typedef struct sysmem_info {
+  int nr_banks;
+  meminfo_t bank[SYSMEM_BANKS_MAX];
+} sysmem_info_t;
+
+extern sysmem_info_t sysmem;
+
+#endif
+#endif
+
+
+
diff --git a/include/asm-xtensa/bug.h b/include/asm-xtensa/bug.h
new file mode 100644 (file)
index 0000000..5670365
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * include/asm-xtensa/bug.h
+ *
+ * Macros to cause a 'bug' message.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_BUG_H
+#define _XTENSA_BUG_H
+
+#include <linux/stringify.h>
+
+#define ILL    __asm__ __volatile__ (".byte 0,0,0\n")
+
+#ifdef CONFIG_KALLSYMS
+# define BUG() do {                                                    \
+       printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__);           \
+       ILL;                                                            \
+} while (0)
+#else
+# define BUG() do {                                                    \
+       printk("kernel BUG!\n");                                        \
+       ILL;                                                            \
+} while (0)
+#endif
+
+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
+#define PAGE_BUG(page) do {  BUG(); } while (0)
+#define WARN_ON(condition) do {                                                   \
+  if (unlikely((condition)!=0)) {                                         \
+    printk ("Warning in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \
+      dump_stack();                                                       \
+  }                                                                       \
+} while (0)
+
+#endif /* _XTENSA_BUG_H */
diff --git a/include/asm-xtensa/bugs.h b/include/asm-xtensa/bugs.h
new file mode 100644 (file)
index 0000000..c422853
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * include/asm-xtensa/bugs.h
+ *
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Xtensa processors don't have any bugs.  :)
+ *
+ * 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 _XTENSA_BUGS_H
+#define _XTENSA_BUGS_H
+
+#include <asm/processor.h>
+
+static void __init check_bugs(void)
+{
+}
+
+#endif /* _XTENSA_BUGS_H */
diff --git a/include/asm-xtensa/byteorder.h b/include/asm-xtensa/byteorder.h
new file mode 100644 (file)
index 0000000..0b15525
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * include/asm-xtensa/byteorder.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_BYTEORDER_H
+#define _XTENSA_BYTEORDER_H
+
+#include <asm/processor.h>
+#include <asm/types.h>
+
+static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
+{
+    __u32 res;
+    /* instruction sequence from Xtensa ISA release 2/2000 */
+    __asm__("ssai     8           \n\t"
+           "srli     %0, %1, 16  \n\t"
+           "src      %0, %0, %1  \n\t"
+           "src      %0, %0, %0  \n\t"
+           "src      %0, %1, %0  \n"
+           : "=&a" (res)
+           : "a" (x)
+           );
+    return res;
+}
+
+static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
+{
+    /* Given that 'short' values are signed (i.e., can be negative),
+     * we cannot assume that the upper 16-bits of the register are
+     * zero.  We are careful to mask values after shifting.
+     */
+
+    /* There exists an anomaly between xt-gcc and xt-xcc.  xt-gcc
+     * inserts an extui instruction after putting this function inline
+     * to ensure that it uses only the least-significant 16 bits of
+     * the result.  xt-xcc doesn't use an extui, but assumes the
+     * __asm__ macro follows convention that the upper 16 bits of an
+     * 'unsigned short' result are still zero.  This macro doesn't
+     * follow convention; indeed, it leaves garbage in the upport 16
+     * bits of the register.
+
+     * Declaring the temporary variables 'res' and 'tmp' to be 32-bit
+     * types while the return type of the function is a 16-bit type
+     * forces both compilers to insert exactly one extui instruction
+     * (or equivalent) to mask off the upper 16 bits. */
+
+    __u32 res;
+    __u32 tmp;
+
+    __asm__("extui    %1, %2, 8, 8\n\t"
+           "slli     %0, %2, 8   \n\t"
+           "or       %0, %0, %1  \n"
+           : "=&a" (res), "=&a" (tmp)
+           : "a" (x)
+           );
+
+    return res;
+}
+
+#define __arch__swab32(x) ___arch__swab32(x)
+#define __arch__swab16(x) ___arch__swab16(x)
+
+#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+#  define __BYTEORDER_HAS_U64__
+#  define __SWAB_64_THRU_32__
+#endif
+
+#ifdef __XTENSA_EL__
+# include <linux/byteorder/little_endian.h>
+#elif defined(__XTENSA_EB__)
+# include <linux/byteorder/big_endian.h>
+#else
+# error processor byte order undefined!
+#endif
+
+#endif /* __ASM_XTENSA_BYTEORDER_H */
diff --git a/include/asm-xtensa/cache.h b/include/asm-xtensa/cache.h
new file mode 100644 (file)
index 0000000..5aae3f1
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * include/asm-xtensa/cacheflush.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ * 2 of the License, or (at your option) any later version.
+ *
+ * (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CACHE_H
+#define _XTENSA_CACHE_H
+
+#include <xtensa/config/core.h>
+
+#if XCHAL_ICACHE_SIZE > 0
+# if (XCHAL_ICACHE_SIZE % (XCHAL_ICACHE_LINESIZE*XCHAL_ICACHE_WAYS*4)) != 0
+#  error cache configuration outside expected/supported range!
+# endif
+#endif
+
+#if XCHAL_DCACHE_SIZE > 0
+# if (XCHAL_DCACHE_SIZE % (XCHAL_DCACHE_LINESIZE*XCHAL_DCACHE_WAYS*4)) != 0
+#  error cache configuration outside expected/supported range!
+# endif
+#endif
+
+#define L1_CACHE_SHIFT         XCHAL_CACHE_LINEWIDTH_MAX
+#define L1_CACHE_BYTES         XCHAL_CACHE_LINESIZE_MAX
+
+#endif /* _XTENSA_CACHE_H */
diff --git a/include/asm-xtensa/cacheflush.h b/include/asm-xtensa/cacheflush.h
new file mode 100644 (file)
index 0000000..44a36e0
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * include/asm-xtensa/cacheflush.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CACHEFLUSH_H
+#define _XTENSA_CACHEFLUSH_H
+
+#ifdef __KERNEL__
+
+#include <linux/mm.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+
+/*
+ * flush and invalidate data cache, invalidate instruction cache:
+ *
+ * __flush_invalidate_cache_all()
+ * __flush_invalidate_cache_range(from,sze)
+ *
+ * invalidate data or instruction cache:
+ *
+ * __invalidate_icache_all()
+ * __invalidate_icache_page(adr)
+ * __invalidate_dcache_page(adr)
+ * __invalidate_icache_range(from,size)
+ * __invalidate_dcache_range(from,size)
+ *
+ * flush data cache:
+ *
+ * __flush_dcache_page(adr)
+ *
+ * flush and invalidate data cache:
+ *
+ * __flush_invalidate_dcache_all()
+ * __flush_invalidate_dcache_page(adr)
+ * __flush_invalidate_dcache_range(from,size)
+ */
+
+extern void __flush_invalidate_cache_all(void);
+extern void __flush_invalidate_cache_range(unsigned long, unsigned long);
+extern void __flush_invalidate_dcache_all(void);
+extern void __invalidate_icache_all(void);
+
+extern void __invalidate_dcache_page(unsigned long);
+extern void __invalidate_icache_page(unsigned long);
+extern void __invalidate_icache_range(unsigned long, unsigned long);
+extern void __invalidate_dcache_range(unsigned long, unsigned long);
+
+#if XCHAL_DCACHE_IS_WRITEBACK
+extern void __flush_dcache_page(unsigned long);
+extern void __flush_invalidate_dcache_page(unsigned long);
+extern void __flush_invalidate_dcache_range(unsigned long, unsigned long);
+#else
+# define __flush_dcache_page(p)                                do { } while(0)
+# define __flush_invalidate_dcache_page(p)             do { } while(0)
+# define __flush_invalidate_dcache_range(p,s)          do { } while(0)
+#endif
+
+/*
+ * We have physically tagged caches - nothing to do here -
+ * unless we have cache aliasing.
+ *
+ * Pages can get remapped. Because this might change the 'color' of that page,
+ * we have to flush the cache before the PTE is changed.
+ * (see also Documentation/cachetlb.txt)
+ */
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+
+#define flush_cache_all()              __flush_invalidate_cache_all();
+#define flush_cache_mm(mm)             __flush_invalidate_cache_all();
+
+#define flush_cache_vmap(start,end)    __flush_invalidate_cache_all();
+#define flush_cache_vunmap(start,end)  __flush_invalidate_cache_all();
+
+extern void flush_dcache_page(struct page*);
+
+extern void flush_cache_range(struct vm_area_struct*, ulong, ulong);
+extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned long);
+
+#else
+
+#define flush_cache_all()                              do { } while (0)
+#define flush_cache_mm(mm)                             do { } while (0)
+
+#define flush_cache_vmap(start,end)                    do { } while (0)
+#define flush_cache_vunmap(start,end)                  do { } while (0)
+
+#define flush_dcache_page(page)                                do { } while (0)
+
+#define flush_cache_page(vma,addr,pfn)                 do { } while (0)
+#define flush_cache_range(vma,start,end)               do { } while (0)
+
+#endif
+
+#define flush_icache_range(start,end)                                  \
+       __invalidate_icache_range(start,(end)-(start))
+
+/* This is not required, see Documentation/cachetlb.txt */
+
+#define        flush_icache_page(vma,page)                     do { } while(0)
+
+#define flush_dcache_mmap_lock(mapping)                        do { } while (0)
+#define flush_dcache_mmap_unlock(mapping)              do { } while (0)
+
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+       memcpy(dst, src, len)
+
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
+       memcpy(dst, src, len)
+
+#endif /* __KERNEL__ */
+
+#endif /* _XTENSA_CACHEFLUSH_H */
+
diff --git a/include/asm-xtensa/checksum.h b/include/asm-xtensa/checksum.h
new file mode 100644 (file)
index 0000000..1a00fad
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * include/asm-xtensa/checksum.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CHECKSUM_H
+#define _XTENSA_CHECKSUM_H
+
+#include <linux/config.h>
+#include <linux/in6.h>
+#include <xtensa/config/core.h>
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+asmlinkage unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums, and handles user-space pointer exceptions correctly, when needed.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
+                                                  int *src_err_ptr, int *dst_err_ptr);
+
+/*
+ *     Note: when you get a NULL pointer exception here this means someone
+ *     passed in an incorrect kernel address to one of these functions.
+ *
+ *     If you use these functions directly please don't forget the
+ *     verify_area().
+ */
+extern __inline__
+unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
+                                       int len, int sum)
+{
+       return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
+}
+
+extern __inline__
+unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
+                                               int len, int sum, int *err_ptr)
+{
+       return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL);
+}
+
+/*
+ * These are the old (and unsafe) way of doing checksums, a warning message will be
+ * printed if they are used and an exeption occurs.
+ *
+ * these functions should go away after some time.
+ */
+
+#define csum_partial_copy_fromuser csum_partial_copy
+unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
+
+/*
+ *     Fold a partial checksum
+ */
+
+static __inline__ unsigned int csum_fold(unsigned int sum)
+{
+       unsigned int __dummy;
+       __asm__("extui  %1, %0, 16, 16\n\t"
+               "extui  %0 ,%0, 0, 16\n\t"
+               "add    %0, %0, %1\n\t"
+               "slli   %1, %0, 16\n\t"
+               "add    %0, %0, %1\n\t"
+               "extui  %0, %0, 16, 16\n\t"
+               "neg    %0, %0\n\t"
+               "addi   %0, %0, -1\n\t"
+               "extui  %0, %0, 0, 16\n\t"
+               : "=r" (sum), "=&r" (__dummy)
+               : "0" (sum));
+       return sum;
+}
+
+/*
+ *     This is a version of ip_compute_csum() optimized for IP headers,
+ *     which always checksum on 4 octet boundaries.
+ */
+static __inline__ unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
+{
+       unsigned int sum, tmp, endaddr;
+
+       __asm__ __volatile__(
+               "sub            %0, %0, %0\n\t"
+#if XCHAL_HAVE_LOOPS
+               "loopgtz        %2, 2f\n\t"
+#else
+               "beqz           %2, 2f\n\t"
+               "slli           %4, %2, 2\n\t"
+               "add            %4, %4, %1\n\t"
+               "0:\t"
+#endif
+               "l32i           %3, %1, 0\n\t"
+               "add            %0, %0, %3\n\t"
+               "bgeu           %0, %3, 1f\n\t"
+               "addi           %0, %0, 1\n\t"
+               "1:\t"
+               "addi           %1, %1, 4\n\t"
+#if !XCHAL_HAVE_LOOPS
+               "blt            %1, %4, 0b\n\t"
+#endif
+               "2:\t"
+       /* Since the input registers which are loaded with iph and ihl
+          are modified, we must also specify them as outputs, or gcc
+          will assume they contain their original values. */
+               : "=r" (sum), "=r" (iph), "=r" (ihl), "=&r" (tmp), "=&r" (endaddr)
+               : "1" (iph), "2" (ihl));
+
+       return  csum_fold(sum);
+}
+
+static __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
+                                                  unsigned long daddr,
+                                                  unsigned short len,
+                                                  unsigned short proto,
+                                                  unsigned int sum)
+{
+
+#ifdef __XTENSA_EL__
+       unsigned long len_proto = (ntohs(len)<<16)+proto*256;
+#elif defined(__XTENSA_EB__)
+       unsigned long len_proto = (proto<<16)+len;
+#else
+# error processor byte order undefined!
+#endif
+       __asm__("add    %0, %0, %1\n\t"
+               "bgeu   %0, %1, 1f\n\t"
+               "addi   %0, %0, 1\n\t"
+               "1:\t"
+               "add    %0, %0, %2\n\t"
+               "bgeu   %0, %2, 1f\n\t"
+               "addi   %0, %0, 1\n\t"
+               "1:\t"
+               "add    %0, %0, %3\n\t"
+               "bgeu   %0, %3, 1f\n\t"
+               "addi   %0, %0, 1\n\t"
+               "1:\t"
+               : "=r" (sum), "=r" (len_proto)
+               : "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum));
+       return sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static __inline__ unsigned short int csum_tcpudp_magic(unsigned long saddr,
+                                                      unsigned long daddr,
+                                                      unsigned short len,
+                                                      unsigned short proto,
+                                                      unsigned int sum)
+{
+       return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+
+static __inline__ unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+    return csum_fold (csum_partial(buff, len, 0));
+}
+
+#define _HAVE_ARCH_IPV6_CSUM
+static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+                                                    struct in6_addr *daddr,
+                                                    __u32 len,
+                                                    unsigned short proto,
+                                                    unsigned int sum)
+{
+       unsigned int __dummy;
+       __asm__("l32i   %1, %2, 0\n\t"
+               "add    %0, %0, %1\n\t"
+               "bgeu   %0, %1, 1f\n\t"
+               "addi   %0, %0, 1\n\t"
+               "1:\t"
+               "l32i   %1, %2, 4\n\t"
+               "add    %0, %0, %1\n\t"
+               "bgeu   %0, %1, 1f\n\t"
+               "addi   %0, %0, 1\n\t"
+               "1:\t"
+               "l32i   %1, %2, 8\n\t"
+               "add    %0, %0, %1\n\t"
+               "bgeu   %0, %1, 1f\n\t"
+               "addi   %0, %0, 1\n\t"
+               "1:\t"
+               "l32i   %1, %2, 12\n\t"
+               "add    %0, %0, %1\n\t"
+               "bgeu   %0, %1, 1f\n\t"
+               "addi   %0, %0, 1\n\t"
+               "1:\t"
+               "l32i   %1, %3, 0\n\t"
+               "add    %0, %0, %1\n\t"
+               "bgeu   %0, %1, 1f\n\t"
+               "addi   %0, %0, 1\n\t"
+               "1:\t"
+               "l32i   %1, %3, 4\n\t"
+               "add    %0, %0, %1\n\t"
+               "bgeu   %0, %1, 1f\n\t"
+               "addi   %0, %0, 1\n\t"
+               "1:\t"
+               "l32i   %1, %3, 8\n\t"
+               "add    %0, %0, %1\n\t"
+               "bgeu   %0, %1, 1f\n\t"
+               "addi   %0, %0, 1\n\t"
+               "1:\t"
+               "l32i   %1, %3, 12\n\t"
+               "add    %0, %0, %1\n\t"
+               "bgeu   %0, %1, 1f\n\t"
+               "addi   %0, %0, 1\n\t"
+               "1:\t"
+               "add    %0, %0, %4\n\t"
+               "bgeu   %0, %4, 1f\n\t"
+               "addi   %0, %0, 1\n\t"
+               "1:\t"
+               "add    %0, %0, %5\n\t"
+               "bgeu   %0, %5, 1f\n\t"
+               "addi   %0, %0, 1\n\t"
+               "1:\t"
+               : "=r" (sum), "=&r" (__dummy)
+               : "r" (saddr), "r" (daddr),
+                 "r" (htonl(len)), "r" (htonl(proto)), "0" (sum));
+
+       return csum_fold(sum);
+}
+
+/*
+ *     Copy and checksum to user
+ */
+#define HAVE_CSUM_COPY_USER
+static __inline__ unsigned int csum_and_copy_to_user (const char *src, char *dst,
+                                   int len, int sum, int *err_ptr)
+{
+       if (access_ok(VERIFY_WRITE, dst, len))
+               return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
+
+       if (len)
+               *err_ptr = -EFAULT;
+
+       return -1; /* invalid checksum */
+}
+#endif
diff --git a/include/asm-xtensa/coprocessor.h b/include/asm-xtensa/coprocessor.h
new file mode 100644 (file)
index 0000000..a91b96d
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * include/asm-xtensa/cpextra.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_COPROCESSOR_H
+#define _XTENSA_COPROCESSOR_H
+
+#include <xtensa/config/core.h>
+
+#define XTOFS(last_start,last_size,align) \
+       ((last_start+last_size+align-1) & -align)
+
+#define XTENSA_CP_EXTRA_OFFSET 0
+#define XTENSA_CP_EXTRA_ALIGN  XCHAL_EXTRA_SA_ALIGN
+
+#define XTENSA_CPE_CP0_OFFSET  \
+       XTOFS(XTENSA_CP_EXTRA_OFFSET, XCHAL_EXTRA_SA_SIZE, XCHAL_CP0_SA_ALIGN)
+#define XTENSA_CPE_CP1_OFFSET  \
+       XTOFS(XTENSA_CPE_CP0_OFFSET, XCHAL_CP0_SA_SIZE, XCHAL_CP1_SA_ALIGN)
+#define XTENSA_CPE_CP2_OFFSET  \
+       XTOFS(XTENSA_CPE_CP1_OFFSET, XCHAL_CP1_SA_SIZE, XCHAL_CP2_SA_ALIGN)
+#define XTENSA_CPE_CP3_OFFSET  \
+       XTOFS(XTENSA_CPE_CP2_OFFSET, XCHAL_CP2_SA_SIZE, XCHAL_CP3_SA_ALIGN)
+#define XTENSA_CPE_CP4_OFFSET  \
+       XTOFS(XTENSA_CPE_CP3_OFFSET, XCHAL_CP3_SA_SIZE, XCHAL_CP4_SA_ALIGN)
+#define XTENSA_CPE_CP5_OFFSET  \
+       XTOFS(XTENSA_CPE_CP4_OFFSET, XCHAL_CP4_SA_SIZE, XCHAL_CP5_SA_ALIGN)
+#define XTENSA_CPE_CP6_OFFSET  \
+       XTOFS(XTENSA_CPE_CP5_OFFSET, XCHAL_CP5_SA_SIZE, XCHAL_CP6_SA_ALIGN)
+#define XTENSA_CPE_CP7_OFFSET  \
+       XTOFS(XTENSA_CPE_CP6_OFFSET, XCHAL_CP6_SA_SIZE, XCHAL_CP7_SA_ALIGN)
+#define XTENSA_CP_EXTRA_SIZE   \
+       XTOFS(XTENSA_CPE_CP7_OFFSET, XCHAL_CP7_SA_SIZE, 16)
+
+#if XCHAL_CP_NUM > 0
+# ifndef __ASSEMBLY__
+/*
+ * Tasks that own contents of (last user) each coprocessor.
+ * Entries are 0 for not-owned or non-existent coprocessors.
+ * Note: The size of this structure is fixed to 8 bytes in entry.S
+ */
+typedef struct {
+       struct task_struct *owner;      /* owner */
+       int offset;                     /* offset in cpextra space. */
+} coprocessor_info_t;
+# else
+#  define COPROCESSOR_INFO_OWNER 0
+#  define COPROCESSOR_INFO_OFFSET 4
+#  define COPROCESSOR_INFO_SIZE 8
+# endif
+#endif
+
+
+#ifndef __ASSEMBLY__
+# if XCHAL_CP_NUM > 0
+struct task_struct;
+extern void release_coprocessors (struct task_struct*);
+extern void save_coprocessor_registers(void*, int);
+# else
+#  define release_coprocessors(task)
+# endif
+#endif
+
+#endif /* _XTENSA_COPROCESSOR_H */
diff --git a/include/asm-xtensa/cpumask.h b/include/asm-xtensa/cpumask.h
new file mode 100644 (file)
index 0000000..ebeede3
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/cpumask.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CPUMASK_H
+#define _XTENSA_CPUMASK_H
+
+#include <asm-generic/cpumask.h>
+
+#endif /* _XTENSA_CPUMASK_H */
diff --git a/include/asm-xtensa/cputime.h b/include/asm-xtensa/cputime.h
new file mode 100644 (file)
index 0000000..a7fb864
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _XTENSA_CPUTIME_H
+#define _XTENSA_CPUTIME_H
+
+#include <asm-generic/cputime.h>
+
+#endif /* _XTENSA_CPUTIME_H */
diff --git a/include/asm-xtensa/current.h b/include/asm-xtensa/current.h
new file mode 100644 (file)
index 0000000..8d1eb5d
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * include/asm-xtensa/current.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CURRENT_H
+#define _XTENSA_CURRENT_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/thread_info.h>
+
+struct task_struct;
+
+static inline struct task_struct *get_current(void)
+{
+       return current_thread_info()->task;
+}
+
+#define current get_current()
+
+#else
+
+#define CURRENT_SHIFT 13
+
+#define GET_CURRENT(reg,sp)            \
+       GET_THREAD_INFO(reg,sp);        \
+       l32i reg, reg, TI_TASK          \
+
+#endif
+
+
+#endif /* XTENSA_CURRENT_H */
diff --git a/include/asm-xtensa/delay.h b/include/asm-xtensa/delay.h
new file mode 100644 (file)
index 0000000..0a123d5
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * include/asm-xtensa/delay.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ */
+
+#ifndef _XTENSA_DELAY_H
+#define _XTENSA_DELAY_H
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/param.h>
+
+extern unsigned long loops_per_jiffy;
+
+extern __inline__ void __delay(unsigned long loops)
+{
+  /* 2 cycles per loop. */
+  __asm__ __volatile__ ("1: addi %0, %0, -2; bgeui %0, 2, 1b"
+                       : "=r" (loops) : "0" (loops));
+}
+
+static __inline__ u32 xtensa_get_ccount(void)
+{
+       u32 ccount;
+       asm volatile ("rsr %0, 234; # CCOUNT\n" : "=r" (ccount));
+       return ccount;
+}
+
+/* For SMP/NUMA systems, change boot_cpu_data to something like
+ * local_cpu_data->... where local_cpu_data points to the current
+ * cpu. */
+
+static __inline__ void udelay (unsigned long usecs)
+{
+       unsigned long start = xtensa_get_ccount();
+       unsigned long cycles = usecs * (loops_per_jiffy / (1000000UL / HZ));
+
+       /* Note: all variables are unsigned (can wrap around)! */
+       while (((unsigned long)xtensa_get_ccount()) - start < cycles)
+               ;
+}
+
+#endif
+
diff --git a/include/asm-xtensa/div64.h b/include/asm-xtensa/div64.h
new file mode 100644 (file)
index 0000000..c4a1057
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * include/asm-xtensa/div64.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_DIV64_H
+#define _XTENSA_DIV64_H
+
+#define do_div(n,base) ({ \
+       int __res = n % ((unsigned int) base); \
+       n /= (unsigned int) base; \
+       __res; })
+
+#endif
diff --git a/include/asm-xtensa/dma-mapping.h b/include/asm-xtensa/dma-mapping.h
new file mode 100644 (file)
index 0000000..e86a206
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * include/asm-xtensa/dma_mapping.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_DMA_MAPPING_H
+#define _XTENSA_DMA_MAPPING_H
+
+#include <asm/scatterlist.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <linux/mm.h>
+
+/*
+ * DMA-consistent mapping functions.
+ */
+
+extern void *consistent_alloc(int, size_t, dma_addr_t, unsigned long);
+extern void consistent_free(void*, size_t, dma_addr_t);
+extern void consistent_sync(void*, size_t, int);
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+                          dma_addr_t *dma_handle, int flag);
+
+void dma_free_coherent(struct device *dev, size_t size,
+                        void *vaddr, dma_addr_t dma_handle);
+
+static inline dma_addr_t
+dma_map_single(struct device *dev, void *ptr, size_t size,
+              enum dma_data_direction direction)
+{
+       BUG_ON(direction == DMA_NONE);
+       consistent_sync(ptr, size, direction);
+       return virt_to_phys(ptr);
+}
+
+static inline void
+dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+                enum dma_data_direction direction)
+{
+       BUG_ON(direction == DMA_NONE);
+}
+
+static inline int
+dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+          enum dma_data_direction direction)
+{
+       int i;
+
+       BUG_ON(direction == DMA_NONE);
+
+       for (i = 0; i < nents; i++, sg++ ) {
+               BUG_ON(!sg->page);
+
+               sg->dma_address = page_to_phys(sg->page) + sg->offset;
+               consistent_sync(page_address(sg->page) + sg->offset,
+                               sg->length, direction);
+       }
+
+       return nents;
+}
+
+static inline dma_addr_t
+dma_map_page(struct device *dev, struct page *page, unsigned long offset,
+            size_t size, enum dma_data_direction direction)
+{
+       BUG_ON(direction == DMA_NONE);
+       return (dma_addr_t)(page_to_pfn(page)) * PAGE_SIZE + offset;
+}
+
+static inline void
+dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+              enum dma_data_direction direction)
+{
+       BUG_ON(direction == DMA_NONE);
+}
+
+
+static inline void
+dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
+            enum dma_data_direction direction)
+{
+       BUG_ON(direction == DMA_NONE);
+}
+
+static inline void
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
+               enum dma_data_direction direction)
+{
+       consistent_sync((void *)bus_to_virt(dma_handle), size, direction);
+}
+
+static inline void
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
+               enum dma_data_direction direction)
+{
+       consistent_sync((void *)bus_to_virt(dma_handle), size, direction);
+}
+
+static inline void
+dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+                     unsigned long offset, size_t size,
+                     enum dma_data_direction direction)
+{
+
+       consistent_sync((void *)bus_to_virt(dma_handle)+offset,size,direction);
+}
+
+static inline void
+dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+                     unsigned long offset, size_t size,
+                     enum dma_data_direction direction)
+{
+
+       consistent_sync((void *)bus_to_virt(dma_handle)+offset,size,direction);
+}
+static inline void
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+                enum dma_data_direction dir)
+{
+       int i;
+       for (i = 0; i < nelems; i++, sg++)
+               consistent_sync(page_address(sg->page) + sg->offset,
+                               sg->length, dir);
+}
+
+static inline void
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
+                enum dma_data_direction dir)
+{
+       int i;
+       for (i = 0; i < nelems; i++, sg++)
+               consistent_sync(page_address(sg->page) + sg->offset,
+                               sg->length, dir);
+}
+static inline int
+dma_mapping_error(dma_addr_t dma_addr)
+{
+       return 0;
+}
+
+static inline int
+dma_supported(struct device *dev, u64 mask)
+{
+       return 1;
+}
+
+static inline int
+dma_set_mask(struct device *dev, u64 mask)
+{
+       if(!dev->dma_mask || !dma_supported(dev, mask))
+               return -EIO;
+
+       *dev->dma_mask = mask;
+
+       return 0;
+}
+
+static inline int
+dma_get_cache_alignment(void)
+{
+       return L1_CACHE_BYTES;
+}
+
+#define dma_is_consistent(d)   (1)
+
+static inline void
+dma_cache_sync(void *vaddr, size_t size,
+              enum dma_data_direction direction)
+{
+       consistent_sync(vaddr, size, direction);
+}
+
+#endif /* _XTENSA_DMA_MAPPING_H */
diff --git a/include/asm-xtensa/dma.h b/include/asm-xtensa/dma.h
new file mode 100644 (file)
index 0000000..1c22b02
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * include/asm-xtensa/dma.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_DMA_H
+#define _XTENSA_DMA_H
+
+#include <linux/config.h>
+#include <asm/io.h>            /* need byte IO */
+#include <xtensa/config/core.h>
+
+/*
+ * This is only to be defined if we have PC-like DMA.
+ * By default this is not true on an Xtensa processor,
+ * however on boards with a PCI bus, such functionality
+ * might be emulated externally.
+ *
+ * NOTE:  there still exists driver code that assumes
+ * this is defined, eg. drivers/sound/soundcard.c (as of 2.4).
+ */
+#define MAX_DMA_CHANNELS       8
+
+/*
+ * The maximum virtual address to which DMA transfers
+ * can be performed on this platform.
+ *
+ * NOTE: This is board (platform) specific, not processor-specific!
+ *
+ * NOTE: This assumes DMA transfers can only be performed on
+ *     the section of physical memory contiguously mapped in virtual
+ *     space for the kernel.  For the Xtensa architecture, this
+ *     means the maximum possible size of this DMA area is
+ *     the size of the statically mapped kernel segment
+ *     (XCHAL_KSEG_{CACHED,BYPASS}_SIZE), ie. 128 MB.
+ *
+ * NOTE: When the entire KSEG area is DMA capable, we substract
+ *     one from the max address so that the virt_to_phys() macro
+ *     works correctly on the address (otherwise the address
+ *     enters another area, and virt_to_phys() may not return
+ *     the value desired).
+ */
+#define MAX_DMA_ADDRESS                (PAGE_OFFSET + XCHAL_KSEG_CACHED_SIZE - 1)
+
+/* Reserve and release a DMA channel */
+extern int request_dma(unsigned int dmanr, const char * device_id);
+extern void free_dma(unsigned int dmanr);
+
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
+#else
+#define isa_dma_bridge_buggy   (0)
+#endif
+
+
+#endif
diff --git a/include/asm-xtensa/elf.h b/include/asm-xtensa/elf.h
new file mode 100644 (file)
index 0000000..64f1f53
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * include/asm-xtensa/elf.h
+ *
+ * ELF register definitions
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_ELF_H
+#define _XTENSA_ELF_H
+
+#include <asm/ptrace.h>
+#include <asm/coprocessor.h>
+#include <xtensa/config/core.h>
+
+/* Xtensa processor ELF architecture-magic number */
+
+#define EM_XTENSA      94
+#define EM_XTENSA_OLD  0xABC7
+
+/* ELF register definitions. This is needed for core dump support.  */
+
+/*
+ * elf_gregset_t contains the application-level state in the following order:
+ * Processor info:     config_version, cpuxy
+ * Processor state:    pc, ps, exccause, excvaddr, wb, ws,
+ *                     lbeg, lend, lcount, sar
+ * GP regs:            ar0 - arXX
+ */
+
+typedef unsigned long elf_greg_t;
+
+typedef struct {
+       elf_greg_t xchal_config_id0;
+       elf_greg_t xchal_config_id1;
+       elf_greg_t cpux;
+       elf_greg_t cpuy;
+       elf_greg_t pc;
+       elf_greg_t ps;
+       elf_greg_t exccause;
+       elf_greg_t excvaddr;
+       elf_greg_t windowbase;
+       elf_greg_t windowstart;
+       elf_greg_t lbeg;
+       elf_greg_t lend;
+       elf_greg_t lcount;
+       elf_greg_t sar;
+       elf_greg_t syscall;
+       elf_greg_t ar[XCHAL_NUM_AREGS];
+} xtensa_gregset_t;
+
+#define ELF_NGREG      (sizeof(xtensa_gregset_t) / sizeof(elf_greg_t))
+
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+/*
+ *  Compute the size of the coprocessor and extra state layout (register info)
+ *  table (in bytes).
+ *  This is actually the maximum size of the table, as opposed to the size,
+ *  which is available from the _xtensa_reginfo_table_size global variable.
+ *
+ *  (See also arch/xtensa/kernel/coprocessor.S)
+ *
+ */
+
+#ifndef XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM
+# define XTENSA_CPE_LTABLE_SIZE                0
+#else
+# define XTENSA_CPE_SEGMENT(num)       (num ? (1+num) : 0)
+# define XTENSA_CPE_LTABLE_ENTRIES     \
+               ( XTENSA_CPE_SEGMENT(XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM) \
+               + XTENSA_CPE_SEGMENT(XCHAL_CP0_SA_CONTENTS_LIBDB_NUM)   \
+               + XTENSA_CPE_SEGMENT(XCHAL_CP1_SA_CONTENTS_LIBDB_NUM)   \
+               + XTENSA_CPE_SEGMENT(XCHAL_CP2_SA_CONTENTS_LIBDB_NUM)   \
+               + XTENSA_CPE_SEGMENT(XCHAL_CP3_SA_CONTENTS_LIBDB_NUM)   \
+               + XTENSA_CPE_SEGMENT(XCHAL_CP4_SA_CONTENTS_LIBDB_NUM)   \
+               + XTENSA_CPE_SEGMENT(XCHAL_CP5_SA_CONTENTS_LIBDB_NUM)   \
+               + XTENSA_CPE_SEGMENT(XCHAL_CP6_SA_CONTENTS_LIBDB_NUM)   \
+               + XTENSA_CPE_SEGMENT(XCHAL_CP7_SA_CONTENTS_LIBDB_NUM)   \
+               + 1             /* final entry */                       \
+               )
+# define XTENSA_CPE_LTABLE_SIZE                (XTENSA_CPE_LTABLE_ENTRIES * 8)
+#endif
+
+
+/*
+ * Instantiations of the elf_fpregset_t type contain, in most
+ * architectures, the floating point (FPU) register set.
+ * For Xtensa, this type is extended to contain all custom state,
+ * ie. coprocessor and "extra" (non-coprocessor) state (including,
+ * for example, TIE-defined states and register files; as well
+ * as other optional processor state).
+ * This includes FPU state if a floating-point coprocessor happens
+ * to have been configured within the Xtensa processor.
+ *
+ * TOTAL_FPREGS_SIZE is the required size (without rounding)
+ * of elf_fpregset_t.  It provides space for the following:
+ *
+ *  a) 32-bit mask of active coprocessors for this task (similar
+ *     to CPENABLE in single-threaded Xtensa processor systems)
+ *
+ *  b) table describing the layout of custom states (ie. of
+ *      individual registers, etc) within the save areas
+ *
+ *  c)  save areas for each coprocessor and for non-coprocessor
+ *      ("extra") state
+ *
+ * Note that save areas may require up to 16-byte alignment when
+ * accessed by save/restore sequences.  We do not need to ensure
+ * such alignment in an elf_fpregset_t structure because custom
+ * state is not directly loaded/stored into it; rather, save area
+ * contents are copied to elf_fpregset_t from the active save areas
+ * (see 'struct task_struct' definition in processor.h for that)
+ * using memcpy().  But we do allow space for such alignment,
+ * to allow optimizations of layout and copying.
+ */
+
+#define TOTAL_FPREGS_SIZE                                              \
+       (4 + XTENSA_CPE_LTABLE_SIZE + XTENSA_CP_EXTRA_SIZE)
+#define ELF_NFPREG                                                     \
+       ((TOTAL_FPREGS_SIZE + sizeof(elf_fpreg_t) - 1) / sizeof(elf_fpreg_t))
+
+typedef unsigned int elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+#define ELF_CORE_COPY_REGS(_eregs, _pregs)                             \
+       xtensa_elf_core_copy_regs (&_eregs, _pregs);
+
+extern void xtensa_elf_core_copy_regs (xtensa_gregset_t *, struct pt_regs *);
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+
+#define elf_check_arch(x) ( ( (x)->e_machine == EM_XTENSA )  || \
+                           ( (x)->e_machine == EM_XTENSA_OLD ) )
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+
+#ifdef __XTENSA_EL__
+# define ELF_DATA      ELFDATA2LSB
+#elif defined(__XTENSA_EB__)
+# define ELF_DATA      ELFDATA2MSB
+#else
+# error processor byte order undefined!
+#endif
+
+#define ELF_CLASS      ELFCLASS32
+#define ELF_ARCH       EM_XTENSA
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE      PAGE_SIZE
+
+/*
+ * This is the location that an ET_DYN program is loaded if exec'ed.  Typical
+ * use of this is to invoke "./ld.so someprog" to test out a new version of
+ * the loader.  We need to make sure that it is out of the way of the program
+ * that it will "exec", and that there is sufficient room for the brk.
+ */
+
+#define ELF_ET_DYN_BASE         (2 * TASK_SIZE / 3)
+
+/*
+ * This yields a mask that user programs can use to figure out what
+ * instruction set this CPU supports.  This could be done in user space,
+ * but it's not easy, and we've already done it here.
+ */
+
+#define ELF_HWCAP      (0)
+
+/*
+ * This yields a string that ld.so will use to load implementation
+ * specific libraries for optimization.  This is more specific in
+ * intent than poking at uname or /proc/cpuinfo.
+ * For the moment, we have only optimizations for the Intel generations,
+ * but that could change...
+ */
+
+#define ELF_PLATFORM  (NULL)
+
+/*
+ * The Xtensa processor ABI says that when the program starts, a2
+ * contains a pointer to a function which might be registered using
+ * `atexit'.  This provides a mean for the dynamic linker to call
+ * DT_FINI functions for shared libraries that have been loaded before
+ * the code runs.
+ *
+ * A value of 0 tells we have no such handler.
+ *
+ * We might as well make sure everything else is cleared too (except
+ * for the stack pointer in a1), just to make things more
+ * deterministic.  Also, clearing a0 terminates debugger backtraces.
+ */
+
+#define ELF_PLAT_INIT(_r, load_addr) \
+  do { _r->areg[0]=0; /*_r->areg[1]=0;*/ _r->areg[2]=0;  _r->areg[3]=0;  \
+       _r->areg[4]=0;  _r->areg[5]=0;    _r->areg[6]=0;  _r->areg[7]=0;  \
+       _r->areg[8]=0;  _r->areg[9]=0;    _r->areg[10]=0; _r->areg[11]=0; \
+       _r->areg[12]=0; _r->areg[13]=0;   _r->areg[14]=0; _r->areg[15]=0; \
+  } while (0)
+
+#ifdef __KERNEL__
+
+#define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT)
+
+extern void do_copy_regs (xtensa_gregset_t*, struct pt_regs*,
+                         struct task_struct*);
+extern void do_restore_regs (xtensa_gregset_t*, struct pt_regs*,
+                            struct task_struct*);
+extern void do_save_fpregs (elf_fpregset_t*, struct pt_regs*,
+                           struct task_struct*);
+extern int do_restore_fpregs (elf_fpregset_t*, struct pt_regs*,
+                             struct task_struct*);
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_ELF_H */
diff --git a/include/asm-xtensa/errno.h b/include/asm-xtensa/errno.h
new file mode 100644 (file)
index 0000000..a0f3b96
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/errno.h
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2002 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_ERRNO_H
+#define _XTENSA_ERRNO_H
+
+#include <asm-generic/errno.h>
+
+#endif /* _XTENSA_ERRNO_H */
diff --git a/include/asm-xtensa/fcntl.h b/include/asm-xtensa/fcntl.h
new file mode 100644 (file)
index 0000000..48876bb
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * include/asm-xtensa/fcntl.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_FCNTL_H
+#define _XTENSA_FCNTL_H
+
+/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
+   located on an ext2 file system */
+#define O_ACCMODE      0x0003
+#define O_RDONLY       0x0000
+#define O_WRONLY       0x0001
+#define O_RDWR         0x0002
+#define O_APPEND       0x0008
+#define O_SYNC         0x0010
+#define O_NONBLOCK     0x0080
+#define O_CREAT         0x0100 /* not fcntl */
+#define O_TRUNC                0x0200  /* not fcntl */
+#define O_EXCL         0x0400  /* not fcntl */
+#define O_NOCTTY       0x0800  /* not fcntl */
+#define FASYNC         0x1000  /* fcntl, for BSD compatibility */
+#define O_LARGEFILE    0x2000  /* allow large file opens - currently ignored */
+#define O_DIRECT       0x8000  /* direct disk access hint - currently ignored*/
+#define O_DIRECTORY    0x10000 /* must be a directory */
+#define O_NOFOLLOW     0x20000 /* don't follow links */
+#define O_NOATIME      0x100000
+
+#define O_NDELAY       O_NONBLOCK
+
+#define F_DUPFD                0       /* dup */
+#define F_GETFD                1       /* get close_on_exec */
+#define F_SETFD                2       /* set/clear close_on_exec */
+#define F_GETFL                3       /* get file->f_flags */
+#define F_SETFL                4       /* set file->f_flags */
+#define F_GETLK                14
+#define F_GETLK64       15
+#define F_SETLK                6
+#define F_SETLKW       7
+#define F_SETLK64       16
+#define F_SETLKW64      17
+
+#define F_SETOWN       24      /*  for sockets. */
+#define F_GETOWN       23      /*  for sockets. */
+#define F_SETSIG       10      /*  for sockets. */
+#define F_GETSIG       11      /*  for sockets. */
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#define F_RDLCK                0
+#define F_WRLCK                1
+#define F_UNLCK                2
+
+/* for old implementation of bsd flock () */
+#define F_EXLCK                4       /* or 3 */
+#define F_SHLCK                8       /* or 4 */
+
+/* for leases */
+#define F_INPROGRESS   16
+
+/* operations for bsd flock(), also used by the kernel implementation */
+#define LOCK_SH                1       /* shared lock */
+#define LOCK_EX                2       /* exclusive lock */
+#define LOCK_NB                4       /* or'd with one of the above to prevent
+                                  blocking */
+#define LOCK_UN                8       /* remove lock */
+
+#define LOCK_MAND      32      /* This is a mandatory flock ... */
+#define LOCK_READ      64      /*  which allows concurrent read operations */
+#define LOCK_WRITE     128     /*  which allows concurrent write operations */
+#define LOCK_RW                192     /*  which allows concurrent read & write ops */
+
+typedef struct flock {
+       short l_type;
+       short l_whence;
+       __kernel_off_t l_start;
+       __kernel_off_t l_len;
+       long  l_sysid;
+       __kernel_pid_t l_pid;
+       long  pad[4];
+} flock_t;
+
+struct flock64 {
+       short  l_type;
+       short  l_whence;
+       __kernel_off_t l_start;
+       __kernel_off_t l_len;
+       pid_t  l_pid;
+};
+
+#define F_LINUX_SPECIFIC_BASE  1024
+
+#endif /* _XTENSA_FCNTL_H */
diff --git a/include/asm-xtensa/fixmap.h b/include/asm-xtensa/fixmap.h
new file mode 100644 (file)
index 0000000..4423b8a
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * include/asm-xtensa/fixmap.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_FIXMAP_H
+#define _XTENSA_FIXMAP_H
+
+#include <asm/processor.h>
+
+#ifdef CONFIG_MMU
+
+/*
+ * Here we define all the compile-time virtual addresses.
+ */
+
+#if XCHAL_SEG_MAPPABLE_VADDR != 0
+# error "Current port requires virtual user space starting at 0"
+#endif
+#if XCHAL_SEG_MAPPABLE_SIZE < 0x80000000
+# error "Current port requires at least 0x8000000 bytes for user space"
+#endif
+
+/* Verify instruction/data ram/rom and xlmi don't overlay vmalloc space. */
+
+#define __IN_VMALLOC(addr)                                             \
+       (((addr) >= VMALLOC_START) && ((addr) < VMALLOC_END))
+#define __SPAN_VMALLOC(start,end)                                      \
+       (((start) < VMALLOC_START) && ((end) >= VMALLOC_END))
+#define INSIDE_VMALLOC(start,end)                                      \
+       (__IN_VMALLOC((start)) || __IN_VMALLOC(end) || __SPAN_VMALLOC((start),(end)))
+
+#if XCHAL_NUM_INSTROM
+# if XCHAL_NUM_INSTROM == 1
+#  if INSIDE_VMALLOC(XCHAL_INSTROM0_VADDR,XCHAL_INSTROM0_VADDR+XCHAL_INSTROM0_SIZE)
+#   error vmalloc range conflicts with instrom0
+#  endif
+# endif
+# if XCHAL_NUM_INSTROM == 2
+#  if INSIDE_VMALLOC(XCHAL_INSTROM1_VADDR,XCHAL_INSTROM1_VADDR+XCHAL_INSTROM1_SIZE)
+#   error vmalloc range conflicts with instrom1
+#  endif
+# endif
+#endif
+
+#if XCHAL_NUM_INSTRAM
+# if XCHAL_NUM_INSTRAM == 1
+#  if INSIDE_VMALLOC(XCHAL_INSTRAM0_VADDR,XCHAL_INSTRAM0_VADDR+XCHAL_INSTRAM0_SIZE)
+#   error vmalloc range conflicts with instram0
+#  endif
+# endif
+# if XCHAL_NUM_INSTRAM == 2
+#  if INSIDE_VMALLOC(XCHAL_INSTRAM1_VADDR,XCHAL_INSTRAM1_VADDR+XCHAL_INSTRAM1_SIZE)
+#   error vmalloc range conflicts with instram1
+#  endif
+# endif
+#endif
+
+#if XCHAL_NUM_DATAROM
+# if XCHAL_NUM_DATAROM == 1
+#  if INSIDE_VMALLOC(XCHAL_DATAROM0_VADDR,XCHAL_DATAROM0_VADDR+XCHAL_DATAROM0_SIZE)
+#   error vmalloc range conflicts with datarom0
+#  endif
+# endif
+# if XCHAL_NUM_DATAROM == 2
+#  if INSIDE_VMALLOC(XCHAL_DATAROM1_VADDR,XCHAL_DATAROM1_VADDR+XCHAL_DATAROM1_SIZE)
+#   error vmalloc range conflicts with datarom1
+#  endif
+# endif
+#endif
+
+#if XCHAL_NUM_DATARAM
+# if XCHAL_NUM_DATARAM == 1
+#  if INSIDE_VMALLOC(XCHAL_DATARAM0_VADDR,XCHAL_DATARAM0_VADDR+XCHAL_DATARAM0_SIZE)
+#   error vmalloc range conflicts with dataram0
+#  endif
+# endif
+# if XCHAL_NUM_DATARAM == 2
+#  if INSIDE_VMALLOC(XCHAL_DATARAM1_VADDR,XCHAL_DATARAM1_VADDR+XCHAL_DATARAM1_SIZE)
+#   error vmalloc range conflicts with dataram1
+#  endif
+# endif
+#endif
+
+#if XCHAL_NUM_XLMI
+# if XCHAL_NUM_XLMI == 1
+#  if INSIDE_VMALLOC(XCHAL_XLMI0_VADDR,XCHAL_XLMI0_VADDR+XCHAL_XLMI0_SIZE)
+#   error vmalloc range conflicts with xlmi0
+#  endif
+# endif
+# if XCHAL_NUM_XLMI == 2
+#  if INSIDE_VMALLOC(XCHAL_XLMI1_VADDR,XCHAL_XLMI1_VADDR+XCHAL_XLMI1_SIZE)
+#   error vmalloc range conflicts with xlmi1
+#  endif
+# endif
+#endif
+
+#if (XCHAL_NUM_INSTROM > 2) || \
+    (XCHAL_NUM_INSTRAM > 2) || \
+    (XCHAL_NUM_DATARAM > 2) || \
+    (XCHAL_NUM_DATAROM > 2) || \
+    (XCHAL_NUM_XLMI    > 2)
+# error Insufficient checks on vmalloc above for more than 2 devices
+#endif
+
+/*
+ * USER_VM_SIZE does not necessarily equal TASK_SIZE.  We bumped
+ * TASK_SIZE down to 0x4000000 to simplify the handling of windowed
+ * call instructions (currently limited to a range of 1 GByte).  User
+ * tasks may very well reclaim the VM space from 0x40000000 to
+ * 0x7fffffff in the future, so we do not want the kernel becoming
+ * accustomed to having any of its stuff (e.g., page tables) in this
+ * region.  This VM region is no-man's land for now.
+ */
+
+#define USER_VM_START          XCHAL_SEG_MAPPABLE_VADDR
+#define USER_VM_SIZE           0x80000000
+
+/*  Size of page table:  */
+
+#define PGTABLE_SIZE_BITS      (32 - XCHAL_MMU_MIN_PTE_PAGE_SIZE + 2)
+#define PGTABLE_SIZE           (1L << PGTABLE_SIZE_BITS)
+
+/*  All kernel-mappable space:  */
+
+#define KERNEL_ALLMAP_START    (USER_VM_START + USER_VM_SIZE)
+#define KERNEL_ALLMAP_SIZE     (XCHAL_SEG_MAPPABLE_SIZE - KERNEL_ALLMAP_START)
+
+/*  Carve out page table at start of kernel-mappable area:  */
+
+#if KERNEL_ALLMAP_SIZE < PGTABLE_SIZE
+#error "Gimme some space for page table!"
+#endif
+#define PGTABLE_START          KERNEL_ALLMAP_START
+
+/*  Remaining kernel-mappable space:  */
+
+#define KERNEL_MAPPED_START    (KERNEL_ALLMAP_START + PGTABLE_SIZE)
+#define KERNEL_MAPPED_SIZE     (KERNEL_ALLMAP_SIZE - PGTABLE_SIZE)
+
+#if KERNEL_MAPPED_SIZE < 0x01000000    /* 16 MB is arbitrary for now */
+# error "Shouldn't the kernel have at least *some* mappable space?"
+#endif
+
+#define MAX_LOW_MEMORY         XCHAL_KSEG_CACHED_SIZE
+
+#endif
+
+/*
+ *  Some constants used elsewhere, but perhaps only in Xtensa header
+ *  files, so maybe we can get rid of some and access compile-time HAL
+ *  directly...
+ *
+ *  Note:  We assume that system RAM is located at the very start of the
+ *        kernel segments !!
+ */
+#define KERNEL_VM_LOW           XCHAL_KSEG_CACHED_VADDR
+#define KERNEL_VM_HIGH          XCHAL_KSEG_BYPASS_VADDR
+#define KERNEL_SPACE            XCHAL_KSEG_CACHED_VADDR
+
+/*
+ * Returns the physical/virtual addresses of the kernel space
+ * (works with the cached kernel segment only, which is the
+ *  one normally used for kernel operation).
+ */
+
+/*                     PHYSICAL        BYPASS          CACHED
+ *
+ *  bypass vaddr       bypass paddr    *               cached vaddr
+ *  cached vaddr       cached paddr    bypass vaddr    *
+ *  bypass paddr       *               bypass vaddr    cached vaddr
+ *  cached paddr       *               bypass vaddr    cached vaddr
+ *  other              *               *               *
+ */
+
+#define PHYSADDR(a)                                                          \
+(((unsigned)(a) >= XCHAL_KSEG_BYPASS_VADDR                                   \
+  && (unsigned)(a) < XCHAL_KSEG_BYPASS_VADDR + XCHAL_KSEG_BYPASS_SIZE) ?      \
+    (unsigned)(a) - XCHAL_KSEG_BYPASS_VADDR + XCHAL_KSEG_BYPASS_PADDR :       \
+    ((unsigned)(a) >= XCHAL_KSEG_CACHED_VADDR                                \
+     && (unsigned)(a) < XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_CACHED_SIZE) ?   \
+        (unsigned)(a) - XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_CACHED_PADDR :   \
+       (unsigned)(a))
+
+#define BYPASS_ADDR(a)                                                       \
+(((unsigned)(a) >= XCHAL_KSEG_BYPASS_PADDR                                   \
+  && (unsigned)(a) < XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_BYPASS_SIZE) ?      \
+    (unsigned)(a) - XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_BYPASS_VADDR :       \
+    ((unsigned)(a) >= XCHAL_KSEG_CACHED_PADDR                                \
+     && (unsigned)(a) < XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_CACHED_SIZE) ?   \
+        (unsigned)(a) - XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_BYPASS_VADDR :   \
+        ((unsigned)(a) >= XCHAL_KSEG_CACHED_VADDR                            \
+         && (unsigned)(a) < XCHAL_KSEG_CACHED_VADDR+XCHAL_KSEG_CACHED_SIZE)?  \
+            (unsigned)(a) - XCHAL_KSEG_CACHED_VADDR+XCHAL_KSEG_BYPASS_VADDR:  \
+           (unsigned)(a))
+
+#define CACHED_ADDR(a)                                                       \
+(((unsigned)(a) >= XCHAL_KSEG_BYPASS_PADDR                                   \
+  && (unsigned)(a) < XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_BYPASS_SIZE) ?      \
+    (unsigned)(a) - XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_CACHED_VADDR :       \
+    ((unsigned)(a) >= XCHAL_KSEG_CACHED_PADDR                                \
+     && (unsigned)(a) < XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_CACHED_SIZE) ?   \
+        (unsigned)(a) - XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_CACHED_VADDR :   \
+        ((unsigned)(a) >= XCHAL_KSEG_BYPASS_VADDR                            \
+         && (unsigned)(a) < XCHAL_KSEG_BYPASS_VADDR+XCHAL_KSEG_BYPASS_SIZE) ? \
+            (unsigned)(a) - XCHAL_KSEG_BYPASS_VADDR+XCHAL_KSEG_CACHED_VADDR : \
+           (unsigned)(a))
+
+#define PHYSADDR_IO(a)                                                       \
+(((unsigned)(a) >= XCHAL_KIO_BYPASS_VADDR                                    \
+  && (unsigned)(a) < XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_BYPASS_SIZE) ?       \
+    (unsigned)(a) - XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_BYPASS_PADDR :        \
+    ((unsigned)(a) >= XCHAL_KIO_CACHED_VADDR                                 \
+     && (unsigned)(a) < XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_CACHED_SIZE) ?     \
+        (unsigned)(a) - XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_CACHED_PADDR :     \
+       (unsigned)(a))
+
+#define BYPASS_ADDR_IO(a)                                                    \
+(((unsigned)(a) >= XCHAL_KIO_BYPASS_PADDR                                    \
+  && (unsigned)(a) < XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_BYPASS_SIZE) ?       \
+    (unsigned)(a) - XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_BYPASS_VADDR :        \
+    ((unsigned)(a) >= XCHAL_KIO_CACHED_PADDR                                 \
+     && (unsigned)(a) < XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_CACHED_SIZE) ?     \
+        (unsigned)(a) - XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_BYPASS_VADDR :     \
+        ((unsigned)(a) >= XCHAL_KIO_CACHED_VADDR                             \
+         && (unsigned)(a) < XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_CACHED_SIZE) ? \
+            (unsigned)(a) - XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_BYPASS_VADDR : \
+           (unsigned)(a))
+
+#define CACHED_ADDR_IO(a)                                                    \
+(((unsigned)(a) >= XCHAL_KIO_BYPASS_PADDR                                    \
+  && (unsigned)(a) < XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_BYPASS_SIZE) ?       \
+    (unsigned)(a) - XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_CACHED_VADDR :        \
+    ((unsigned)(a) >= XCHAL_KIO_CACHED_PADDR                                 \
+     && (unsigned)(a) < XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_CACHED_SIZE) ?     \
+        (unsigned)(a) - XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_CACHED_VADDR :     \
+        ((unsigned)(a) >= XCHAL_KIO_BYPASS_VADDR                             \
+         && (unsigned)(a) < XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_BYPASS_SIZE) ? \
+            (unsigned)(a) - XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_CACHED_VADDR : \
+           (unsigned)(a))
+
+#endif /* _XTENSA_ADDRSPACE_H */
+
+
+
+
+
diff --git a/include/asm-xtensa/hardirq.h b/include/asm-xtensa/hardirq.h
new file mode 100644 (file)
index 0000000..e07c76c
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * include/asm-xtensa/hardirq.h
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2002 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_HARDIRQ_H
+#define _XTENSA_HARDIRQ_H
+
+#include <linux/config.h>
+#include <linux/cache.h>
+#include <asm/irq.h>
+
+/* headers.S is sensitive to the offsets of these fields */
+typedef struct {
+       unsigned int __softirq_pending;
+       unsigned int __syscall_count;
+       struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
+       unsigned int __nmi_count;              /* arch dependent */
+} ____cacheline_aligned irq_cpustat_t;
+
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+
+#endif /* _XTENSA_HARDIRQ_H */
diff --git a/include/asm-xtensa/hdreg.h b/include/asm-xtensa/hdreg.h
new file mode 100644 (file)
index 0000000..64b8060
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * include/asm-xtensa/hdreg.h
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2002 - 2005 Tensilica Inc.
+ * Copyright (C) 1994-1996  Linus Torvalds & authors
+ */
+
+#ifndef _XTENSA_HDREG_H
+#define _XTENSA_HDREG_H
+
+typedef unsigned int ide_ioreg_t;
+
+#endif
diff --git a/include/asm-xtensa/highmem.h b/include/asm-xtensa/highmem.h
new file mode 100644 (file)
index 0000000..0a046ca
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * include/asm-xtensa/highmem.h
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2003 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_HIGHMEM_H
+#define _XTENSA_HIGHMEM_H
+
+extern void flush_cache_kmaps(void);
+
+#endif
+
diff --git a/include/asm-xtensa/hw_irq.h b/include/asm-xtensa/hw_irq.h
new file mode 100644 (file)
index 0000000..ccf4362
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * include/asm-xtensa/hw_irq.h
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2002 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_HW_IRQ_H
+#define _XTENSA_HW_IRQ_H
+
+static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
+{
+}
+
+#endif
diff --git a/include/asm-xtensa/ide.h b/include/asm-xtensa/ide.h
new file mode 100644 (file)
index 0000000..b523cd4
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * include/asm-xtensa/ide.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994 - 1996  Linus Torvalds & authors
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_IDE_H
+#define _XTENSA_IDE_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
+#ifndef MAX_HWIFS
+# define MAX_HWIFS     1
+#endif
+
+static __inline__ int ide_default_irq(unsigned long base)
+{
+       /* Unsupported! */
+       return 0;
+}
+
+static __inline__ unsigned long ide_default_io_base(int index)
+{
+       /* Unsupported! */
+       return 0;
+}
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_IDE_H */
diff --git a/include/asm-xtensa/io.h b/include/asm-xtensa/io.h
new file mode 100644 (file)
index 0000000..2c471c4
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * linux/include/asm-xtensa/io.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_IO_H
+#define _XTENSA_IO_H
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#include <asm/byteorder.h>
+
+#include <linux/types.h>
+#include <asm/fixmap.h>
+
+#define _IO_BASE 0
+
+
+/*
+ * swap functions to change byte order from little-endian to big-endian and
+ * vice versa.
+ */
+
+static inline unsigned short _swapw (unsigned short v)
+{
+       return (v << 8) | (v >> 8);
+}
+
+static inline unsigned int _swapl (unsigned int v)
+{
+       return (v << 24) | ((v & 0xff00) << 8) | ((v >> 8) & 0xff00) | (v >> 24);
+}
+
+/*
+ * Change virtual addresses to physical addresses and vv.
+ * These are trivial on the 1:1 Linux/Xtensa mapping
+ */
+
+extern inline unsigned long virt_to_phys(volatile void * address)
+{
+       return PHYSADDR((unsigned long)address);
+}
+
+extern inline void * phys_to_virt(unsigned long address)
+{
+       return (void*) CACHED_ADDR(address);
+}
+
+/*
+ * IO bus memory addresses are also 1:1 with the physical address
+ */
+
+extern inline unsigned long virt_to_bus(volatile void * address)
+{
+       return PHYSADDR((unsigned long)address);
+}
+
+extern inline void * bus_to_virt (unsigned long address)
+{
+       return (void *) CACHED_ADDR(address);
+}
+
+/*
+ * Change "struct page" to physical address.
+ */
+
+extern inline void *ioremap(unsigned long offset, unsigned long size)
+{
+        return (void *) CACHED_ADDR_IO(offset);
+}
+
+extern inline void *ioremap_nocache(unsigned long offset, unsigned long size)
+{
+        return (void *) BYPASS_ADDR_IO(offset);
+}
+
+extern inline void iounmap(void *addr)
+{
+}
+
+/*
+ * Generic I/O
+ */
+
+#define readb(addr) \
+       ({ unsigned char __v = (*(volatile unsigned char *)(addr)); __v; })
+#define readw(addr) \
+       ({ unsigned short __v = (*(volatile unsigned short *)(addr)); __v; })
+#define readl(addr) \
+       ({ unsigned int __v = (*(volatile unsigned int *)(addr)); __v; })
+#define writeb(b, addr) (void)((*(volatile unsigned char *)(addr)) = (b))
+#define writew(b, addr) (void)((*(volatile unsigned short *)(addr)) = (b))
+#define writel(b, addr) (void)((*(volatile unsigned int *)(addr)) = (b))
+
+static inline __u8 __raw_readb(const volatile void __iomem *addr)
+{
+          return *(__force volatile __u8 *)(addr);
+}
+static inline __u16 __raw_readw(const volatile void __iomem *addr)
+{
+          return *(__force volatile __u16 *)(addr);
+}
+static inline __u32 __raw_readl(const volatile void __iomem *addr)
+{
+          return *(__force volatile __u32 *)(addr);
+}
+static inline void __raw_writeb(__u8 b, volatile void __iomem *addr)
+{
+          *(__force volatile __u8 *)(addr) = b;
+}
+static inline void __raw_writew(__u16 b, volatile void __iomem *addr)
+{
+          *(__force volatile __u16 *)(addr) = b;
+}
+static inline void __raw_writel(__u32 b, volatile void __iomem *addr)
+{
+          *(__force volatile __u32 *)(addr) = b;
+}
+
+
+
+
+/* These are the definitions for the x86 IO instructions
+ * inb/inw/inl/outb/outw/outl, the "string" versions
+ * insb/insw/insl/outsb/outsw/outsl, and the "pausing" versions
+ * inb_p/inw_p/...
+ * The macros don't do byte-swapping.
+ */
+
+#define inb(port)              readb((u8 *)((port)+_IO_BASE))
+#define outb(val, port)                writeb((val),(u8 *)((unsigned long)(port)+_IO_BASE))
+#define inw(port)              readw((u16 *)((port)+_IO_BASE))
+#define outw(val, port)                writew((val),(u16 *)((unsigned long)(port)+_IO_BASE))
+#define inl(port)              readl((u32 *)((port)+_IO_BASE))
+#define outl(val, port)                writel((val),(u32 *)((unsigned long)(port)))
+
+#define inb_p(port)            inb((port))
+#define outb_p(val, port)      outb((val), (port))
+#define inw_p(port)            inw((port))
+#define outw_p(val, port)      outw((val), (port))
+#define inl_p(port)            inl((port))
+#define outl_p(val, port)      outl((val), (port))
+
+extern void insb (unsigned long port, void *dst, unsigned long count);
+extern void insw (unsigned long port, void *dst, unsigned long count);
+extern void insl (unsigned long port, void *dst, unsigned long count);
+extern void outsb (unsigned long port, const void *src, unsigned long count);
+extern void outsw (unsigned long port, const void *src, unsigned long count);
+extern void outsl (unsigned long port, const void *src, unsigned long count);
+
+#define IO_SPACE_LIMIT ~0
+
+#define memset_io(a,b,c)       memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c)   memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c)      memcpy((void *)(a),(b),(c))
+
+/* At this point the Xtensa doesn't provide byte swap instructions */
+
+#ifdef __XTENSA_EB__
+# define in_8(addr) (*(u8*)(addr))
+# define in_le16(addr) _swapw(*(u16*)(addr))
+# define in_le32(addr) _swapl(*(u32*)(addr))
+# define out_8(b, addr) *(u8*)(addr) = (b)
+# define out_le16(b, addr) *(u16*)(addr) = _swapw(b)
+# define out_le32(b, addr) *(u32*)(addr) = _swapl(b)
+#elif defined(__XTENSA_EL__)
+# define in_8(addr)  (*(u8*)(addr))
+# define in_le16(addr) (*(u16*)(addr))
+# define in_le32(addr) (*(u32*)(addr))
+# define out_8(b, addr) *(u8*)(addr) = (b)
+# define out_le16(b, addr) *(u16*)(addr) = (b)
+# define out_le32(b, addr) *(u32*)(addr) = (b)
+#else
+# error processor byte order undefined!
+#endif
+
+
+/*
+ *  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ *   * access
+ *    */
+#define xlate_dev_mem_ptr(p)    __va(p)
+
+/*
+ *  * Convert a virtual cached pointer to an uncached pointer
+ *   */
+#define xlate_dev_kmem_ptr(p)   p
+
+
+#endif /* __KERNEL__ */
+
+#endif /* _XTENSA_IO_H */
diff --git a/include/asm-xtensa/ioctl.h b/include/asm-xtensa/ioctl.h
new file mode 100644 (file)
index 0000000..856c605
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * include/asm-xtensa/ioctl.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 - 2005 Tensilica Inc.
+ *
+ * Derived from "include/asm-i386/ioctl.h"
+ */
+
+#ifndef _XTENSA_IOCTL_H
+#define _XTENSA_IOCTL_H
+
+
+/* ioctl command encoding: 32 bits total, command in lower 16 bits,
+ * size of the parameter structure in the lower 14 bits of the
+ * upper 16 bits.
+ * Encoding the size of the parameter structure in the ioctl request
+ * is useful for catching programs compiled with old versions
+ * and to avoid overwriting user space outside the user buffer area.
+ * The highest 2 bits are reserved for indicating the ``access mode''.
+ * NOTE: This limits the max parameter size to 16kB -1 !
+ */
+
+/*
+ * The following is for compatibility across the various Linux
+ * platforms.  The i386 ioctl numbering scheme doesn't really enforce
+ * a type field.  De facto, however, the top 8 bits of the lower 16
+ * bits are indeed used as a type field, so we might just as well make
+ * this explicit here.  Please be sure to use the decoding macros
+ * below from now on.
+ */
+#define _IOC_NRBITS    8
+#define _IOC_TYPEBITS  8
+#define _IOC_SIZEBITS  14
+#define _IOC_DIRBITS   2
+
+#define _IOC_NRMASK    ((1 << _IOC_NRBITS)-1)
+#define _IOC_TYPEMASK  ((1 << _IOC_TYPEBITS)-1)
+#define _IOC_SIZEMASK  ((1 << _IOC_SIZEBITS)-1)
+#define _IOC_DIRMASK   ((1 << _IOC_DIRBITS)-1)
+
+#define _IOC_NRSHIFT   0
+#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
+#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
+#define _IOC_DIRSHIFT  (_IOC_SIZESHIFT+_IOC_SIZEBITS)
+
+/*
+ * Direction bits.
+ */
+#define _IOC_NONE      0U
+#define _IOC_WRITE     1U
+#define _IOC_READ      2U
+
+#define _IOC(dir,type,nr,size) \
+       (((dir)  << _IOC_DIRSHIFT) | \
+        ((type) << _IOC_TYPESHIFT) | \
+        ((nr)   << _IOC_NRSHIFT) | \
+        ((size) << _IOC_SIZESHIFT))
+
+/* used to create numbers */
+#define _IO(type,nr)           _IOC(_IOC_NONE,(type),(nr),0)
+#define _IOR(type,nr,size)     _IOC(_IOC_READ,(type),(nr),sizeof(size))
+#define _IOW(type,nr,size)     _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
+#define _IOWR(type,nr,size)    _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
+
+/* used to decode ioctl numbers.. */
+#define _IOC_DIR(nr)           (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+#define _IOC_TYPE(nr)          (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
+#define _IOC_NR(nr)            (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
+#define _IOC_SIZE(nr)          (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+
+/* ...and for the drivers/sound files... */
+
+#define IOC_IN         (_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT                (_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT      ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK   (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT  (_IOC_SIZESHIFT)
+
+#endif
diff --git a/include/asm-xtensa/ioctls.h b/include/asm-xtensa/ioctls.h
new file mode 100644 (file)
index 0000000..10c4434
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * include/asm-xtensa/ioctl.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 - 2005 Tensilica Inc.
+ *
+ * Derived from "include/asm-i386/ioctls.h"
+ */
+
+#ifndef _XTENSA_IOCTLS_H
+#define _XTENSA_IOCTLS_H
+
+#include <asm/ioctl.h>
+
+#define FIOCLEX                _IO('f', 1)
+#define FIONCLEX       _IO('f', 2)
+#define FIOASYNC       _IOW('f', 125, int)
+#define FIONBIO                _IOW('f', 126, int)
+#define FIONREAD       _IOR('f', 127, int)
+#define TIOCINQ                FIONREAD
+#define FIOQSIZE       _IOR('f', 128, loff_t)
+
+#define TCGETS         0x5401
+#define TCSETS         0x5402
+#define TCSETSW                0x5403
+#define TCSETSF                0x5404
+
+#define TCGETA         _IOR('t', 23, struct termio)
+#define TCSETA         _IOW('t', 24, struct termio)
+#define TCSETAW                _IOW('t', 25, struct termio)
+#define TCSETAF                _IOW('t', 28, struct termio)
+
+#define TCSBRK         _IO('t', 29)
+#define TCXONC         _IO('t', 30)
+#define TCFLSH         _IO('t', 31)
+
+#define TIOCSWINSZ     _IOW('t', 103, struct winsize)
+#define TIOCGWINSZ     _IOR('t', 104, struct winsize)
+#define        TIOCSTART       _IO('t', 110)           /* start output, like ^Q */
+#define        TIOCSTOP        _IO('t', 111)           /* stop output, like ^S */
+#define TIOCOUTQ        _IOR('t', 115, int)     /* output queue size */
+
+#define TIOCSPGRP      _IOW('t', 118, int)
+#define TIOCGPGRP      _IOR('t', 119, int)
+
+#define TIOCEXCL       _IO('T', 12)
+#define TIOCNXCL       _IO('T', 13)
+#define TIOCSCTTY      _IO('T', 14)
+
+#define TIOCSTI                _IOW('T', 18, char)
+#define TIOCMGET       _IOR('T', 21, unsigned int)
+#define TIOCMBIS       _IOW('T', 22, unsigned int)
+#define TIOCMBIC       _IOW('T', 23, unsigned int)
+#define TIOCMSET       _IOW('T', 24, unsigned int)
+# define TIOCM_LE      0x001
+# define TIOCM_DTR     0x002
+# define TIOCM_RTS     0x004
+# define TIOCM_ST      0x008
+# define TIOCM_SR      0x010
+# define TIOCM_CTS     0x020
+# define TIOCM_CAR     0x040
+# define TIOCM_RNG     0x080
+# define TIOCM_DSR     0x100
+# define TIOCM_CD      TIOCM_CAR
+# define TIOCM_RI      TIOCM_RNG
+
+#define TIOCGSOFTCAR   _IOR('T', 25, unsigned int)
+#define TIOCSSOFTCAR   _IOW('T', 26, unsigned int)
+#define TIOCLINUX      _IOW('T', 28, char)
+#define TIOCCONS       _IO('T', 29)
+#define TIOCGSERIAL    _IOR('T', 30, struct serial_struct)
+#define TIOCSSERIAL    _IOW('T', 31, struct serial_struct)
+#define TIOCPKT                _IOW('T', 32, int)
+# define TIOCPKT_DATA           0
+# define TIOCPKT_FLUSHREAD      1
+# define TIOCPKT_FLUSHWRITE     2
+# define TIOCPKT_STOP           4
+# define TIOCPKT_START          8
+# define TIOCPKT_NOSTOP                16
+# define TIOCPKT_DOSTOP                32
+
+
+#define TIOCNOTTY      _IO('T', 34)
+#define TIOCSETD       _IOW('T', 35, int)
+#define TIOCGETD       _IOR('T', 36, int)
+#define TCSBRKP                _IOW('T', 37, int)   /* Needed for POSIX tcsendbreak()*/
+#define TIOCTTYGSTRUCT _IOR('T', 38, struct tty_struct) /* For debugging only*/
+#define TIOCSBRK       _IO('T', 39)         /* BSD compatibility */
+#define TIOCCBRK       _IO('T', 40)         /* BSD compatibility */
+#define TIOCGSID       _IOR('T', 41, pid_t) /* Return the session ID of FD*/
+#define TIOCGPTN       _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK     _IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define TIOCSERCONFIG  _IO('T', 83)
+#define TIOCSERGWILD   _IOR('T', 84,  int)
+#define TIOCSERSWILD   _IOW('T', 85,  int)
+#define TIOCGLCKTRMIOS 0x5456
+#define TIOCSLCKTRMIOS 0x5457
+#define TIOCSERGSTRUCT 0x5458               /* For debugging only */
+#define TIOCSERGETLSR   _IOR('T', 89, unsigned int) /* Get line status reg. */
+  /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+# define TIOCSER_TEMT    0x01               /* Transmitter physically empty */
+#define TIOCSERGETMULTI _IOR('T', 90, struct serial_multiport_struct) /* Get multiport config  */
+#define TIOCSERSETMULTI _IOW('T', 91, struct serial_multiport_struct) /* Set multiport config */
+
+#define TIOCMIWAIT     _IO('T', 92) /* wait for a change on serial input line(s) */
+#define TIOCGICOUNT    _IOR('T', 93, struct async_icount) /* read serial port inline interrupt counts */
+
+#endif /* _XTENSA_IOCTLS_H */
diff --git a/include/asm-xtensa/ipc.h b/include/asm-xtensa/ipc.h
new file mode 100644 (file)
index 0000000..a9eed4e
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/ipc.h
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_IPC_H
+#define _XTENSA_IPC_H
+
+#include <asm-generic/ipc.h>
+
+#endif /* _XTENSA_IPC_H */
diff --git a/include/asm-xtensa/ipcbuf.h b/include/asm-xtensa/ipcbuf.h
new file mode 100644 (file)
index 0000000..c33aa6a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * include/asm-xtensa/ipcbuf.h
+ *
+ * The ipc64_perm structure for the Xtensa architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_IPCBUF_H
+#define _XTENSA_IPCBUF_H
+
+/*
+ * Pad space is left for:
+ * - 32-bit mode_t and seq
+ * - 2 miscellaneous 32-bit values
+ *
+ * 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.
+ */
+
+struct ipc64_perm
+{
+       __kernel_key_t          key;
+       __kernel_uid32_t        uid;
+       __kernel_gid32_t        gid;
+       __kernel_uid32_t        cuid;
+       __kernel_gid32_t        cgid;
+       __kernel_mode_t         mode;
+       unsigned long           seq;
+       unsigned long           __unused1;
+       unsigned long           __unused2;
+};
+
+#endif /* _XTENSA_IPCBUF_H */
diff --git a/include/asm-xtensa/irq.h b/include/asm-xtensa/irq.h
new file mode 100644 (file)
index 0000000..d984e95
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * include/asm-xtensa/irq.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_IRQ_H
+#define _XTENSA_IRQ_H
+
+#include <linux/config.h>
+#include <asm/platform/hardware.h>
+
+#include <xtensa/config/core.h>
+
+#ifndef PLATFORM_NR_IRQS
+# define PLATFORM_NR_IRQS 0
+#endif
+#define XTENSA_NR_IRQS XCHAL_NUM_INTERRUPTS
+#define NR_IRQS (XTENSA_NR_IRQS + PLATFORM_NR_IRQS)
+
+static __inline__ int irq_canonicalize(int irq)
+{
+       return (irq);
+}
+
+struct irqaction;
+#if 0 // FIXME
+extern void disable_irq_nosync(unsigned int);
+extern void disable_irq(unsigned int);
+extern void enable_irq(unsigned int);
+#endif
+
+#endif /* _XTENSA_IRQ_H */
diff --git a/include/asm-xtensa/kmap_types.h b/include/asm-xtensa/kmap_types.h
new file mode 100644 (file)
index 0000000..9e822d2
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * include/asm-xtensa/kmap_types.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_KMAP_TYPES_H
+#define _XTENSA_KMAP_TYPES_H
+
+enum km_type {
+  KM_BOUNCE_READ,
+  KM_SKB_SUNRPC_DATA,
+  KM_SKB_DATA_SOFTIRQ,
+  KM_USER0,
+  KM_USER1,
+  KM_BIO_SRC_IRQ,
+  KM_BIO_DST_IRQ,
+  KM_PTE0,
+  KM_PTE1,
+  KM_IRQ0,
+  KM_IRQ1,
+  KM_SOFTIRQ0,
+  KM_SOFTIRQ1,
+  KM_TYPE_NR
+};
+
+#endif /* _XTENSA_KMAP_TYPES_H */
diff --git a/include/asm-xtensa/linkage.h b/include/asm-xtensa/linkage.h
new file mode 100644 (file)
index 0000000..bf2128a
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/linkage.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_LINKAGE_H
+#define _XTENSA_LINKAGE_H
+
+/* Nothing to do here ... */
+
+#endif /* _XTENSA_LINKAGE_H */
diff --git a/include/asm-xtensa/local.h b/include/asm-xtensa/local.h
new file mode 100644 (file)
index 0000000..48723e5
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/local.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_LOCAL_H
+#define _XTENSA_LOCAL_H
+
+#include <asm-generic/local.h>
+
+#endif /* _XTENSA_LOCAL_H */
diff --git a/include/asm-xtensa/mman.h b/include/asm-xtensa/mman.h
new file mode 100644 (file)
index 0000000..9a95a45
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * include/asm-xtensa/mman.h
+ *
+ * Xtensa Processor memory-manager definitions
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_MMAN_H
+#define _XTENSA_MMAN_H
+
+/*
+ * Protections are chosen from these bits, OR'd together.  The
+ * implementation does not necessarily support PROT_EXEC or PROT_WRITE
+ * without PROT_READ.  The only guarantees are that no writing will be
+ * allowed without PROT_WRITE and no access will be allowed for PROT_NONE.
+ */
+
+#define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_READ      0x1             /* page can be read */
+#define PROT_WRITE     0x2             /* page can be written */
+#define PROT_EXEC      0x4             /* page can be executed */
+
+#define PROT_SEM       0x10            /* page may be used for atomic ops */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end fo growsup vma */
+
+/*
+ * Flags for mmap
+ */
+#define MAP_SHARED     0x001           /* Share changes */
+#define MAP_PRIVATE    0x002           /* Changes are private */
+#define MAP_TYPE       0x00f           /* Mask for type of mapping */
+#define MAP_FIXED      0x010           /* Interpret addr exactly */
+
+/* not used by linux, but here to make sure we don't clash with ABI defines */
+#define MAP_RENAME     0x020           /* Assign page to file */
+#define MAP_AUTOGROW   0x040           /* File may grow by writing */
+#define MAP_LOCAL      0x080           /* Copy on fork/sproc */
+#define MAP_AUTORSRV   0x100           /* Logical swap reserved on demand */
+
+/* These are linux-specific */
+#define MAP_NORESERVE  0x0400          /* don't check for reservations */
+#define MAP_ANONYMOUS  0x0800          /* don't use a file */
+#define MAP_GROWSDOWN  0x1000          /* stack-like segment */
+#define MAP_DENYWRITE  0x2000          /* ETXTBSY */
+#define MAP_EXECUTABLE 0x4000          /* mark it as an executable */
+#define MAP_LOCKED     0x8000          /* pages are locked */
+#define MAP_POPULATE   0x10000         /* populate (prefault) pagetables */
+#define MAP_NONBLOCK   0x20000         /* do not block on IO */
+
+/*
+ * Flags for msync
+ */
+#define MS_ASYNC       0x0001          /* sync memory asynchronously */
+#define MS_INVALIDATE  0x0002          /* invalidate mappings & caches */
+#define MS_SYNC                0x0004          /* synchronous memory sync */
+
+/*
+ * Flags for mlockall
+ */
+#define MCL_CURRENT    1               /* lock all current mappings */
+#define MCL_FUTURE     2               /* lock all future mappings */
+
+#define MADV_NORMAL    0x0             /* default page-in behavior */
+#define MADV_RANDOM    0x1             /* page-in minimum required */
+#define MADV_SEQUENTIAL        0x2             /* read-ahead aggressively */
+#define MADV_WILLNEED  0x3             /* pre-fault pages */
+#define MADV_DONTNEED  0x4             /* discard these pages */
+
+/* compatibility flags */
+#define MAP_ANON       MAP_ANONYMOUS
+#define MAP_FILE       0
+
+#endif /* _XTENSA_MMAN_H */
diff --git a/include/asm-xtensa/mmu.h b/include/asm-xtensa/mmu.h
new file mode 100644 (file)
index 0000000..44c5bb0
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * include/asm-xtensa/mmu.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_MMU_H
+#define _XTENSA_MMU_H
+
+/* Default "unsigned long" context */
+typedef unsigned long mm_context_t;
+
+#endif /* _XTENSA_MMU_H */
diff --git a/include/asm-xtensa/mmu_context.h b/include/asm-xtensa/mmu_context.h
new file mode 100644 (file)
index 0000000..1b08015
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * include/asm-xtensa/mmu_context.h
+ *
+ * Switch an MMU context.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_MMU_CONTEXT_H
+#define _XTENSA_MMU_CONTEXT_H
+
+#include <linux/config.h>
+#include <linux/stringify.h>
+
+#include <asm/pgtable.h>
+#include <asm/mmu_context.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+
+/*
+ * Linux was ported to Xtensa assuming all auto-refill ways in set 0
+ * had the same properties (a very likely assumption).  Multiple sets
+ * of auto-refill ways will still work properly, but not as optimally
+ * as the Xtensa designer may have assumed.
+ *
+ * We make this case a hard #error, killing the kernel build, to alert
+ * the developer to this condition (which is more likely an error).
+ * You super-duper clever developers can change it to a warning or
+ * remove it altogether if you think you know what you're doing.  :)
+ */
+
+#if (XCHAL_HAVE_TLBS != 1)
+# error "Linux must have an MMU!"
+#endif
+
+#if ((XCHAL_ITLB_ARF_WAYS == 0) || (XCHAL_DTLB_ARF_WAYS == 0))
+# error "MMU must have auto-refill ways"
+#endif
+
+#if ((XCHAL_ITLB_ARF_SETS != 1) || (XCHAL_DTLB_ARF_SETS != 1))
+# error Linux may not use all auto-refill ways as efficiently as you think
+#endif
+
+#if (XCHAL_MMU_MAX_PTE_PAGE_SIZE != XCHAL_MMU_MIN_PTE_PAGE_SIZE)
+# error Only one page size allowed!
+#endif
+
+extern unsigned long asid_cache;
+extern pgd_t *current_pgd;
+
+/*
+ * Define the number of entries per auto-refill way in set 0 of both I and D
+ * TLBs.  We deal only with set 0 here (an assumption further explained in
+ * assertions.h).  Also, define the total number of ARF entries in both TLBs.
+ */
+
+#define ITLB_ENTRIES_PER_ARF_WAY  (XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,ENTRIES))
+#define DTLB_ENTRIES_PER_ARF_WAY  (XCHAL_DTLB_SET(XCHAL_DTLB_ARF_SET0,ENTRIES))
+
+#define ITLB_ENTRIES                                                   \
+       (ITLB_ENTRIES_PER_ARF_WAY * (XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,WAYS)))
+#define DTLB_ENTRIES                                                   \
+       (DTLB_ENTRIES_PER_ARF_WAY * (XCHAL_DTLB_SET(XCHAL_DTLB_ARF_SET0,WAYS)))
+
+
+/*
+ * SMALLEST_NTLB_ENTRIES is the smaller of ITLB_ENTRIES and DTLB_ENTRIES.
+ * In practice, they are probably equal.  This macro simplifies function
+ * flush_tlb_range().
+ */
+
+#if (DTLB_ENTRIES < ITLB_ENTRIES)
+# define SMALLEST_NTLB_ENTRIES  DTLB_ENTRIES
+#else
+# define SMALLEST_NTLB_ENTRIES  ITLB_ENTRIES
+#endif
+
+
+/*
+ * asid_cache tracks only the ASID[USER_RING] field of the RASID special
+ * register, which is the current user-task asid allocation value.
+ * mm->context has the same meaning.  When it comes time to write the
+ * asid_cache or mm->context values to the RASID special register, we first
+ * shift the value left by 8, then insert the value.
+ * ASID[0] always contains the kernel's asid value, and we reserve three
+ * other asid values that we never assign to user tasks.
+ */
+
+#define ASID_INC       0x1
+#define ASID_MASK      ((1 << XCHAL_MMU_ASID_BITS) - 1)
+
+/*
+ * XCHAL_MMU_ASID_INVALID is a configurable Xtensa processor constant
+ * indicating invalid address space.  XCHAL_MMU_ASID_KERNEL is a configurable
+ * Xtensa processor constant indicating the kernel address space.  They can
+ * be arbitrary values.
+ *
+ * We identify three more unique, reserved ASID values to use in the unused
+ * ring positions.  No other user process will be assigned these reserved
+ * ASID values.
+ *
+ * For example, given that
+ *
+ *     XCHAL_MMU_ASID_INVALID == 0
+ *     XCHAL_MMU_ASID_KERNEL  == 1
+ *
+ * the following maze of #if statements would generate
+ *
+ *     ASID_RESERVED_1        == 2
+ *     ASID_RESERVED_2        == 3
+ *     ASID_RESERVED_3        == 4
+ *     ASID_FIRST_NONRESERVED == 5
+ */
+
+#if (XCHAL_MMU_ASID_INVALID != XCHAL_MMU_ASID_KERNEL + 1)
+# define ASID_RESERVED_1         ((XCHAL_MMU_ASID_KERNEL + 1) & ASID_MASK)
+#else
+# define ASID_RESERVED_1         ((XCHAL_MMU_ASID_KERNEL + 2) & ASID_MASK)
+#endif
+
+#if (XCHAL_MMU_ASID_INVALID != ASID_RESERVED_1 + 1)
+# define ASID_RESERVED_2         ((ASID_RESERVED_1 + 1) & ASID_MASK)
+#else
+# define ASID_RESERVED_2         ((ASID_RESERVED_1 + 2) & ASID_MASK)
+#endif
+
+#if (XCHAL_MMU_ASID_INVALID != ASID_RESERVED_2 + 1)
+# define ASID_RESERVED_3         ((ASID_RESERVED_2 + 1) & ASID_MASK)
+#else
+# define ASID_RESERVED_3         ((ASID_RESERVED_2 + 2) & ASID_MASK)
+#endif
+
+#if (XCHAL_MMU_ASID_INVALID != ASID_RESERVED_3 + 1)
+# define ASID_FIRST_NONRESERVED  ((ASID_RESERVED_3 + 1) & ASID_MASK)
+#else
+# define ASID_FIRST_NONRESERVED  ((ASID_RESERVED_3 + 2) & ASID_MASK)
+#endif
+
+#define ASID_ALL_RESERVED ( ((ASID_RESERVED_1) << 24) + \
+                            ((ASID_RESERVED_2) << 16) + \
+                            ((ASID_RESERVED_3) <<  8) + \
+                            ((XCHAL_MMU_ASID_KERNEL))   )
+
+
+/*
+ * NO_CONTEXT is the invalid ASID value that we don't ever assign to
+ * any user or kernel context.  NO_CONTEXT is a better mnemonic than
+ * XCHAL_MMU_ASID_INVALID, so we use it in code instead.
+ */
+
+#define NO_CONTEXT   XCHAL_MMU_ASID_INVALID
+
+#if (KERNEL_RING != 0)
+# error The KERNEL_RING really should be zero.
+#endif
+
+#if (USER_RING >= XCHAL_MMU_RINGS)
+# error USER_RING cannot be greater than the highest numbered ring.
+#endif
+
+#if (USER_RING == KERNEL_RING)
+# error The user and kernel rings really should not be equal.
+#endif
+
+#if (USER_RING == 1)
+#define ASID_INSERT(x) ( ((ASID_RESERVED_1)   << 24) + \
+                         ((ASID_RESERVED_2)   << 16) + \
+                         (((x) & (ASID_MASK)) <<  8) + \
+                         ((XCHAL_MMU_ASID_KERNEL))   )
+
+#elif (USER_RING == 2)
+#define ASID_INSERT(x) ( ((ASID_RESERVED_1)   << 24) + \
+                         (((x) & (ASID_MASK)) << 16) + \
+                         ((ASID_RESERVED_2)   <<  8) + \
+                         ((XCHAL_MMU_ASID_KERNEL))   )
+
+#elif (USER_RING == 3)
+#define ASID_INSERT(x) ( (((x) & (ASID_MASK)) << 24) + \
+                        ((ASID_RESERVED_1)   << 16) + \
+                         ((ASID_RESERVED_2)   <<  8) + \
+                         ((XCHAL_MMU_ASID_KERNEL))   )
+
+#else
+#error Goofy value for USER_RING
+
+#endif /* USER_RING == 1 */
+
+
+/*
+ *  All unused by hardware upper bits will be considered
+ *  as a software asid extension.
+ */
+
+#define ASID_VERSION_MASK  ((unsigned long)~(ASID_MASK|(ASID_MASK-1)))
+#define ASID_FIRST_VERSION                                             \
+       ((unsigned long)(~ASID_VERSION_MASK) + 1 + ASID_FIRST_NONRESERVED)
+
+extern inline void set_rasid_register (unsigned long val)
+{
+       __asm__ __volatile__ (" wsr %0, "__stringify(RASID)"\n\t"
+                             " isync\n" : : "a" (val));
+}
+
+extern inline unsigned long get_rasid_register (void)
+{
+       unsigned long tmp;
+       __asm__ __volatile__ (" rsr %0, "__stringify(RASID)"\n\t" : "=a" (tmp));
+       return tmp;
+}
+
+
+#if ((XCHAL_MMU_ASID_INVALID == 0) && (XCHAL_MMU_ASID_KERNEL == 1))
+
+extern inline void
+get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
+{
+       extern void flush_tlb_all(void);
+       if (! ((asid += ASID_INC) & ASID_MASK) ) {
+               flush_tlb_all(); /* start new asid cycle */
+               if (!asid)      /* fix version if needed */
+                       asid = ASID_FIRST_VERSION - ASID_FIRST_NONRESERVED;
+               asid += ASID_FIRST_NONRESERVED;
+       }
+       mm->context = asid_cache = asid;
+}
+
+#else
+#warning ASID_{INVALID,KERNEL} values impose non-optimal get_new_mmu_context implementation
+
+/* XCHAL_MMU_ASID_INVALID == 0 and XCHAL_MMU_ASID_KERNEL ==1 are
+   really the best, but if you insist... */
+
+extern inline int validate_asid (unsigned long asid)
+{
+       switch (asid) {
+       case XCHAL_MMU_ASID_INVALID:
+       case XCHAL_MMU_ASID_KERNEL:
+       case ASID_RESERVED_1:
+       case ASID_RESERVED_2:
+       case ASID_RESERVED_3:
+               return 0; /* can't use these values as ASIDs */
+       }
+       return 1; /* valid */
+}
+
+extern inline void
+get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
+{
+       extern void flush_tlb_all(void);
+       while (1) {
+               asid += ASID_INC;
+               if ( ! (asid & ASID_MASK) ) {
+                       flush_tlb_all(); /* start new asid cycle */
+                       if (!asid)      /* fix version if needed */
+                               asid = ASID_FIRST_VERSION - ASID_FIRST_NONRESERVED;
+                       asid += ASID_FIRST_NONRESERVED;
+                       break; /* no need to validate here */
+               }
+               if (validate_asid (asid & ASID_MASK))
+                       break;
+       }
+       mm->context = asid_cache = asid;
+}
+
+#endif
+
+
+/*
+ * Initialize the context related info for a new mm_struct
+ * instance.
+ */
+
+extern inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+       mm->context = NO_CONTEXT;
+       return 0;
+}
+
+extern inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+                             struct task_struct *tsk)
+{
+       unsigned long asid = asid_cache;
+
+       /* Check if our ASID is of an older version and thus invalid */
+
+       if ((next->context ^ asid) & ASID_VERSION_MASK)
+               get_new_mmu_context(next, asid);
+
+       set_rasid_register (ASID_INSERT(next->context));
+       invalidate_page_directory();
+}
+
+#define deactivate_mm(tsk, mm) do { } while(0)
+
+/*
+ * Destroy context related info for an mm_struct that is about
+ * to be put to rest.
+ */
+extern inline void destroy_context(struct mm_struct *mm)
+{
+       /* Nothing to do. */
+}
+
+/*
+ * After we have set current->mm to a new value, this activates
+ * the context for the new mm so we see the new mappings.
+ */
+extern inline void
+activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+       /* Unconditionally get a new ASID.  */
+
+       get_new_mmu_context(next, asid_cache);
+       set_rasid_register (ASID_INSERT(next->context));
+       invalidate_page_directory();
+}
+
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+       /* Nothing to do. */
+
+}
+
+#endif /* _XTENSA_MMU_CONTEXT_H */
diff --git a/include/asm-xtensa/module.h b/include/asm-xtensa/module.h
new file mode 100644 (file)
index 0000000..ffb25bf
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * include/asm-xtensa/module.h
+ *
+ * This file contains the module code specific to the Xtensa architecture.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_MODULE_H
+#define _XTENSA_MODULE_H
+
+struct mod_arch_specific
+{
+       /* Module support is not completely implemented. */
+};
+
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#define Elf_Ehdr Elf32_Ehdr
+
+#endif /* _XTENSA_MODULE_H */
diff --git a/include/asm-xtensa/msgbuf.h b/include/asm-xtensa/msgbuf.h
new file mode 100644 (file)
index 0000000..693c967
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * include/asm-xtensa/msgbuf.h
+ *
+ * The msqid64_ds structure for the Xtensa architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ *
+ * 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 _XTENSA_MSGBUF_H
+#define _XTENSA_MSGBUF_H
+
+struct msqid64_ds {
+       struct ipc64_perm msg_perm;
+#ifdef __XTENSA_EB__
+       unsigned int    __unused1;
+       __kernel_time_t msg_stime;      /* last msgsnd time */
+       unsigned int    __unused2;
+       __kernel_time_t msg_rtime;      /* last msgrcv time */
+       unsigned int    __unused3;
+       __kernel_time_t msg_ctime;      /* last change time */
+#elif defined(__XTENSA_EL__)
+       __kernel_time_t msg_stime;      /* last msgsnd time */
+       unsigned int    __unused1;
+       __kernel_time_t msg_rtime;      /* last msgrcv time */
+       unsigned int    __unused2;
+       __kernel_time_t msg_ctime;      /* last change time */
+       unsigned int    __unused3;
+#else
+# error processor byte order undefined!
+#endif
+       unsigned long  msg_cbytes;      /* current number of bytes on queue */
+       unsigned long  msg_qnum;        /* number of messages in queue */
+       unsigned long  msg_qbytes;      /* max number of bytes on queue */
+       __kernel_pid_t msg_lspid;       /* pid of last msgsnd */
+       __kernel_pid_t msg_lrpid;       /* last receive pid */
+       unsigned long  __unused4;
+       unsigned long  __unused5;
+};
+
+#endif /* _XTENSA_MSGBUF_H */
diff --git a/include/asm-xtensa/namei.h b/include/asm-xtensa/namei.h
new file mode 100644 (file)
index 0000000..3fdff03
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * include/asm-xtensa/namei.h
+ *
+ * Included from linux/fs/namei.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_NAMEI_H
+#define _XTENSA_NAMEI_H
+
+#ifdef __KERNEL__
+
+/* This dummy routine maybe changed to something useful
+ * for /usr/gnemul/ emulation stuff.
+ * Look at asm-sparc/namei.h for details.
+ */
+
+#define __emul_prefix() NULL
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_NAMEI_H */
diff --git a/include/asm-xtensa/page.h b/include/asm-xtensa/page.h
new file mode 100644 (file)
index 0000000..b495e5b
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * linux/include/asm-xtensa/page.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PAGE_H
+#define _XTENSA_PAGE_H
+
+#ifdef __KERNEL__
+
+#include <asm/processor.h>
+#include <linux/config.h>
+
+/*
+ * PAGE_SHIFT determines the page size
+ * PAGE_ALIGN(x) aligns the pointer to the (next) page boundary
+ */
+
+#define PAGE_SHIFT             XCHAL_MMU_MIN_PTE_PAGE_SIZE
+#define PAGE_SIZE              (1 << PAGE_SHIFT)
+#define PAGE_MASK              (~(PAGE_SIZE-1))
+#define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE - 1) & PAGE_MASK)
+
+#define DCACHE_WAY_SIZE                (XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS)
+#define PAGE_OFFSET            XCHAL_KSEG_CACHED_VADDR
+
+#ifdef __ASSEMBLY__
+
+#define __pgprot(x)    (x)
+
+#else
+
+/*
+ * These are used to make use of C type-checking..
+ */
+
+typedef struct { unsigned long pte; } pte_t;           /* page table entry */
+typedef struct { unsigned long pgd; } pgd_t;           /* PGD table entry */
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#define pte_val(x)     ((x).pte)
+#define pgd_val(x)     ((x).pgd)
+#define pgprot_val(x)  ((x).pgprot)
+
+#define __pte(x)       ((pte_t) { (x) } )
+#define __pgd(x)       ((pgd_t) { (x) } )
+#define __pgprot(x)    ((pgprot_t) { (x) } )
+
+/*
+ * Pure 2^n version of get_order
+ */
+
+extern __inline__ int get_order(unsigned long size)
+{
+       int order;
+#ifndef XCHAL_HAVE_NSU
+       unsigned long x1, x2, x4, x8, x16;
+
+       size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       x1  = size & 0xAAAAAAAA;
+       x2  = size & 0xCCCCCCCC;
+       x4  = size & 0xF0F0F0F0;
+       x8  = size & 0xFF00FF00;
+       x16 = size & 0xFFFF0000;
+       order = x2 ? 2 : 0;
+       order += (x16 != 0) * 16;
+       order += (x8 != 0) * 8;
+       order += (x4 != 0) * 4;
+       order += (x1 != 0);
+
+       return order;
+#else
+       size = (size - 1) >> PAGE_SHIFT;
+       asm ("nsau %0, %1" : "=r" (order) : "r" (size));
+       return 32 - order;
+#endif
+}
+
+
+struct page;
+extern void clear_page(void *page);
+extern void copy_page(void *to, void *from);
+
+/*
+ * If we have cache aliasing and writeback caches, we might have to do
+ * some extra work
+ */
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+void clear_user_page(void *addr, unsigned long vaddr, struct page* page);
+void copy_user_page(void *to,void* from,unsigned long vaddr,struct page* page);
+#else
+# define clear_user_page(page,vaddr,pg)                clear_page(page)
+# define copy_user_page(to, from, vaddr, pg)   copy_page(to, from)
+#endif
+
+/*
+ * This handles the memory map.  We handle pages at
+ * XCHAL_KSEG_CACHED_VADDR for kernels with 32 bit address space.
+ * These macros are for conversion of kernel address, not user
+ * addresses.
+ */
+
+#define __pa(x)                        ((unsigned long) (x) - PAGE_OFFSET)
+#define __va(x)                        ((void *)((unsigned long) (x) + PAGE_OFFSET))
+#define pfn_valid(pfn)         ((unsigned long)pfn < max_mapnr)
+#ifndef CONFIG_DISCONTIGMEM
+# define pfn_to_page(pfn)      (mem_map + (pfn))
+# define page_to_pfn(page)     ((unsigned long)((page) - mem_map))
+#else
+# error CONFIG_DISCONTIGMEM not supported
+#endif
+
+#define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+#define page_to_virt(page)     __va(page_to_pfn(page) << PAGE_SHIFT)
+#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+#define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
+
+#define WANT_PAGE_VIRTUAL
+
+
+#endif /* __ASSEMBLY__ */
+
+#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
+                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_PAGE_H */
diff --git a/include/asm-xtensa/page.h.n b/include/asm-xtensa/page.h.n
new file mode 100644 (file)
index 0000000..546cc66
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * linux/include/asm-xtensa/page.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PAGE_H
+#define _XTENSA_PAGE_H
+
+#ifdef __KERNEL__
+
+#include <asm/processor.h>
+#include <linux/config.h>
+
+/*
+ * PAGE_SHIFT determines the page size
+ * PAGE_ALIGN(x) aligns the pointer to the (next) page boundary
+ */
+#define PAGE_SHIFT             XCHAL_MMU_MIN_PTE_PAGE_SIZE
+#define PAGE_SIZE              (1 << PAGE_SHIFT)
+#define PAGE_MASK              (~(PAGE_SIZE-1))
+#define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE - 1) & PAGE_MASK)
+
+#define DCACHE_WAY_SIZE                (XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS)
+#define PAGE_OFFSET            XCHAL_KSEG_CACHED_VADDR
+
+#ifdef __ASSEMBLY__
+
+#define __pgprot(x)    (x)
+
+#else
+
+
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long pte; } pte_t;           /* page table entry */
+typedef struct { unsigned long pmd; } pmd_t;           /* PMD table entry */
+typedef struct { unsigned long pgd; } pgd_t;           /* PGD table entry */
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#define pte_val(x)     ((x).pte)
+#define pmd_val(x)     ((x).pmd)
+#define pgd_val(x)     ((x).pgd)
+#define pgprot_val(x)  ((x).pgprot)
+
+#define __pte(x)       ((pte_t) { (x) } )
+#define __pmd(x)       ((pmd_t) { (x) } )
+#define __pgd(x)       ((pgd_t) { (x) } )
+#define __pgprot(x)    ((pgprot_t) { (x) } )
+
+/*
+ * Pure 2^n version of get_order
+ */
+extern __inline__ int get_order(unsigned long size)
+{
+       int order;
+#ifndef XCHAL_HAVE_NSU
+       unsigned long x1, x2, x4, x8, x16;
+
+       size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       x1  = size & 0xAAAAAAAA;
+       x2  = size & 0xCCCCCCCC;
+       x4  = size & 0xF0F0F0F0;
+       x8  = size & 0xFF00FF00;
+       x16 = size & 0xFFFF0000;
+       order = x2 ? 2 : 0;
+       order += (x16 != 0) * 16;
+       order += (x8 != 0) * 8;
+       order += (x4 != 0) * 4;
+       order += (x1 != 0);
+
+       return order;
+#else
+       size = (size - 1) >> PAGE_SHIFT;
+       asm ("nsau %0, %1" : "=r" (order) : "r" (size));
+       return 32 - order;
+#endif
+}
+
+
+struct page;
+extern void clear_page(void *page);
+extern void copy_page(void *to, void *from);
+
+/*
+ * If we have cache aliasing and writeback caches, we might have to do
+ * some extra work
+ */
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+void clear_user_page(void *addr, unsigned long vaddr, struct page* page);
+void copy_user_page(void *to, void* from, unsigned long vaddr, struct page* page);
+#else
+# define clear_user_page(page,vaddr,pg)                clear_page(page)
+# define copy_user_page(to, from, vaddr, pg)   copy_page(to, from)
+#endif
+
+
+/*
+ * This handles the memory map.  We handle pages at
+ * XCHAL_KSEG_CACHED_VADDR for kernels with 32 bit address space.
+ * These macros are for conversion of kernel address, not user
+ * addresses.
+ */
+
+#define __pa(x)                        ((unsigned long) (x) - PAGE_OFFSET)
+#define __va(x)                        ((void *)((unsigned long) (x) + PAGE_OFFSET))
+#define pfn_valid(pfn)         ((unsigned long)pfn < max_mapnr)
+#ifndef CONFIG_DISCONTIGMEM
+# define pfn_to_page(pfn)      (mem_map + (pfn))
+# define page_to_pfn(page)     ((unsigned long)((page) - mem_map))
+#else
+# error CONFIG_DISCONTIGMEM not supported
+#endif
+
+#define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+#define page_to_virt(page)     __va(page_to_pfn(page) << PAGE_SHIFT)
+#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+#define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
+
+#define WANT_PAGE_VIRTUAL
+
+
+#endif /* __ASSEMBLY__ */
+
+#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
+                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_PAGE_H */
diff --git a/include/asm-xtensa/param.h b/include/asm-xtensa/param.h
new file mode 100644 (file)
index 0000000..c0eec82
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * include/asm-xtensa/param.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PARAM_H
+#define _XTENSA_PARAM_H
+
+#include <xtensa/config/core.h>
+
+#ifdef __KERNEL__
+# define HZ            100             /* internal timer frequency */
+# define USER_HZ       100             /* for user interfaces in "ticks" */
+# define CLOCKS_PER_SEC (USER_HZ)      /* frequnzy at which times() counts */
+#endif
+
+#define EXEC_PAGESIZE  (1 << XCHAL_MMU_MIN_PTE_PAGE_SIZE)
+
+#ifndef NGROUPS
+#define NGROUPS                32
+#endif
+
+#ifndef NOGROUP
+#define NOGROUP                (-1)
+#endif
+
+#define MAXHOSTNAMELEN 64      /* max length of hostname */
+
+#endif /* _XTENSA_PARAM_H */
diff --git a/include/asm-xtensa/pci-bridge.h b/include/asm-xtensa/pci-bridge.h
new file mode 100644 (file)
index 0000000..00fcbd7
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * include/asm-xtensa/pci-bridge.h
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PCI_BRIDGE_H
+#define _XTENSA_PCI_BRIDGE_H
+
+#ifdef __KERNEL__
+
+struct device_node;
+struct pci_controller;
+
+/*
+ * pciauto_bus_scan() enumerates the pci space.
+ */
+
+extern int pciauto_bus_scan(struct pci_controller *, int);
+
+struct pci_space {
+       unsigned long start;
+       unsigned long end;
+       unsigned long base;
+};
+
+/*
+ * Structure of a PCI controller (host bridge)
+ */
+
+struct pci_controller {
+       int index;                      /* used for pci_controller_num */
+       struct pci_controller *next;
+        struct pci_bus *bus;
+       void *arch_data;
+
+       int first_busno;
+       int last_busno;
+
+       struct pci_ops *ops;
+       volatile unsigned int *cfg_addr;
+       volatile unsigned char *cfg_data;
+
+       /* Currently, we limit ourselves to 1 IO range and 3 mem
+        * ranges since the common pci_bus structure can't handle more
+        */
+       struct resource io_resource;
+       struct resource mem_resources[3];
+       int mem_resource_count;
+
+       /* Host bridge I/O and Memory space
+        * Used for BAR placement algorithms
+        */
+       struct pci_space io_space;
+       struct pci_space mem_space;
+
+       /* Return the interrupt number fo a device. */
+       int (*map_irq)(struct pci_dev*, u8, u8);
+
+};
+
+static inline void pcibios_init_resource(struct resource *res,
+               unsigned long start, unsigned long end, int flags, char *name)
+{
+       res->start = start;
+       res->end = end;
+       res->flags = flags;
+       res->name = name;
+       res->parent = NULL;
+       res->sibling = NULL;
+       res->child = NULL;
+}
+
+
+/* These are used for config access before all the PCI probing has been done. */
+int early_read_config_byte(struct pci_controller*, int, int, int, u8*);
+int early_read_config_word(struct pci_controller*, int, int, int, u16*);
+int early_read_config_dword(struct pci_controller*, int, int, int, u32*);
+int early_write_config_byte(struct pci_controller*, int, int, int, u8);
+int early_write_config_word(struct pci_controller*, int, int, int, u16);
+int early_write_config_dword(struct pci_controller*, int, int, int, u32);
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_PCI_BRIDGE_H */
diff --git a/include/asm-xtensa/pci.h b/include/asm-xtensa/pci.h
new file mode 100644 (file)
index 0000000..6817742
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * linux/include/asm-xtensa/pci.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PCI_H
+#define _XTENSA_PCI_H
+
+#ifdef __KERNEL__
+
+/* Can be used to override the logic in pci_scan_bus for skipping
+ * already-configured bus numbers - to be used for buggy BIOSes
+ * or architectures with incomplete PCI setup by the loader
+ */
+
+#define pcibios_assign_all_busses()    0
+
+extern struct pci_controller* pcibios_alloc_controller(void);
+
+extern inline void pcibios_set_master(struct pci_dev *dev)
+{
+       /* No special bus mastering setup handling */
+}
+
+extern inline void pcibios_penalize_isa_irq(int irq)
+{
+       /* We don't do dynamic PCI IRQ allocation */
+}
+
+/* Assume some values. (We should revise them, if necessary) */
+
+#define PCIBIOS_MIN_IO         0x2000
+#define PCIBIOS_MIN_MEM                0x10000000
+
+/* Dynamic DMA mapping stuff.
+ * Xtensa has everything mapped statically like x86.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/scatterlist.h>
+#include <linux/string.h>
+#include <asm/io.h>
+
+struct pci_dev;
+
+/* The PCI address space does equal the physical memory address space.
+ * The networking and block device layers use this boolean for bounce buffer
+ * decisions.
+ */
+
+#define PCI_DMA_BUS_IS_PHYS    (1)
+
+/* pci_unmap_{page,single} is a no-op, so */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)         (0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        do { } while (0)
+#define pci_ubnmap_len(PTR, LEN_NAME)          (0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
+
+/* We cannot access memory above 4GB */
+#define pci_dac_dma_supported(pci_dev, mask)   (0)
+
+/* Map a range of PCI memory or I/O space for a device into user space */
+int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
+                        enum pci_mmap_state mmap_state, int write_combine);
+
+/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
+#define HAVE_PCI_MMAP  1
+
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
+#endif /* __KERNEL__ */
+
+/* Implement the pci_ DMA API in terms of the generic device dma_ one */
+#include <asm-generic/pci-dma-compat.h>
+
+/* Generic PCI */
+#include <asm-generic/pci.h>
+
+#endif /* _XTENSA_PCI_H */
diff --git a/include/asm-xtensa/percpu.h b/include/asm-xtensa/percpu.h
new file mode 100644 (file)
index 0000000..6d2bc2a
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-xtensa/percpu.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PERCPU__
+#define _XTENSA_PERCPU__
+
+#include <asm-generic/percpu.h>
+
+#endif /* _XTENSA_PERCPU__ */
diff --git a/include/asm-xtensa/pgalloc.h b/include/asm-xtensa/pgalloc.h
new file mode 100644 (file)
index 0000000..734a8d0
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * linux/include/asm-xtensa/pgalloc.h
+ *
+ * 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.
+ *
+ * Copyright (C) 2001-2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PGALLOC_H
+#define _XTENSA_PGALLOC_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/highmem.h>
+#include <asm/processor.h>
+#include <asm/cacheflush.h>
+
+
+/* Cache aliasing:
+ *
+ * If the cache size for one way is greater than the page size, we have to
+ * deal with cache aliasing. The cache index is wider than the page size:
+ *
+ *      |cache |
+ * |pgnum |page|       virtual address
+ * |xxxxxX|zzzz|
+ * |      |    |
+ *   \  / |    |
+ *  trans.|    |
+ *   /  \ |    |
+ * |yyyyyY|zzzz|       physical address
+ *
+ * When the page number is translated to the physical page address, the lowest
+ * bit(s) (X) that are also part of the cache index are also translated (Y).
+ * If this translation changes this bit (X), the cache index is also afected,
+ * thus resulting in a different cache line than before.
+ * The kernel does not provide a mechanism to ensure that the page color
+ * (represented by this bit) remains the same when allocated or when pages
+ * are remapped. When user pages are mapped into kernel space, the color of
+ * the page might also change.
+ *
+ * We use the address space VMALLOC_END ... VMALLOC_END + DCACHE_WAY_SIZE * 2
+ * to temporarily map a patch so we can match the color.
+ */
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+# define PAGE_COLOR_MASK       (PAGE_MASK & (DCACHE_WAY_SIZE-1))
+# define PAGE_COLOR(a)         \
+       (((unsigned long)(a)&PAGE_COLOR_MASK) >> PAGE_SHIFT)
+# define PAGE_COLOR_EQ(a,b)    \
+       ((((unsigned long)(a) ^ (unsigned long)(b)) & PAGE_COLOR_MASK) == 0)
+# define PAGE_COLOR_MAP0(v)    \
+       (VMALLOC_END + ((unsigned long)(v) & PAGE_COLOR_MASK))
+# define PAGE_COLOR_MAP1(v)    \
+       (VMALLOC_END + ((unsigned long)(v) & PAGE_COLOR_MASK) + DCACHE_WAY_SIZE)
+#endif
+
+/*
+ * Allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+
+#define pgd_free(pgd)  free_page((unsigned long)(pgd))
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+
+static inline void
+pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *pte)
+{
+       pmd_val(*(pmdp)) = (unsigned long)(pte);
+       __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp));
+}
+
+static inline void
+pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *page)
+{
+       pmd_val(*(pmdp)) = (unsigned long)page_to_virt(page);
+       __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp));
+}
+
+
+
+#else
+
+# define pmd_populate_kernel(mm, pmdp, pte)                                 \
+       (pmd_val(*(pmdp)) = (unsigned long)(pte))
+# define pmd_populate(mm, pmdp, page)                                       \
+       (pmd_val(*(pmdp)) = (unsigned long)page_to_virt(page))
+
+#endif
+
+static inline pgd_t*
+pgd_alloc(struct mm_struct *mm)
+{
+       pgd_t *pgd;
+
+       pgd = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGD_ORDER);
+
+       if (likely(pgd != NULL))
+               __flush_dcache_page((unsigned long)pgd);
+
+       return 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);
+
+#define pte_free_kernel(pte) free_page((unsigned long)pte)
+#define pte_free(pte) __free_page(pte)
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_PGALLOC_H */
diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h
new file mode 100644 (file)
index 0000000..0bb6416
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ * linux/include/asm-xtensa/page.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PGTABLE_H
+#define _XTENSA_PGTABLE_H
+
+#include <asm-generic/pgtable-nopmd.h>
+#include <asm/page.h>
+
+/* Assertions. */
+
+#ifdef CONFIG_MMU
+
+
+#if (XCHAL_MMU_RINGS < 2)
+# error Linux build assumes at least 2 ring levels.
+#endif
+
+#if (XCHAL_MMU_CA_BITS != 4)
+# error We assume exactly four bits for CA.
+#endif
+
+#if (XCHAL_MMU_SR_BITS != 0)
+# error We have no room for SR bits.
+#endif
+
+/*
+ * Use the first min-wired way for mapping page-table pages.
+ * Page coloring requires a second min-wired way.
+ */
+
+#if (XCHAL_DTLB_MINWIRED_SETS == 0)
+# error Need a min-wired way for mapping page-table pages
+#endif
+
+#define DTLB_WAY_PGTABLE XCHAL_DTLB_SET(XCHAL_DTLB_MINWIRED_SET0, WAY)
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+# if XCHAL_DTLB_SET(XCHAL_DTLB_MINWIRED_SET0, WAYS) >= 2
+#  define DTLB_WAY_DCACHE_ALIAS0 (DTLB_WAY_PGTABLE + 1)
+#  define DTLB_WAY_DCACHE_ALIAS1 (DTLB_WAY_PGTABLE + 2)
+# else
+#  error Page coloring requires its own wired dtlb way!
+# endif
+#endif
+
+#endif /* CONFIG_MMU */
+
+/*
+ * We only use two ring levels, user and kernel space.
+ */
+
+#define USER_RING              1       /* user ring level */
+#define KERNEL_RING            0       /* kernel ring level */
+
+/*
+ * The Xtensa architecture port of Linux has a two-level page table system,
+ * i.e. the logical three-level Linux page table layout are folded.
+ * Each task has the following memory page tables:
+ *
+ *   PGD table (page directory), ie. 3rd-level page table:
+ *     One page (4 kB) of 1024 (PTRS_PER_PGD) pointers to PTE tables
+ *     (Architectures that don't have the PMD folded point to the PMD tables)
+ *
+ *     The pointer to the PGD table for a given task can be retrieved from
+ *     the task structure (struct task_struct*) t, e.g. current():
+ *       (t->mm ? t->mm : t->active_mm)->pgd
+ *
+ *   PMD tables (page middle-directory), ie. 2nd-level page tables:
+ *     Absent for the Xtensa architecture (folded, PTRS_PER_PMD == 1).
+ *
+ *   PTE tables (page table entry), ie. 1st-level page tables:
+ *     One page (4 kB) of 1024 (PTRS_PER_PTE) PTEs with a special PTE
+ *     invalid_pte_table for absent mappings.
+ *
+ * The individual pages are 4 kB big with special pages for the empty_zero_page.
+ */
+#define PGDIR_SHIFT    22
+#define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK     (~(PGDIR_SIZE-1))
+
+/*
+ * Entries per page directory level: we use two-level, so
+ * we don't really have any PMD directory physically.
+ */
+#define PTRS_PER_PTE           1024
+#define PTRS_PER_PTE_SHIFT     10
+#define PTRS_PER_PMD           1
+#define PTRS_PER_PGD           1024
+#define PGD_ORDER              0
+#define PMD_ORDER              0
+#define USER_PTRS_PER_PGD      (TASK_SIZE/PGDIR_SIZE)
+#define FIRST_USER_ADDRESS      XCHAL_SEG_MAPPABLE_VADDR
+#define FIRST_USER_PGD_NR      (FIRST_USER_ADDRESS >> PGDIR_SHIFT)
+
+/* virtual memory area. We keep a distance to other memory regions to be
+ * on the safe side. We also use this area for cache aliasing.
+ */
+
+// FIXME: virtual memory area must be configuration-dependent
+
+#define VMALLOC_START          0xC0000000
+#define VMALLOC_END            0xC7FF0000
+
+/* Xtensa Linux config PTE layout (when present):
+ *     31-12:  PPN
+ *     11-6:   Software
+ *     5-4:    RING
+ *     3-0:    CA
+ *
+ * Similar to the Alpha and MIPS ports, we need to keep track of the ref
+ * and mod bits in software.  We have a software "you can read
+ * from this page" bit, and a hardware one which actually lets the
+ * process read from the page.  On the same token we have a software
+ * writable bit and the real hardware one which actually lets the
+ * process write to the page.
+ *
+ * See further below for PTE layout for swapped-out pages.
+ */
+
+#define _PAGE_VALID            (1<<0)  /* hardware: page is accessible */
+#define _PAGE_WRENABLE         (1<<1)  /* hardware: page is writable */
+
+/* None of these cache modes include MP coherency:  */
+#define _PAGE_NO_CACHE         (0<<2)  /* bypass, non-speculative */
+#if XCHAL_DCACHE_IS_WRITEBACK
+# define _PAGE_WRITEBACK       (1<<2)  /* write back */
+# define _PAGE_WRITETHRU       (2<<2)  /* write through */
+#else
+# define _PAGE_WRITEBACK       (1<<2)  /* assume write through */
+# define _PAGE_WRITETHRU       (1<<2)
+#endif
+#define _PAGE_NOALLOC          (3<<2)  /* don't allocate cache,if not cached */
+#define _CACHE_MASK            (3<<2)
+
+#define _PAGE_USER             (1<<4)  /* user access (ring=1) */
+#define _PAGE_KERNEL           (0<<4)  /* kernel access (ring=0) */
+
+/* Software */
+#define _PAGE_RW               (1<<6)  /* software: page writable */
+#define _PAGE_DIRTY            (1<<7)  /* software: page dirty */
+#define _PAGE_ACCESSED         (1<<8)  /* software: page accessed (read) */
+#define _PAGE_FILE             (1<<9)  /* nonlinear file mapping*/
+
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _CACHE_MASK | _PAGE_DIRTY)
+#define _PAGE_PRESENT  ( _PAGE_VALID | _PAGE_WRITEBACK | _PAGE_ACCESSED)
+
+#ifdef CONFIG_MMU
+
+# define PAGE_NONE     __pgprot(_PAGE_PRESENT)
+# define PAGE_SHARED   __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_RW)
+# define PAGE_COPY     __pgprot(_PAGE_PRESENT | _PAGE_USER)
+# define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER)
+# define PAGE_KERNEL   __pgprot(_PAGE_PRESENT | _PAGE_KERNEL | _PAGE_WRENABLE)
+# define PAGE_INVALID  __pgprot(_PAGE_USER)
+
+# if (DCACHE_WAY_SIZE > PAGE_SIZE)
+#  define PAGE_DIRECTORY  __pgprot(_PAGE_VALID | _PAGE_ACCESSED | _PAGE_KERNEL)
+# else
+#  define PAGE_DIRECTORY  __pgprot(_PAGE_PRESENT | _PAGE_KERNEL)
+# endif
+
+#else /* no mmu */
+
+# define PAGE_NONE       __pgprot(0)
+# define PAGE_SHARED     __pgprot(0)
+# define PAGE_COPY       __pgprot(0)
+# define PAGE_READONLY   __pgprot(0)
+# define PAGE_KERNEL     __pgprot(0)
+
+#endif
+
+/*
+ * On certain configurations of Xtensa MMUs (eg. the initial Linux config),
+ * the MMU can't do page protection for execute, and considers that the same as
+ * read.  Also, write permissions may imply read permissions.
+ * What follows is the closest we can get by reasonable means..
+ * See linux/mm/mmap.c for protection_map[] array that uses these definitions.
+ */
+#define __P000 PAGE_NONE       /* private --- */
+#define __P001 PAGE_READONLY   /* private --r */
+#define __P010 PAGE_COPY       /* private -w- */
+#define __P011 PAGE_COPY       /* private -wr */
+#define __P100 PAGE_READONLY   /* private x-- */
+#define __P101 PAGE_READONLY   /* private x-r */
+#define __P110 PAGE_COPY       /* private xw- */
+#define __P111 PAGE_COPY       /* private xwr */
+
+#define __S000 PAGE_NONE       /* shared  --- */
+#define __S001 PAGE_READONLY   /* shared  --r */
+#define __S010 PAGE_SHARED     /* shared  -w- */
+#define __S011 PAGE_SHARED     /* shared  -wr */
+#define __S100 PAGE_READONLY   /* shared  x-- */
+#define __S101 PAGE_READONLY   /* shared  x-r */
+#define __S110 PAGE_SHARED     /* shared  xw- */
+#define __S111 PAGE_SHARED     /* shared  xwr */
+
+#ifndef __ASSEMBLY__
+
+#define pte_ERROR(e) \
+       printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pgd_ERROR(e) \
+       printk("%s:%d: bad pgd entry %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+extern unsigned long empty_zero_page[1024];
+
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+extern pgd_t swapper_pg_dir[PAGE_SIZE/sizeof(pgd_t)];
+
+/*
+ * The pmd contains the kernel virtual address of the pte page.
+ */
+#define pmd_page_kernel(pmd) ((unsigned long)(pmd_val(pmd) & PAGE_MASK))
+#define pmd_page(pmd) virt_to_page(pmd_val(pmd))
+
+/*
+ * The following only work if pte_present() is true.
+ */
+#define pte_none(pte)   (!(pte_val(pte) ^ _PAGE_USER))
+#define pte_present(pte) (pte_val(pte) & _PAGE_VALID)
+#define pte_clear(mm,addr,ptep)                                                \
+       do { update_pte(ptep, __pte(_PAGE_USER)); } while(0)
+
+#define pmd_none(pmd)   (!pmd_val(pmd))
+#define pmd_present(pmd) (pmd_val(pmd) & PAGE_MASK)
+#define pmd_clear(pmdp)         do { set_pmd(pmdp, __pmd(0)); } while (0)
+#define pmd_bad(pmd)    (pmd_val(pmd) & ~PAGE_MASK)
+
+/* Note: We use the _PAGE_USER bit to indicate write-protect kernel memory */
+
+static inline int pte_read(pte_t pte)  { return pte_val(pte) & _PAGE_USER; }
+static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
+static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
+static inline int pte_file(pte_t pte)  { return pte_val(pte) & _PAGE_FILE; }
+static inline pte_t pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~(_PAGE_RW | _PAGE_WRENABLE); return pte; }
+static inline pte_t pte_rdprotect(pte_t pte)   { pte_val(pte) &= ~_PAGE_USER; return pte; }
+static inline pte_t pte_mkclean(pte_t pte)     { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkold(pte_t pte)       { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkread(pte_t pte)      { pte_val(pte) |= _PAGE_USER; return pte; }
+static inline pte_t pte_mkdirty(pte_t pte)     { pte_val(pte) |= _PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkyoung(pte_t pte)     { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkwrite(pte_t pte)     { pte_val(pte) |= _PAGE_RW; return pte; }
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+#define pte_pfn(pte)           (pte_val(pte) >> PAGE_SHIFT)
+#define pte_same(a,b)          (pte_val(a) == pte_val(b))
+#define pte_page(x)            pfn_to_page(pte_pfn(x))
+#define pfn_pte(pfn, prot)     __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define mk_pte(page, prot)     pfn_pte(page_to_pfn(page), prot)
+
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+       return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot));
+}
+
+/*
+ * Certain architectures need to do special things when pte's
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+static inline void update_pte(pte_t *ptep, pte_t pteval)
+{
+       *ptep = pteval;
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+       __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (ptep));
+#endif
+}
+
+extern inline void
+set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval)
+{
+       update_pte(ptep, pteval);
+}
+
+
+extern inline void
+set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+       *pmdp = pmdval;
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+       __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp));
+#endif
+}
+
+
+static inline int
+ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr,
+                         pte_t *ptep)
+{
+       pte_t pte = *ptep;
+       if (!pte_young(pte))
+               return 0;
+       update_pte(ptep, pte_mkold(pte));
+       return 1;
+}
+
+static inline int
+ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr,
+                         pte_t *ptep)
+{
+       pte_t pte = *ptep;
+       if (!pte_dirty(pte))
+               return 0;
+       update_pte(ptep, pte_mkclean(pte));
+       return 1;
+}
+
+static inline pte_t
+ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+       pte_t pte = *ptep;
+       pte_clear(mm, addr, ptep);
+       return pte;
+}
+
+static inline void
+ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+       pte_t pte = *ptep;
+       update_pte(ptep, pte_wrprotect(pte));
+}
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address)  pgd_offset(&init_mm, address)
+
+/* to find an entry in a page-table-directory */
+#define pgd_offset(mm,address) ((mm)->pgd + pgd_index(address))
+
+#define pgd_index(address)     ((address) >> PGDIR_SHIFT)
+
+/* Find an entry in the second-level page table.. */
+#define pmd_offset(dir,address) ((pmd_t*)(dir))
+
+/* Find an entry in the third-level page table.. */
+#define pte_index(address)     (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset_kernel(dir,addr)                                    \
+       ((pte_t*) pmd_page_kernel(*(dir)) + pte_index(addr))
+#define pte_offset_map(dir,addr)       pte_offset_kernel((dir),(addr))
+#define pte_offset_map_nested(dir,addr)        pte_offset_kernel((dir),(addr))
+
+#define pte_unmap(pte)         do { } while (0)
+#define pte_unmap_nested(pte)  do { } while (0)
+
+
+/*
+ * Encode and decode a swap entry.
+ * Each PTE in a process VM's page table is either:
+ *   "present" -- valid and not swapped out, protection bits are meaningful;
+ *   "not present" -- which further subdivides in these two cases:
+ *      "none" -- no mapping at all; identified by pte_none(), set by pte_clear(
+ *      "swapped out" -- the page is swapped out, and the SWP macros below
+ *                      are used to store swap file info in the PTE itself.
+ *
+ * In the Xtensa processor MMU, any PTE entries in user space (or anywhere
+ * in virtual memory that can map differently across address spaces)
+ * must have a correct ring value that represents the RASID field that
+ * is changed when switching address spaces.  Eg. such PTE entries cannot
+ * be set to ring zero, because that can cause a (global) kernel ASID
+ * entry to be created in the TLBs (even with invalid cache attribute),
+ * potentially causing a multihit exception when going back to another
+ * address space that mapped the same virtual address at another ring.
+ *
+ * SO: we avoid using ring bits (_PAGE_RING_MASK) in "not present" PTEs.
+ * We also avoid using the _PAGE_VALID bit which must be zero for non-present
+ * pages.
+ *
+ * We end up with the following available bits:  1..3 and 7..31.
+ * We don't bother with 1..3 for now (we can use them later if needed),
+ * and chose to allocate 6 bits for SWP_TYPE and the remaining 19 bits
+ * for SWP_OFFSET.  At least 5 bits are needed for SWP_TYPE, because it
+ * is currently implemented as an index into swap_info[MAX_SWAPFILES]
+ * and MAX_SWAPFILES is currently defined as 32 in <linux/swap.h>.
+ * However, for some reason all other architectures in the 2.4 kernel
+ * reserve either 6, 7, or 8 bits so I'll not detract from that for now.  :)
+ * SWP_OFFSET is an offset into the swap file in page-size units, so
+ * with 4 kB pages, 19 bits supports a maximum swap file size of 2 GB.
+ *
+ * FIXME:  2 GB isn't very big.  Other bits can be used to allow
+ * larger swap sizes.  In the meantime, it appears relatively easy to get
+ * around the 2 GB limitation by simply using multiple swap files.
+ */
+
+#define __swp_type(entry)      (((entry).val >> 7) & 0x3f)
+#define __swp_offset(entry)    ((entry).val >> 13)
+#define __swp_entry(type,offs) ((swp_entry_t) {((type) << 7) | ((offs) << 13)})
+#define __pte_to_swp_entry(pte)        ((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(x)  ((pte_t) { (x).val })
+
+#define PTE_FILE_MAX_BITS      29
+#define pte_to_pgoff(pte)      (pte_val(pte) >> 3)
+#define pgoff_to_pte(off)      ((pte_t) { ((off) << 3) | _PAGE_FILE })
+
+
+#endif /*  !defined (__ASSEMBLY__) */
+
+
+#ifdef __ASSEMBLY__
+
+/* Assembly macro _PGD_INDEX is the same as C pgd_index(unsigned long),
+ *                _PGD_OFFSET as C pgd_offset(struct mm_struct*, unsigned long),
+ *                _PMD_OFFSET as C pmd_offset(pgd_t*, unsigned long)
+ *                _PTE_OFFSET as C pte_offset(pmd_t*, unsigned long)
+ *
+ * Note: We require an additional temporary register which can be the same as
+ *       the register that holds the address.
+ *
+ * ((pte_t*) ((unsigned long)(pmd_val(*pmd) & PAGE_MASK)) + pte_index(addr))
+ *
+ */
+#define _PGD_INDEX(rt,rs)      extui   rt, rs, PGDIR_SHIFT, 32-PGDIR_SHIFT
+#define _PTE_INDEX(rt,rs)      extui   rt, rs, PAGE_SHIFT, PTRS_PER_PTE_SHIFT
+
+#define _PGD_OFFSET(mm,adr,tmp)                l32i    mm, mm, MM_PGD;         \
+                                       _PGD_INDEX(tmp, adr);           \
+                                       addx4   mm, tmp, mm
+
+#define _PTE_OFFSET(pmd,adr,tmp)       _PTE_INDEX(tmp, adr);           \
+                                       srli    pmd, pmd, PAGE_SHIFT;   \
+                                       slli    pmd, pmd, PAGE_SHIFT;   \
+                                       addx4   pmd, tmp, pmd
+
+#else
+
+extern void paging_init(void);
+
+#define kern_addr_valid(addr)  (1)
+
+extern  void update_mmu_cache(struct vm_area_struct * vma,
+                             unsigned long address, pte_t pte);
+
+/*
+ * remap a physical address `phys' of size `size' with page protection `prot'
+ * into virtual address `from'
+ */
+#define io_remap_page_range(vma,from,phys,size,prot) \
+                remap_pfn_range(vma, from, (phys) >> PAGE_SHIFT, size, prot)
+
+
+/* No page table caches to init */
+
+#define pgtable_cache_init()   do { } while (0)
+
+typedef pte_t *pte_addr_t;
+
+#endif /* !defined (__ASSEMBLY__) */
+
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+#define __HAVE_ARCH_PTEP_MKDIRTY
+#define __HAVE_ARCH_PTE_SAME
+
+#include <asm-generic/pgtable.h>
+
+#endif /* _XTENSA_PGTABLE_H */
diff --git a/include/asm-xtensa/platform-iss/hardware.h b/include/asm-xtensa/platform-iss/hardware.h
new file mode 100644 (file)
index 0000000..22240f0
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * include/asm-xtensa/platform-iss/hardware.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 Tensilica Inc.
+ */
+
+/*
+ * This file contains the default configuration of ISS.
+ */
+
+#ifndef __ASM_XTENSA_ISS_HARDWARE
+#define __ASM_XTENSA_ISS_HARDWARE
+
+/*
+ * Memory configuration.
+ */
+
+#define PLATFORM_DEFAULT_MEM_START XSHAL_RAM_PADDR
+#define PLATFORM_DEFAULT_MEM_SIZE XSHAL_RAM_VSIZE
+
+/*
+ * Interrupt configuration.
+ */
+
+#endif /* __ASM_XTENSA_ISS_HARDWARE */
diff --git a/include/asm-xtensa/platform.h b/include/asm-xtensa/platform.h
new file mode 100644 (file)
index 0000000..3616389
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * include/asm-xtensa/platform.h
+ *
+ * Platform specific functions
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PLATFORM_H
+#define _XTENSA_PLATFORM_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+#include <asm/bootparam.h>
+
+/*
+ * platform_init is called before the mmu is initialized to give the
+ * platform a early hook-up. bp_tag_t is a list of configuration tags
+ * passed from the boot-loader.
+ */
+extern void platform_init(bp_tag_t*);
+
+/*
+ * platform_setup is called from setup_arch with a pointer to the command-line
+ * string.
+ */
+extern void platform_setup (char **);
+
+/*
+ * platform_init_irq is called from init_IRQ.
+ */
+extern void platform_init_irq (void);
+
+/*
+ * platform_restart is called to restart the system.
+ */
+extern void platform_restart (void);
+
+/*
+ * platform_halt is called to stop the system and halt.
+ */
+extern void platform_halt (void);
+
+/*
+ * platform_power_off is called to stop the system and power it off.
+ */
+extern void platform_power_off (void);
+
+/*
+ * platform_idle is called from the idle function.
+ */
+extern void platform_idle (void);
+
+/*
+ * platform_heartbeat is called every HZ
+ */
+extern void platform_heartbeat (void);
+
+/*
+ * platform_pcibios_init is called to allow the platform to setup the pci bus.
+ */
+extern void platform_pcibios_init (void);
+
+/*
+ * platform_pcibios_fixup allows to modify the PCI configuration.
+ */
+extern int platform_pcibios_fixup (void);
+
+/*
+ * platform_calibrate_ccount calibrates cpu clock freq (CONFIG_XTENSA_CALIBRATE)
+ */
+extern void platform_calibrate_ccount (void);
+
+/*
+ * platform_get_rtc_time returns RTC seconds (returns 0 for no error)
+ */
+extern int platform_get_rtc_time(time_t*);
+
+/*
+ * platform_set_rtc_time set RTC seconds (returns 0 for no error)
+ */
+extern int platform_set_rtc_time(time_t);
+
+
+#endif /* _XTENSA_PLATFORM_H */
+
diff --git a/include/asm-xtensa/poll.h b/include/asm-xtensa/poll.h
new file mode 100644 (file)
index 0000000..dffe447
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * include/asm-xtensa/poll.h
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_POLL_H
+#define _XTENSA_POLL_H
+
+
+#define POLLIN         0x0001
+#define POLLPRI                0x0002
+#define POLLOUT                0x0004
+
+#define POLLERR                0x0008
+#define POLLHUP                0x0010
+#define POLLNVAL       0x0020
+
+#define POLLRDNORM     0x0040
+#define POLLRDBAND     0x0080
+#define POLLWRNORM     POLLOUT
+#define POLLWRBAND     0x0100
+
+#define POLLMSG                0x0400
+#define POLLREMOVE     0x0800
+
+struct pollfd {
+       int fd;
+       short events;
+       short revents;
+};
+
+#endif /* _XTENSA_POLL_H */
diff --git a/include/asm-xtensa/posix_types.h b/include/asm-xtensa/posix_types.h
new file mode 100644 (file)
index 0000000..2c816b0
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * include/asm-xtensa/posix_types.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Largely copied from include/asm-ppc/posix_types.h
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_POSIX_TYPES_H
+#define _XTENSA_POSIX_TYPES_H
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.  Also, we cannot
+ * assume GCC is being used.
+ */
+
+typedef unsigned long  __kernel_ino_t;
+typedef unsigned int   __kernel_mode_t;
+typedef unsigned short __kernel_nlink_t;
+typedef long           __kernel_off_t;
+typedef int            __kernel_pid_t;
+typedef unsigned short __kernel_ipc_pid_t;
+typedef unsigned int   __kernel_uid_t;
+typedef unsigned int   __kernel_gid_t;
+typedef unsigned int   __kernel_size_t;
+typedef int            __kernel_ssize_t;
+typedef long           __kernel_ptrdiff_t;
+typedef long           __kernel_time_t;
+typedef long           __kernel_suseconds_t;
+typedef long           __kernel_clock_t;
+typedef int            __kernel_timer_t;
+typedef int            __kernel_clockid_t;
+typedef int            __kernel_daddr_t;
+typedef char *         __kernel_caddr_t;
+typedef unsigned short __kernel_uid16_t;
+typedef unsigned short __kernel_gid16_t;
+typedef unsigned int   __kernel_uid32_t;
+typedef unsigned int   __kernel_gid32_t;
+
+typedef unsigned short __kernel_old_uid_t;
+typedef unsigned short __kernel_old_gid_t;
+typedef unsigned short __kernel_old_dev_t;
+
+#ifdef __GNUC__
+typedef long long      __kernel_loff_t;
+#endif
+
+typedef struct {
+       int     val[2];
+} __kernel_fsid_t;
+
+#ifndef __GNUC__
+
+#define        __FD_SET(d, set)        ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
+#define        __FD_CLR(d, set)        ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
+#define        __FD_ISSET(d, set)      ((set)->fds_bits[__FDELT(d)] & __FDMASK(d))
+#define        __FD_ZERO(set)  \
+  ((void) memset ((__ptr_t) (set), 0, sizeof (__kernel_fd_set)))
+
+#else /* __GNUC__ */
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) \
+    || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
+/* With GNU C, use inline functions instead so args are evaluated only once: */
+
+#undef __FD_SET
+static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp)
+{
+       unsigned long _tmp = fd / __NFDBITS;
+       unsigned long _rem = fd % __NFDBITS;
+       fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
+}
+
+#undef __FD_CLR
+static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp)
+{
+       unsigned long _tmp = fd / __NFDBITS;
+       unsigned long _rem = fd % __NFDBITS;
+       fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
+}
+
+#undef __FD_ISSET
+static __inline__ int __FD_ISSET(unsigned long fd, __kernel_fd_set *p)
+{
+       unsigned long _tmp = fd / __NFDBITS;
+       unsigned long _rem = fd % __NFDBITS;
+       return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0;
+}
+
+/*
+ * This will unroll the loop for the normal constant case (8 ints,
+ * for a 256-bit fd_set)
+ */
+#undef __FD_ZERO
+static __inline__ void __FD_ZERO(__kernel_fd_set *p)
+{
+       unsigned int *tmp = (unsigned int *)p->fds_bits;
+       int i;
+
+       if (__builtin_constant_p(__FDSET_LONGS)) {
+               switch (__FDSET_LONGS) {
+                       case 8:
+                               tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0;
+                               tmp[4] = 0; tmp[5] = 0; tmp[6] = 0; tmp[7] = 0;
+                               return;
+               }
+       }
+       i = __FDSET_LONGS;
+       while (i) {
+               i--;
+               *tmp = 0;
+               tmp++;
+       }
+}
+
+#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
+#endif /* __GNUC__ */
+#endif /* _XTENSA_POSIX_TYPES_H */
diff --git a/include/asm-xtensa/processor.h b/include/asm-xtensa/processor.h
new file mode 100644 (file)
index 0000000..9cab5e4
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * include/asm-xtensa/processor.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PROCESSOR_H
+#define _XTENSA_PROCESSOR_H
+
+#ifdef __ASSEMBLY__
+#define _ASMLANGUAGE
+#endif
+
+#include <xtensa/config/core.h>
+#include <xtensa/config/specreg.h>
+#include <xtensa/config/tie.h>
+#include <xtensa/config/system.h>
+
+#include <asm/ptrace.h>
+#include <asm/types.h>
+#include <asm/coprocessor.h>
+
+/* Assertions. */
+
+#if (XCHAL_HAVE_WINDOWED != 1)
+#error Linux requires the Xtensa Windowed Registers Option.
+#endif
+
+/*
+ * User space process size: 1 GB.
+ * Windowed call ABI requires caller and callee to be located within the same
+ * 1 GB region. The C compiler places trampoline code on the stack for sources
+ * that take the address of a nested C function (a feature used by glibc), so
+ * the 1 GB requirement applies to the stack as well.
+ */
+
+#define TASK_SIZE      0x40000000
+
+/*
+ * General exception cause assigned to debug exceptions. Debug exceptions go
+ * to their own vector, rather than the general exception vectors (user,
+ * kernel, double); and their specific causes are reported via DEBUGCAUSE
+ * rather than EXCCAUSE.  However it is sometimes convenient to redirect debug
+ * exceptions to the general exception mechanism.  To do this, an otherwise
+ * unused EXCCAUSE value was assigned to debug exceptions for this purpose.
+ */
+
+#define EXCCAUSE_MAPPED_DEBUG  63
+
+/*
+ * We use DEPC also as a flag to distinguish between double and regular
+ * exceptions. For performance reasons, DEPC might contain the value of
+ * EXCCAUSE for regular exceptions, so we use this definition to mark a
+ * valid double exception address.
+ * (Note: We use it in bgeui, so it should be 64, 128, or 256)
+ */
+
+#define VALID_DOUBLE_EXCEPTION_ADDRESS 64
+
+/* LOCKLEVEL defines the interrupt level that masks all
+ * general-purpose interrupts.
+ */
+#define LOCKLEVEL 1
+
+/* WSBITS and WBBITS are the width of the WINDOWSTART and WINDOWBASE
+ * registers
+ */
+#define WSBITS  (XCHAL_NUM_AREGS / 4)      /* width of WINDOWSTART in bits */
+#define WBBITS  (XCHAL_NUM_AREGS_LOG2 - 2) /* width of WINDOWBASE in bits */
+
+#ifndef __ASSEMBLY__
+
+/* Build a valid return address for the specified call winsize.
+ * winsize must be 1 (call4), 2 (call8), or 3 (call12)
+ */
+#define MAKE_RA_FOR_CALL(ra,ws)   (((ra) & 0x3fffffff) | (ws) << 30)
+
+/* Convert return address to a valid pc
+ * Note: We assume that the stack pointer is in the same 1GB ranges as the ra
+ */
+#define MAKE_PC_FROM_RA(ra,sp)    (((ra) & 0x3fffffff) | ((sp) & 0xc0000000))
+
+typedef struct {
+    unsigned long seg;
+} mm_segment_t;
+
+struct thread_struct {
+
+       /* kernel's return address and stack pointer for context switching */
+       unsigned long ra; /* kernel's a0: return address and window call size */
+       unsigned long sp; /* kernel's a1: stack pointer */
+
+       mm_segment_t current_ds;    /* see uaccess.h for example uses */
+
+       /* struct xtensa_cpuinfo info; */
+
+       unsigned long bad_vaddr; /* last user fault */
+       unsigned long bad_uaddr; /* last kernel fault accessing user space */
+       unsigned long error_code;
+
+       unsigned long ibreak[XCHAL_NUM_IBREAK];
+       unsigned long dbreaka[XCHAL_NUM_DBREAK];
+       unsigned long dbreakc[XCHAL_NUM_DBREAK];
+
+       /* Allocate storage for extra state and coprocessor state. */
+       unsigned char cp_save[XTENSA_CP_EXTRA_SIZE]
+               __attribute__ ((aligned(XTENSA_CP_EXTRA_ALIGN)));
+
+       /* Make structure 16 bytes aligned. */
+       int align[0] __attribute__ ((aligned(16)));
+};
+
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr()  ({ __label__ _l; _l: &&_l;})
+
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE     (TASK_SIZE / 2)
+
+#define INIT_THREAD  \
+{                                                                      \
+       ra:             0,                                              \
+       sp:             sizeof(init_stack) + (long) &init_stack,        \
+       current_ds:     {0},                                            \
+       /*info:         {0}, */                                         \
+       bad_vaddr:      0,                                              \
+       bad_uaddr:      0,                                              \
+       error_code:     0,                                              \
+}
+
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ * Note: We set-up ps as if we did a call4 to the new pc.
+ *       set_thread_state in signal.c depends on it.
+ */
+#define USER_PS_VALUE ( (1 << XCHAL_PS_WOE_SHIFT) + \
+                        (1 << XCHAL_PS_CALLINC_SHIFT) + \
+                        (USER_RING << XCHAL_PS_RING_SHIFT) + \
+                        (1 << XCHAL_PS_PROGSTACK_SHIFT) + \
+                        (1 << XCHAL_PS_EXCM_SHIFT) )
+
+/* Clearing a0 terminates the backtrace. */
+#define start_thread(regs, new_pc, new_sp) \
+       regs->pc = new_pc; \
+       regs->ps = USER_PS_VALUE; \
+       regs->areg[1] = new_sp; \
+       regs->areg[0] = 0; \
+       regs->wmask = 1; \
+       regs->depc = 0; \
+       regs->windowbase = 0; \
+       regs->windowstart = 1;
+
+/* Forward declaration */
+struct task_struct;
+struct mm_struct;
+
+// FIXME: do we need release_thread for CP??
+/* Free all resources held by a thread. */
+#define release_thread(thread) do { } while(0)
+
+// FIXME: do we need prepare_to_copy (lazy status) for CP??
+/* Prepare to copy thread state - unlazy all lazy status */
+#define prepare_to_copy(tsk)   do { } while (0)
+
+/*
+ * create a kernel thread without removing it from tasklists
+ */
+extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+/* Copy and release all segment info associated with a VM */
+
+#define copy_segments(p, mm)   do { } while(0)
+#define release_segments(mm)   do { } while(0)
+#define forget_segments()      do { } while (0)
+
+#define thread_saved_pc(tsk)   (xtensa_pt_regs(tsk)->pc)
+
+extern unsigned long get_wchan(struct task_struct *p);
+
+#define KSTK_EIP(tsk)          (xtensa_pt_regs(tsk)->pc)
+#define KSTK_ESP(tsk)          (xtensa_pt_regs(tsk)->areg[1])
+
+#define cpu_relax()  do { } while (0)
+
+/* Special register access. */
+
+#define WSR(v,sr) __asm__ __volatile__ ("wsr %0,"__stringify(sr) :: "a"(v));
+#define RSR(v,sr) __asm__ __volatile__ ("rsr %0,"__stringify(sr) : "=a"(v));
+
+#define set_sr(x,sr) ({unsigned int v=(unsigned int)x; WSR(v,sr);})
+#define get_sr(sr) ({unsigned int v; RSR(v,sr); v; })
+
+#endif /* __ASSEMBLY__ */
+#endif /* _XTENSA_PROCESSOR_H */
diff --git a/include/asm-xtensa/ptrace.h b/include/asm-xtensa/ptrace.h
new file mode 100644 (file)
index 0000000..2848a5f
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * include/asm-xtensa/ptrace.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PTRACE_H
+#define _XTENSA_PTRACE_H
+
+#include <xtensa/config/core.h>
+
+/*
+ * Kernel stack
+ *
+ *             +-----------------------+  -------- STACK_SIZE
+ *             |     register file     |  |
+ *             +-----------------------+  |
+ *             |    struct pt_regs     |  |
+ *             +-----------------------+  | ------ PT_REGS_OFFSET
+ * double      :  16 bytes spill area  :  |  ^
+ * excetion    :- - - - - - - - - - - -:  |  |
+ * frame       :    struct pt_regs     :  |  |
+ *             :- - - - - - - - - - - -:  |  |
+ *             |                       |  |  |
+ *             |     memory stack      |  |  |
+ *             |                       |  |  |
+ *             ~                       ~  ~  ~
+ *             ~                       ~  ~  ~
+ *             |                       |  |  |
+ *             |                       |  |  |
+ *             +-----------------------+  |  | --- STACK_BIAS
+ *             |  struct task_struct   |  |  |  ^
+ *  current --> +-----------------------+  |  |  |
+ *             |  struct thread_info   |  |  |  |
+ *             +-----------------------+ --------
+ */
+
+#define KERNEL_STACK_SIZE (2 * PAGE_SIZE)
+
+/*  Offsets for exception_handlers[] (3 x 64-entries x 4-byte tables). */
+
+#define EXC_TABLE_KSTK         0x004   /* Kernel Stack */
+#define EXC_TABLE_DOUBLE_SAVE  0x008   /* Double exception save area for a0 */
+#define EXC_TABLE_FIXUP                0x00c   /* Fixup handler */
+#define EXC_TABLE_PARAM                0x010   /* For passing a parameter to fixup */
+#define EXC_TABLE_SYSCALL_SAVE 0x014   /* For fast syscall handler */
+#define EXC_TABLE_FAST_USER    0x100   /* Fast user exception handler */
+#define EXC_TABLE_FAST_KERNEL  0x200   /* Fast kernel exception handler */
+#define EXC_TABLE_DEFAULT      0x300   /* Default C-Handler */
+#define EXC_TABLE_SIZE         0x400
+
+/* Registers used by strace */
+
+#define REG_A_BASE     0xfc000000
+#define REG_AR_BASE    0x04000000
+#define REG_PC         0x14000000
+#define REG_PS         0x080000e6
+#define REG_WB         0x08000048
+#define REG_WS         0x08000049
+#define REG_LBEG       0x08000000
+#define REG_LEND       0x08000001
+#define REG_LCOUNT     0x08000002
+#define REG_SAR                0x08000003
+#define REG_DEPC       0x080000c0
+#define        REG_EXCCAUSE    0x080000e8
+#define REG_EXCVADDR   0x080000ee
+#define SYSCALL_NR     0x1
+
+#define AR_REGNO_TO_A_REGNO(ar, wb) (ar - wb*4) & ~(XCHAL_NUM_AREGS - 1)
+
+/* Other PTRACE_ values defined in <linux/ptrace.h> using values 0-9,16,17,24 */
+
+#define PTRACE_GETREGS            12
+#define PTRACE_SETREGS            13
+#define PTRACE_GETFPREGS          14
+#define PTRACE_SETFPREGS          15
+#define PTRACE_GETFPREGSIZE       18
+
+#ifndef __ASSEMBLY__
+
+/*
+ * This struct defines the way the registers are stored on the
+ * kernel stack during a system call or other kernel entry.
+ */
+struct pt_regs {
+       unsigned long pc;               /*   4 */
+       unsigned long ps;               /*   8 */
+       unsigned long depc;             /*  12 */
+       unsigned long exccause;         /*  16 */
+       unsigned long excvaddr;         /*  20 */
+       unsigned long debugcause;       /*  24 */
+       unsigned long wmask;            /*  28 */
+       unsigned long lbeg;             /*  32 */
+       unsigned long lend;             /*  36 */
+       unsigned long lcount;           /*  40 */
+       unsigned long sar;              /*  44 */
+       unsigned long windowbase;       /*  48 */
+       unsigned long windowstart;      /*  52 */
+       unsigned long syscall;          /*  56 */
+       int reserved[2];                /*  64 */
+
+       /* Make sure the areg field is 16 bytes aligned. */
+       int align[0] __attribute__ ((aligned(16)));
+
+       /* current register frame.
+        * Note: The ESF for kernel exceptions ends after 16 registers!
+        */
+       unsigned long areg[16];         /* 128 (64) */
+};
+
+#ifdef __KERNEL__
+# define xtensa_pt_regs(tsk) ((struct pt_regs*) \
+  (((long)(tsk)->thread_info + KERNEL_STACK_SIZE - (XCHAL_NUM_AREGS-16)*4)) - 1)
+# define user_mode(regs) (((regs)->ps & 0x00000020)!=0)
+# define instruction_pointer(regs) ((regs)->pc)
+extern void show_regs(struct pt_regs *);
+
+# ifndef CONFIG_SMP
+#  define profile_pc(regs) instruction_pointer(regs)
+# endif
+#endif /* __KERNEL__ */
+
+#else  /* __ASSEMBLY__ */
+
+#ifdef __KERNEL__
+# include <asm/offsets.h>
+#define PT_REGS_OFFSET   (KERNEL_STACK_SIZE - PT_USER_SIZE)
+#endif
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _XTENSA_PTRACE_H */
diff --git a/include/asm-xtensa/resource.h b/include/asm-xtensa/resource.h
new file mode 100644 (file)
index 0000000..17b5ab3
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/resource.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_RESOURCE_H
+#define _XTENSA_RESOURCE_H
+
+#include <asm-generic/resource.h>
+
+#endif /* _XTENSA_RESOURCE_H */
diff --git a/include/asm-xtensa/rmap.h b/include/asm-xtensa/rmap.h
new file mode 100644 (file)
index 0000000..649588b
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/rmap.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_RMAP_H
+#define _XTENSA_RMAP_H
+
+#include <asm-generic/rmap.h>
+
+#endif
diff --git a/include/asm-xtensa/rwsem.h b/include/asm-xtensa/rwsem.h
new file mode 100644 (file)
index 0000000..3c02b0e
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * include/asm-xtensa/rwsem.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Largely copied from include/asm-ppc/rwsem.h
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_RWSEM_H
+#define _XTENSA_RWSEM_H
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+       signed long             count;
+#define RWSEM_UNLOCKED_VALUE           0x00000000
+#define RWSEM_ACTIVE_BIAS              0x00000001
+#define RWSEM_ACTIVE_MASK              0x0000ffff
+#define RWSEM_WAITING_BIAS             (-0x00010000)
+#define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+       spinlock_t              wait_lock;
+       struct list_head        wait_list;
+#if RWSEM_DEBUG
+       int                     debug;
+#endif
+};
+
+/*
+ * initialisation
+ */
+#if RWSEM_DEBUG
+#define __RWSEM_DEBUG_INIT      , 0
+#else
+#define __RWSEM_DEBUG_INIT     /* */
+#endif
+
+#define __RWSEM_INITIALIZER(name) \
+       { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \
+         LIST_HEAD_INIT((name).wait_list) \
+         __RWSEM_DEBUG_INIT }
+
+#define DECLARE_RWSEM(name)            \
+       struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
+
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+       sem->count = RWSEM_UNLOCKED_VALUE;
+       spin_lock_init(&sem->wait_lock);
+       INIT_LIST_HEAD(&sem->wait_list);
+#if RWSEM_DEBUG
+       sem->debug = 0;
+#endif
+}
+
+/*
+ * lock for reading
+ */
+static inline void __down_read(struct rw_semaphore *sem)
+{
+       if (atomic_add_return(1,(atomic_t *)(&sem->count)) > 0)
+               smp_wmb();
+       else
+               rwsem_down_read_failed(sem);
+}
+
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+       int tmp;
+
+       while ((tmp = sem->count) >= 0) {
+               if (tmp == cmpxchg(&sem->count, tmp,
+                                  tmp + RWSEM_ACTIVE_READ_BIAS)) {
+                       smp_wmb();
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * lock for writing
+ */
+static inline void __down_write(struct rw_semaphore *sem)
+{
+       int tmp;
+
+       tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
+                               (atomic_t *)(&sem->count));
+       if (tmp == RWSEM_ACTIVE_WRITE_BIAS)
+               smp_wmb();
+       else
+               rwsem_down_write_failed(sem);
+}
+
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+       int tmp;
+
+       tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
+                     RWSEM_ACTIVE_WRITE_BIAS);
+       smp_wmb();
+       return tmp == RWSEM_UNLOCKED_VALUE;
+}
+
+/*
+ * unlock after reading
+ */
+static inline void __up_read(struct rw_semaphore *sem)
+{
+       int tmp;
+
+       smp_wmb();
+       tmp = atomic_sub_return(1,(atomic_t *)(&sem->count));
+       if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
+               rwsem_wake(sem);
+}
+
+/*
+ * unlock after writing
+ */
+static inline void __up_write(struct rw_semaphore *sem)
+{
+       smp_wmb();
+       if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
+                             (atomic_t *)(&sem->count)) < 0)
+               rwsem_wake(sem);
+}
+
+/*
+ * implement atomic add functionality
+ */
+static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
+{
+       atomic_add(delta, (atomic_t *)(&sem->count));
+}
+
+/*
+ * downgrade write lock to read lock
+ */
+static inline void __downgrade_write(struct rw_semaphore *sem)
+{
+       int tmp;
+
+       smp_wmb();
+       tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
+       if (tmp < 0)
+               rwsem_downgrade_wake(sem);
+}
+
+/*
+ * implement exchange and add functionality
+ */
+static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
+{
+       smp_mb();
+       return atomic_add_return(delta, (atomic_t *)(&sem->count));
+}
+
+#endif /* _XTENSA_RWSEM_XADD_H */
diff --git a/include/asm-xtensa/scatterlist.h b/include/asm-xtensa/scatterlist.h
new file mode 100644 (file)
index 0000000..38a2b9a
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * include/asm-xtensa/scatterlist.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SCATTERLIST_H
+#define _XTENSA_SCATTERLIST_H
+
+struct scatterlist {
+       struct page     *page;
+       unsigned int    offset;
+       dma_addr_t      dma_address;
+       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 (~0UL)
+
+#endif /* _XTENSA_SCATTERLIST_H */
diff --git a/include/asm-xtensa/sections.h b/include/asm-xtensa/sections.h
new file mode 100644 (file)
index 0000000..40b5191
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/sections.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SECTIONS_H
+#define _XTENSA_SECTIONS_H
+
+#include <asm-generic/sections.h>
+
+#endif /* _XTENSA_SECTIONS_H */
diff --git a/include/asm-xtensa/segment.h b/include/asm-xtensa/segment.h
new file mode 100644 (file)
index 0000000..a2eb547
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/segment.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SEGMENT_H
+#define _XTENSA_SEGMENT_H
+
+#include <asm/uaccess.h>
+
+#endif /* _XTENSA_SEGEMENT_H */
diff --git a/include/asm-xtensa/semaphore.h b/include/asm-xtensa/semaphore.h
new file mode 100644 (file)
index 0000000..c8a7574
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * linux/include/asm-xtensa/semaphore.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SEMAPHORE_H
+#define _XTENSA_SEMAPHORE_H
+
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <linux/wait.h>
+#include <linux/rwsem.h>
+
+struct semaphore {
+       atomic_t count;
+       int sleepers;
+       wait_queue_head_t wait;
+#if WAITQUEUE_DEBUG
+       long __magic;
+#endif
+};
+
+#if WAITQUEUE_DEBUG
+# define __SEM_DEBUG_INIT(name) \
+               , (int)&(name).__magic
+#else
+# define __SEM_DEBUG_INIT(name)
+#endif
+
+#define __SEMAPHORE_INITIALIZER(name,count)                    \
+       { ATOMIC_INIT(count),                                   \
+         0,                                                    \
+         __WAIT_QUEUE_HEAD_INITIALIZER((name).wait)            \
+       __SEM_DEBUG_INIT(name) }
+
+#define __MUTEX_INITIALIZER(name) \
+       __SEMAPHORE_INITIALIZER(name, 1)
+
+#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
+       struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
+
+#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
+#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
+
+extern inline void sema_init (struct semaphore *sem, int val)
+{
+/*
+ *     *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
+ *
+ * i'd rather use the more flexible initialization above, but sadly
+ * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well.
+ */
+       atomic_set(&sem->count, val);
+       init_waitqueue_head(&sem->wait);
+#if WAITQUEUE_DEBUG
+       sem->__magic = (int)&sem->__magic;
+#endif
+}
+
+static inline void init_MUTEX (struct semaphore *sem)
+{
+       sema_init(sem, 1);
+}
+
+static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+{
+       sema_init(sem, 0);
+}
+
+asmlinkage void __down(struct semaphore * sem);
+asmlinkage int  __down_interruptible(struct semaphore * sem);
+asmlinkage int  __down_trylock(struct semaphore * sem);
+asmlinkage void __up(struct semaphore * sem);
+
+extern spinlock_t semaphore_wake_lock;
+
+extern __inline__ void down(struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+       CHECK_MAGIC(sem->__magic);
+#endif
+
+       if (atomic_sub_return(1, &sem->count) < 0)
+               __down(sem);
+}
+
+extern __inline__ int down_interruptible(struct semaphore * sem)
+{
+       int ret = 0;
+#if WAITQUEUE_DEBUG
+       CHECK_MAGIC(sem->__magic);
+#endif
+
+       if (atomic_sub_return(1, &sem->count) < 0)
+               ret = __down_interruptible(sem);
+       return ret;
+}
+
+extern __inline__ int down_trylock(struct semaphore * sem)
+{
+       int ret = 0;
+#if WAITQUEUE_DEBUG
+       CHECK_MAGIC(sem->__magic);
+#endif
+
+       if (atomic_sub_return(1, &sem->count) < 0)
+               ret = __down_trylock(sem);
+       return ret;
+}
+
+/*
+ * Note! This is subtle. We jump to wake people up only if
+ * the semaphore was negative (== somebody was waiting on it).
+ */
+extern __inline__ void up(struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+       CHECK_MAGIC(sem->__magic);
+#endif
+       if (atomic_add_return(1, &sem->count) <= 0)
+               __up(sem);
+}
+
+#endif /* _XTENSA_SEMAPHORE_H */
diff --git a/include/asm-xtensa/sembuf.h b/include/asm-xtensa/sembuf.h
new file mode 100644 (file)
index 0000000..2d26c47
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * include/asm-xtensa/sembuf.h
+ *
+ * The semid64_ds structure for Xtensa architecture.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ *
+ */
+
+#ifndef _XTENSA_SEMBUF_H
+#define _XTENSA_SEMBUF_H
+
+#include <asm/byteorder.h>
+
+struct semid64_ds {
+       struct ipc64_perm sem_perm;             /* permissions .. see ipc.h */
+#if XCHAL_HAVE_LE
+       __kernel_time_t sem_otime;              /* last semop time */
+       unsigned long   __unused1;
+       __kernel_time_t sem_ctime;              /* last change time */
+       unsigned long   __unused2;
+#else
+       unsigned long   __unused1;
+       __kernel_time_t sem_otime;              /* last semop time */
+       unsigned long   __unused2;
+       __kernel_time_t sem_ctime;              /* last change time */
+#endif
+       unsigned long   sem_nsems;              /* no. of semaphores in array */
+       unsigned long   __unused3;
+       unsigned long   __unused4;
+};
+
+#endif /* __ASM_XTENSA_SEMBUF_H */
diff --git a/include/asm-xtensa/serial.h b/include/asm-xtensa/serial.h
new file mode 100644 (file)
index 0000000..ec04114
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * include/asm-xtensa/serial.h
+ *
+ * Configuration details for 8250, 16450, 16550, etc. serial ports
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SERIAL_H
+#define _XTENSA_SERIAL_H
+
+#include <asm/platform/serial.h>
+
+#endif /* _XTENSA_SERIAL_H */
diff --git a/include/asm-xtensa/setup.h b/include/asm-xtensa/setup.h
new file mode 100644 (file)
index 0000000..e363652
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/setup.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SETUP_H
+#define _XTENSA_SETUP_H
+
+#define COMMAND_LINE_SIZE      256
+
+#endif
diff --git a/include/asm-xtensa/shmbuf.h b/include/asm-xtensa/shmbuf.h
new file mode 100644 (file)
index 0000000..a30b81a
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * include/asm-xtensa/shmbuf.h
+ *
+ * The shmid64_ds structure for Xtensa architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SHMBUF_H
+#define _XTENSA_SHMBUF_H
+
+struct shmid64_ds {
+       struct ipc64_perm       shm_perm;       /* operation perms */
+       size_t                  shm_segsz;      /* size of segment (bytes) */
+       __kernel_time_t         shm_atime;      /* last attach time */
+       unsigned long           __unused1;
+       __kernel_time_t         shm_dtime;      /* last detach time */
+       unsigned long           __unused2;
+       __kernel_time_t         shm_ctime;      /* last change time */
+       unsigned long           __unused3;
+       __kernel_pid_t          shm_cpid;       /* pid of creator */
+       __kernel_pid_t          shm_lpid;       /* pid of last operator */
+       unsigned long           shm_nattch;     /* no. of current attaches */
+       unsigned long           __unused4;
+       unsigned long           __unused5;
+};
+
+struct shminfo64 {
+       unsigned long   shmmax;
+       unsigned long   shmmin;
+       unsigned long   shmmni;
+       unsigned long   shmseg;
+       unsigned long   shmall;
+       unsigned long   __unused1;
+       unsigned long   __unused2;
+       unsigned long   __unused3;
+       unsigned long   __unused4;
+};
+
+#endif /* _XTENSA_SHMBUF_H */
diff --git a/include/asm-xtensa/shmparam.h b/include/asm-xtensa/shmparam.h
new file mode 100644 (file)
index 0000000..d3b65bf
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * include/asm-xtensa/shmparam.h
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ */
+
+#ifndef _XTENSA_SHMPARAM_H
+#define _XTENSA_SHMPARAM_H
+
+#include <asm/processor.h>
+
+/*
+ * Xtensa can have variable size caches, and if
+ * the size of single way is larger than the page size,
+ * then we have to start worrying about cache aliasing
+ * problems.
+ */
+
+#define SHMLBA ((PAGE_SIZE > DCACHE_WAY_SIZE)? PAGE_SIZE : DCACHE_WAY_SIZE)
+
+#endif /* _XTENSA_SHMPARAM_H */
diff --git a/include/asm-xtensa/sigcontext.h b/include/asm-xtensa/sigcontext.h
new file mode 100644 (file)
index 0000000..a751772
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * include/asm-xtensa/sigcontext.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2003 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SIGCONTEXT_H
+#define _XTENSA_SIGCONTEXT_H
+
+#define _ASMLANGUAGE
+#include <asm/processor.h>
+#include <asm/coprocessor.h>
+
+
+struct _cpstate {
+       unsigned char _cpstate[XTENSA_CP_EXTRA_SIZE];
+} __attribute__ ((aligned (XTENSA_CP_EXTRA_ALIGN)));
+
+
+struct sigcontext {
+       unsigned long   oldmask;
+
+       /* CPU registers */
+       unsigned long sc_pc;
+       unsigned long sc_ps;
+       unsigned long sc_wmask;
+       unsigned long sc_windowbase;
+       unsigned long sc_windowstart;
+       unsigned long sc_lbeg;
+       unsigned long sc_lend;
+       unsigned long sc_lcount;
+       unsigned long sc_sar;
+       unsigned long sc_depc;
+       unsigned long sc_dareg0;
+       unsigned long sc_treg[4];
+       unsigned long sc_areg[XCHAL_NUM_AREGS];
+       struct _cpstate *sc_cpstate;
+};
+
+#endif /* __ASM_XTENSA_SIGCONTEXT_H */
diff --git a/include/asm-xtensa/siginfo.h b/include/asm-xtensa/siginfo.h
new file mode 100644 (file)
index 0000000..44f0ae7
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/processor.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SIGINFO_H
+#define _XTENSA_SIGINFO_H
+
+#include <asm-generic/siginfo.h>
+
+#endif /* _XTENSA_SIGINFO_H */
diff --git a/include/asm-xtensa/signal.h b/include/asm-xtensa/signal.h
new file mode 100644 (file)
index 0000000..5d6fc9c
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * include/asm-xtensa/signal.h
+ *
+ * Swiped from SH.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SIGNAL_H
+#define _XTENSA_SIGNAL_H
+
+
+#define _NSIG          64
+#define _NSIG_BPW      32
+#define _NSIG_WORDS    (_NSIG / _NSIG_BPW)
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+/* Avoid too many header ordering problems.  */
+struct siginfo;
+typedef unsigned long old_sigset_t;            /* at least 32 bits */
+typedef struct {
+       unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#endif
+
+#define SIGHUP          1
+#define SIGINT          2
+#define SIGQUIT                 3
+#define SIGILL          4
+#define SIGTRAP                 5
+#define SIGABRT                 6
+#define SIGIOT          6
+#define SIGBUS          7
+#define SIGFPE          8
+#define SIGKILL                 9
+#define SIGUSR1                10
+#define SIGSEGV                11
+#define SIGUSR2                12
+#define SIGPIPE                13
+#define SIGALRM                14
+#define SIGTERM                15
+#define SIGSTKFLT      16
+#define SIGCHLD                17
+#define SIGCONT                18
+#define SIGSTOP                19
+#define SIGTSTP                20
+#define SIGTTIN                21
+#define SIGTTOU                22
+#define SIGURG         23
+#define SIGXCPU                24
+#define SIGXFSZ                25
+#define SIGVTALRM      26
+#define SIGPROF                27
+#define SIGWINCH       28
+#define SIGIO          29
+#define SIGPOLL                SIGIO
+/* #define SIGLOST             29 */
+#define SIGPWR         30
+#define SIGSYS         31
+#define        SIGUNUSED       31
+
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN       32
+#define SIGRTMAX       (_NSIG-1)
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP   0x00000001
+#define SA_NOCLDWAIT   0x00000002 /* not supported yet */
+#define SA_SIGINFO     0x00000004
+#define SA_ONSTACK     0x08000000
+#define SA_RESTART     0x10000000
+#define SA_NODEFER     0x40000000
+#define SA_RESETHAND   0x80000000
+
+#define SA_NOMASK      SA_NODEFER
+#define SA_ONESHOT     SA_RESETHAND
+#define SA_INTERRUPT   0x20000000 /* dummy -- ignored */
+
+#define SA_RESTORER    0x04000000
+
+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK     1
+#define SS_DISABLE     2
+
+#define MINSIGSTKSZ    2048
+#define SIGSTKSZ       8192
+
+#ifndef __ASSEMBLY__
+#ifdef __KERNEL__
+
+/*
+ * These values of sa_flags are used only by the kernel as part of the
+ * irq handling routines.
+ *
+ * SA_INTERRUPT is also used by the irq handling routines.
+ * SA_SHIRQ is for shared interrupt support on PCI and EISA.
+ */
+#define SA_PROBE               SA_ONESHOT
+#define SA_SAMPLE_RANDOM       SA_RESTART
+#define SA_SHIRQ               0x04000000
+#endif
+
+#define SIG_BLOCK          0   /* for blocking signals */
+#define SIG_UNBLOCK        1   /* for unblocking signals */
+#define SIG_SETMASK        2   /* for setting the signal mask */
+
+/* Type of a signal handler.  */
+typedef void (*__sighandler_t)(int);
+
+#define SIG_DFL        ((__sighandler_t)0)     /* default signal handling */
+#define SIG_IGN        ((__sighandler_t)1)     /* ignore signal */
+#define SIG_ERR        ((__sighandler_t)-1)    /* error return from signal */
+
+#ifdef __KERNEL__
+struct old_sigaction {
+       __sighandler_t sa_handler;
+       old_sigset_t sa_mask;
+       unsigned long sa_flags;
+       void (*sa_restorer)(void);
+};
+
+struct sigaction {
+       __sighandler_t sa_handler;
+       unsigned long sa_flags;
+       void (*sa_restorer)(void);
+       sigset_t sa_mask;               /* mask last for extensibility */
+};
+
+struct k_sigaction {
+       struct sigaction sa;
+};
+
+#else
+
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+struct sigaction {
+       union {
+         __sighandler_t _sa_handler;
+         void (*_sa_sigaction)(int, struct siginfo *, void *);
+       } _u;
+       sigset_t sa_mask;
+       unsigned long sa_flags;
+       void (*sa_restorer)(void);
+};
+
+#define sa_handler     _u._sa_handler
+#define sa_sigaction   _u._sa_sigaction
+
+#endif /* __KERNEL__ */
+
+typedef struct sigaltstack {
+       void *ss_sp;
+       int ss_flags;
+       size_t ss_size;
+} stack_t;
+
+#ifdef __KERNEL__
+#include <asm/sigcontext.h>
+#define ptrace_signal_deliver(regs, cookie) do { } while (0)
+
+#endif /* __KERNEL__ */
+#endif /* __ASSEMBLY__ */
+#endif /* _XTENSA_SIGNAL_H */
diff --git a/include/asm-xtensa/smp.h b/include/asm-xtensa/smp.h
new file mode 100644 (file)
index 0000000..83c569e
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * include/asm-xtensa/smp.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SMP_H
+#define _XTENSA_SMP_H
+
+extern struct xtensa_cpuinfo boot_cpu_data;
+
+#define cpu_data (&boot_cpu_data)
+#define current_cpu_data boot_cpu_data
+
+struct xtensa_cpuinfo {
+       unsigned long   *pgd_cache;
+       unsigned long   *pte_cache;
+       unsigned long   pgtable_cache_sz;
+};
+
+#define cpu_logical_map(cpu)   (cpu)
+
+#endif /* _XTENSA_SMP_H */
diff --git a/include/asm-xtensa/socket.h b/include/asm-xtensa/socket.h
new file mode 100644 (file)
index 0000000..daccd05
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * include/asm-xtensa/socket.h
+ *
+ * Copied from i386.
+ *
+ * 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 _XTENSA_SOCKET_H
+#define _XTENSA_SOCKET_H
+
+#include <asm/sockios.h>
+
+/* For setsockoptions(2) */
+#define SOL_SOCKET     1
+
+#define SO_DEBUG       1
+#define SO_REUSEADDR   2
+#define SO_TYPE                3
+#define SO_ERROR       4
+#define SO_DONTROUTE   5
+#define SO_BROADCAST   6
+#define SO_SNDBUF      7
+#define SO_RCVBUF      8
+#define SO_KEEPALIVE   9
+#define SO_OOBINLINE   10
+#define SO_NO_CHECK    11
+#define SO_PRIORITY    12
+#define SO_LINGER      13
+#define SO_BSDCOMPAT   14
+/* To add :#define SO_REUSEPORT 15 */
+#define SO_PASSCRED    16
+#define SO_PEERCRED    17
+#define SO_RCVLOWAT    18
+#define SO_SNDLOWAT    19
+#define SO_RCVTIMEO    20
+#define SO_SNDTIMEO    21
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+
+#define SO_SECURITY_AUTHENTICATION             22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT       23
+#define SO_SECURITY_ENCRYPTION_NETWORK         24
+
+#define SO_BINDTODEVICE        25
+
+/* Socket filtering */
+
+#define SO_ATTACH_FILTER        26
+#define SO_DETACH_FILTER        27
+
+#define SO_PEERNAME            28
+#define SO_TIMESTAMP           29
+#define SCM_TIMESTAMP          SO_TIMESTAMP
+
+#define SO_ACCEPTCONN          30
+#define SO_PEERSEC             31
+
+#endif /* _XTENSA_SOCKET_H */
diff --git a/include/asm-xtensa/sockios.h b/include/asm-xtensa/sockios.h
new file mode 100644 (file)
index 0000000..20d2ba1
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * include/asm-xtensa/sockios.h
+ *
+ * Socket-level I/O control calls.  Copied from MIPS.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ * Copyright (C) 2001 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SOCKIOS_H
+#define _XTENSA_SOCKIOS_H
+
+#include <asm/ioctl.h>
+
+/* Socket-level I/O control calls. */
+
+#define FIOGETOWN      _IOR('f', 123, int)
+#define FIOSETOWN      _IOW('f', 124, int)
+
+#define SIOCATMARK     _IOR('s', 7, int)
+#define SIOCSPGRP      _IOW('s', 8, pid_t)
+#define SIOCGPGRP      _IOR('s', 9, pid_t)
+
+#define SIOCGSTAMP     0x8906          /* Get stamp - linux-specific */
+
+#endif /* _XTENSA_SOCKIOS_H */
diff --git a/include/asm-xtensa/spinlock.h b/include/asm-xtensa/spinlock.h
new file mode 100644 (file)
index 0000000..8ff2364
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/spinlock.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SPINLOCK_H
+#define _XTENSA_SPINLOCK_H
+
+#include <linux/spinlock.h>
+
+#endif /* _XTENSA_SPINLOCK_H */
diff --git a/include/asm-xtensa/stat.h b/include/asm-xtensa/stat.h
new file mode 100644 (file)
index 0000000..2f4662f
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * include/asm-xtensa/stat.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_STAT_H
+#define _XTENSA_STAT_H
+
+#include <linux/types.h>
+
+struct __old_kernel_stat {
+       unsigned short st_dev;
+       unsigned short st_ino;
+       unsigned short st_mode;
+       unsigned short st_nlink;
+       unsigned short st_uid;
+       unsigned short st_gid;
+       unsigned short st_rdev;
+       unsigned long  st_size;
+       unsigned long  st_atime;
+       unsigned long  st_mtime;
+       unsigned long  st_ctime;
+};
+
+#define STAT_HAVE_NSEC 1
+
+struct stat {
+       unsigned short st_dev;
+       unsigned short __pad1;
+       unsigned long st_ino;
+       unsigned short st_mode;
+       unsigned short st_nlink;
+       unsigned short st_uid;
+       unsigned short st_gid;
+       unsigned short st_rdev;
+       unsigned short __pad2;
+       unsigned long  st_size;
+       unsigned long  st_blksize;
+       unsigned long  st_blocks;
+       unsigned long  st_atime;
+       unsigned long  st_atime_nsec;
+       unsigned long  st_mtime;
+       unsigned long  st_mtime_nsec;
+       unsigned long  st_ctime;
+       unsigned long  st_ctime_nsec;
+       unsigned long  __unused4;
+       unsigned long  __unused5;
+};
+
+/* This matches struct stat64 in glibc-2.2.3. */
+
+struct stat64  {
+#ifdef __XTENSA_EL__
+       unsigned short  st_dev;         /* Device */
+       unsigned char   __pad0[10];
+#else
+       unsigned char   __pad0[6];
+       unsigned short  st_dev;
+       unsigned char   __pad1[2];
+#endif
+
+#define STAT64_HAS_BROKEN_ST_INO       1
+       unsigned long __st_ino;         /* 32bit file serial number. */
+
+       unsigned int  st_mode;          /* File mode. */
+       unsigned int  st_nlink;         /* Link count. */
+       unsigned int  st_uid;           /* User ID of the file's owner. */
+       unsigned int  st_gid;           /* Group ID of the file's group. */
+
+#ifdef __XTENSA_EL__
+       unsigned short  st_rdev;        /* Device number, if device. */
+       unsigned char   __pad3[10];
+#else
+       unsigned char   __pad2[6];
+       unsigned short  st_rdev;
+       unsigned char   __pad3[2];
+#endif
+
+       long long int  st_size;         /* Size of file, in bytes. */
+       long int st_blksize;            /* Optimal block size for I/O. */
+
+#ifdef __XTENSA_EL__
+       unsigned long  st_blocks;       /* Number 512-byte blocks allocated. */
+       unsigned long  __pad4;
+#else
+       unsigned long  __pad4;
+       unsigned long  st_blocks;
+#endif
+
+       unsigned long  __pad5;
+       long int st_atime;              /* Time of last access. */
+       unsigned long  st_atime_nsec;
+       long int st_mtime;              /* Time of last modification. */
+       unsigned long  st_mtime_nsec;
+       long int  st_ctime;             /* Time of last status change. */
+       unsigned long  st_ctime_nsec;
+       unsigned long long int st_ino;  /* File serial number. */
+};
+
+#endif /* _XTENSA_STAT_H */
diff --git a/include/asm-xtensa/statfs.h b/include/asm-xtensa/statfs.h
new file mode 100644 (file)
index 0000000..9c3d1a2
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * include/asm-xtensa/statfs.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_STATFS_H
+#define _XTENSA_STATFS_H
+
+#include <asm-generic/statfs.h>
+
+#endif /* _XTENSA_STATFS_H */
+
diff --git a/include/asm-xtensa/string.h b/include/asm-xtensa/string.h
new file mode 100644 (file)
index 0000000..3f81b27
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * include/asm-xtensa/string.h
+ *
+ * These trivial string functions are considered part of the public domain.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+/* We should optimize these. See arch/xtensa/lib/strncpy_user.S */
+
+#ifndef _XTENSA_STRING_H
+#define _XTENSA_STRING_H
+
+#define __HAVE_ARCH_STRCPY
+extern __inline__ char *strcpy(char *__dest, const char *__src)
+{
+       register char *__xdest = __dest;
+       unsigned long __dummy;
+
+       __asm__ __volatile__("1:\n\t"
+               "l8ui   %2, %1, 0\n\t"
+               "s8i    %2, %0, 0\n\t"
+               "addi   %1, %1, 1\n\t"
+               "addi   %0, %0, 1\n\t"
+               "bnez   %2, 1b\n\t"
+               : "=r" (__dest), "=r" (__src), "=&r" (__dummy)
+               : "0" (__dest), "1" (__src)
+               : "memory");
+
+       return __xdest;
+}
+
+#define __HAVE_ARCH_STRNCPY
+extern __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
+{
+       register char *__xdest = __dest;
+       unsigned long __dummy;
+
+       if (__n == 0)
+               return __xdest;
+
+       __asm__ __volatile__(
+               "1:\n\t"
+               "l8ui   %2, %1, 0\n\t"
+               "s8i    %2, %0, 0\n\t"
+               "addi   %1, %1, 1\n\t"
+               "addi   %0, %0, 1\n\t"
+               "beqz   %2, 2f\n\t"
+               "bne    %1, %5, 1b\n"
+               "2:"
+               : "=r" (__dest), "=r" (__src), "=&r" (__dummy)
+               : "0" (__dest), "1" (__src), "r" (__src+__n)
+               : "memory");
+
+       return __xdest;
+}
+
+#define __HAVE_ARCH_STRCMP
+extern __inline__ int strcmp(const char *__cs, const char *__ct)
+{
+       register int __res;
+       unsigned long __dummy;
+
+       __asm__ __volatile__(
+               "1:\n\t"
+               "l8ui   %3, %1, 0\n\t"
+               "addi   %1, %1, 1\n\t"
+               "l8ui   %2, %0, 0\n\t"
+               "addi   %0, %0, 1\n\t"
+               "beqz   %2, 2f\n\t"
+               "beq    %2, %3, 1b\n"
+               "2:\n\t"
+               "sub    %2, %3, %2"
+               : "=r" (__cs), "=r" (__ct), "=&r" (__res), "=&r" (__dummy)
+               : "0" (__cs), "1" (__ct));
+
+       return __res;
+}
+
+#define __HAVE_ARCH_STRNCMP
+extern __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n)
+{
+       register int __res;
+       unsigned long __dummy;
+
+       __asm__ __volatile__(
+               "mov    %2, %3\n"
+               "1:\n\t"
+               "beq    %0, %6, 2f\n\t"
+               "l8ui   %3, %1, 0\n\t"
+               "addi   %1, %1, 1\n\t"
+               "l8ui   %2, %0, 0\n\t"
+               "addi   %0, %0, 1\n\t"
+               "beqz   %2, 2f\n\t"
+               "beqz   %3, 2f\n\t"
+               "beq    %2, %3, 1b\n"
+               "2:\n\t"
+               "sub    %2, %3, %2"
+               : "=r" (__cs), "=r" (__ct), "=&r" (__res), "=&r" (__dummy)
+               : "0" (__cs), "1" (__ct), "r" (__cs+__n));
+
+       return __res;
+}
+
+#define __HAVE_ARCH_MEMSET
+extern void *memset(void *__s, int __c, size_t __count);
+
+#define __HAVE_ARCH_MEMCPY
+extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
+
+#define __HAVE_ARCH_MEMMOVE
+extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
+
+/* Don't build bcopy at all ...  */
+#define __HAVE_ARCH_BCOPY
+
+#define __HAVE_ARCH_MEMSCAN
+#define memscan memchr
+
+#endif /* _XTENSA_STRING_H */
diff --git a/include/asm-xtensa/system.h b/include/asm-xtensa/system.h
new file mode 100644 (file)
index 0000000..690fe32
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * include/asm-xtensa/system.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SYSTEM_H
+#define _XTENSA_SYSTEM_H
+
+#include <linux/config.h>
+#include <linux/stringify.h>
+
+#include <asm/processor.h>
+
+/* interrupt control */
+
+#define local_save_flags(x)                                            \
+       __asm__ __volatile__ ("rsr %0,"__stringify(PS) : "=a" (x));
+#define local_irq_restore(x)   do {                                    \
+       __asm__ __volatile__ ("wsr %0, "__stringify(PS)" ; rsync"       \
+                             :: "a" (x) : "memory"); } while(0);
+#define local_irq_save(x)      do {                                    \
+       __asm__ __volatile__ ("rsil %0, "__stringify(LOCKLEVEL)         \
+                             : "=a" (x) :: "memory");} while(0);
+
+static inline void local_irq_disable(void)
+{
+       unsigned long flags;
+       __asm__ __volatile__ ("rsil %0, "__stringify(LOCKLEVEL)
+                             : "=a" (flags) :: "memory");
+}
+static inline void local_irq_enable(void)
+{
+       unsigned long flags;
+       __asm__ __volatile__ ("rsil %0, 0" : "=a" (flags) :: "memory");
+
+}
+
+static inline int irqs_disabled(void)
+{
+       unsigned long flags;
+       local_save_flags(flags);
+       return flags & 0xf;
+}
+
+#define RSR_CPENABLE(x)        do {                                              \
+       __asm__ __volatile__("rsr %0," __stringify(CPENABLE) : "=a" (x)); \
+       } while(0);
+#define WSR_CPENABLE(x)        do {                                              \
+       __asm__ __volatile__("wsr %0," __stringify(CPENABLE)";rsync"      \
+                            :: "a" (x));} while(0);
+
+#define clear_cpenable() __clear_cpenable()
+
+extern __inline__ void __clear_cpenable(void)
+{
+#if XCHAL_HAVE_CP
+       unsigned long i = 0;
+       WSR_CPENABLE(i);
+#endif
+}
+
+extern __inline__ void enable_coprocessor(int i)
+{
+#if XCHAL_HAVE_CP
+       int cp;
+       RSR_CPENABLE(cp);
+       cp |= 1 << i;
+       WSR_CPENABLE(cp);
+#endif
+}
+
+extern __inline__ void disable_coprocessor(int i)
+{
+#if XCHAL_HAVE_CP
+       int cp;
+       RSR_CPENABLE(cp);
+       cp &= ~(1 << i);
+       WSR_CPENABLE(cp);
+#endif
+}
+
+#define smp_read_barrier_depends() do { } while(0)
+#define read_barrier_depends() do { } while(0)
+
+#define mb()  barrier()
+#define rmb() mb()
+#define wmb() mb()
+
+#ifdef CONFIG_SMP
+#error smp_* not defined
+#else
+#define smp_mb()       barrier()
+#define smp_rmb()      barrier()
+#define smp_wmb()      barrier()
+#endif
+
+#define set_mb(var, value)     do { var = value; mb(); } while (0)
+#define set_wmb(var, value)    do { var = value; wmb(); } while (0)
+
+#if !defined (__ASSEMBLY__)
+
+/* * switch_to(n) should switch tasks to task nr n, first
+ * checking that n isn't the current task, in which case it does nothing.
+ */
+extern void *_switch_to(void *last, void *next);
+
+#endif /* __ASSEMBLY__ */
+
+#define prepare_to_switch()    do { } while(0)
+
+#define switch_to(prev,next,last)              \
+do {                                           \
+       clear_cpenable();                       \
+       (last) = _switch_to(prev, next);        \
+} while(0)
+
+/*
+ * cmpxchg
+ */
+
+extern __inline__ unsigned long
+__cmpxchg_u32(volatile int *p, int old, int new)
+{
+  __asm__ __volatile__("rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
+                      "l32i    %0, %1, 0              \n\t"
+                      "bne     %0, %2, 1f             \n\t"
+                      "s32i    %3, %1, 0              \n\t"
+                      "1:                             \n\t"
+                      "wsr     a15, "__stringify(PS)" \n\t"
+                      "rsync                          \n\t"
+                      : "=&a" (old)
+                      : "a" (p), "a" (old), "r" (new)
+                      : "a15", "memory");
+  return old;
+}
+/* This function doesn't exist, so you'll get a linker error
+ * if something tries to do an invalid cmpxchg(). */
+
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+static __inline__ unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
+{
+       switch (size) {
+       case 4:  return __cmpxchg_u32(ptr, old, new);
+       default: __cmpxchg_called_with_bad_pointer();
+                return old;
+       }
+}
+
+#define cmpxchg(ptr,o,n)                                                     \
+       ({ __typeof__(*(ptr)) _o_ = (o);                                      \
+          __typeof__(*(ptr)) _n_ = (n);                                      \
+          (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,          \
+                                       (unsigned long)_n_, sizeof (*(ptr))); \
+       })
+
+
+
+
+/*
+ * xchg_u32
+ *
+ * Note that a15 is used here because the register allocation
+ * done by the compiler is not guaranteed and a window overflow
+ * may not occur between the rsil and wsr instructions. By using
+ * a15 in the rsil, the machine is guaranteed to be in a state
+ * where no register reference will cause an overflow.
+ */
+
+extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val)
+{
+  unsigned long tmp;
+  __asm__ __volatile__("rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
+                      "l32i    %0, %1, 0              \n\t"
+                      "s32i    %2, %1, 0              \n\t"
+                      "wsr     a15, "__stringify(PS)" \n\t"
+                      "rsync                          \n\t"
+                      : "=&a" (tmp)
+                      : "a" (m), "a" (val)
+                      : "a15", "memory");
+  return tmp;
+}
+
+#define tas(ptr) (xchg((ptr),1))
+
+#if ( __XCC__ == 1 )
+
+/* xt-xcc processes __inline__ differently than xt-gcc and decides to
+ * insert an out-of-line copy of function __xchg.  This presents the
+ * unresolved symbol at link time of __xchg_called_with_bad_pointer,
+ * even though such a function would never be called at run-time.
+ * xt-gcc always inlines __xchg, and optimizes away the undefined
+ * bad_pointer function.
+ */
+
+#define xchg(ptr,x) xchg_u32(ptr,x)
+
+#else  /* assume xt-gcc */
+
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+/*
+ * This only works if the compiler isn't horribly bad at optimizing.
+ * gcc-2.5.8 reportedly can't handle this, but I define that one to
+ * be dead anyway.
+ */
+
+extern void __xchg_called_with_bad_pointer(void);
+
+static __inline__ unsigned long
+__xchg(unsigned long x, volatile void * ptr, int size)
+{
+       switch (size) {
+               case 4:
+                       return xchg_u32(ptr, x);
+       }
+       __xchg_called_with_bad_pointer();
+       return x;
+}
+
+#endif
+
+extern void set_except_vector(int n, void *addr);
+
+static inline void spill_registers(void)
+{
+       unsigned int a0, ps;
+
+       __asm__ __volatile__ (
+               "movi   a14," __stringify (PS_EXCM_MASK) " | 1\n\t"
+               "mov    a12, a0\n\t"
+               "rsr    a13," __stringify(SAR) "\n\t"
+               "xsr    a14," __stringify(PS) "\n\t"
+               "movi   a0, _spill_registers\n\t"
+               "rsync\n\t"
+               "callx0 a0\n\t"
+               "mov    a0, a12\n\t"
+               "wsr    a13," __stringify(SAR) "\n\t"
+               "wsr    a14," __stringify(PS) "\n\t"
+               :: "a" (&a0), "a" (&ps)
+               : "a2", "a3", "a12", "a13", "a14", "a15", "memory");
+}
+
+#define arch_align_stack(x) (x)
+
+#endif /* _XTENSA_SYSTEM_H */
diff --git a/include/asm-xtensa/termbits.h b/include/asm-xtensa/termbits.h
new file mode 100644 (file)
index 0000000..c780593
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * include/asm-xtensa/termbits.h
+ *
+ * Copied from SH.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_TERMBITS_H
+#define _XTENSA_TERMBITS_H
+
+
+#include <linux/posix_types.h>
+
+typedef unsigned char  cc_t;
+typedef unsigned int   speed_t;
+typedef unsigned int   tcflag_t;
+
+#define NCCS 19
+struct termios {
+       tcflag_t c_iflag;               /* input mode flags */
+       tcflag_t c_oflag;               /* output mode flags */
+       tcflag_t c_cflag;               /* control mode flags */
+       tcflag_t c_lflag;               /* local mode flags */
+       cc_t c_line;                    /* line discipline */
+       cc_t c_cc[NCCS];                /* control characters */
+};
+
+/* c_cc characters */
+
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+/* c_iflag bits */
+
+#define IGNBRK 0000001
+#define BRKINT 0000002
+#define IGNPAR 0000004
+#define PARMRK 0000010
+#define INPCK  0000020
+#define ISTRIP 0000040
+#define INLCR  0000100
+#define IGNCR  0000200
+#define ICRNL  0000400
+#define IUCLC  0001000
+#define IXON   0002000
+#define IXANY  0004000
+#define IXOFF  0010000
+#define IMAXBEL        0020000
+#define IUTF8  0040000
+
+/* c_oflag bits */
+
+#define OPOST  0000001
+#define OLCUC  0000002
+#define ONLCR  0000004
+#define OCRNL  0000010
+#define ONOCR  0000020
+#define ONLRET 0000040
+#define OFILL  0000100
+#define OFDEL  0000200
+#define NLDLY  0000400
+#define   NL0  0000000
+#define   NL1  0000400
+#define CRDLY  0003000
+#define   CR0  0000000
+#define   CR1  0001000
+#define   CR2  0002000
+#define   CR3  0003000
+#define TABDLY 0014000
+#define   TAB0 0000000
+#define   TAB1 0004000
+#define   TAB2 0010000
+#define   TAB3 0014000
+#define   XTABS        0014000
+#define BSDLY  0020000
+#define   BS0  0000000
+#define   BS1  0020000
+#define VTDLY  0040000
+#define   VT0  0000000
+#define   VT1  0040000
+#define FFDLY  0100000
+#define   FF0  0000000
+#define   FF1  0100000
+
+/* c_cflag bit meaning */
+
+#define CBAUD  0010017
+#define  B0    0000000         /* hang up */
+#define  B50   0000001
+#define  B75   0000002
+#define  B110  0000003
+#define  B134  0000004
+#define  B150  0000005
+#define  B200  0000006
+#define  B300  0000007
+#define  B600  0000010
+#define  B1200 0000011
+#define  B1800 0000012
+#define  B2400 0000013
+#define  B4800 0000014
+#define  B9600 0000015
+#define  B19200        0000016
+#define  B38400        0000017
+#define EXTA B19200
+#define EXTB B38400
+#define CSIZE  0000060
+#define   CS5  0000000
+#define   CS6  0000020
+#define   CS7  0000040
+#define   CS8  0000060
+#define CSTOPB 0000100
+#define CREAD  0000200
+#define PARENB 0000400
+#define PARODD 0001000
+#define HUPCL  0002000
+#define CLOCAL 0004000
+#define CBAUDEX 0010000
+#define    B57600 0010001
+#define   B115200 0010002
+#define   B230400 0010003
+#define   B460800 0010004
+#define   B500000 0010005
+#define   B576000 0010006
+#define   B921600 0010007
+#define  B1000000 0010010
+#define  B1152000 0010011
+#define  B1500000 0010012
+#define  B2000000 0010013
+#define  B2500000 0010014
+#define  B3000000 0010015
+#define  B3500000 0010016
+#define  B4000000 0010017
+#define CIBAUD   002003600000  /* input baud rate (not used) */
+#define CMSPAR   010000000000          /* mark or space (stick) parity */
+#define CRTSCTS          020000000000          /* flow control */
+
+/* c_lflag bits */
+
+#define ISIG   0000001
+#define ICANON 0000002
+#define XCASE  0000004
+#define ECHO   0000010
+#define ECHOE  0000020
+#define ECHOK  0000040
+#define ECHONL 0000100
+#define NOFLSH 0000200
+#define TOSTOP 0000400
+#define ECHOCTL        0001000
+#define ECHOPRT        0002000
+#define ECHOKE 0004000
+#define FLUSHO 0010000
+#define PENDIN 0040000
+#define IEXTEN 0100000
+
+/* tcflow() and TCXONC use these */
+
+#define        TCOOFF          0
+#define        TCOON           1
+#define        TCIOFF          2
+#define        TCION           3
+
+/* tcflush() and TCFLSH use these */
+
+#define        TCIFLUSH        0
+#define        TCOFLUSH        1
+#define        TCIOFLUSH       2
+
+/* tcsetattr uses these */
+
+#define        TCSANOW         0
+#define        TCSADRAIN       1
+#define        TCSAFLUSH       2
+
+#endif /* _XTENSA_TERMBITS_H */
diff --git a/include/asm-xtensa/termios.h b/include/asm-xtensa/termios.h
new file mode 100644 (file)
index 0000000..83c6aed
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * include/asm-xtensa/termios.h
+ *
+ * Copied from SH.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_TERMIOS_H
+#define _XTENSA_TERMIOS_H
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+
+struct winsize {
+       unsigned short ws_row;
+       unsigned short ws_col;
+       unsigned short ws_xpixel;
+       unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+       unsigned short c_iflag;         /* input mode flags */
+       unsigned short c_oflag;         /* output mode flags */
+       unsigned short c_cflag;         /* control mode flags */
+       unsigned short c_lflag;         /* local mode flags */
+       unsigned char c_line;           /* line discipline */
+       unsigned char c_cc[NCC];        /* control characters */
+};
+
+/* Modem lines */
+
+#define TIOCM_LE       0x001
+#define TIOCM_DTR      0x002
+#define TIOCM_RTS      0x004
+#define TIOCM_ST       0x008
+#define TIOCM_SR       0x010
+#define TIOCM_CTS      0x020
+#define TIOCM_CAR      0x040
+#define TIOCM_RNG      0x080
+#define TIOCM_DSR      0x100
+#define TIOCM_CD       TIOCM_CAR
+#define TIOCM_RI       TIOCM_RNG
+#define TIOCM_OUT1     0x2000
+#define TIOCM_OUT2     0x4000
+#define TIOCM_LOOP     0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+/* Line disciplines */
+
+#define N_TTY          0
+#define N_SLIP         1
+#define N_MOUSE                2
+#define N_PPP          3
+#define N_STRIP                4
+#define N_AX25         5
+#define N_X25          6       /* X.25 async */
+#define N_6PACK                7
+#define N_MASC         8       /* Reserved for Mobitex module <kaz@cafe.net> */
+#define N_R3964                9       /* Reserved for Simatic R3964 module */
+#define N_PROFIBUS_FDL 10      /* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA         11      /* Linux IR - http://irda.sourceforge.net/ */
+#define N_SMSBLOCK     12      /* SMS block mode - for talking to GSM data cards about SMS messages */
+#define N_HDLC         13      /* synchronous HDLC */
+#define N_SYNC_PPP     14
+#define N_HCI          15      /* Bluetooth HCI UART */
+
+#ifdef __KERNEL__
+
+/*     intr=^C         quit=^\         erase=del       kill=^U
+       eof=^D          vtime=\0        vmin=\1         sxtc=\0
+       start=^Q        stop=^S         susp=^Z         eol=\0
+       reprint=^R      discard=^U      werase=^W       lnext=^V
+       eol2=\0
+*/
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+
+/*
+ * Translate a "termio" structure into a "termios". Ugh.
+ */
+
+#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
+       unsigned short __tmp; \
+       get_user(__tmp,&(termio)->x); \
+       *(unsigned short *) &(termios)->x = __tmp; \
+}
+
+#define user_termio_to_kernel_termios(termios, termio) \
+({ \
+       SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
+       SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
+       SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
+       SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
+       copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+})
+
+/*
+ * Translate a "termios" structure into a "termio". Ugh.
+ */
+
+#define kernel_termios_to_user_termio(termio, termios) \
+({ \
+       put_user((termios)->c_iflag, &(termio)->c_iflag); \
+       put_user((termios)->c_oflag, &(termio)->c_oflag); \
+       put_user((termios)->c_cflag, &(termio)->c_cflag); \
+       put_user((termios)->c_lflag, &(termio)->c_lflag); \
+       put_user((termios)->c_line,  &(termio)->c_line); \
+       copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+})
+
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+
+#endif /* __KERNEL__ */
+
+#endif /* _XTENSA_TERMIOS_H */
diff --git a/include/asm-xtensa/thread_info.h b/include/asm-xtensa/thread_info.h
new file mode 100644 (file)
index 0000000..af208d4
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * include/asm-xtensa/thread_info.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_THREAD_INFO_H
+#define _XTENSA_THREAD_INFO_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+# include <asm/processor.h>
+#endif
+
+/*
+ * low level task data that entry.S needs immediate access to
+ * - this struct should fit entirely inside of one cache line
+ * - this struct shares the supervisor stack pages
+ * - if the contents of this structure are changed, the assembly constants
+ *   must also be changed
+ */
+
+#ifndef __ASSEMBLY__
+
+struct thread_info {
+       struct task_struct      *task;          /* main task structure */
+       struct exec_domain      *exec_domain;   /* execution domain */
+       unsigned long           flags;          /* low level flags */
+       unsigned long           status;         /* thread-synchronous flags */
+       __u32                   cpu;            /* current CPU */
+       __s32                   preempt_count;  /* 0 => preemptable,< 0 => BUG*/
+
+       mm_segment_t            addr_limit;     /* thread address space */
+       struct restart_block    restart_block;
+
+
+};
+
+#else /* !__ASSEMBLY__ */
+
+/* offsets into the thread_info struct for assembly code access */
+#define TI_TASK                 0x00000000
+#define TI_EXEC_DOMAIN  0x00000004
+#define TI_FLAGS        0x00000008
+#define TI_STATUS       0x0000000C
+#define TI_CPU          0x00000010
+#define TI_PRE_COUNT    0x00000014
+#define TI_ADDR_LIMIT   0x00000018
+#define TI_RESTART_BLOCK 0x000001C
+
+#endif
+
+#define PREEMPT_ACTIVE         0x10000000
+
+/*
+ * macros/functions for gaining access to the thread information structure
+ *
+ * preempt_count needs to be 1 initially, until the scheduler is functional.
+ */
+
+#ifndef __ASSEMBLY__
+
+#define INIT_THREAD_INFO(tsk)                  \
+{                                              \
+       .task           = &tsk,                 \
+       .exec_domain    = &default_exec_domain, \
+       .flags          = 0,                    \
+       .cpu            = 0,                    \
+       .preempt_count  = 1,                    \
+       .addr_limit     = KERNEL_DS,            \
+       .restart_block = {                      \
+               .fn = do_no_restart_syscall,    \
+       },                                      \
+}
+
+#define init_thread_info       (init_thread_union.thread_info)
+#define init_stack             (init_thread_union.stack)
+
+/* how to get the thread information struct from C */
+static inline struct thread_info *current_thread_info(void)
+{
+       struct thread_info *ti;
+        __asm__("extui %0,a1,0,13\n\t"
+                "xor %0, a1, %0" : "=&r" (ti) : );
+       return ti;
+}
+
+/* thread information allocation */
+#define alloc_thread_info(tsk) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
+#define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
+#define get_thread_info(ti) get_task_struct((ti)->task)
+#define put_thread_info(ti) put_task_struct((ti)->task)
+
+#else /* !__ASSEMBLY__ */
+
+/* how to get the thread information struct from ASM */
+#define GET_THREAD_INFO(reg,sp) \
+       extui reg, sp, 0, 13; \
+       xor   reg, sp, reg
+#endif
+
+
+/*
+ * thread information flags
+ * - these are process state flags that various assembly files may need to access
+ * - pending work-to-be-done flags are in LSW
+ * - other flags in MSW
+ */
+#define TIF_SYSCALL_TRACE      0       /* syscall trace active */
+#define TIF_NOTIFY_RESUME      1       /* resumption notification requested */
+#define TIF_SIGPENDING         2       /* signal pending */
+#define TIF_NEED_RESCHED       3       /* rescheduling necessary */
+#define TIF_SINGLESTEP         4       /* restore singlestep on return to user mode */
+#define TIF_IRET               5       /* return with iret */
+#define TIF_MEMDIE             6
+#define TIF_POLLING_NRFLAG     16      /* true if poll_idle() is polling TIF_NEED_RESCHED */
+
+#define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
+#define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
+#define _TIF_SINGLESTEP                (1<<TIF_SINGLESTEP)
+#define _TIF_IRET              (1<<TIF_IRET)
+#define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
+
+#define _TIF_WORK_MASK         0x0000FFFE      /* work to do on interrupt/exception return */
+#define _TIF_ALLWORK_MASK      0x0000FFFF      /* work to do on any return to u-space */
+
+/*
+ * Thread-synchronous status.
+ *
+ * This is different from the flags in that nobody else
+ * ever touches our thread-synchronous status, so we don't
+ * have to worry about atomic accesses.
+ */
+#define TS_USEDFPU             0x0001  /* FPU was used by this task this quantum (SMP) */
+
+#define THREAD_SIZE 8192       //(2*PAGE_SIZE)
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_THREAD_INFO */
diff --git a/include/asm-xtensa/timex.h b/include/asm-xtensa/timex.h
new file mode 100644 (file)
index 0000000..d14a375
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * include/asm-xtensa/timex.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_TIMEX_H
+#define _XTENSA_TIMEX_H
+
+#ifdef __KERNEL__
+
+#include <asm/processor.h>
+#include <linux/stringify.h>
+
+#if XCHAL_INT_LEVEL(XCHAL_TIMER0_INTERRUPT) == 1
+# define LINUX_TIMER     0
+#elif XCHAL_INT_LEVEL(XCHAL_TIMER1_INTERRUPT) == 1
+# define LINUX_TIMER     1
+#elif XCHAL_INT_LEVEL(XCHAL_TIMER2_INTERRUPT) == 1
+# define LINUX_TIMER     2
+#else
+# error "Bad timer number for Linux configurations!"
+#endif
+
+#define LINUX_TIMER_INT         XCHAL_TIMER_INTERRUPT(LINUX_TIMER)
+#define LINUX_TIMER_MASK        (1L << LINUX_TIMER_INT)
+
+#define CLOCK_TICK_RATE        1193180 /* (everyone is using this value) */
+#define CLOCK_TICK_FACTOR       20 /* Factor of both 10^6 and CLOCK_TICK_RATE */
+#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
+       (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
+               << (SHIFT_SCALE-SHIFT_HZ)) / HZ)
+
+#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
+extern unsigned long ccount_per_jiffy;
+extern unsigned long ccount_nsec;
+#define CCOUNT_PER_JIFFY ccount_per_jiffy
+#define CCOUNT_NSEC ccount_nsec
+#else
+#define CCOUNT_PER_JIFFY (CONFIG_XTENSA_CPU_CLOCK*(1000000UL/HZ))
+#define CCOUNT_NSEC (1000000000UL / CONFIG_XTENSA_CPU_CLOCK)
+#endif
+
+
+typedef unsigned long long cycles_t;
+
+/*
+ * Only used for SMP.
+ */
+
+extern cycles_t cacheflush_time;
+
+#define get_cycles()   (0)
+
+
+/*
+ * Register access.
+ */
+
+#define WSR_CCOUNT(r)    __asm__("wsr %0,"__stringify(CCOUNT) :: "a" (r))
+#define RSR_CCOUNT(r)    __asm__("rsr %0,"__stringify(CCOUNT) : "=a" (r))
+#define WSR_CCOMPARE(x,r) __asm__("wsr %0,"__stringify(CCOMPARE_0)"+"__stringify(x) :: "a"(r))
+#define RSR_CCOMPARE(x,r) __asm__("rsr %0,"__stringify(CCOMPARE_0)"+"__stringify(x) : "=a"(r))
+
+static inline unsigned long get_ccount (void)
+{
+       unsigned long ccount;
+       RSR_CCOUNT(ccount);
+       return ccount;
+}
+
+static inline void set_ccount (unsigned long ccount)
+{
+       WSR_CCOUNT(ccount);
+}
+
+static inline unsigned long get_linux_timer (void)
+{
+       unsigned ccompare;
+       RSR_CCOMPARE(LINUX_TIMER, ccompare);
+       return ccompare;
+}
+
+static inline void set_linux_timer (unsigned long ccompare)
+{
+       WSR_CCOMPARE(LINUX_TIMER, ccompare);
+}
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_TIMEX_H */
diff --git a/include/asm-xtensa/tlb.h b/include/asm-xtensa/tlb.h
new file mode 100644 (file)
index 0000000..4562b2d
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * include/asm-xtensa/tlb.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_TLB_H
+#define _XTENSA_TLB_H
+
+#define tlb_start_vma(tlb,vma)                 do { } while (0)
+#define tlb_end_vma(tlb,vma)                   do { } while (0)
+#define __tlb_remove_tlb_entry(tlb,pte,addr)   do { } while (0)
+
+#define tlb_flush(tlb)                         flush_tlb_mm((tlb)->mm)
+
+#include <asm-generic/tlb.h>
+#include <asm/page.h>
+
+#define __pte_free_tlb(tlb,pte)                        pte_free(pte)
+
+#endif /* _XTENSA_TLB_H */
diff --git a/include/asm-xtensa/tlbflush.h b/include/asm-xtensa/tlbflush.h
new file mode 100644 (file)
index 0000000..23bfe9d
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * include/asm-xtensa/tlbflush.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_TLBFLUSH_H
+#define _XTENSA_TLBFLUSH_H
+
+#define DEBUG_TLB
+
+#ifdef __KERNEL__
+
+#include <asm/processor.h>
+#include <linux/stringify.h>
+
+/* TLB flushing:
+ *
+ *  - flush_tlb_all() flushes all processes TLB entries
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB entries
+ *  - flush_tlb_page(mm, vmaddr) flushes a single page
+ *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ */
+
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct*);
+extern void flush_tlb_page(struct vm_area_struct*,unsigned long);
+extern void flush_tlb_range(struct vm_area_struct*,unsigned long,unsigned long);
+
+#define flush_tlb_kernel_range(start,end) flush_tlb_all()
+
+
+/* This is calld in munmap when we have freed up some page-table pages.
+ * We don't need to do anything here, there's nothing special about our
+ * page-table pages.
+ */
+
+extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+                                      unsigned long start, unsigned long end)
+{
+}
+
+/* TLB operations. */
+
+#define ITLB_WAYS_LOG2      XCHAL_ITLB_WAY_BITS
+#define DTLB_WAYS_LOG2      XCHAL_DTLB_WAY_BITS
+#define ITLB_PROBE_SUCCESS  (1 << ITLB_WAYS_LOG2)
+#define DTLB_PROBE_SUCCESS  (1 << DTLB_WAYS_LOG2)
+
+extern inline unsigned long itlb_probe(unsigned long addr)
+{
+       unsigned long tmp;
+       __asm__ __volatile__("pitlb  %0, %1\n\t" : "=a" (tmp) : "a" (addr));
+       return tmp;
+}
+
+extern inline unsigned long dtlb_probe(unsigned long addr)
+{
+       unsigned long tmp;
+       __asm__ __volatile__("pdtlb  %0, %1\n\t" : "=a" (tmp) : "a" (addr));
+       return tmp;
+}
+
+extern inline void invalidate_itlb_entry (unsigned long probe)
+{
+       __asm__ __volatile__("iitlb  %0; isync\n\t" : : "a" (probe));
+}
+
+extern inline void invalidate_dtlb_entry (unsigned long probe)
+{
+       __asm__ __volatile__("idtlb  %0; dsync\n\t" : : "a" (probe));
+}
+
+/* Use the .._no_isync functions with caution.  Generally, these are
+ * handy for bulk invalidates followed by a single 'isync'.  The
+ * caller must follow up with an 'isync', which can be relatively
+ * expensive on some Xtensa implementations.
+ */
+extern inline void invalidate_itlb_entry_no_isync (unsigned entry)
+{
+       /* Caller must follow up with 'isync'. */
+       __asm__ __volatile__ ("iitlb  %0\n" : : "a" (entry) );
+}
+
+extern inline void invalidate_dtlb_entry_no_isync (unsigned entry)
+{
+       /* Caller must follow up with 'isync'. */
+       __asm__ __volatile__ ("idtlb  %0\n" : : "a" (entry) );
+}
+
+extern inline void set_itlbcfg_register (unsigned long val)
+{
+       __asm__ __volatile__("wsr  %0, "__stringify(ITLBCFG)"\n\t" "isync\n\t"
+                            : : "a" (val));
+}
+
+extern inline void set_dtlbcfg_register (unsigned long val)
+{
+       __asm__ __volatile__("wsr  %0, "__stringify(DTLBCFG)"; dsync\n\t"
+                            : : "a" (val));
+}
+
+extern inline void set_ptevaddr_register (unsigned long val)
+{
+       __asm__ __volatile__(" wsr  %0, "__stringify(PTEVADDR)"; isync\n"
+                            : : "a" (val));
+}
+
+extern inline unsigned long read_ptevaddr_register (void)
+{
+       unsigned long tmp;
+       __asm__ __volatile__("rsr  %0, "__stringify(PTEVADDR)"\n\t" : "=a" (tmp));
+       return tmp;
+}
+
+extern inline void write_dtlb_entry (pte_t entry, int way)
+{
+       __asm__ __volatile__("wdtlb  %1, %0; dsync\n\t"
+                            : : "r" (way), "r" (entry) );
+}
+
+extern inline void write_itlb_entry (pte_t entry, int way)
+{
+       __asm__ __volatile__("witlb  %1, %0; isync\n\t"
+                            : : "r" (way), "r" (entry) );
+}
+
+extern inline void invalidate_page_directory (void)
+{
+       invalidate_dtlb_entry (DTLB_WAY_PGTABLE);
+}
+
+extern inline void invalidate_itlb_mapping (unsigned address)
+{
+       unsigned long tlb_entry;
+       while ((tlb_entry = itlb_probe (address)) & ITLB_PROBE_SUCCESS)
+               invalidate_itlb_entry (tlb_entry);
+}
+
+extern inline void invalidate_dtlb_mapping (unsigned address)
+{
+       unsigned long tlb_entry;
+       while ((tlb_entry = dtlb_probe (address)) & DTLB_PROBE_SUCCESS)
+               invalidate_dtlb_entry (tlb_entry);
+}
+
+#define check_pgt_cache()      do { } while (0)
+
+
+#ifdef DEBUG_TLB
+
+/* DO NOT USE THESE FUNCTIONS.  These instructions aren't part of the Xtensa
+ * ISA and exist only for test purposes..
+ * You may find it helpful for MMU debugging, however.
+ *
+ * 'at' is the unmodified input register
+ * 'as' is the output register, as follows (specific to the Linux config):
+ *
+ *      as[31..12] contain the virtual address
+ *      as[11..08] are meaningless
+ *      as[07..00] contain the asid
+ */
+
+extern inline unsigned long read_dtlb_virtual (int way)
+{
+       unsigned long tmp;
+       __asm__ __volatile__("rdtlb0  %0, %1\n\t" : "=a" (tmp), "+a" (way));
+       return tmp;
+}
+
+extern inline unsigned long read_dtlb_translation (int way)
+{
+       unsigned long tmp;
+       __asm__ __volatile__("rdtlb1  %0, %1\n\t" : "=a" (tmp), "+a" (way));
+       return tmp;
+}
+
+extern inline unsigned long read_itlb_virtual (int way)
+{
+       unsigned long tmp;
+       __asm__ __volatile__("ritlb0  %0, %1\n\t" : "=a" (tmp), "+a" (way));
+       return tmp;
+}
+
+extern inline unsigned long read_itlb_translation (int way)
+{
+       unsigned long tmp;
+       __asm__ __volatile__("ritlb1  %0, %1\n\t" : "=a" (tmp), "+a" (way));
+       return tmp;
+}
+
+#endif /* DEBUG_TLB */
+
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_PGALLOC_H */
diff --git a/include/asm-xtensa/topology.h b/include/asm-xtensa/topology.h
new file mode 100644 (file)
index 0000000..7309e38
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/topology.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_TOPOLOGY_H
+#define _XTENSA_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _XTENSA_TOPOLOGY_H */
diff --git a/include/asm-xtensa/types.h b/include/asm-xtensa/types.h
new file mode 100644 (file)
index 0000000..ebac004
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * include/asm-xtensa/types.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_TYPES_H
+#define _XTENSA_TYPES_H
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned short umode_t;
+
+/*
+ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+ * header files exported to user space
+ */
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef __signed__ long long __s64;
+typedef unsigned long long __u64;
+#endif
+
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+
+typedef __signed__ char s8;
+typedef unsigned char u8;
+
+typedef __signed__ short s16;
+typedef unsigned short u16;
+
+typedef __signed__ int s32;
+typedef unsigned int u32;
+
+typedef __signed__ long long s64;
+typedef unsigned long long u64;
+
+
+#define BITS_PER_LONG 32
+
+/* Dma addresses are 32-bits wide.  */
+
+typedef u32 dma_addr_t;
+
+typedef unsigned int kmem_bufctl_t;
+
+#endif /* __KERNEL__ */
+#endif
+
+#endif /* _XTENSA_TYPES_H */
diff --git a/include/asm-xtensa/uaccess.h b/include/asm-xtensa/uaccess.h
new file mode 100644 (file)
index 0000000..35576b2
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ * include/asm-xtensa/uaccess.h
+ *
+ * User space memory access functions
+ *
+ * These routines provide basic accessing functions to the user memory
+ * space for the kernel. This header file provides fuctions such as:
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_UACCESS_H
+#define _XTENSA_UACCESS_H
+
+#include <linux/errno.h>
+
+#define VERIFY_READ    0
+#define VERIFY_WRITE   1
+
+#ifdef __ASSEMBLY__
+
+#define _ASMLANGUAGE
+#include <asm/current.h>
+#include <asm/offsets.h>
+#include <asm/processor.h>
+
+/*
+ * These assembly macros mirror the C macros that follow below.  They
+ * should always have identical functionality.  See
+ * arch/xtensa/kernel/sys.S for usage.
+ */
+
+#define KERNEL_DS      0
+#define USER_DS                1
+
+#define get_ds         (KERNEL_DS)
+
+/*
+ * get_fs reads current->thread.current_ds into a register.
+ * On Entry:
+ *     <ad>    anything
+ *     <sp>    stack
+ * On Exit:
+ *     <ad>    contains current->thread.current_ds
+ */
+       .macro  get_fs  ad, sp
+       GET_CURRENT(\ad,\sp)
+       l32i    \ad, \ad, THREAD_CURRENT_DS
+       .endm
+
+/*
+ * set_fs sets current->thread.current_ds to some value.
+ * On Entry:
+ *     <at>    anything (temp register)
+ *     <av>    value to write
+ *     <sp>    stack
+ * On Exit:
+ *     <at>    destroyed (actually, current)
+ *     <av>    preserved, value to write
+ */
+       .macro  set_fs  at, av, sp
+       GET_CURRENT(\at,\sp)
+       s32i    \av, \at, THREAD_CURRENT_DS
+       .endm
+
+/*
+ * kernel_ok determines whether we should bypass addr/size checking.
+ * See the equivalent C-macro version below for clarity.
+ * On success, kernel_ok branches to a label indicated by parameter
+ * <success>.  This implies that the macro falls through to the next
+ * insruction on an error.
+ *
+ * Note that while this macro can be used independently, we designed
+ * in for optimal use in the access_ok macro below (i.e., we fall
+ * through on error).
+ *
+ * On Entry:
+ *     <at>            anything (temp register)
+ *     <success>       label to branch to on success; implies
+ *                     fall-through macro on error
+ *     <sp>            stack pointer
+ * On Exit:
+ *     <at>            destroyed (actually, current->thread.current_ds)
+ */
+
+#if ((KERNEL_DS != 0) || (USER_DS == 0))
+# error Assembly macro kernel_ok fails
+#endif
+       .macro  kernel_ok  at, sp, success
+       get_fs  \at, \sp
+       beqz    \at, \success
+       .endm
+
+/*
+ * user_ok determines whether the access to user-space memory is allowed.
+ * See the equivalent C-macro version below for clarity.
+ *
+ * On error, user_ok branches to a label indicated by parameter
+ * <error>.  This implies that the macro falls through to the next
+ * instruction on success.
+ *
+ * Note that while this macro can be used independently, we designed
+ * in for optimal use in the access_ok macro below (i.e., we fall
+ * through on success).
+ *
+ * On Entry:
+ *     <aa>    register containing memory address
+ *     <as>    register containing memory size
+ *     <at>    temp register
+ *     <error> label to branch to on error; implies fall-through
+ *             macro on success
+ * On Exit:
+ *     <aa>    preserved
+ *     <as>    preserved
+ *     <at>    destroyed (actually, (TASK_SIZE + 1 - size))
+ */
+       .macro  user_ok aa, as, at, error
+       movi    \at, (TASK_SIZE+1)
+       bgeu    \as, \at, \error
+       sub     \at, \at, \as
+       bgeu    \aa, \at, \error
+       .endm
+
+/*
+ * access_ok determines whether a memory access is allowed.  See the
+ * equivalent C-macro version below for clarity.
+ *
+ * On error, access_ok branches to a label indicated by parameter
+ * <error>.  This implies that the macro falls through to the next
+ * instruction on success.
+ *
+ * Note that we assume success is the common case, and we optimize the
+ * branch fall-through case on success.
+ *
+ * On Entry:
+ *     <aa>    register containing memory address
+ *     <as>    register containing memory size
+ *     <at>    temp register
+ *     <sp>
+ *     <error> label to branch to on error; implies fall-through
+ *             macro on success
+ * On Exit:
+ *     <aa>    preserved
+ *     <as>    preserved
+ *     <at>    destroyed
+ */
+       .macro  access_ok  aa, as, at, sp, error
+       kernel_ok  \at, \sp, .Laccess_ok_\@
+       user_ok    \aa, \as, \at, \error
+.Laccess_ok_\@:
+       .endm
+
+/*
+ * verify_area determines whether a memory access is allowed.  It's
+ * mostly an unnecessary wrapper for access_ok, but we provide it as a
+ * duplicate of the verify_area() C inline function below.  See the
+ * equivalent C version below for clarity.
+ *
+ * On error, verify_area branches to a label indicated by parameter
+ * <error>.  This implies that the macro falls through to the next
+ * instruction on success.
+ *
+ * Note that we assume success is the common case, and we optimize the
+ * branch fall-through case on success.
+ *
+ * On Entry:
+ *     <aa>    register containing memory address
+ *     <as>    register containing memory size
+ *     <at>    temp register
+ *     <error> label to branch to on error; implies fall-through
+ *             macro on success
+ * On Exit:
+ *     <aa>    preserved
+ *     <as>    preserved
+ *     <at>    destroyed
+ */
+       .macro  verify_area     aa, as, at, sp, error
+       access_ok  \at, \aa, \as, \sp, \error
+       .endm
+
+
+#else /* __ASSEMBLY__ not defined */
+
+#include <linux/sched.h>
+#include <asm/types.h>
+
+/*
+ * The fs value determines whether argument validity checking should
+ * be performed or not.  If get_fs() == USER_DS, checking is
+ * performed, with get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons (Data Segment Register?), these macros are
+ * grossly misnamed.
+ */
+
+#define KERNEL_DS      ((mm_segment_t) { 0 })
+#define USER_DS                ((mm_segment_t) { 1 })
+
+#define get_ds()       (KERNEL_DS)
+#define get_fs()       (current->thread.current_ds)
+#define set_fs(val)    (current->thread.current_ds = (val))
+
+#define segment_eq(a,b)        ((a).seg == (b).seg)
+
+#define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
+#define __user_ok(addr,size) (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size)))
+#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
+#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
+
+extern inline int verify_area(int type, const void * addr, unsigned long size)
+{
+       return access_ok(type,addr,size) ? 0 : -EFAULT;
+}
+
+/*
+ * These are the main single-value transfer routines.  They
+ * automatically use the right size if we just have the right pointer
+ * type.
+ *
+ * This gets kind of ugly. We want to return _two_ values in
+ * "get_user()" and yet we don't want to do any pointers, because that
+ * is too much of a performance impact. Thus we have a few rather ugly
+ * macros here, and hide all the uglyness from the user.
+ *
+ * Careful to not
+ * (a) re-use the arguments for side effects (sizeof is ok)
+ * (b) require any knowledge of processes at this stage
+ */
+#define put_user(x,ptr)        __put_user_check((x),(ptr),sizeof(*(ptr)))
+#define get_user(x,ptr) __get_user_check((x),(ptr),sizeof(*(ptr)))
+
+/*
+ * The "__xxx" versions of the user access functions are versions that
+ * do not verify the address space, that must have been done previously
+ * with a separate "access_ok()" call (this is used when we do multiple
+ * accesses to the same area of user memory).
+ */
+#define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
+#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+
+
+extern long __put_user_bad(void);
+
+#define __put_user_nocheck(x,ptr,size)                 \
+({                                                     \
+       long __pu_err;                                  \
+       __put_user_size((x),(ptr),(size),__pu_err);     \
+       __pu_err;                                       \
+})
+
+#define __put_user_check(x,ptr,size)                           \
+({                                                             \
+       long __pu_err = -EFAULT;                                \
+       __typeof__(*(ptr)) *__pu_addr = (ptr);                  \
+       if (access_ok(VERIFY_WRITE,__pu_addr,size))             \
+               __put_user_size((x),__pu_addr,(size),__pu_err); \
+       __pu_err;                                               \
+})
+
+#define __put_user_size(x,ptr,size,retval)                     \
+do {                                                           \
+       retval = 0;                                             \
+       switch (size) {                                         \
+        case 1: __put_user_asm(x,ptr,retval,1,"s8i");  break;  \
+        case 2: __put_user_asm(x,ptr,retval,2,"s16i"); break;   \
+        case 4: __put_user_asm(x,ptr,retval,4,"s32i"); break;   \
+        case 8: {                                              \
+                    __typeof__(*ptr) __v64 = x;                \
+                    retval = __copy_to_user(ptr,&__v64,8);     \
+                    break;                                     \
+               }                                               \
+       default: __put_user_bad();                              \
+       }                                                       \
+} while (0)
+
+
+/*
+ * Consider a case of a user single load/store would cause both an
+ * unaligned exception and an MMU-related exception (unaligned
+ * exceptions happen first):
+ *
+ * User code passes a bad variable ptr to a system call.
+ * Kernel tries to access the variable.
+ * Unaligned exception occurs.
+ * Unaligned exception handler tries to make aligned accesses.
+ * Double exception occurs for MMU-related cause (e.g., page not mapped).
+ * do_page_fault() thinks the fault address belongs to the kernel, not the
+ * user, and panics.
+ *
+ * The kernel currently prohibits user unaligned accesses.  We use the
+ * __check_align_* macros to check for unaligned addresses before
+ * accessing user space so we don't crash the kernel.  Both
+ * __put_user_asm and __get_user_asm use these alignment macros, so
+ * macro-specific labels such as 0f, 1f, %0, %2, and %3 must stay in
+ * sync.
+ */
+
+#define __check_align_1  ""
+
+#define __check_align_2                                \
+       "   _bbci.l %2,  0, 1f          \n"     \
+       "   movi    %0, %3              \n"     \
+       "   _j      2f                  \n"
+
+#define __check_align_4                                \
+       "   _bbsi.l %2,  0, 0f          \n"     \
+       "   _bbci.l %2,  1, 1f          \n"     \
+       "0: movi    %0, %3              \n"     \
+       "   _j      2f                  \n"
+
+
+/*
+ * We don't tell gcc that we are accessing memory, but this is OK
+ * because we do not write to any memory gcc knows about, so there
+ * are no aliasing issues.
+ *
+ * WARNING: If you modify this macro at all, verify that the
+ * __check_align_* macros still work.
+ */
+#define __put_user_asm(x, addr, err, align, insn) \
+   __asm__ __volatile__(                       \
+       __check_align_##align                   \
+       "1: "insn"  %1, %2, 0           \n"     \
+       "2:                             \n"     \
+       "   .section  .fixup,\"ax\"     \n"     \
+       "   .align 4                    \n"     \
+       "4:                             \n"     \
+       "   .long  2b                   \n"     \
+       "5:                             \n"     \
+       "   l32r   %2, 4b               \n"     \
+        "   movi   %0, %3              \n"     \
+        "   jx     %2                  \n"     \
+       "   .previous                   \n"     \
+       "   .section  __ex_table,\"a\"  \n"     \
+       "   .long       1b, 5b          \n"     \
+       "   .previous"                          \
+       :"=r" (err)                             \
+       :"r" ((int)(x)), "r" (addr), "i" (-EFAULT), "0" (err))
+
+#define __get_user_nocheck(x,ptr,size)                         \
+({                                                             \
+       long __gu_err, __gu_val;                                \
+       __get_user_size(__gu_val,(ptr),(size),__gu_err);        \
+       (x) = (__typeof__(*(ptr)))__gu_val;                     \
+       __gu_err;                                               \
+})
+
+#define __get_user_check(x,ptr,size)                                   \
+({                                                                     \
+       long __gu_err = -EFAULT, __gu_val = 0;                          \
+       const __typeof__(*(ptr)) *__gu_addr = (ptr);                    \
+       if (access_ok(VERIFY_READ,__gu_addr,size))                      \
+               __get_user_size(__gu_val,__gu_addr,(size),__gu_err);    \
+       (x) = (__typeof__(*(ptr)))__gu_val;                             \
+       __gu_err;                                                       \
+})
+
+extern long __get_user_bad(void);
+
+#define __get_user_size(x,ptr,size,retval)                             \
+do {                                                                   \
+       retval = 0;                                                     \
+        switch (size) {                                                        \
+          case 1: __get_user_asm(x,ptr,retval,1,"l8ui");  break;       \
+          case 2: __get_user_asm(x,ptr,retval,2,"l16ui"); break;       \
+          case 4: __get_user_asm(x,ptr,retval,4,"l32i");  break;       \
+          case 8: retval = __copy_from_user(&x,ptr,8);    break;       \
+          default: (x) = __get_user_bad();                             \
+        }                                                              \
+} while (0)
+
+
+/*
+ * WARNING: If you modify this macro at all, verify that the
+ * __check_align_* macros still work.
+ */
+#define __get_user_asm(x, addr, err, align, insn) \
+   __asm__ __volatile__(                       \
+       __check_align_##align                   \
+       "1: "insn"  %1, %2, 0           \n"     \
+       "2:                             \n"     \
+       "   .section  .fixup,\"ax\"     \n"     \
+       "   .align 4                    \n"     \
+       "4:                             \n"     \
+       "   .long  2b                   \n"     \
+       "5:                             \n"     \
+       "   l32r   %2, 4b               \n"     \
+       "   movi   %1, 0                \n"     \
+        "   movi   %0, %3              \n"     \
+        "   jx     %2                  \n"     \
+       "   .previous                   \n"     \
+       "   .section  __ex_table,\"a\"  \n"     \
+       "   .long       1b, 5b          \n"     \
+       "   .previous"                          \
+       :"=r" (err), "=r" (x)                   \
+       :"r" (addr), "i" (-EFAULT), "0" (err))
+
+
+/*
+ * Copy to/from user space
+ */
+
+/*
+ * We use a generic, arbitrary-sized copy subroutine.  The Xtensa
+ * architecture would cause heavy code bloat if we tried to inline
+ * these functions and provide __constant_copy_* equivalents like the
+ * i386 versions.  __xtensa_copy_user is quite efficient.  See the
+ * .fixup section of __xtensa_copy_user for a discussion on the
+ * X_zeroing equivalents for Xtensa.
+ */
+
+extern unsigned __xtensa_copy_user(void *to, const void *from, unsigned n);
+#define __copy_user(to,from,size) __xtensa_copy_user(to,from,size)
+
+
+static inline unsigned long
+__generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n)
+{
+       return __copy_user(to,from,n);
+}
+
+static inline unsigned long
+__generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n)
+{
+       return __copy_user(to,from,n);
+}
+
+static inline unsigned long
+__generic_copy_to_user(void *to, const void *from, unsigned long n)
+{
+       prefetch(from);
+       if (access_ok(VERIFY_WRITE, to, n))
+               return __copy_user(to,from,n);
+       return n;
+}
+
+static inline unsigned long
+__generic_copy_from_user(void *to, const void *from, unsigned long n)
+{
+       prefetchw(to);
+       if (access_ok(VERIFY_READ, from, n))
+               return __copy_user(to,from,n);
+       else
+               memset(to, 0, n);
+       return n;
+}
+
+#define copy_to_user(to,from,n) __generic_copy_to_user((to),(from),(n))
+#define copy_from_user(to,from,n) __generic_copy_from_user((to),(from),(n))
+#define __copy_to_user(to,from,n) __generic_copy_to_user_nocheck((to),(from),(n))
+#define __copy_from_user(to,from,n) __generic_copy_from_user_nocheck((to),(from),(n))
+#define __copy_to_user_inatomic __copy_to_user
+#define __copy_from_user_inatomic __copy_from_user
+
+
+/*
+ * We need to return the number of bytes not cleared.  Our memset()
+ * returns zero if a problem occurs while accessing user-space memory.
+ * In that event, return no memory cleared.  Otherwise, zero for
+ * success.
+ */
+
+extern inline unsigned long
+__xtensa_clear_user(void *addr, unsigned long size)
+{
+       if ( ! memset(addr, 0, size) )
+               return size;
+       return 0;
+}
+
+extern inline unsigned long
+clear_user(void *addr, unsigned long size)
+{
+       if (access_ok(VERIFY_WRITE, addr, size))
+               return __xtensa_clear_user(addr, size);
+       return size ? -EFAULT : 0;
+}
+
+#define __clear_user  __xtensa_clear_user
+
+
+extern long __strncpy_user(char *, const char *, long);
+#define __strncpy_from_user __strncpy_user
+
+extern inline long
+strncpy_from_user(char *dst, const char *src, long count)
+{
+       if (access_ok(VERIFY_READ, src, 1))
+               return __strncpy_from_user(dst, src, count);
+       return -EFAULT;
+}
+
+
+#define strlen_user(str) strnlen_user((str), TASK_SIZE - 1)
+
+/*
+ * Return the size of a string (including the ending 0!)
+ */
+extern long __strnlen_user(const char *, long);
+
+extern inline long strnlen_user(const char *str, long len)
+{
+       unsigned long top = __kernel_ok ? ~0UL : TASK_SIZE - 1;
+
+       if ((unsigned long)str > top)
+               return 0;
+       return __strnlen_user(str, len);
+}
+
+
+struct exception_table_entry
+{
+       unsigned long insn, fixup;
+};
+
+/* Returns 0 if exception not found and fixup.unit otherwise.  */
+
+extern unsigned long search_exception_table(unsigned long addr);
+extern void sort_exception_table(void);
+
+/* Returns the new pc */
+#define fixup_exception(map_reg, fixup_unit, pc)                \
+({                                                              \
+       fixup_unit;                                             \
+})
+
+#endif /* __ASSEMBLY__ */
+#endif /* _XTENSA_UACCESS_H */
diff --git a/include/asm-xtensa/ucontext.h b/include/asm-xtensa/ucontext.h
new file mode 100644 (file)
index 0000000..94c94ed
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * include/asm-xtensa/ucontext.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_UCONTEXT_H
+#define _XTENSA_UCONTEXT_H
+
+struct ucontext {
+       unsigned long     uc_flags;
+       struct ucontext  *uc_link;
+       stack_t           uc_stack;
+       struct sigcontext uc_mcontext;
+       sigset_t          uc_sigmask;   /* mask last for extensibility */
+};
+
+#endif /* _XTENSA_UCONTEXT_H */
diff --git a/include/asm-xtensa/unaligned.h b/include/asm-xtensa/unaligned.h
new file mode 100644 (file)
index 0000000..2822089
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * include/asm-xtensa/unaligned.h
+ *
+ * Xtensa doesn't handle unaligned accesses efficiently.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_UNALIGNED_H
+#define _XTENSA_UNALIGNED_H
+
+#include <linux/string.h>
+
+/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
+
+#define get_unaligned(ptr) \
+  ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
+
+#define put_unaligned(val, ptr)                                \
+  ({ __typeof__(*(ptr)) __tmp = (val);                 \
+     memmove((ptr), &__tmp, sizeof(*(ptr)));           \
+     (void)0; })
+
+#endif /* _XTENSA_UNALIGNED_H */
diff --git a/include/asm-xtensa/unistd.h b/include/asm-xtensa/unistd.h
new file mode 100644 (file)
index 0000000..64c64dd
--- /dev/null
@@ -0,0 +1,537 @@
+/*
+ * include/asm-xtensa/unistd.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_UNISTD_H
+#define _XTENSA_UNISTD_H
+
+#include <linux/linkage.h>
+
+//#define __NR_setup             0 /* used only by init, to get system going */
+#define __NR_spill               0
+#define __NR_exit                1
+#define __NR_fork                2
+#define __NR_read                3
+#define __NR_write               4
+#define __NR_open                5
+#define __NR_close               6
+#define __NR_waitpid             7
+#define __NR_creat               8
+#define __NR_link                9
+#define __NR_unlink             10
+#define __NR_execve             11
+#define __NR_chdir              12
+#define __NR_time               13
+#define __NR_mknod              14
+#define __NR_chmod              15
+#define __NR_lchown             16
+#define __NR_break              17
+#define __NR_oldstat            18
+#define __NR_lseek              19
+#define __NR_getpid             20
+#define __NR_mount              21
+#define __NR_oldumount          22
+#define __NR_setuid             23
+#define __NR_getuid             24
+#define __NR_stime              25
+#define __NR_ptrace             26
+#define __NR_alarm              27
+#define __NR_oldfstat           28
+#define __NR_pause              29
+#define __NR_utime              30
+#define __NR_stty               31
+#define __NR_gtty               32
+#define __NR_access             33
+#define __NR_nice               34
+#define __NR_ftime              35
+#define __NR_sync               36
+#define __NR_kill               37
+#define __NR_rename             38
+#define __NR_mkdir              39
+#define __NR_rmdir              40
+#define __NR_dup                41
+#define __NR_pipe               42
+#define __NR_times              43
+#define __NR_prof               44
+#define __NR_brk                45
+#define __NR_setgid             46
+#define __NR_getgid             47
+#define __NR_signal             48
+#define __NR_geteuid            49
+#define __NR_getegid            50
+#define __NR_acct               51
+#define __NR_umount             52
+#define __NR_lock               53
+#define __NR_ioctl              54
+#define __NR_fcntl              55
+#define __NR_mpx                56
+#define __NR_setpgid            57
+#define __NR_ulimit             58
+#define __NR_oldolduname        59
+#define __NR_umask              60
+#define __NR_chroot             61
+#define __NR_ustat              62
+#define __NR_dup2               63
+#define __NR_getppid            64
+#define __NR_getpgrp            65
+#define __NR_setsid             66
+#define __NR_sigaction          67
+#define __NR_sgetmask           68
+#define __NR_ssetmask           69
+#define __NR_setreuid           70
+#define __NR_setregid           71
+#define __NR_sigsuspend                 72
+#define __NR_sigpending                 73
+#define __NR_sethostname        74
+#define __NR_setrlimit          75
+#define __NR_getrlimit          76     /* Back compatible 2Gig limited rlimit */
+#define __NR_getrusage          77
+#define __NR_gettimeofday       78
+#define __NR_settimeofday       79
+#define __NR_getgroups          80
+#define __NR_setgroups          81
+#define __NR_select             82
+#define __NR_symlink            83
+#define __NR_oldlstat           84
+#define __NR_readlink           85
+#define __NR_uselib             86
+#define __NR_swapon             87
+#define __NR_reboot             88
+#define __NR_readdir            89
+#define __NR_mmap               90
+#define __NR_munmap             91
+#define __NR_truncate           92
+#define __NR_ftruncate          93
+#define __NR_fchmod             94
+#define __NR_fchown             95
+#define __NR_getpriority        96
+#define __NR_setpriority        97
+#define __NR_profil             98
+#define __NR_statfs             99
+#define __NR_fstatfs           100
+#define __NR_ioperm            101
+#define __NR_socketcall                102
+#define __NR_syslog            103
+#define __NR_setitimer         104
+#define __NR_getitimer         105
+#define __NR_stat              106
+#define __NR_lstat             107
+#define __NR_fstat             108
+#define __NR_olduname          109
+#define __NR_iopl              110
+#define __NR_vhangup           111
+#define __NR_idle              112
+#define __NR_vm86              113
+#define __NR_wait4             114
+#define __NR_swapoff           115
+#define __NR_sysinfo           116
+#define __NR_ipc               117
+#define __NR_fsync             118
+#define __NR_sigreturn         119
+#define __NR_clone             120
+#define __NR_setdomainname     121
+#define __NR_uname             122
+#define __NR_modify_ldt                123
+#define __NR_adjtimex          124
+#define __NR_mprotect          125
+#define __NR_sigprocmask       126
+#define __NR_create_module     127
+#define __NR_init_module       128
+#define __NR_delete_module     129
+#define __NR_get_kernel_syms   130
+#define __NR_quotactl          131
+#define __NR_getpgid           132
+#define __NR_fchdir            133
+#define __NR_bdflush           134
+#define __NR_sysfs             135
+#define __NR_personality       136
+#define __NR_afs_syscall       137 /* Syscall for Andrew File System */
+#define __NR_setfsuid          138
+#define __NR_setfsgid          139
+#define __NR__llseek           140
+#define __NR_getdents          141
+#define __NR__newselect                142
+#define __NR_flock             143
+#define __NR_msync             144
+#define __NR_readv             145
+#define __NR_writev            146
+#define __NR_cacheflush         147
+#define __NR_cachectl           148
+#define __NR_sysxtensa          149
+#define __NR_sysdummy           150
+#define __NR_getsid            151
+#define __NR_fdatasync         152
+#define __NR__sysctl           153
+#define __NR_mlock             154
+#define __NR_munlock           155
+#define __NR_mlockall          156
+#define __NR_munlockall                157
+#define __NR_sched_setparam            158
+#define __NR_sched_getparam            159
+#define __NR_sched_setscheduler                160
+#define __NR_sched_getscheduler                161
+#define __NR_sched_yield               162
+#define __NR_sched_get_priority_max    163
+#define __NR_sched_get_priority_min    164
+#define __NR_sched_rr_get_interval     165
+#define __NR_nanosleep         166
+#define __NR_mremap            167
+#define __NR_accept             168
+#define __NR_bind               169
+#define __NR_connect            170
+#define __NR_getpeername        171
+#define __NR_getsockname        172
+#define __NR_getsockopt         173
+#define __NR_listen             174
+#define __NR_recv               175
+#define __NR_recvfrom           176
+#define __NR_recvmsg            177
+#define __NR_send               178
+#define __NR_sendmsg            179
+#define __NR_sendto             180
+#define __NR_setsockopt         181
+#define __NR_shutdown           182
+#define __NR_socket             183
+#define __NR_socketpair         184
+#define __NR_setresuid         185
+#define __NR_getresuid         186
+#define __NR_query_module      187
+#define __NR_poll              188
+#define __NR_nfsservctl                189
+#define __NR_setresgid         190
+#define __NR_getresgid         191
+#define __NR_prctl              192
+#define __NR_rt_sigreturn      193
+#define __NR_rt_sigaction      194
+#define __NR_rt_sigprocmask    195
+#define __NR_rt_sigpending     196
+#define __NR_rt_sigtimedwait   197
+#define __NR_rt_sigqueueinfo   198
+#define __NR_rt_sigsuspend     199
+#define __NR_pread             200
+#define __NR_pwrite            201
+#define __NR_chown             202
+#define __NR_getcwd            203
+#define __NR_capget            204
+#define __NR_capset            205
+#define __NR_sigaltstack       206
+#define __NR_sendfile          207
+#define __NR_streams1          208     /* some people actually want it */
+#define __NR_streams2          209     /* some people actually want it */
+#define __NR_mmap2             210
+#define __NR_truncate64                211
+#define __NR_ftruncate64       212
+#define __NR_stat64            213
+#define __NR_lstat64           214
+#define __NR_fstat64           215
+#define __NR_pivot_root                216
+#define __NR_mincore           217
+#define __NR_madvise           218
+#define __NR_getdents64                219
+#define __NR_vfork             220
+
+/* Keep this last; should always equal the last valid call number. */
+#define __NR_Linux_syscalls     220
+
+/* user-visible error numbers are in the range -1 - -125: see
+ * <asm-xtensa/errno.h> */
+
+#define SYSXTENSA_RESERVED        0    /* don't use this */
+#define SYSXTENSA_ATOMIC_SET      1    /* set variable */
+#define SYSXTENSA_ATOMIC_EXG_ADD   2   /* exchange memory and add */
+#define SYSXTENSA_ATOMIC_ADD      3    /* add to memory */
+#define SYSXTENSA_ATOMIC_CMP_SWP   4   /* compare and swap */
+
+#define SYSXTENSA_COUNT                   5    /* count of syscall0 functions*/
+
+#ifdef __KERNEL__
+#define __syscall_return(type, res) return ((type)(res))
+#else
+#define __syscall_return(type, res) \
+do { \
+       if ((unsigned long)(res) >= (unsigned long)(-125)) { \
+       /* Avoid using "res" which is declared to be in register r2; \
+        * errno might expand to a function call and clobber it.  */ \
+               int __err = -(res); \
+               errno = __err; \
+               res = -1; \
+       } \
+       return (type) (res); \
+} while (0)
+#endif
+
+
+/* Tensilica's xt-xcc compiler is much more agressive at code
+ * optimization than gcc.  Multiple __asm__ statements are
+ * insufficient for xt-xcc because subsequent optimization passes
+ * (beyond the front-end that knows of __asm__ statements and other
+ * such GNU Extensions to C) can modify the register selection for
+ * containment of C variables.
+ *
+ * xt-xcc cannot modify the contents of a single __asm__ statement, so
+ * we create single-asm versions of the syscall macros that are
+ * suitable and optimal for both xt-xcc and gcc.
+ *
+ * Linux takes system-call arguments in registers.  The following
+ * design is optimized for user-land apps (e.g., glibc) which
+ * typically have a function wrapper around the "syscall" assembly
+ * instruction.  It satisfies the Xtensa ABI while minizing argument
+ * shifting.
+ *
+ * The Xtensa ABI and software conventions require the system-call
+ * number in a2.  If an argument exists in a2, we move it to the next
+ * available register.  Note that for improved efficiency, we do NOT
+ * shift all parameters down one register to maintain the original
+ * order.
+ *
+ * At best case (zero arguments), we just write the syscall number to
+ * a2.  At worst case (1 to 6 arguments), we move the argument in a2
+ * to the next available register, then write the syscall number to
+ * a2.
+ *
+ * For clarity, the following truth table enumerates all possibilities.
+ *
+ * arguments   syscall number  arg0, arg1, arg2, arg3, arg4, arg5
+ * ---------   --------------  ----------------------------------
+ *     0             a2
+ *     1             a2        a3
+ *     2             a2        a4,   a3
+ *     3             a2        a5,   a3,   a4
+ *     4             a2        a6,   a3,   a4,   a5
+ *     5             a2        a7,   a3,   a4,   a5,   a6
+ *     6             a2        a8,   a3,   a4,   a5,   a6,   a7
+ */
+
+#define _syscall0(type,name) \
+type name(void) \
+{ \
+long __res; \
+__asm__ __volatile__ ( \
+       "  movi  a2, %1 \n" \
+       "  syscall      \n" \
+       "  mov   %0, a2 \n" \
+       : "=a" (__res) \
+       : "i" (__NR_##name) \
+       : "a2" \
+       ); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall1(type,name,type0,arg0) \
+type name(type0 arg0) \
+{ \
+long __res; \
+__asm__ __volatile__ ( \
+       "  mov   a3, %2 \n" \
+       "  movi  a2, %1 \n" \
+       "  syscall      \n" \
+       "  mov   %0, a2 \n" \
+       : "=a" (__res) \
+       : "i" (__NR_##name), "a" (arg0) \
+       : "a2", "a3" \
+       ); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall2(type,name,type0,arg0,type1,arg1) \
+type name(type0 arg0,type1 arg1) \
+{ \
+long __res; \
+__asm__ __volatile__ ( \
+       "  mov   a4, %2 \n" \
+       "  mov   a3, %3 \n" \
+       "  movi  a2, %1 \n" \
+       "  syscall      \n" \
+       "  mov   %0, a2 \n" \
+       : "=a" (__res) \
+       : "i" (__NR_##name), "a" (arg0), "a" (arg1) \
+       : "a2", "a3", "a4" \
+       ); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall3(type,name,type0,arg0,type1,arg1,type2,arg2) \
+type name(type0 arg0,type1 arg1,type2 arg2) \
+{ \
+long __res; \
+__asm__ __volatile__ ( \
+       "  mov   a5, %2 \n" \
+       "  mov   a4, %4 \n" \
+       "  mov   a3, %3 \n" \
+       "  movi  a2, %1 \n" \
+       "  syscall      \n" \
+       "  mov   %0, a2 \n" \
+       : "=a" (__res) \
+       : "i" (__NR_##name), "a" (arg0), "a" (arg1), "a" (arg2) \
+       : "a2", "a3", "a4", "a5" \
+       ); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall4(type,name,type0,arg0,type1,arg1,type2,arg2,type3,arg3) \
+type name(type0 arg0,type1 arg1,type2 arg2,type3 arg3) \
+{ \
+long __res; \
+__asm__ __volatile__ ( \
+       "  mov   a6, %2 \n" \
+       "  mov   a5, %5 \n" \
+       "  mov   a4, %4 \n" \
+       "  mov   a3, %3 \n" \
+       "  movi  a2, %1 \n" \
+       "  syscall      \n" \
+       "  mov   %0, a2 \n" \
+       : "=a" (__res) \
+       : "i" (__NR_##name), "a" (arg0), "a" (arg1), "a" (arg2), "a" (arg3) \
+       : "a2", "a3", "a4", "a5", "a6" \
+       ); \
+__syscall_return(type,__res); \
+}
+
+/* Note that we save and restore the a7 frame pointer.
+ * Including a7 in the clobber list doesn't do what you'd expect.
+ */
+#define _syscall5(type,name,type0,arg0,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
+type name(type0 arg0,type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
+{ \
+long __res; \
+__asm__ __volatile__ ( \
+       "  mov   a9, a7 \n" \
+       "  mov   a7, %2 \n" \
+       "  mov   a6, %6 \n" \
+       "  mov   a5, %5 \n" \
+       "  mov   a4, %4 \n" \
+       "  mov   a3, %3 \n" \
+       "  movi  a2, %1 \n" \
+       "  syscall      \n" \
+       "  mov   a7, a9 \n" \
+       "  mov   %0, a2 \n" \
+       : "=a" (__res) \
+       : "i" (__NR_##name), "a" (arg0), "a" (arg1), "a" (arg2), \
+                             "a" (arg3), "a" (arg4) \
+       : "a2", "a3", "a4", "a5", "a6", "a9" \
+       ); \
+__syscall_return(type,__res); \
+}
+
+/* Note that we save and restore the a7 frame pointer.
+ * Including a7 in the clobber list doesn't do what you'd expect.
+ */
+#define _syscall6(type,name,type0,arg0,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
+type name(type0 arg0,type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
+{ \
+long __res; \
+__asm__ __volatile__ ( \
+       "  mov   a9, a7 \n" \
+       "  mov   a8, %2 \n" \
+       "  mov   a7, %7 \n" \
+       "  mov   a6, %6 \n" \
+       "  mov   a5, %5 \n" \
+       "  mov   a4, %4 \n" \
+       "  mov   a3, %3 \n" \
+       "  movi  a2, %1 \n" \
+       "  syscall      \n" \
+       "  mov   a7, a9 \n" \
+       "  mov   %0, a2 \n" \
+       : "=a" (__res) \
+       : "i" (__NR_##name), "a" (arg0), "a" (arg1), "a" (arg2), \
+                             "a" (arg3), "a" (arg4), "a" (arg5)  \
+       : "a2", "a3", "a4", "a5", "a6", "a8", "a9" \
+       ); \
+__syscall_return(type,__res); \
+}
+
+
+#ifdef __KERNEL_SYSCALLS__
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/syscalls.h>
+
+/*
+ * we need this inline - forking from kernel space will result
+ * in NO COPY ON WRITE (!!!), until an execve is executed. This
+ * is no problem, but for the stack. This is handled by not letting
+ * main() use the stack at all after fork(). Thus, no function
+ * calls - which means inline code for fork too, as otherwise we
+ * would use the stack upon exit from 'fork()'.
+ *
+ * Actually only pause and fork are needed inline, so that there
+ * won't be any messing with the stack from main(), but we define
+ * some others too.
+ */
+
+#define __NR__exit __NR_exit
+
+static __inline__ _syscall0(int,pause)
+//static __inline__ _syscall1(int,setup,int,magic) FIXME
+static __inline__ _syscall0(int,sync)
+static __inline__ _syscall0(pid_t,setsid)
+static __inline__ _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count)
+static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+static __inline__ _syscall1(int,dup,int,fd)
+static __inline__ _syscall3(int,execve,const char*,file,char**,argv,char**,envp)
+static __inline__ _syscall3(int,open,const char *,file,int,flag,int,mode)
+static __inline__ _syscall1(int,close,int,fd)
+static __inline__ _syscall1(int,_exit,int,exitcode)
+static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+static __inline__ _syscall1(int,delete_module,const char *,name)
+
+struct stat;
+static __inline__ _syscall2(int,fstat,int,fd,struct stat *,buf)
+static __inline__ _syscall0(pid_t,getpid)
+static __inline__ _syscall2(int,kill,int,pid,int,sig)
+static __inline__ _syscall2(int,stat,const char *, path,struct stat *,buf)
+static __inline__ _syscall1(int,unlink,char *,pathname)
+
+
+
+extern pid_t waitpid(int, int*, int );
+static __inline__ pid_t wait(int * wait_stat)
+{
+       return waitpid(-1,wait_stat,0);
+}
+#endif
+
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
+#ifdef __KERNEL__
+#define __ARCH_WANT_IPC_PARSE_VERSION
+#define __ARCH_WANT_OLD_READDIR
+#define __ARCH_WANT_OLD_STAT
+#define __ARCH_WANT_STAT64
+#define __ARCH_WANT_SYS_ALARM
+#define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_PAUSE
+#define __ARCH_WANT_SYS_SGETMASK
+#define __ARCH_WANT_SYS_SIGNAL
+#define __ARCH_WANT_SYS_TIME
+#define __ARCH_WANT_SYS_UTIME
+#define __ARCH_WANT_SYS_WAITPID
+#define __ARCH_WANT_SYS_SOCKETCALL
+#define __ARCH_WANT_SYS_FADVISE64
+#define __ARCH_WANT_SYS_GETPGRP
+#define __ARCH_WANT_SYS_LLSEEK
+#define __ARCH_WANT_SYS_NICE
+#define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_SYS_OLDUMOUNT
+#define __ARCH_WANT_SYS_SIGPENDING
+#define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
+#endif
+
+
+
+#endif /* _XTENSA_UNISTD_H */
diff --git a/include/asm-xtensa/user.h b/include/asm-xtensa/user.h
new file mode 100644 (file)
index 0000000..2c3ed23
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * include/asm-xtensa/user.h
+ *
+ * Xtensa Processor version.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_USER_H
+#define _XTENSA_USER_H
+
+/* This file usually defines a 'struct user' structure. However, it it only
+ * used for a.out file, which are not supported on Xtensa.
+ */
+
+#endif /* _XTENSA_USER_H */
diff --git a/include/asm-xtensa/vga.h b/include/asm-xtensa/vga.h
new file mode 100644 (file)
index 0000000..23d82f6
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * include/asm-xtensa/vga.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_VGA_H
+#define _XTENSA_VGA_H
+
+#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x)
+
+#define vga_readb(x)   (*(x))
+#define vga_writeb(x,y)        (*(y) = (x))
+
+#endif
diff --git a/include/asm-xtensa/xor.h b/include/asm-xtensa/xor.h
new file mode 100644 (file)
index 0000000..e7b1f08
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/xor.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_XOR_H
+#define _XTENSA_XOR_H
+
+#include <asm-generic/xor.h>
+
+#endif
diff --git a/include/asm-xtensa/xtensa/cacheasm.h b/include/asm-xtensa/xtensa/cacheasm.h
new file mode 100644 (file)
index 0000000..0cdbb0b
--- /dev/null
@@ -0,0 +1,708 @@
+#ifndef XTENSA_CACHEASM_H
+#define XTENSA_CACHEASM_H
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * include/asm-xtensa/xtensa/cacheasm.h -- assembler-specific cache
+ * related definitions that depend on CORE configuration.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002 Tensilica Inc.
+ */
+
+
+#include <xtensa/coreasm.h>
+
+
+/*
+ *  This header file defines assembler macros of the form:
+ *     <x>cache_<func>
+ *  where <x> is 'i' or 'd' for instruction and data caches,
+ *  and <func> indicates the function of the macro.
+ *
+ *  The following functions <func> are defined,
+ *  and apply only to the specified cache (I or D):
+ *
+ *  reset
+ *     Resets the cache.
+ *
+ *  sync
+ *     Makes sure any previous cache instructions have been completed;
+ *     ie. makes sure any previous cache control operations
+ *     have had full effect and been synchronized to memory.
+ *     Eg. any invalidate completed [so as not to generate a hit],
+ *     any writebacks or other pipelined writes written to memory, etc.
+ *
+ *  invalidate_line            (single cache line)
+ *  invalidate_region          (specified memory range)
+ *  invalidate_all             (entire cache)
+ *     Invalidates all cache entries that cache
+ *     data from the specified memory range.
+ *     NOTE: locked entries are not invalidated.
+ *
+ *  writeback_line             (single cache line)
+ *  writeback_region           (specified memory range)
+ *  writeback_all              (entire cache)
+ *     Writes back to memory all dirty cache entries
+ *     that cache data from the specified memory range,
+ *     and marks these entries as clean.
+ *     NOTE: on some future implementations, this might
+ *             also invalidate.
+ *     NOTE: locked entries are written back, but never invalidated.
+ *     NOTE: instruction caches never implement writeback.
+ *
+ *  writeback_inv_line         (single cache line)
+ *  writeback_inv_region       (specified memory range)
+ *  writeback_inv_all          (entire cache)
+ *     Writes back to memory all dirty cache entries
+ *     that cache data from the specified memory range,
+ *     and invalidates these entries (including all clean
+ *     cache entries that cache data from that range).
+ *     NOTE: locked entries are written back but not invalidated.
+ *     NOTE: instruction caches never implement writeback.
+ *
+ *  lock_line                  (single cache line)
+ *  lock_region                        (specified memory range)
+ *     Prefetch and lock the specified memory range into cache.
+ *     NOTE:  if any part of the specified memory range cannot
+ *     be locked, a ??? exception occurs.  These macros don't
+ *     do anything special (yet anyway) to handle this situation.
+ *
+ *  unlock_line                        (single cache line)
+ *  unlock_region              (specified memory range)
+ *  unlock_all                 (entire cache)
+ *     Unlock cache entries that cache the specified memory range.
+ *     Entries not already locked are unaffected.
+ */
+
+
+
+/***************************   GENERIC -- ALL CACHES   ***************************/
+
+
+/*
+ *  The following macros assume the following cache size/parameter limits
+ *  in the current Xtensa core implementation:
+ *     cache size:     1024 bytes minimum
+ *     line size:      16 - 64 bytes
+ *     way count:      1 - 4
+ *
+ *  Minimum entries per way (ie. per associativity) = 1024 / 64 / 4 = 4
+ *  Hence the assumption that each loop can execute four cache instructions.
+ *
+ *  Correspondingly, the offset range of instructions is assumed able to cover
+ *  four lines, ie. offsets {0,1,2,3} * line_size are assumed valid for
+ *  both hit and indexed cache instructions.  Ie. these offsets are all
+ *  valid:  0, 16, 32, 48, 64, 96, 128, 192 (for line sizes 16, 32, 64).
+ *  This is true of all original cache instructions
+ *  (dhi, ihi, dhwb, dhwbi, dii, iii) which have offsets
+ *  of 0 to 1020 in multiples of 4 (ie. 8 bits shifted by 2).
+ *  This is also true of subsequent cache instructions
+ *  (dhu, ihu, diu, iiu, diwb, diwbi, dpfl, ipfl) which have offsets
+ *  of 0 to 240 in multiples of 16 (ie. 4 bits shifted by 4).
+ *
+ *  (Maximum cache size, currently 32k, doesn't affect the following macros.
+ *  Cache ways > MMU min page size cause aliasing but that's another matter.)
+ */
+
+
+
+/*
+ *  Macro to apply an 'indexed' cache instruction to the entire cache.
+ *
+ *  Parameters:
+ *     cainst          instruction/ that takes an address register parameter
+ *                     and an offset parameter (in range 0 .. 3*linesize).
+ *     size            size of cache in bytes
+ *     linesize        size of cache line in bytes
+ *     assoc_or1       number of associativities (ways/sets) in cache
+ *                     if all sets affected by cainst,
+ *                     or 1 if only one set (or not all sets) of the cache
+ *                     is affected by cainst (eg. DIWB or DIWBI [not yet ISA defined]).
+ *     aa, ab          unique address registers (temporaries)
+ */
+
+       .macro  cache_index_all         cainst, size, linesize, assoc_or1, aa, ab
+
+       //  Sanity-check on cache parameters:
+       .ifne   (\size % (\linesize * \assoc_or1 * 4))
+       .err    //  cache configuration outside expected/supported range!
+       .endif
+
+       //  \size byte cache, \linesize byte lines, \assoc_or1 way(s) affected by each \cainst.
+       movi    \aa, (\size / (\linesize * \assoc_or1 * 4))
+       // Possible improvement: need only loop if \aa > 1 ;
+       // however that particular condition is highly unlikely.
+       movi    \ab, 0          // to iterate over cache
+       floop           \aa, cachex\@
+       \cainst         \ab, 0*\linesize
+       \cainst         \ab, 1*\linesize
+       \cainst         \ab, 2*\linesize
+       \cainst         \ab, 3*\linesize
+       addi            \ab, \ab, 4*\linesize   // move to next line
+       floopend        \aa, cachex\@
+
+       .endm
+
+
+/*
+ *  Macro to apply a 'hit' cache instruction to a memory region,
+ *  ie. to any cache entries that cache a specified portion (region) of memory.
+ *  Takes care of the unaligned cases, ie. may apply to one
+ *  more cache line than $asize / lineSize if $aaddr is not aligned.
+ *
+ *
+ *  Parameters are:
+ *     cainst  instruction/macro that takes an address register parameter
+ *             and an offset parameter (currently always zero)
+ *             and generates a cache instruction (eg. "dhi", "dhwb", "ihi", etc.)
+ *     linesize_log2   log2(size of cache line in bytes)
+ *     addr    register containing start address of region (clobbered)
+ *     asize   register containing size of the region in bytes (clobbered)
+ *     askew   unique register used as temporary
+ *
+ * !?!?! 2DO: optimization: iterate max(cache_size and \asize) / linesize
+ */
+
+       .macro  cache_hit_region        cainst, linesize_log2, addr, asize, askew
+
+       //  Make \asize the number of iterations:
+       extui   \askew, \addr, 0, \linesize_log2        // get unalignment amount of \addr
+       add     \asize, \asize, \askew                  // ... and add it to \asize
+       addi    \asize, \asize, (1 << \linesize_log2) - 1       // round up!
+       srli    \asize, \asize, \linesize_log2
+
+       //  Iterate over region:
+       floopnez        \asize, cacheh\@
+       \cainst         \addr, 0
+       addi            \addr, \addr, (1 << \linesize_log2)     // move to next line
+       floopend        \asize, cacheh\@
+
+       .endm
+
+
+
+
+
+/***************************   INSTRUCTION CACHE   ***************************/
+
+
+/*
+ *  Reset/initialize the instruction cache by simply invalidating it:
+ *  (need to unlock first also, if cache locking implemented):
+ *
+ *  Parameters:
+ *     aa, ab          unique address registers (temporaries)
+ */
+       .macro  icache_reset    aa, ab
+       icache_unlock_all       \aa, \ab
+       icache_invalidate_all   \aa, \ab
+       .endm
+
+
+/*
+ * Synchronize after an instruction cache operation,
+ * to be sure everything is in sync with memory as to be
+ * expected following any previous instruction cache control operations.
+ *
+ * Parameters are:
+ *     ar      an address register (temporary) (currently unused, but may be used in future)
+ */
+       .macro  icache_sync     ar
+#if XCHAL_ICACHE_SIZE > 0
+       isync
+#endif
+       .endm
+
+
+
+/*
+ *  Invalidate a single line of the instruction cache.
+ *  Parameters are:
+ *     ar      address register that contains (virtual) address to invalidate
+ *             (may get clobbered in a future implementation, but not currently)
+ *     offset  (optional) offset to add to \ar to compute effective address to invalidate
+ *             (note: some number of lsbits are ignored)
+ */
+       .macro  icache_invalidate_line  ar, offset
+#if XCHAL_ICACHE_SIZE > 0
+       ihi     \ar, \offset            // invalidate icache line
+       /*
+        *  NOTE:  in some version of the silicon [!!!SHOULD HAVE BEEN DOCUMENTED!!!]
+        *  'ihi' doesn't work, so it had been replaced with 'iii'
+        *  (which would just invalidate more than it should,
+        *  which should be okay other than the performance hit
+        *  because cache locking did not exist in that version,
+        *  unless user somehow relies on something being cached).
+        *  [WHAT VERSION IS IT!!?!?
+        *  IS THERE ANY WAY TO TEST FOR THAT HERE, TO OUTPUT 'III' ONLY IF NEEDED!?!?].
+        *
+        *      iii     \ar, \offset
+        */
+       icache_sync     \ar
+#endif
+       .endm
+
+
+
+
+/*
+ *  Invalidate instruction  cache entries that cache a specified portion of memory.
+ *  Parameters are:
+ *     astart  start address (register gets clobbered)
+ *     asize   size of the region in bytes (register gets clobbered)
+ *     ac      unique register used as temporary
+ */
+       .macro  icache_invalidate_region        astart, asize, ac
+#if XCHAL_ICACHE_SIZE > 0
+       //  Instruction cache region invalidation:
+       cache_hit_region        ihi, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac
+       icache_sync     \ac
+       //  End of instruction cache region invalidation
+#endif
+       .endm
+
+
+
+/*
+ *  Invalidate entire instruction cache.
+ *
+ *  Parameters:
+ *     aa, ab          unique address registers (temporaries)
+ */
+       .macro  icache_invalidate_all   aa, ab
+#if XCHAL_ICACHE_SIZE > 0
+       //  Instruction cache invalidation:
+       cache_index_all         iii, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE, XCHAL_ICACHE_WAYS, \aa, \ab
+       icache_sync     \aa
+       //  End of instruction cache invalidation
+#endif
+       .endm
+
+
+
+/*
+ *  Lock (prefetch & lock) a single line of the instruction cache.
+ *
+ *  Parameters are:
+ *     ar      address register that contains (virtual) address to lock
+ *             (may get clobbered in a future implementation, but not currently)
+ *     offset  offset to add to \ar to compute effective address to lock
+ *             (note: some number of lsbits are ignored)
+ */
+       .macro  icache_lock_line        ar, offset
+#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
+       ipfl    \ar, \offset    /* prefetch and lock icache line */
+       icache_sync     \ar
+#endif
+       .endm
+
+
+
+/*
+ *  Lock (prefetch & lock) a specified portion of memory into the instruction cache.
+ *  Parameters are:
+ *     astart  start address (register gets clobbered)
+ *     asize   size of the region in bytes (register gets clobbered)
+ *     ac      unique register used as temporary
+ */
+       .macro  icache_lock_region      astart, asize, ac
+#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
+       //  Instruction cache region lock:
+       cache_hit_region        ipfl, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac
+       icache_sync     \ac
+       //  End of instruction cache region lock
+#endif
+       .endm
+
+
+
+/*
+ *  Unlock a single line of the instruction cache.
+ *
+ *  Parameters are:
+ *     ar      address register that contains (virtual) address to unlock
+ *             (may get clobbered in a future implementation, but not currently)
+ *     offset  offset to add to \ar to compute effective address to unlock
+ *             (note: some number of lsbits are ignored)
+ */
+       .macro  icache_unlock_line      ar, offset
+#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
+       ihu     \ar, \offset    /* unlock icache line */
+       icache_sync     \ar
+#endif
+       .endm
+
+
+
+/*
+ *  Unlock a specified portion of memory from the instruction cache.
+ *  Parameters are:
+ *     astart  start address (register gets clobbered)
+ *     asize   size of the region in bytes (register gets clobbered)
+ *     ac      unique register used as temporary
+ */
+       .macro  icache_unlock_region    astart, asize, ac
+#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
+       //  Instruction cache region unlock:
+       cache_hit_region        ihu, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac
+       icache_sync     \ac
+       //  End of instruction cache region unlock
+#endif
+       .endm
+
+
+
+/*
+ *  Unlock entire instruction cache.
+ *
+ *  Parameters:
+ *     aa, ab          unique address registers (temporaries)
+ */
+       .macro  icache_unlock_all       aa, ab
+#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
+       //  Instruction cache unlock:
+       cache_index_all         iiu, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE, 1, \aa, \ab
+       icache_sync     \aa
+       //  End of instruction cache unlock
+#endif
+       .endm
+
+
+
+
+
+/***************************   DATA CACHE   ***************************/
+
+
+
+/*
+ *  Reset/initialize the data cache by simply invalidating it
+ *  (need to unlock first also, if cache locking implemented):
+ *
+ *  Parameters:
+ *     aa, ab          unique address registers (temporaries)
+ */
+       .macro  dcache_reset    aa, ab
+       dcache_unlock_all       \aa, \ab
+       dcache_invalidate_all   \aa, \ab
+       .endm
+
+
+
+
+/*
+ * Synchronize after a data cache operation,
+ * to be sure everything is in sync with memory as to be
+ * expected following any previous data cache control operations.
+ *
+ * Parameters are:
+ *     ar      an address register (temporary) (currently unused, but may be used in future)
+ */
+       .macro  dcache_sync     ar
+#if XCHAL_DCACHE_SIZE > 0
+       //  This previous sequence errs on the conservative side (too much so); a DSYNC should be sufficient:
+       //memw          // synchronize data cache changes relative to subsequent memory accesses
+       //isync         // be conservative and ISYNC as well (just to be sure)
+
+       dsync
+#endif
+       .endm
+
+
+
+/*
+ * Synchronize after a data store operation,
+ * to be sure the stored data is completely off the processor
+ * (and assuming there is no buffering outside the processor,
+ *  that the data is in memory).  This may be required to
+ * ensure that the processor's write buffers are emptied.
+ * A MEMW followed by a read guarantees this, by definition.
+ * We also try to make sure the read itself completes.
+ *
+ * Parameters are:
+ *     ar      an address register (temporary)
+ */
+       .macro  write_sync      ar
+       memw                    // ensure previous memory accesses are complete prior to subsequent memory accesses
+       l32i    \ar, sp, 0      // completing this read ensures any previous write has completed, because of MEMW
+       //slot
+       add     \ar, \ar, \ar   // use the result of the read to help ensure the read completes (in future architectures)
+       .endm
+
+
+/*
+ *  Invalidate a single line of the data cache.
+ *  Parameters are:
+ *     ar      address register that contains (virtual) address to invalidate
+ *             (may get clobbered in a future implementation, but not currently)
+ *     offset  (optional) offset to add to \ar to compute effective address to invalidate
+ *             (note: some number of lsbits are ignored)
+ */
+       .macro  dcache_invalidate_line  ar, offset
+#if XCHAL_DCACHE_SIZE > 0
+       dhi     \ar, \offset
+       dcache_sync     \ar
+#endif
+       .endm
+
+
+
+
+
+/*
+ *  Invalidate data cache entries that cache a specified portion of memory.
+ *  Parameters are:
+ *     astart  start address (register gets clobbered)
+ *     asize   size of the region in bytes (register gets clobbered)
+ *     ac      unique register used as temporary
+ */
+       .macro  dcache_invalidate_region        astart, asize, ac
+#if XCHAL_DCACHE_SIZE > 0
+       //  Data cache region invalidation:
+       cache_hit_region        dhi, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
+       dcache_sync     \ac
+       //  End of data cache region invalidation
+#endif
+       .endm
+
+
+
+#if 0
+/*
+ *  This is a work-around for a bug in SiChip1 (???).
+ *  There should be a proper mechanism for not outputting
+ *  these instructions when not needed.
+ *  To enable work-around, uncomment this and replace 'dii'
+ *  with 'dii_s1' everywhere, eg. in dcache_invalidate_all
+ *  macro below.
+ */
+       .macro  dii_s1  ar, offset
+       dii     \ar, \offset
+       or      \ar, \ar, \ar
+       or      \ar, \ar, \ar
+       or      \ar, \ar, \ar
+       or      \ar, \ar, \ar
+       .endm
+#endif
+
+
+/*
+ *  Invalidate entire data cache.
+ *
+ *  Parameters:
+ *     aa, ab          unique address registers (temporaries)
+ */
+       .macro  dcache_invalidate_all   aa, ab
+#if XCHAL_DCACHE_SIZE > 0
+       //  Data cache invalidation:
+       cache_index_all         dii, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, XCHAL_DCACHE_WAYS, \aa, \ab
+       dcache_sync     \aa
+       //  End of data cache invalidation
+#endif
+       .endm
+
+
+
+/*
+ *  Writeback a single line of the data cache.
+ *  Parameters are:
+ *     ar      address register that contains (virtual) address to writeback
+ *             (may get clobbered in a future implementation, but not currently)
+ *     offset  offset to add to \ar to compute effective address to writeback
+ *             (note: some number of lsbits are ignored)
+ */
+       .macro  dcache_writeback_line   ar, offset
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK
+       dhwb    \ar, \offset
+       dcache_sync     \ar
+#endif
+       .endm
+
+
+
+/*
+ *  Writeback dirty data cache entries that cache a specified portion of memory.
+ *  Parameters are:
+ *     astart  start address (register gets clobbered)
+ *     asize   size of the region in bytes (register gets clobbered)
+ *     ac      unique register used as temporary
+ */
+       .macro  dcache_writeback_region         astart, asize, ac
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK
+       //  Data cache region writeback:
+       cache_hit_region        dhwb, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
+       dcache_sync     \ac
+       //  End of data cache region writeback
+#endif
+       .endm
+
+
+
+/*
+ *  Writeback entire data cache.
+ *  Parameters:
+ *     aa, ab          unique address registers (temporaries)
+ */
+       .macro  dcache_writeback_all    aa, ab
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK
+       //  Data cache writeback:
+       cache_index_all         diwb, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab
+       dcache_sync     \aa
+       //  End of data cache writeback
+#endif
+       .endm
+
+
+
+/*
+ *  Writeback and invalidate a single line of the data cache.
+ *  Parameters are:
+ *     ar      address register that contains (virtual) address to writeback and invalidate
+ *             (may get clobbered in a future implementation, but not currently)
+ *     offset  offset to add to \ar to compute effective address to writeback and invalidate
+ *             (note: some number of lsbits are ignored)
+ */
+       .macro  dcache_writeback_inv_line       ar, offset
+#if XCHAL_DCACHE_SIZE > 0
+       dhwbi   \ar, \offset    /* writeback and invalidate dcache line */
+       dcache_sync     \ar
+#endif
+       .endm
+
+
+
+/*
+ *  Writeback and invalidate data cache entries that cache a specified portion of memory.
+ *  Parameters are:
+ *     astart  start address (register gets clobbered)
+ *     asize   size of the region in bytes (register gets clobbered)
+ *     ac      unique register used as temporary
+ */
+       .macro  dcache_writeback_inv_region     astart, asize, ac
+#if XCHAL_DCACHE_SIZE > 0
+       //  Data cache region writeback and invalidate:
+       cache_hit_region        dhwbi, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
+       dcache_sync     \ac
+       //  End of data cache region writeback and invalidate
+#endif
+       .endm
+
+
+
+/*
+ *  Writeback and invalidate entire data cache.
+ *  Parameters:
+ *     aa, ab          unique address registers (temporaries)
+ */
+       .macro  dcache_writeback_inv_all        aa, ab
+#if XCHAL_DCACHE_SIZE > 0
+       //  Data cache writeback and invalidate:
+#if XCHAL_DCACHE_IS_WRITEBACK
+       cache_index_all         diwbi, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab
+       dcache_sync     \aa
+#else /*writeback*/
+       //  Data cache does not support writeback, so just invalidate: */
+       dcache_invalidate_all   \aa, \ab
+#endif /*writeback*/
+       //  End of data cache writeback and invalidate
+#endif
+       .endm
+
+
+
+
+/*
+ *  Lock (prefetch & lock) a single line of the data cache.
+ *
+ *  Parameters are:
+ *     ar      address register that contains (virtual) address to lock
+ *             (may get clobbered in a future implementation, but not currently)
+ *     offset  offset to add to \ar to compute effective address to lock
+ *             (note: some number of lsbits are ignored)
+ */
+       .macro  dcache_lock_line        ar, offset
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
+       dpfl    \ar, \offset    /* prefetch and lock dcache line */
+       dcache_sync     \ar
+#endif
+       .endm
+
+
+
+/*
+ *  Lock (prefetch & lock) a specified portion of memory into the data cache.
+ *  Parameters are:
+ *     astart  start address (register gets clobbered)
+ *     asize   size of the region in bytes (register gets clobbered)
+ *     ac      unique register used as temporary
+ */
+       .macro  dcache_lock_region      astart, asize, ac
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
+       //  Data cache region lock:
+       cache_hit_region        dpfl, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
+       dcache_sync     \ac
+       //  End of data cache region lock
+#endif
+       .endm
+
+
+
+/*
+ *  Unlock a single line of the data cache.
+ *
+ *  Parameters are:
+ *     ar      address register that contains (virtual) address to unlock
+ *             (may get clobbered in a future implementation, but not currently)
+ *     offset  offset to add to \ar to compute effective address to unlock
+ *             (note: some number of lsbits are ignored)
+ */
+       .macro  dcache_unlock_line      ar, offset
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
+       dhu     \ar, \offset    /* unlock dcache line */
+       dcache_sync     \ar
+#endif
+       .endm
+
+
+
+/*
+ *  Unlock a specified portion of memory from the data cache.
+ *  Parameters are:
+ *     astart  start address (register gets clobbered)
+ *     asize   size of the region in bytes (register gets clobbered)
+ *     ac      unique register used as temporary
+ */
+       .macro  dcache_unlock_region    astart, asize, ac
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
+       //  Data cache region unlock:
+       cache_hit_region        dhu, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
+       dcache_sync     \ac
+       //  End of data cache region unlock
+#endif
+       .endm
+
+
+
+/*
+ *  Unlock entire data cache.
+ *
+ *  Parameters:
+ *     aa, ab          unique address registers (temporaries)
+ */
+       .macro  dcache_unlock_all       aa, ab
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
+       //  Data cache unlock:
+       cache_index_all         diu, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab
+       dcache_sync     \aa
+       //  End of data cache unlock
+#endif
+       .endm
+
+
+#endif /*XTENSA_CACHEASM_H*/
+
diff --git a/include/asm-xtensa/xtensa/cacheattrasm.h b/include/asm-xtensa/xtensa/cacheattrasm.h
new file mode 100644 (file)
index 0000000..1c3e117
--- /dev/null
@@ -0,0 +1,432 @@
+#ifndef XTENSA_CACHEATTRASM_H
+#define XTENSA_CACHEATTRASM_H
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * include/asm-xtensa/xtensa/cacheattrasm.h -- assembler-specific
+ * CACHEATTR register related definitions that depend on CORE
+ * configuration.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002 Tensilica Inc.
+ */
+
+
+#include <xtensa/coreasm.h>
+
+
+/*
+ *  This header file defines assembler macros of the form:
+ *     <x>cacheattr_<func>
+ *  where:
+ *     <x> is 'i', 'd' or absent for instruction, data
+ *             or both caches; and
+ *     <func> indicates the function of the macro.
+ *
+ *  The following functions are defined:
+ *
+ *  icacheattr_get
+ *     Reads I-cache CACHEATTR into a2 (clobbers a3-a5).
+ *
+ *  dcacheattr_get
+ *     Reads D-cache CACHEATTR into a2 (clobbers a3-a5).
+ *     (Note:  for configs with a real CACHEATTR register, the
+ *      above two macros are identical.)
+ *
+ *  cacheattr_set
+ *     Writes both I-cache and D-cache CACHEATTRs from a2 (a3-a8 clobbered).
+ *     Works even when changing one's own code's attributes.
+ *
+ *  icacheattr_is_enabled  label
+ *     Branches to \label if I-cache appears to have been enabled
+ *     (eg. if CACHEATTR contains a cache-enabled attribute).
+ *     (clobbers a2-a5,SAR)
+ *
+ *  dcacheattr_is_enabled  label
+ *     Branches to \label if D-cache appears to have been enabled
+ *     (eg. if CACHEATTR contains a cache-enabled attribute).
+ *     (clobbers a2-a5,SAR)
+ *
+ *  cacheattr_is_enabled  label
+ *     Branches to \label if either I-cache or D-cache appears to have been enabled
+ *     (eg. if CACHEATTR contains a cache-enabled attribute).
+ *     (clobbers a2-a5,SAR)
+ *
+ *  The following macros are only defined under certain conditions:
+ *
+ *  icacheattr_set     (if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR)
+ *     Writes I-cache CACHEATTR from a2 (a3-a8 clobbered).
+ *
+ *  dcacheattr_set     (if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR)
+ *     Writes D-cache CACHEATTR from a2 (a3-a8 clobbered).
+ */
+
+
+
+/***************************   GENERIC -- ALL CACHES   ***************************/
+
+/*
+ *  _cacheattr_get
+ *
+ *  (Internal macro.)
+ *  Returns value of CACHEATTR register (or closest equivalent) in a2.
+ *
+ *  Entry:
+ *     (none)
+ *  Exit:
+ *     a2      value read from CACHEATTR
+ *     a3-a5   clobbered (temporaries)
+ */
+       .macro  _cacheattr_get  tlb
+#if XCHAL_HAVE_CACHEATTR
+       rsr     a2, CACHEATTR
+#elif XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
+       //  We have a config that "mimics" CACHEATTR using a simplified
+       //  "MMU" composed of a single statically-mapped way.
+       //  DTLB and ITLB are independent, so there's no single
+       //  cache attribute that can describe both.  So for now
+       //  just return the DTLB state.
+       movi    a5, 0xE0000000
+       movi    a2, 0
+       movi    a3, 0
+1:     add     a3, a3, a5      // next segment
+       r&tlb&1 a4, a3          // get PPN+CA of segment at 0xE0000000, 0xC0000000, ..., 0
+       dsync   // interlock???
+       slli    a2, a2, 4
+       extui   a4, a4, 0, 4    // extract CA
+       or      a2, a2, a4
+       bnez    a3, 1b
+#else
+       //  This macro isn't applicable to arbitrary MMU configurations.
+       //  Just return zero.
+       movi    a2, 0
+#endif
+       .endm
+
+       .macro  icacheattr_get
+       _cacheattr_get  itlb
+       .endm
+
+       .macro  dcacheattr_get
+       _cacheattr_get  dtlb
+       .endm
+
+
+#define XCHAL_CACHEATTR_ALL_BYPASS     0x22222222      /* default (powerup/reset) value of CACHEATTR, all BYPASS
+                                                          mode (ie. disabled/bypassed caches) */
+
+#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
+
+#define XCHAL_FCA_ENAMASK      0x001A  /* bitmap of fetch attributes that require enabled icache */
+#define XCHAL_LCA_ENAMASK      0x0003  /* bitmap of load  attributes that require enabled dcache */
+#define XCHAL_SCA_ENAMASK      0x0003  /* bitmap of store attributes that require enabled dcache */
+#define XCHAL_LSCA_ENAMASK     (XCHAL_LCA_ENAMASK|XCHAL_SCA_ENAMASK)   /* l/s attrs requiring enabled dcache */
+#define XCHAL_ALLCA_ENAMASK    (XCHAL_FCA_ENAMASK|XCHAL_LSCA_ENAMASK)  /* all attrs requiring enabled caches */
+
+/*
+ *  _cacheattr_is_enabled
+ *
+ *  (Internal macro.)
+ *  Branches to \label if CACHEATTR in a2 indicates an enabled
+ *  cache, using mask in a3.
+ *
+ *  Parameters:
+ *     label   where to branch to if cache is enabled
+ *  Entry:
+ *     a2      contains CACHEATTR value used to determine whether
+ *             caches are enabled
+ *     a3      16-bit constant where each bit correspond to
+ *             one of the 16 possible CA values (in a CACHEATTR mask);
+ *             CA values that indicate the cache is enabled
+ *             have their corresponding bit set in this mask
+ *             (eg. use XCHAL_xCA_ENAMASK , above)
+ *  Exit:
+ *     a2,a4,a5        clobbered
+ *     SAR             clobbered
+ */
+       .macro  _cacheattr_is_enabled   label
+       movi    a4, 8           // loop 8 times
+.Lcaife\@:
+       extui   a5, a2, 0, 4    // get CA nibble
+       ssr     a5              // index into mask according to CA...
+       srl     a5, a3          // ...and get CA's mask bit in a5 bit 0
+       bbsi.l  a5, 0, \label   // if CA indicates cache enabled, jump to label
+       srli    a2, a2, 4       // next nibble
+       addi    a4, a4, -1
+       bnez    a4, .Lcaife\@   // loop for each nibble
+       .endm
+
+#else /* XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR */
+       .macro  _cacheattr_is_enabled   label
+       j       \label          // macro not applicable, assume caches always enabled
+       .endm
+#endif /* XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR */
+
+
+
+/*
+ *  icacheattr_is_enabled
+ *
+ *  Branches to \label if I-cache is enabled.
+ *
+ *  Parameters:
+ *     label   where to branch to if icache is enabled
+ *  Entry:
+ *     (none)
+ *  Exit:
+ *     a2-a5, SAR      clobbered (temporaries)
+ */
+       .macro  icacheattr_is_enabled   label
+#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
+       icacheattr_get
+       movi    a3, XCHAL_FCA_ENAMASK
+#endif
+       _cacheattr_is_enabled   \label
+       .endm
+
+/*
+ *  dcacheattr_is_enabled
+ *
+ *  Branches to \label if D-cache is enabled.
+ *
+ *  Parameters:
+ *     label   where to branch to if dcache is enabled
+ *  Entry:
+ *     (none)
+ *  Exit:
+ *     a2-a5, SAR      clobbered (temporaries)
+ */
+       .macro  dcacheattr_is_enabled   label
+#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
+       dcacheattr_get
+       movi    a3, XCHAL_LSCA_ENAMASK
+#endif
+       _cacheattr_is_enabled   \label
+       .endm
+
+/*
+ *  cacheattr_is_enabled
+ *
+ *  Branches to \label if either I-cache or D-cache is enabled.
+ *
+ *  Parameters:
+ *     label   where to branch to if a cache is enabled
+ *  Entry:
+ *     (none)
+ *  Exit:
+ *     a2-a5, SAR      clobbered (temporaries)
+ */
+       .macro  cacheattr_is_enabled    label
+#if XCHAL_HAVE_CACHEATTR
+       rsr     a2, CACHEATTR
+       movi    a3, XCHAL_ALLCA_ENAMASK
+#elif XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
+       icacheattr_get
+       movi    a3, XCHAL_FCA_ENAMASK
+       _cacheattr_is_enabled   \label
+       dcacheattr_get
+       movi    a3, XCHAL_LSCA_ENAMASK
+#endif
+       _cacheattr_is_enabled   \label
+       .endm
+
+
+
+/*
+ *  The ISA does not have a defined way to change the
+ *  instruction cache attributes of the running code,
+ *  ie. of the memory area that encloses the current PC.
+ *  However, each micro-architecture (or class of
+ *  configurations within a micro-architecture)
+ *  provides a way to deal with this issue.
+ *
+ *  Here are a few macros used to implement the relevant
+ *  approach taken.
+ */
+
+#if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
+       //  We have a config that "mimics" CACHEATTR using a simplified
+       //  "MMU" composed of a single statically-mapped way.
+
+/*
+ *  icacheattr_set
+ *
+ *  Entry:
+ *     a2              cacheattr value to set
+ *  Exit:
+ *     a2              unchanged
+ *     a3-a8           clobbered (temporaries)
+ */
+       .macro  icacheattr_set
+
+       movi    a5, 0xE0000000  // mask of upper 3 bits
+       movi    a6, 3f          // PC where ITLB is set
+       movi    a3, 0           // start at region 0 (0 .. 7)
+       and     a6, a6, a5      // upper 3 bits of local PC area
+       mov     a7, a2          // copy a2 so it doesn't get clobbered
+       j       3f
+
+# if XCHAL_HAVE_XLT_CACHEATTR
+       //  Can do translations, use generic method:
+1:     sub     a6, a3, a5      // address of some other segment
+       ritlb1  a8, a6          // save its PPN+CA
+       dsync   // interlock??
+       witlb   a4, a6          // make it translate to this code area
+       movi    a6, 5f          // where to jump into it
+       isync
+       sub     a6, a6, a5      // adjust jump address within that other segment
+       jx      a6
+
+       //  Note that in the following code snippet, which runs at a different virtual
+       //  address than it is assembled for, we avoid using literals (eg. via movi/l32r)
+       //  just in case literals end up in a different 512 MB segment, and we avoid
+       //  instructions that rely on the current PC being what is expected.
+       //
+       .align  4
+       _j      6f              // this is at label '5' minus 4 bytes
+       .align  4
+5:     witlb   a4, a3          // we're in other segment, now can write previous segment's CA
+       isync
+       add     a6, a6, a5      // back to previous segment
+       addi    a6, a6, -4      // next jump label
+       jx      a6
+
+6:     sub     a6, a3, a5      // address of some other segment
+       witlb   a8, a6          // restore PPN+CA of other segment
+       mov     a6, a3          // restore a6
+       isync
+# else /* XCHAL_HAVE_XLT_CACHEATTR */
+       //  Use micro-architecture specific method.
+       //  The following 4-instruction sequence is aligned such that
+       //  it all fits within a single I-cache line.  Sixteen byte
+       //  alignment is sufficient for this (using XCHAL_ICACHE_LINESIZE
+       //  actually causes problems because that can be greater than
+       //  the alignment of the reset vector, where this macro is often
+       //  invoked, which would cause the linker to align the reset
+       //  vector code away from the reset vector!!).
+       .align  16 /*XCHAL_ICACHE_LINESIZE*/
+1:     _witlb  a4, a3          // write wired PTE (CA, no PPN) of 512MB segment to ITLB
+       _isync
+       nop
+       nop
+# endif /* XCHAL_HAVE_XLT_CACHEATTR */
+       beq     a3, a5, 4f      // done?
+
+       //  Note that in the WITLB loop, we don't do any load/stores
+       //  (may not be an issue here, but it is important in the DTLB case).
+2:     srli    a7, a7, 4       // next CA
+       sub     a3, a3, a5      // next segment (add 0x20000000)
+3:
+# if XCHAL_HAVE_XLT_CACHEATTR  /* if have translation, preserve it */
+       ritlb1  a8, a3          // get current PPN+CA of segment
+       dsync   // interlock???
+       extui   a4, a7, 0, 4    // extract CA to set
+       srli    a8, a8, 4       // clear CA but keep PPN ...
+       slli    a8, a8, 4       // ...
+       add     a4, a4, a8      // combine new CA with PPN to preserve
+# else
+       extui   a4, a7, 0, 4    // extract CA
+# endif
+       beq     a3, a6, 1b      // current PC's region? if so, do it in a safe way
+       witlb   a4, a3          // write wired PTE (CA [+PPN]) of 512MB segment to ITLB
+       bne     a3, a5, 2b
+       isync                   // make sure all ifetch changes take effect
+4:
+       .endm   // icacheattr_set
+
+
+/*
+ *  dcacheattr_set
+ *
+ *  Entry:
+ *     a2              cacheattr value to set
+ *  Exit:
+ *     a2              unchanged
+ *     a3-a8           clobbered (temporaries)
+ */
+
+       .macro  dcacheattr_set
+
+       movi    a5, 0xE0000000  // mask of upper 3 bits
+       movi    a3, 0           // start at region 0 (0 .. 7)
+       mov     a7, a2          // copy a2 so it doesn't get clobbered
+       j       3f
+       //  Note that in the WDTLB loop, we don't do any load/stores
+       //  (including implicit l32r via movi) because it isn't safe.
+2:     srli    a7, a7, 4       // next CA
+       sub     a3, a3, a5      // next segment (add 0x20000000)
+3:
+# if XCHAL_HAVE_XLT_CACHEATTR  /* if have translation, preserve it */
+       rdtlb1  a8, a3          // get current PPN+CA of segment
+       dsync   // interlock???
+       extui   a4, a7, 0, 4    // extract CA to set
+       srli    a8, a8, 4       // clear CA but keep PPN ...
+       slli    a8, a8, 4       // ...
+       add     a4, a4, a8      // combine new CA with PPN to preserve
+# else
+       extui   a4, a7, 0, 4    // extract CA to set
+# endif
+       wdtlb   a4, a3          // write wired PTE (CA [+PPN]) of 512MB segment to DTLB
+       bne     a3, a5, 2b
+       dsync                   // make sure all data path changes take effect
+       .endm   // dcacheattr_set
+
+#endif /* XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR */
+
+
+
+/*
+ *  cacheattr_set
+ *
+ *  Macro that sets the current CACHEATTR safely
+ *  (both i and d) according to the current contents of a2.
+ *  It works even when changing the cache attributes of
+ *  the currently running code.
+ *
+ *  Entry:
+ *     a2              cacheattr value to set
+ *  Exit:
+ *     a2              unchanged
+ *     a3-a8           clobbered (temporaries)
+ */
+       .macro  cacheattr_set
+
+#if XCHAL_HAVE_CACHEATTR
+# if XCHAL_ICACHE_LINESIZE < 4
+       //  No i-cache, so can always safely write to CACHEATTR:
+       wsr     a2, CACHEATTR
+# else
+       //  The Athens micro-architecture, when using the old
+       //  exception architecture option (ie. with the CACHEATTR register)
+       //  allows changing the cache attributes of the running code
+       //  using the following exact sequence aligned to be within
+       //  an instruction cache line.  (NOTE: using XCHAL_ICACHE_LINESIZE
+       //  alignment actually causes problems because that can be greater
+       //  than the alignment of the reset vector, where this macro is often
+       //  invoked, which would cause the linker to align the reset
+       //  vector code away from the reset vector!!).
+       j       1f
+       .align  16 /*XCHAL_ICACHE_LINESIZE*/    // align to within an I-cache line
+1:     _wsr    a2, CACHEATTR
+       _isync
+       nop
+       nop
+# endif
+#elif XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
+       //  DTLB and ITLB are independent, but to keep semantics
+       //  of this macro we simply write to both.
+       icacheattr_set
+       dcacheattr_set
+#else
+       //  This macro isn't applicable to arbitrary MMU configurations.
+       //  Do nothing in this case.
+#endif
+       .endm
+
+
+#endif /*XTENSA_CACHEATTRASM_H*/
+
diff --git a/include/asm-xtensa/xtensa/config-linux_be/core.h b/include/asm-xtensa/xtensa/config-linux_be/core.h
new file mode 100644 (file)
index 0000000..d54fe5e
--- /dev/null
@@ -0,0 +1,1270 @@
+/*
+ * xtensa/config/core.h -- HAL definitions that are dependent on CORE configuration
+ *
+ *  This header file is sometimes referred to as the "compile-time HAL" or CHAL.
+ *  It was generated for a specific Xtensa processor configuration.
+ *
+ *  Source for configuration-independent binaries (which link in a
+ *  configuration-specific HAL library) must NEVER include this file.
+ *  It is perfectly normal, however, for the HAL source itself to include this file.
+ */
+
+/*
+ * Copyright (c) 2003 Tensilica, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ */
+
+
+#ifndef XTENSA_CONFIG_CORE_H
+#define XTENSA_CONFIG_CORE_H
+
+#include <xtensa/hal.h>
+
+
+/*----------------------------------------------------------------------
+                               GENERAL
+  ----------------------------------------------------------------------*/
+
+/*
+ *  Separators for macros that expand into arrays.
+ *  These can be predefined by files that #include this one,
+ *  when different separators are required.
+ */
+/*  Element separator for macros that expand into 1-dimensional arrays:  */
+#ifndef XCHAL_SEP
+#define XCHAL_SEP                      ,
+#endif
+/*  Array separator for macros that expand into 2-dimensional arrays:  */
+#ifndef XCHAL_SEP2
+#define XCHAL_SEP2                     },{
+#endif
+
+
+/*----------------------------------------------------------------------
+                               ENDIANNESS
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_BE                  1
+#define XCHAL_HAVE_LE                  0
+#define XCHAL_MEMORY_ORDER             XTHAL_BIGENDIAN
+
+
+/*----------------------------------------------------------------------
+                               REGISTER WINDOWS
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_WINDOWED            1       /* 1 if windowed registers option configured, 0 otherwise */
+#define XCHAL_NUM_AREGS                        64      /* number of physical address regs */
+#define XCHAL_NUM_AREGS_LOG2           6       /* log2(XCHAL_NUM_AREGS) */
+
+
+/*----------------------------------------------------------------------
+                               ADDRESS ALIGNMENT
+  ----------------------------------------------------------------------*/
+
+/*  These apply to a selected set of core load and store instructions only (see ISA):  */
+#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1       /* 1 if unaligned loads cause an exception, 0 otherwise */
+#define XCHAL_UNALIGNED_STORE_EXCEPTION        1       /* 1 if unaligned stores cause an exception, 0 otherwise */
+
+
+/*----------------------------------------------------------------------
+                               INTERRUPTS
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_INTERRUPTS          1       /* 1 if interrupt option configured, 0 otherwise */
+#define XCHAL_HAVE_HIGHPRI_INTERRUPTS  1       /* 1 if high-priority interrupt option configured, 0 otherwise */
+#define XCHAL_HAVE_HIGHLEVEL_INTERRUPTS        XCHAL_HAVE_HIGHPRI_INTERRUPTS
+#define XCHAL_HAVE_NMI                 0       /* 1 if NMI option configured, 0 otherwise */
+#define XCHAL_NUM_INTERRUPTS           17      /* number of interrupts */
+#define XCHAL_NUM_INTERRUPTS_LOG2      5       /* number of bits to hold an interrupt number: roundup(log2(number of interrupts)) */
+#define XCHAL_NUM_EXTINTERRUPTS                10      /* number of external interrupts */
+#define XCHAL_NUM_INTLEVELS            4       /* number of interrupt levels (not including level zero!) */
+#define XCHAL_NUM_LOWPRI_LEVELS                1                       /* number of low-priority interrupt levels (always 1) */
+#define XCHAL_FIRST_HIGHPRI_LEVEL      (XCHAL_NUM_LOWPRI_LEVELS+1)     /* level of first high-priority interrupt (always 2) */
+#define XCHAL_EXCM_LEVEL               1                       /* level of interrupts masked by PS.EXCM (XEA2 only; always 1 in T10xx);
+                                                                  for XEA1, where there is no PS.EXCM, this is always 1;
+                                                                  interrupts at levels FIRST_HIGHPRI <= n <= EXCM_LEVEL, if any,
+                                                                  are termed "medium priority" interrupts (post T10xx only) */
+/*  Note:  1 <= LOWPRI_LEVELS <= EXCM_LEVEL < DEBUGLEVEL <= NUM_INTLEVELS < NMILEVEL <= 15  */
+
+/*  Masks of interrupts at each interrupt level:  */
+#define XCHAL_INTLEVEL0_MASK           0x00000000
+#define XCHAL_INTLEVEL1_MASK           0x000064F9
+#define XCHAL_INTLEVEL2_MASK           0x00008902
+#define XCHAL_INTLEVEL3_MASK           0x00011204
+#define XCHAL_INTLEVEL4_MASK           0x00000000
+#define XCHAL_INTLEVEL5_MASK           0x00000000
+#define XCHAL_INTLEVEL6_MASK           0x00000000
+#define XCHAL_INTLEVEL7_MASK           0x00000000
+#define XCHAL_INTLEVEL8_MASK           0x00000000
+#define XCHAL_INTLEVEL9_MASK           0x00000000
+#define XCHAL_INTLEVEL10_MASK          0x00000000
+#define XCHAL_INTLEVEL11_MASK          0x00000000
+#define XCHAL_INTLEVEL12_MASK          0x00000000
+#define XCHAL_INTLEVEL13_MASK          0x00000000
+#define XCHAL_INTLEVEL14_MASK          0x00000000
+#define XCHAL_INTLEVEL15_MASK          0x00000000
+/*  As an array of entries (eg. for C constant arrays):  */
+#define XCHAL_INTLEVEL_MASKS           0x00000000      XCHAL_SEP \
+                                       0x000064F9      XCHAL_SEP \
+                                       0x00008902      XCHAL_SEP \
+                                       0x00011204      XCHAL_SEP \
+                                       0x00000000      XCHAL_SEP \
+                                       0x00000000      XCHAL_SEP \
+                                       0x00000000      XCHAL_SEP \
+                                       0x00000000      XCHAL_SEP \
+                                       0x00000000      XCHAL_SEP \
+                                       0x00000000      XCHAL_SEP \
+                                       0x00000000      XCHAL_SEP \
+                                       0x00000000      XCHAL_SEP \
+                                       0x00000000      XCHAL_SEP \
+                                       0x00000000      XCHAL_SEP \
+                                       0x00000000      XCHAL_SEP \
+                                       0x00000000
+
+/*  Masks of interrupts at each range 1..n of interrupt levels:  */
+#define XCHAL_INTLEVEL0_ANDBELOW_MASK  0x00000000
+#define XCHAL_INTLEVEL1_ANDBELOW_MASK  0x000064F9
+#define XCHAL_INTLEVEL2_ANDBELOW_MASK  0x0000EDFB
+#define XCHAL_INTLEVEL3_ANDBELOW_MASK  0x0001FFFF
+#define XCHAL_INTLEVEL4_ANDBELOW_MASK  0x0001FFFF
+#define XCHAL_INTLEVEL5_ANDBELOW_MASK  0x0001FFFF
+#define XCHAL_INTLEVEL6_ANDBELOW_MASK  0x0001FFFF
+#define XCHAL_INTLEVEL7_ANDBELOW_MASK  0x0001FFFF
+#define XCHAL_INTLEVEL8_ANDBELOW_MASK  0x0001FFFF
+#define XCHAL_INTLEVEL9_ANDBELOW_MASK  0x0001FFFF
+#define XCHAL_INTLEVEL10_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL11_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL12_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL13_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL14_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL15_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_LOWPRI_MASK              XCHAL_INTLEVEL1_ANDBELOW_MASK   /* mask of all low-priority interrupts */
+#define XCHAL_EXCM_MASK                        XCHAL_INTLEVEL1_ANDBELOW_MASK   /* mask of all interrupts masked by PS.EXCM (or CEXCM) */
+/*  As an array of entries (eg. for C constant arrays):  */
+#define XCHAL_INTLEVEL_ANDBELOW_MASKS  0x00000000      XCHAL_SEP \
+                                       0x000064F9      XCHAL_SEP \
+                                       0x0000EDFB      XCHAL_SEP \
+                                       0x0001FFFF      XCHAL_SEP \
+                                       0x0001FFFF      XCHAL_SEP \
+                                       0x0001FFFF      XCHAL_SEP \
+                                       0x0001FFFF      XCHAL_SEP \
+                                       0x0001FFFF      XCHAL_SEP \
+                                       0x0001FFFF      XCHAL_SEP \
+                                       0x0001FFFF      XCHAL_SEP \
+                                       0x0001FFFF      XCHAL_SEP \
+                                       0x0001FFFF      XCHAL_SEP \
+                                       0x0001FFFF      XCHAL_SEP \
+                                       0x0001FFFF      XCHAL_SEP \
+                                       0x0001FFFF      XCHAL_SEP \
+                                       0x0001FFFF
+
+/*  Interrupt numbers for each interrupt level at which only one interrupt was configured:  */
+/*#define XCHAL_INTLEVEL1_NUM          ...more than one interrupt at this level...*/
+/*#define XCHAL_INTLEVEL2_NUM          ...more than one interrupt at this level...*/
+/*#define XCHAL_INTLEVEL3_NUM          ...more than one interrupt at this level...*/
+
+/*  Level of each interrupt:  */
+#define XCHAL_INT0_LEVEL               1
+#define XCHAL_INT1_LEVEL               2
+#define XCHAL_INT2_LEVEL               3
+#define XCHAL_INT3_LEVEL               1
+#define XCHAL_INT4_LEVEL               1
+#define XCHAL_INT5_LEVEL               1
+#define XCHAL_INT6_LEVEL               1
+#define XCHAL_INT7_LEVEL               1
+#define XCHAL_INT8_LEVEL               2
+#define XCHAL_INT9_LEVEL               3
+#define XCHAL_INT10_LEVEL              1
+#define XCHAL_INT11_LEVEL              2
+#define XCHAL_INT12_LEVEL              3
+#define XCHAL_INT13_LEVEL              1
+#define XCHAL_INT14_LEVEL              1
+#define XCHAL_INT15_LEVEL              2
+#define XCHAL_INT16_LEVEL              3
+#define XCHAL_INT17_LEVEL              0
+#define XCHAL_INT18_LEVEL              0
+#define XCHAL_INT19_LEVEL              0
+#define XCHAL_INT20_LEVEL              0
+#define XCHAL_INT21_LEVEL              0
+#define XCHAL_INT22_LEVEL              0
+#define XCHAL_INT23_LEVEL              0
+#define XCHAL_INT24_LEVEL              0
+#define XCHAL_INT25_LEVEL              0
+#define XCHAL_INT26_LEVEL              0
+#define XCHAL_INT27_LEVEL              0
+#define XCHAL_INT28_LEVEL              0
+#define XCHAL_INT29_LEVEL              0
+#define XCHAL_INT30_LEVEL              0
+#define XCHAL_INT31_LEVEL              0
+/*  As an array of entries (eg. for C constant arrays):  */
+#define XCHAL_INT_LEVELS               1       XCHAL_SEP \
+                                       2       XCHAL_SEP \
+                                       3       XCHAL_SEP \
+                                       1       XCHAL_SEP \
+                                       1       XCHAL_SEP \
+                                       1       XCHAL_SEP \
+                                       1       XCHAL_SEP \
+                                       1       XCHAL_SEP \
+                                       2       XCHAL_SEP \
+                                       3       XCHAL_SEP \
+                                       1       XCHAL_SEP \
+                                       2       XCHAL_SEP \
+                                       3       XCHAL_SEP \
+                                       1       XCHAL_SEP \
+                                       1       XCHAL_SEP \
+                                       2       XCHAL_SEP \
+                                       3       XCHAL_SEP \
+                                       0       XCHAL_SEP \
+                                       0       XCHAL_SEP \
+                                       0       XCHAL_SEP \
+                                       0       XCHAL_SEP \
+                                       0       XCHAL_SEP \
+                                       0       XCHAL_SEP \
+                                       0       XCHAL_SEP \
+                                       0       XCHAL_SEP \
+                                       0       XCHAL_SEP \
+                                       0       XCHAL_SEP \
+                                       0       XCHAL_SEP \
+                                       0       XCHAL_SEP \
+                                       0       XCHAL_SEP \
+                                       0       XCHAL_SEP \
+                                       0
+
+/*  Type of each interrupt:  */
+#define XCHAL_INT0_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT1_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT2_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT3_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT4_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT5_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT6_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT7_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT8_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT9_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT10_TYPE       XTHAL_INTTYPE_TIMER
+#define XCHAL_INT11_TYPE       XTHAL_INTTYPE_TIMER
+#define XCHAL_INT12_TYPE       XTHAL_INTTYPE_TIMER
+#define XCHAL_INT13_TYPE       XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT14_TYPE       XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT15_TYPE       XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT16_TYPE       XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT17_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT18_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT19_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT20_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT21_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT22_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT23_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT24_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT25_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT26_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT27_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT28_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT29_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT30_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT31_TYPE       XTHAL_INTTYPE_UNCONFIGURED
+/*  As an array of entries (eg. for C constant arrays):  */
+#define XCHAL_INT_TYPES                XTHAL_INTTYPE_EXTERN_LEVEL      XCHAL_SEP \
+                               XTHAL_INTTYPE_EXTERN_LEVEL      XCHAL_SEP \
+                               XTHAL_INTTYPE_EXTERN_LEVEL      XCHAL_SEP \
+                               XTHAL_INTTYPE_EXTERN_LEVEL      XCHAL_SEP \
+                               XTHAL_INTTYPE_EXTERN_LEVEL      XCHAL_SEP \
+                               XTHAL_INTTYPE_EXTERN_LEVEL      XCHAL_SEP \
+                               XTHAL_INTTYPE_EXTERN_LEVEL      XCHAL_SEP \
+                               XTHAL_INTTYPE_EXTERN_EDGE       XCHAL_SEP \
+                               XTHAL_INTTYPE_EXTERN_EDGE       XCHAL_SEP \
+                               XTHAL_INTTYPE_EXTERN_EDGE       XCHAL_SEP \
+                               XTHAL_INTTYPE_TIMER             XCHAL_SEP \
+                               XTHAL_INTTYPE_TIMER             XCHAL_SEP \
+                               XTHAL_INTTYPE_TIMER             XCHAL_SEP \
+                               XTHAL_INTTYPE_SOFTWARE          XCHAL_SEP \
+                               XTHAL_INTTYPE_SOFTWARE          XCHAL_SEP \
+                               XTHAL_INTTYPE_SOFTWARE          XCHAL_SEP \
+                               XTHAL_INTTYPE_SOFTWARE          XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
+                               XTHAL_INTTYPE_UNCONFIGURED
+
+/*  Masks of interrupts for each type of interrupt:  */
+#define XCHAL_INTTYPE_MASK_UNCONFIGURED        0xFFFE0000
+#define XCHAL_INTTYPE_MASK_SOFTWARE    0x0001E000
+#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00000380
+#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL        0x0000007F
+#define XCHAL_INTTYPE_MASK_TIMER       0x00001C00
+#define XCHAL_INTTYPE_MASK_NMI         0x00000000
+/*  As an array of entries (eg. for C constant arrays):  */
+#define XCHAL_INTTYPE_MASKS            0xFFFE0000      XCHAL_SEP \
+                                       0x0001E000      XCHAL_SEP \
+                                       0x00000380      XCHAL_SEP \
+                                       0x0000007F      XCHAL_SEP \
+                                       0x00001C00      XCHAL_SEP \
+                                       0x00000000
+
+/*  Interrupts assigned to each timer (CCOMPARE0 to CCOMPARE3), -1 if unassigned  */
+#define XCHAL_TIMER0_INTERRUPT 10
+#define XCHAL_TIMER1_INTERRUPT 11
+#define XCHAL_TIMER2_INTERRUPT 12
+#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED
+/*  As an array of entries (eg. for C constant arrays):  */
+#define XCHAL_TIMER_INTERRUPTS 10      XCHAL_SEP \
+                               11      XCHAL_SEP \
+                               12      XCHAL_SEP \
+                               XTHAL_TIMER_UNCONFIGURED
+
+/*  Indexing macros:  */
+#define _XCHAL_INTLEVEL_MASK(n)                XCHAL_INTLEVEL ## n ## _MASK
+#define XCHAL_INTLEVEL_MASK(n)         _XCHAL_INTLEVEL_MASK(n)         /* n = 0 .. 15 */
+#define _XCHAL_INTLEVEL_ANDBELOWMASK(n)        XCHAL_INTLEVEL ## n ## _ANDBELOW_MASK
+#define XCHAL_INTLEVEL_ANDBELOW_MASK(n)        _XCHAL_INTLEVEL_ANDBELOWMASK(n) /* n = 0 .. 15 */
+#define _XCHAL_INT_LEVEL(n)            XCHAL_INT ## n ## _LEVEL
+#define XCHAL_INT_LEVEL(n)             _XCHAL_INT_LEVEL(n)             /* n = 0 .. 31 */
+#define _XCHAL_INT_TYPE(n)             XCHAL_INT ## n ## _TYPE
+#define XCHAL_INT_TYPE(n)              _XCHAL_INT_TYPE(n)              /* n = 0 .. 31 */
+#define _XCHAL_TIMER_INTERRUPT(n)      XCHAL_TIMER ## n ## _INTERRUPT
+#define XCHAL_TIMER_INTERRUPT(n)       _XCHAL_TIMER_INTERRUPT(n)       /* n = 0 .. 3 */
+
+
+
+/*
+ *  External interrupt vectors/levels.
+ *  These macros describe how Xtensa processor interrupt numbers
+ *  (as numbered internally, eg. in INTERRUPT and INTENABLE registers)
+ *  map to external BInterrupt<n> pins, for those interrupts
+ *  configured as external (level-triggered, edge-triggered, or NMI).
+ *  See the Xtensa processor databook for more details.
+ */
+
+/*  Core interrupt numbers mapped to each EXTERNAL interrupt number:  */
+#define XCHAL_EXTINT0_NUM              0       /* (intlevel 1) */
+#define XCHAL_EXTINT1_NUM              1       /* (intlevel 2) */
+#define XCHAL_EXTINT2_NUM              2       /* (intlevel 3) */
+#define XCHAL_EXTINT3_NUM              3       /* (intlevel 1) */
+#define XCHAL_EXTINT4_NUM              4       /* (intlevel 1) */
+#define XCHAL_EXTINT5_NUM              5       /* (intlevel 1) */
+#define XCHAL_EXTINT6_NUM              6       /* (intlevel 1) */
+#define XCHAL_EXTINT7_NUM              7       /* (intlevel 1) */
+#define XCHAL_EXTINT8_NUM              8       /* (intlevel 2) */
+#define XCHAL_EXTINT9_NUM              9       /* (intlevel 3) */
+
+/*  Corresponding interrupt masks:  */
+#define XCHAL_EXTINT0_MASK             0x00000001
+#define XCHAL_EXTINT1_MASK             0x00000002
+#define XCHAL_EXTINT2_MASK             0x00000004
+#define XCHAL_EXTINT3_MASK             0x00000008
+#define XCHAL_EXTINT4_MASK             0x00000010
+#define XCHAL_EXTINT5_MASK             0x00000020
+#define XCHAL_EXTINT6_MASK             0x00000040
+#define XCHAL_EXTINT7_MASK             0x00000080
+#define XCHAL_EXTINT8_MASK             0x00000100
+#define XCHAL_EXTINT9_MASK             0x00000200
+
+/*  Core config interrupt levels mapped to each external interrupt:  */
+#define XCHAL_EXTINT0_LEVEL            1       /* (int number 0) */
+#define XCHAL_EXTINT1_LEVEL            2       /* (int number 1) */
+#define XCHAL_EXTINT2_LEVEL            3       /* (int number 2) */
+#define XCHAL_EXTINT3_LEVEL            1       /* (int number 3) */
+#define XCHAL_EXTINT4_LEVEL            1       /* (int number 4) */
+#define XCHAL_EXTINT5_LEVEL            1       /* (int number 5) */
+#define XCHAL_EXTINT6_LEVEL            1       /* (int number 6) */
+#define XCHAL_EXTINT7_LEVEL            1       /* (int number 7) */
+#define XCHAL_EXTINT8_LEVEL            2       /* (int number 8) */
+#define XCHAL_EXTINT9_LEVEL            3       /* (int number 9) */
+
+
+/*----------------------------------------------------------------------
+                       EXCEPTIONS and VECTORS
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_EXCEPTIONS          1       /* 1 if exception option configured, 0 otherwise */
+
+#define XCHAL_XEA_VERSION              2       /* Xtensa Exception Architecture number: 1 for XEA1 (old), 2 for XEA2 (new) */
+#define XCHAL_HAVE_XEA1                        0       /* 1 if XEA1, 0 otherwise */
+#define XCHAL_HAVE_XEA2                        1       /* 1 if XEA2, 0 otherwise */
+/*  For backward compatibility ONLY -- DO NOT USE (will be removed in future release):  */
+#define XCHAL_HAVE_OLD_EXC_ARCH                XCHAL_HAVE_XEA1 /* (DEPRECATED) 1 if old exception architecture (XEA1), 0 otherwise (eg. XEA2) */
+#define XCHAL_HAVE_EXCM                        XCHAL_HAVE_XEA2 /* (DEPRECATED) 1 if PS.EXCM bit exists (currently equals XCHAL_HAVE_TLBS) */
+
+#define XCHAL_RESET_VECTOR_VADDR       0xFE000020
+#define XCHAL_RESET_VECTOR_PADDR       0xFE000020
+#define XCHAL_USER_VECTOR_VADDR                0xD0000220
+#define XCHAL_PROGRAMEXC_VECTOR_VADDR  XCHAL_USER_VECTOR_VADDR         /* for backward compatibility */
+#define XCHAL_USEREXC_VECTOR_VADDR     XCHAL_USER_VECTOR_VADDR         /* for backward compatibility */
+#define XCHAL_USER_VECTOR_PADDR                0x00000220
+#define XCHAL_PROGRAMEXC_VECTOR_PADDR  XCHAL_USER_VECTOR_PADDR         /* for backward compatibility */
+#define XCHAL_USEREXC_VECTOR_PADDR     XCHAL_USER_VECTOR_PADDR         /* for backward compatibility */
+#define XCHAL_KERNEL_VECTOR_VADDR      0xD0000200
+#define XCHAL_STACKEDEXC_VECTOR_VADDR  XCHAL_KERNEL_VECTOR_VADDR       /* for backward compatibility */
+#define XCHAL_KERNELEXC_VECTOR_VADDR   XCHAL_KERNEL_VECTOR_VADDR       /* for backward compatibility */
+#define XCHAL_KERNEL_VECTOR_PADDR      0x00000200
+#define XCHAL_STACKEDEXC_VECTOR_PADDR  XCHAL_KERNEL_VECTOR_PADDR       /* for backward compatibility */
+#define XCHAL_KERNELEXC_VECTOR_PADDR   XCHAL_KERNEL_VECTOR_PADDR       /* for backward compatibility */
+#define XCHAL_DOUBLEEXC_VECTOR_VADDR   0xD0000290
+#define XCHAL_DOUBLEEXC_VECTOR_PADDR   0x00000290
+#define XCHAL_WINDOW_VECTORS_VADDR     0xD0000000
+#define XCHAL_WINDOW_VECTORS_PADDR     0x00000000
+#define XCHAL_INTLEVEL2_VECTOR_VADDR   0xD0000240
+#define XCHAL_INTLEVEL2_VECTOR_PADDR   0x00000240
+#define XCHAL_INTLEVEL3_VECTOR_VADDR   0xD0000250
+#define XCHAL_INTLEVEL3_VECTOR_PADDR   0x00000250
+#define XCHAL_INTLEVEL4_VECTOR_VADDR   0xFE000520
+#define XCHAL_INTLEVEL4_VECTOR_PADDR   0xFE000520
+#define XCHAL_DEBUG_VECTOR_VADDR       XCHAL_INTLEVEL4_VECTOR_VADDR
+#define XCHAL_DEBUG_VECTOR_PADDR       XCHAL_INTLEVEL4_VECTOR_PADDR
+
+/*  Indexing macros:  */
+#define _XCHAL_INTLEVEL_VECTOR_VADDR(n)                XCHAL_INTLEVEL ## n ## _VECTOR_VADDR
+#define XCHAL_INTLEVEL_VECTOR_VADDR(n)         _XCHAL_INTLEVEL_VECTOR_VADDR(n)         /* n = 0 .. 15 */
+
+/*
+ *  General Exception Causes
+ *  (values of EXCCAUSE special register set by general exceptions,
+ *   which vector to the user, kernel, or double-exception vectors):
+ */
+#define XCHAL_EXCCAUSE_ILLEGAL_INSTRUCTION             0       /* Illegal Instruction (IllegalInstruction) */
+#define XCHAL_EXCCAUSE_SYSTEM_CALL                     1       /* System Call (SystemCall) */
+#define XCHAL_EXCCAUSE_INSTRUCTION_FETCH_ERROR         2       /* Instruction Fetch Error (InstructionFetchError) */
+#define XCHAL_EXCCAUSE_LOAD_STORE_ERROR                        3       /* Load Store Error (LoadStoreError) */
+#define XCHAL_EXCCAUSE_LEVEL1_INTERRUPT                        4       /* Level 1 Interrupt (Level1Interrupt) */
+#define XCHAL_EXCCAUSE_ALLOCA                          5       /* Stack Extension Assist (Alloca) */
+#define XCHAL_EXCCAUSE_INTEGER_DIVIDE_BY_ZERO          6       /* Integer Divide by Zero (IntegerDivideByZero) */
+#define XCHAL_EXCCAUSE_SPECULATION                     7       /* Speculation (Speculation) */
+#define XCHAL_EXCCAUSE_PRIVILEGED                      8       /* Privileged Instruction (Privileged) */
+#define XCHAL_EXCCAUSE_UNALIGNED                       9       /* Unaligned Load Store (Unaligned) */
+#define XCHAL_EXCCAUSE_ITLB_MISS                       16      /* ITlb Miss Exception (ITlbMiss) */
+#define XCHAL_EXCCAUSE_ITLB_MULTIHIT                   17      /* ITlb Mutltihit Exception (ITlbMultihit) */
+#define XCHAL_EXCCAUSE_ITLB_PRIVILEGE                  18      /* ITlb Privilege Exception (ITlbPrivilege) */
+#define XCHAL_EXCCAUSE_ITLB_SIZE_RESTRICTION           19      /* ITlb Size Restriction Exception (ITlbSizeRestriction) */
+#define XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE           20      /* Fetch Cache Attribute Exception (FetchCacheAttribute) */
+#define XCHAL_EXCCAUSE_DTLB_MISS                       24      /* DTlb Miss Exception (DTlbMiss) */
+#define XCHAL_EXCCAUSE_DTLB_MULTIHIT                   25      /* DTlb Multihit Exception (DTlbMultihit) */
+#define XCHAL_EXCCAUSE_DTLB_PRIVILEGE                  26      /* DTlb Privilege Exception (DTlbPrivilege) */
+#define XCHAL_EXCCAUSE_DTLB_SIZE_RESTRICTION           27      /* DTlb Size Restriction Exception (DTlbSizeRestriction) */
+#define XCHAL_EXCCAUSE_LOAD_CACHE_ATTRIBUTE            28      /* Load Cache Attribute Exception (LoadCacheAttribute) */
+#define XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE           29      /* Store Cache Attribute Exception (StoreCacheAttribute) */
+#define XCHAL_EXCCAUSE_FLOATING_POINT                  40      /* Floating Point Exception (FloatingPoint) */
+
+
+
+/*----------------------------------------------------------------------
+                               TIMERS
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_CCOUNT              1       /* 1 if have CCOUNT, 0 otherwise */
+/*#define XCHAL_HAVE_TIMERS            XCHAL_HAVE_CCOUNT*/
+#define XCHAL_NUM_TIMERS               3       /* number of CCOMPAREn regs */
+
+
+
+/*----------------------------------------------------------------------
+                               DEBUG
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_DEBUG               1       /* 1 if debug option configured, 0 otherwise */
+#define XCHAL_HAVE_OCD                 1       /* 1 if OnChipDebug option configured, 0 otherwise */
+#define XCHAL_NUM_IBREAK               2       /* number of IBREAKn regs */
+#define XCHAL_NUM_DBREAK               2       /* number of DBREAKn regs */
+#define XCHAL_DEBUGLEVEL               4       /* debug interrupt level */
+/*DebugExternalInterrupt               0               0|1*/
+/*DebugUseDIRArray                     0               0|1*/
+
+
+
+
+/*----------------------------------------------------------------------
+                       COPROCESSORS and EXTRA STATE
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_CP                  0       /* 1 if coprocessor option configured (CPENABLE present) */
+#define XCHAL_CP_MAXCFG                        0       /* max allowed cp id plus one (per cfg) */
+
+#include <xtensa/config/tie.h>
+
+
+
+
+/*----------------------------------------------------------------------
+                       INTERNAL I/D RAM/ROMs and XLMI
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_INSTROM              0       /* number of core instruction ROMs configured */
+#define XCHAL_NUM_INSTRAM              0       /* number of core instruction RAMs configured */
+#define XCHAL_NUM_DATAROM              0       /* number of core data ROMs configured */
+#define XCHAL_NUM_DATARAM              0       /* number of core data RAMs configured */
+#define XCHAL_NUM_XLMI                 0       /* number of core XLMI ports configured */
+#define  XCHAL_NUM_IROM                        XCHAL_NUM_INSTROM       /* (DEPRECATED) */
+#define  XCHAL_NUM_IRAM                        XCHAL_NUM_INSTRAM       /* (DEPRECATED) */
+#define  XCHAL_NUM_DROM                        XCHAL_NUM_DATAROM       /* (DEPRECATED) */
+#define  XCHAL_NUM_DRAM                        XCHAL_NUM_DATARAM       /* (DEPRECATED) */
+
+
+
+/*----------------------------------------------------------------------
+                               CACHE
+  ----------------------------------------------------------------------*/
+
+/*  Size of the cache lines in log2(bytes):  */
+#define XCHAL_ICACHE_LINEWIDTH         4
+#define XCHAL_DCACHE_LINEWIDTH         4
+/*  Size of the cache lines in bytes:  */
+#define XCHAL_ICACHE_LINESIZE          16
+#define XCHAL_DCACHE_LINESIZE          16
+/*  Max for both I-cache and D-cache (used for general alignment):  */
+#define XCHAL_CACHE_LINEWIDTH_MAX      4
+#define XCHAL_CACHE_LINESIZE_MAX       16
+
+/*  Number of cache sets in log2(lines per way):  */
+#define XCHAL_ICACHE_SETWIDTH          8
+#define XCHAL_DCACHE_SETWIDTH          8
+/*  Max for both I-cache and D-cache (used for general cache-coherency page alignment):  */
+#define XCHAL_CACHE_SETWIDTH_MAX       8
+#define XCHAL_CACHE_SETSIZE_MAX                256
+
+/*  Cache set associativity (number of ways):  */
+#define XCHAL_ICACHE_WAYS              2
+#define XCHAL_DCACHE_WAYS              2
+
+/*  Size of the caches in bytes (ways * 2^(linewidth + setwidth)):  */
+#define XCHAL_ICACHE_SIZE              8192
+#define XCHAL_DCACHE_SIZE              8192
+
+/*  Cache features:  */
+#define XCHAL_DCACHE_IS_WRITEBACK      0
+/*  Whether cache locking feature is available:  */
+#define XCHAL_ICACHE_LINE_LOCKABLE     0
+#define XCHAL_DCACHE_LINE_LOCKABLE     0
+
+/*  Number of (encoded) cache attribute bits:  */
+#define XCHAL_CA_BITS                  4       /* number of bits needed to hold cache attribute encoding */
+/*  (The number of access mode bits (decoded cache attribute bits) is defined by the architecture; see xtensa/hal.h?)  */
+
+
+/*  Cache Attribute encodings -- lists of access modes for each cache attribute:  */
+#define XCHAL_FCA_LIST         XTHAL_FAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_FAM_BYPASS        XCHAL_SEP \
+                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_FAM_BYPASS        XCHAL_SEP \
+                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_FAM_CACHED        XCHAL_SEP \
+                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_FAM_CACHED        XCHAL_SEP \
+                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_FAM_CACHED        XCHAL_SEP \
+                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_FAM_CACHED        XCHAL_SEP \
+                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_FAM_EXCEPTION
+#define XCHAL_LCA_LIST         XTHAL_LAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_LAM_BYPASSG       XCHAL_SEP \
+                               XTHAL_LAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_LAM_BYPASSG       XCHAL_SEP \
+                               XTHAL_LAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_LAM_CACHED        XCHAL_SEP \
+                               XTHAL_LAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_LAM_CACHED        XCHAL_SEP \
+                               XTHAL_LAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_LAM_NACACHED      XCHAL_SEP \
+                               XTHAL_LAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_LAM_NACACHED      XCHAL_SEP \
+                               XTHAL_LAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_LAM_ISOLATE       XCHAL_SEP \
+                               XTHAL_LAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_LAM_CACHED
+#define XCHAL_SCA_LIST         XTHAL_SAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_SAM_BYPASS        XCHAL_SEP \
+                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_SAM_WRITETHRU     XCHAL_SEP \
+                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_SAM_WRITETHRU     XCHAL_SEP \
+                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_SAM_ISOLATE       XCHAL_SEP \
+                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
+                               XTHAL_SAM_WRITETHRU
+
+/*  Test:
+       read/only: 0 + 1 + 2 + 4 + 5 + 6 + 8 + 9 + 10 + 12 + 14
+       read/only: 0 + 1 + 2 + 4 + 5 + 6 + 8 + 9 + 10 + 12 + 14
+       all:       0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15
+       fault:     0 + 2 + 4 + 6 + 8 + 10 + 12 + 14
+       r/w/x cached:
+       r/w/x dcached:
+       I-bypass:  1 + 3
+
+       load guard bit set: 1 + 3
+       load guard bit clr: 0 + 2 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15
+       hit-cache r/w/x: 7 + 11
+
+       fams: 5
+       fams: 0 / 6 / 18 / 1 / 2
+       fams: Bypass / Isolate / Cached / Exception / NACached
+
+        MMU okay:  yes
+*/
+
+
+/*----------------------------------------------------------------------
+                               MMU
+  ----------------------------------------------------------------------*/
+
+/*
+ *  General notes on MMU parameters.
+ *
+ *  Terminology:
+ *     ASID = address-space ID (acts as an "extension" of virtual addresses)
+ *     VPN  = virtual page number
+ *     PPN  = physical page number
+ *     CA   = encoded cache attribute (access modes)
+ *     TLB  = translation look-aside buffer (term is stretched somewhat here)
+ *     I    = instruction (fetch accesses)
+ *     D    = data (load and store accesses)
+ *     way  = each TLB (ITLB and DTLB) consists of a number of "ways"
+ *             that simultaneously match the virtual address of an access;
+ *             a TLB successfully translates a virtual address if exactly
+ *             one way matches the vaddr; if none match, it is a miss;
+ *             if multiple match, one gets a "multihit" exception;
+ *             each way can be independently configured in terms of number of
+ *             entries, page sizes, which fields are writable or constant, etc.
+ *     set  = group of contiguous ways with exactly identical parameters
+ *     ARF  = auto-refill; hardware services a 1st-level miss by loading a PTE
+ *             from the page table and storing it in one of the auto-refill ways;
+ *             if this PTE load also misses, a miss exception is posted for s/w.
+ *     min-wired = a "min-wired" way can be used to map a single (minimum-sized)
+ *             page arbitrarily under program control; it has a single entry,
+ *             is non-auto-refill (some other way(s) must be auto-refill),
+ *             all its fields (VPN, PPN, ASID, CA) are all writable, and it
+ *             supports the XCHAL_MMU_MIN_PTE_PAGE_SIZE page size (a current
+ *             restriction is that this be the only page size it supports).
+ *
+ *  TLB way entries are virtually indexed.
+ *  TLB ways that support multiple page sizes:
+ *     - must have all writable VPN and PPN fields;
+ *     - can only use one page size at any given time (eg. setup at startup),
+ *       selected by the respective ITLBCFG or DTLBCFG special register,
+ *       whose bits n*4+3 .. n*4 index the list of page sizes for way n
+ *       (XCHAL_xTLB_SETm_PAGESZ_LOG2_LIST for set m corresponding to way n);
+ *       this list may be sparse for auto-refill ways because auto-refill
+ *       ways have independent lists of supported page sizes sharing a
+ *       common encoding with PTE entries; the encoding is the index into
+ *       this list; unsupported sizes for a given way are zero in the list;
+ *       selecting unsupported sizes results in undefined hardware behaviour;
+ *     - is only possible for ways 0 thru 7 (due to ITLBCFG/DTLBCFG definition).
+ */
+
+#define XCHAL_HAVE_CACHEATTR           0       /* 1 if CACHEATTR register present, 0 if TLBs present instead */
+#define XCHAL_HAVE_TLBS                        1       /* 1 if TLBs present, 0 if CACHEATTR present instead */
+#define XCHAL_HAVE_MMU                 XCHAL_HAVE_TLBS /* (DEPRECATED; use XCHAL_HAVE_TLBS instead; will be removed in future release) */
+#define XCHAL_HAVE_SPANNING_WAY                0       /* 1 if single way maps entire virtual address space in I+D */
+#define XCHAL_HAVE_IDENTITY_MAP                0       /* 1 if virtual addr == physical addr always, 0 otherwise */
+#define XCHAL_HAVE_MIMIC_CACHEATTR     0       /* 1 if have MMU that mimics a CACHEATTR config (CaMMU) */
+#define XCHAL_HAVE_XLT_CACHEATTR       0       /* 1 if have MMU that mimics a CACHEATTR config, but with translation (CaXltMMU) */
+
+#define XCHAL_MMU_ASID_BITS            8       /* number of bits in ASIDs (address space IDs) */
+#define XCHAL_MMU_ASID_INVALID         0       /* ASID value indicating invalid address space */
+#define XCHAL_MMU_ASID_KERNEL          1       /* ASID value indicating kernel (ring 0) address space */
+#define XCHAL_MMU_RINGS                        4       /* number of rings supported (1..4) */
+#define XCHAL_MMU_RING_BITS            2       /* number of bits needed to hold ring number */
+#define XCHAL_MMU_SR_BITS              0       /* number of size-restriction bits supported */
+#define XCHAL_MMU_CA_BITS              4       /* number of bits needed to hold cache attribute encoding */
+#define XCHAL_MMU_MAX_PTE_PAGE_SIZE    12      /* max page size in a PTE structure (log2) */
+#define XCHAL_MMU_MIN_PTE_PAGE_SIZE    12      /* min page size in a PTE structure (log2) */
+
+
+/***  Instruction TLB:  ***/
+
+#define XCHAL_ITLB_WAY_BITS            3       /* number of bits holding the ways */
+#define XCHAL_ITLB_WAYS                        7       /* number of ways (n-way set-associative TLB) */
+#define XCHAL_ITLB_ARF_WAYS            4       /* number of auto-refill ways */
+#define XCHAL_ITLB_SETS                        4       /* number of sets (groups of ways with identical settings) */
+
+/*  Way set to which each way belongs:  */
+#define XCHAL_ITLB_WAY0_SET            0
+#define XCHAL_ITLB_WAY1_SET            0
+#define XCHAL_ITLB_WAY2_SET            0
+#define XCHAL_ITLB_WAY3_SET            0
+#define XCHAL_ITLB_WAY4_SET            1
+#define XCHAL_ITLB_WAY5_SET            2
+#define XCHAL_ITLB_WAY6_SET            3
+
+/*  Ways sets that are used by hardware auto-refill (ARF):  */
+#define XCHAL_ITLB_ARF_SETS            1       /* number of auto-refill sets */
+#define XCHAL_ITLB_ARF_SET0            0       /* index of n'th auto-refill set */
+
+/*  Way sets that are "min-wired" (see terminology comment above):  */
+#define XCHAL_ITLB_MINWIRED_SETS       0       /* number of "min-wired" sets */
+
+
+/*  ITLB way set 0 (group of ways 0 thru 3):  */
+#define XCHAL_ITLB_SET0_WAY                    0       /* index of first way in this way set */
+#define XCHAL_ITLB_SET0_WAYS                   4       /* number of (contiguous) ways in this way set */
+#define XCHAL_ITLB_SET0_ENTRIES_LOG2           2       /* log2(number of entries in this way) */
+#define XCHAL_ITLB_SET0_ENTRIES                        4       /* number of entries in this way (always a power of 2) */
+#define XCHAL_ITLB_SET0_ARF                    1       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_ITLB_SET0_PAGESIZES              1       /* number of supported page sizes in this way */
+#define XCHAL_ITLB_SET0_PAGESZ_BITS            0       /* number of bits to encode the page size */
+#define XCHAL_ITLB_SET0_PAGESZ_LOG2_MIN                12      /* log2(minimum supported page size) */
+#define XCHAL_ITLB_SET0_PAGESZ_LOG2_MAX                12      /* log2(maximum supported page size) */
+#define XCHAL_ITLB_SET0_PAGESZ_LOG2_LIST       12      /* list of log2(page size)s, separated by XCHAL_SEP;
+                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_ITLB_SET0_ASID_CONSTMASK         0       /* constant ASID bits; 0 if all writable */
+#define XCHAL_ITLB_SET0_VPN_CONSTMASK          0       /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET0_PPN_CONSTMASK          0       /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET0_CA_CONSTMASK           0       /* constant CA bits; 0 if all writable */
+#define XCHAL_ITLB_SET0_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET0_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET0_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET0_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
+
+/*  ITLB way set 1 (group of ways 4 thru 4):  */
+#define XCHAL_ITLB_SET1_WAY                    4       /* index of first way in this way set */
+#define XCHAL_ITLB_SET1_WAYS                   1       /* number of (contiguous) ways in this way set */
+#define XCHAL_ITLB_SET1_ENTRIES_LOG2           2       /* log2(number of entries in this way) */
+#define XCHAL_ITLB_SET1_ENTRIES                        4       /* number of entries in this way (always a power of 2) */
+#define XCHAL_ITLB_SET1_ARF                    0       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_ITLB_SET1_PAGESIZES              4       /* number of supported page sizes in this way */
+#define XCHAL_ITLB_SET1_PAGESZ_BITS            2       /* number of bits to encode the page size */
+#define XCHAL_ITLB_SET1_PAGESZ_LOG2_MIN                20      /* log2(minimum supported page size) */
+#define XCHAL_ITLB_SET1_PAGESZ_LOG2_MAX                26      /* log2(maximum supported page size) */
+#define XCHAL_ITLB_SET1_PAGESZ_LOG2_LIST       20 XCHAL_SEP 22 XCHAL_SEP 24 XCHAL_SEP 26       /* list of log2(page size)s, separated by XCHAL_SEP;
+                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_ITLB_SET1_ASID_CONSTMASK         0       /* constant ASID bits; 0 if all writable */
+#define XCHAL_ITLB_SET1_VPN_CONSTMASK          0       /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET1_PPN_CONSTMASK          0       /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET1_CA_CONSTMASK           0       /* constant CA bits; 0 if all writable */
+#define XCHAL_ITLB_SET1_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET1_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET1_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET1_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
+
+/*  ITLB way set 2 (group of ways 5 thru 5):  */
+#define XCHAL_ITLB_SET2_WAY                    5       /* index of first way in this way set */
+#define XCHAL_ITLB_SET2_WAYS                   1       /* number of (contiguous) ways in this way set */
+#define XCHAL_ITLB_SET2_ENTRIES_LOG2           1       /* log2(number of entries in this way) */
+#define XCHAL_ITLB_SET2_ENTRIES                        2       /* number of entries in this way (always a power of 2) */
+#define XCHAL_ITLB_SET2_ARF                    0       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_ITLB_SET2_PAGESIZES              1       /* number of supported page sizes in this way */
+#define XCHAL_ITLB_SET2_PAGESZ_BITS            0       /* number of bits to encode the page size */
+#define XCHAL_ITLB_SET2_PAGESZ_LOG2_MIN                27      /* log2(minimum supported page size) */
+#define XCHAL_ITLB_SET2_PAGESZ_LOG2_MAX                27      /* log2(maximum supported page size) */
+#define XCHAL_ITLB_SET2_PAGESZ_LOG2_LIST       27      /* list of log2(page size)s, separated by XCHAL_SEP;
+                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_ITLB_SET2_ASID_CONSTMASK         0xFF    /* constant ASID bits; 0 if all writable */
+#define XCHAL_ITLB_SET2_VPN_CONSTMASK          0xF0000000      /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET2_PPN_CONSTMASK          0xF8000000      /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET2_CA_CONSTMASK           0x0000000F      /* constant CA bits; 0 if all writable */
+#define XCHAL_ITLB_SET2_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET2_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET2_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET2_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
+/*  Constant ASID values for each entry of ITLB way set 2 (because ASID_CONSTMASK is non-zero):  */
+#define XCHAL_ITLB_SET2_E0_ASID_CONST          0x01
+#define XCHAL_ITLB_SET2_E1_ASID_CONST          0x01
+/*  Constant VPN values for each entry of ITLB way set 2 (because VPN_CONSTMASK is non-zero):  */
+#define XCHAL_ITLB_SET2_E0_VPN_CONST           0xD0000000
+#define XCHAL_ITLB_SET2_E1_VPN_CONST           0xD8000000
+/*  Constant PPN values for each entry of ITLB way set 2 (because PPN_CONSTMASK is non-zero):  */
+#define XCHAL_ITLB_SET2_E0_PPN_CONST           0x00000000
+#define XCHAL_ITLB_SET2_E1_PPN_CONST           0x00000000
+/*  Constant CA values for each entry of ITLB way set 2 (because CA_CONSTMASK is non-zero):  */
+#define XCHAL_ITLB_SET2_E0_CA_CONST            0x07
+#define XCHAL_ITLB_SET2_E1_CA_CONST            0x03
+
+/*  ITLB way set 3 (group of ways 6 thru 6):  */
+#define XCHAL_ITLB_SET3_WAY                    6       /* index of first way in this way set */
+#define XCHAL_ITLB_SET3_WAYS                   1       /* number of (contiguous) ways in this way set */
+#define XCHAL_ITLB_SET3_ENTRIES_LOG2           1       /* log2(number of entries in this way) */
+#define XCHAL_ITLB_SET3_ENTRIES                        2       /* number of entries in this way (always a power of 2) */
+#define XCHAL_ITLB_SET3_ARF                    0       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_ITLB_SET3_PAGESIZES              1       /* number of supported page sizes in this way */
+#define XCHAL_ITLB_SET3_PAGESZ_BITS            0       /* number of bits to encode the page size */
+#define XCHAL_ITLB_SET3_PAGESZ_LOG2_MIN                28      /* log2(minimum supported page size) */
+#define XCHAL_ITLB_SET3_PAGESZ_LOG2_MAX                28      /* log2(maximum supported page size) */
+#define XCHAL_ITLB_SET3_PAGESZ_LOG2_LIST       28      /* list of log2(page size)s, separated by XCHAL_SEP;
+                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_ITLB_SET3_ASID_CONSTMASK         0xFF    /* constant ASID bits; 0 if all writable */
+#define XCHAL_ITLB_SET3_VPN_CONSTMASK          0xE0000000      /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET3_PPN_CONSTMASK          0xF0000000      /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET3_CA_CONSTMASK           0x0000000F      /* constant CA bits; 0 if all writable */
+#define XCHAL_ITLB_SET3_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET3_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET3_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET3_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
+/*  Constant ASID values for each entry of ITLB way set 3 (because ASID_CONSTMASK is non-zero):  */
+#define XCHAL_ITLB_SET3_E0_ASID_CONST          0x01
+#define XCHAL_ITLB_SET3_E1_ASID_CONST          0x01
+/*  Constant VPN values for each entry of ITLB way set 3 (because VPN_CONSTMASK is non-zero):  */
+#define XCHAL_ITLB_SET3_E0_VPN_CONST           0xE0000000
+#define XCHAL_ITLB_SET3_E1_VPN_CONST           0xF0000000
+/*  Constant PPN values for each entry of ITLB way set 3 (because PPN_CONSTMASK is non-zero):  */
+#define XCHAL_ITLB_SET3_E0_PPN_CONST           0xF0000000
+#define XCHAL_ITLB_SET3_E1_PPN_CONST           0xF0000000
+/*  Constant CA values for each entry of ITLB way set 3 (because CA_CONSTMASK is non-zero):  */
+#define XCHAL_ITLB_SET3_E0_CA_CONST            0x07
+#define XCHAL_ITLB_SET3_E1_CA_CONST            0x03
+
+/*  Indexing macros:  */
+#define _XCHAL_ITLB_SET(n,_what)       XCHAL_ITLB_SET ## n ## _what
+#define XCHAL_ITLB_SET(n,what)         _XCHAL_ITLB_SET(n, _ ## what )
+#define _XCHAL_ITLB_SET_E(n,i,_what)   XCHAL_ITLB_SET ## n ## _E ## i ## _what
+#define XCHAL_ITLB_SET_E(n,i,what)     _XCHAL_ITLB_SET_E(n,i, _ ## what )
+/*
+ *  Example use:  XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,ENTRIES)
+ *     to get the value of XCHAL_ITLB_SET<n>_ENTRIES where <n> is the first auto-refill set.
+ */
+
+
+/***  Data TLB:  ***/
+
+#define XCHAL_DTLB_WAY_BITS            4       /* number of bits holding the ways */
+#define XCHAL_DTLB_WAYS                        10      /* number of ways (n-way set-associative TLB) */
+#define XCHAL_DTLB_ARF_WAYS            4       /* number of auto-refill ways */
+#define XCHAL_DTLB_SETS                        5       /* number of sets (groups of ways with identical settings) */
+
+/*  Way set to which each way belongs:  */
+#define XCHAL_DTLB_WAY0_SET            0
+#define XCHAL_DTLB_WAY1_SET            0
+#define XCHAL_DTLB_WAY2_SET            0
+#define XCHAL_DTLB_WAY3_SET            0
+#define XCHAL_DTLB_WAY4_SET            1
+#define XCHAL_DTLB_WAY5_SET            2
+#define XCHAL_DTLB_WAY6_SET            3
+#define XCHAL_DTLB_WAY7_SET            4
+#define XCHAL_DTLB_WAY8_SET            4
+#define XCHAL_DTLB_WAY9_SET            4
+
+/*  Ways sets that are used by hardware auto-refill (ARF):  */
+#define XCHAL_DTLB_ARF_SETS            1       /* number of auto-refill sets */
+#define XCHAL_DTLB_ARF_SET0            0       /* index of n'th auto-refill set */
+
+/*  Way sets that are "min-wired" (see terminology comment above):  */
+#define XCHAL_DTLB_MINWIRED_SETS       1       /* number of "min-wired" sets */
+#define XCHAL_DTLB_MINWIRED_SET0       4       /* index of n'th "min-wired" set */
+
+
+/*  DTLB way set 0 (group of ways 0 thru 3):  */
+#define XCHAL_DTLB_SET0_WAY                    0       /* index of first way in this way set */
+#define XCHAL_DTLB_SET0_WAYS                   4       /* number of (contiguous) ways in this way set */
+#define XCHAL_DTLB_SET0_ENTRIES_LOG2           2       /* log2(number of entries in this way) */
+#define XCHAL_DTLB_SET0_ENTRIES                        4       /* number of entries in this way (always a power of 2) */
+#define XCHAL_DTLB_SET0_ARF                    1       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_DTLB_SET0_PAGESIZES              1       /* number of supported page sizes in this way */
+#define XCHAL_DTLB_SET0_PAGESZ_BITS            0       /* number of bits to encode the page size */
+#define XCHAL_DTLB_SET0_PAGESZ_LOG2_MIN                12      /* log2(minimum supported page size) */
+#define XCHAL_DTLB_SET0_PAGESZ_LOG2_MAX                12      /* log2(maximum supported page size) */
+#define XCHAL_DTLB_SET0_PAGESZ_LOG2_LIST       12      /* list of log2(page size)s, separated by XCHAL_SEP;
+                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_DTLB_SET0_ASID_CONSTMASK         0       /* constant ASID bits; 0 if all writable */
+#define XCHAL_DTLB_SET0_VPN_CONSTMASK          0       /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET0_PPN_CONSTMASK          0       /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET0_CA_CONSTMASK           0       /* constant CA bits; 0 if all writable */
+#define XCHAL_DTLB_SET0_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET0_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET0_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET0_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
+
+/*  DTLB way set 1 (group of ways 4 thru 4):  */
+#define XCHAL_DTLB_SET1_WAY                    4       /* index of first way in this way set */
+#define XCHAL_DTLB_SET1_WAYS                   1       /* number of (contiguous) ways in this way set */
+#define XCHAL_DTLB_SET1_ENTRIES_LOG2           2       /* log2(number of entries in this way) */
+#define XCHAL_DTLB_SET1_ENTRIES                        4       /* number of entries in this way (always a power of 2) */
+#define XCHAL_DTLB_SET1_ARF                    0       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_DTLB_SET1_PAGESIZES              4       /* number of supported page sizes in this way */
+#define XCHAL_DTLB_SET1_PAGESZ_BITS            2       /* number of bits to encode the page size */
+#define XCHAL_DTLB_SET1_PAGESZ_LOG2_MIN                20      /* log2(minimum supported page size) */
+#define XCHAL_DTLB_SET1_PAGESZ_LOG2_MAX                26      /* log2(maximum supported page size) */
+#define XCHAL_DTLB_SET1_PAGESZ_LOG2_LIST       20 XCHAL_SEP 22 XCHAL_SEP 24 XCHAL_SEP 26       /* list of log2(page size)s, separated by XCHAL_SEP;
+                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_DTLB_SET1_ASID_CONSTMASK         0       /* constant ASID bits; 0 if all writable */
+#define XCHAL_DTLB_SET1_VPN_CONSTMASK          0       /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET1_PPN_CONSTMASK          0       /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET1_CA_CONSTMASK           0       /* constant CA bits; 0 if all writable */
+#define XCHAL_DTLB_SET1_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET1_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET1_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET1_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
+
+/*  DTLB way set 2 (group of ways 5 thru 5):  */
+#define XCHAL_DTLB_SET2_WAY                    5       /* index of first way in this way set */
+#define XCHAL_DTLB_SET2_WAYS                   1       /* number of (contiguous) ways in this way set */
+#define XCHAL_DTLB_SET2_ENTRIES_LOG2           1       /* log2(number of entries in this way) */
+#define XCHAL_DTLB_SET2_ENTRIES                        2       /* number of entries in this way (always a power of 2) */
+#define XCHAL_DTLB_SET2_ARF                    0       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_DTLB_SET2_PAGESIZES              1       /* number of supported page sizes in this way */
+#define XCHAL_DTLB_SET2_PAGESZ_BITS            0       /* number of bits to encode the page size */
+#define XCHAL_DTLB_SET2_PAGESZ_LOG2_MIN                27      /* log2(minimum supported page size) */
+#define XCHAL_DTLB_SET2_PAGESZ_LOG2_MAX                27      /* log2(maximum supported page size) */
+#define XCHAL_DTLB_SET2_PAGESZ_LOG2_LIST       27      /* list of log2(page size)s, separated by XCHAL_SEP;
+                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_DTLB_SET2_ASID_CONSTMASK         0xFF    /* constant ASID bits; 0 if all writable */
+#define XCHAL_DTLB_SET2_VPN_CONSTMASK          0xF0000000      /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET2_PPN_CONSTMASK          0xF8000000      /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET2_CA_CONSTMASK           0x0000000F      /* constant CA bits; 0 if all writable */
+#define XCHAL_DTLB_SET2_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET2_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET2_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET2_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
+/*  Constant ASID values for each entry of DTLB way set 2 (because ASID_CONSTMASK is non-zero):  */
+#define XCHAL_DTLB_SET2_E0_ASID_CONST          0x01
+#define XCHAL_DTLB_SET2_E1_ASID_CONST          0x01
+/*  Constant VPN values for each entry of DTLB way set 2 (because VPN_CONSTMASK is non-zero):  */
+#define XCHAL_DTLB_SET2_E0_VPN_CONST           0xD0000000
+#define XCHAL_DTLB_SET2_E1_VPN_CONST           0xD8000000
+/*  Constant PPN values for each entry of DTLB way set 2 (because PPN_CONSTMASK is non-zero):  */
+#define XCHAL_DTLB_SET2_E0_PPN_CONST           0x00000000
+#define XCHAL_DTLB_SET2_E1_PPN_CONST           0x00000000
+/*  Constant CA values for each entry of DTLB way set 2 (because CA_CONSTMASK is non-zero):  */
+#define XCHAL_DTLB_SET2_E0_CA_CONST            0x07
+#define XCHAL_DTLB_SET2_E1_CA_CONST            0x03
+
+/*  DTLB way set 3 (group of ways 6 thru 6):  */
+#define XCHAL_DTLB_SET3_WAY                    6       /* index of first way in this way set */
+#define XCHAL_DTLB_SET3_WAYS                   1       /* number of (contiguous) ways in this way set */
+#define XCHAL_DTLB_SET3_ENTRIES_LOG2           1       /* log2(number of entries in this way) */
+#define XCHAL_DTLB_SET3_ENTRIES                        2       /* number of entries in this way (always a power of 2) */
+#define XCHAL_DTLB_SET3_ARF                    0       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_DTLB_SET3_PAGESIZES              1       /* number of supported page sizes in this way */
+#define XCHAL_DTLB_SET3_PAGESZ_BITS            0       /* number of bits to encode the page size */
+#define XCHAL_DTLB_SET3_PAGESZ_LOG2_MIN                28      /* log2(minimum supported page size) */
+#define XCHAL_DTLB_SET3_PAGESZ_LOG2_MAX                28      /* log2(maximum supported page size) */
+#define XCHAL_DTLB_SET3_PAGESZ_LOG2_LIST       28      /* list of log2(page size)s, separated by XCHAL_SEP;
+                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_DTLB_SET3_ASID_CONSTMASK         0xFF    /* constant ASID bits; 0 if all writable */
+#define XCHAL_DTLB_SET3_VPN_CONSTMASK          0xE0000000      /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET3_PPN_CONSTMASK          0xF0000000      /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET3_CA_CONSTMASK           0x0000000F      /* constant CA bits; 0 if all writable */
+#define XCHAL_DTLB_SET3_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET3_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET3_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET3_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
+/*  Constant ASID values for each entry of DTLB way set 3 (because ASID_CONSTMASK is non-zero):  */
+#define XCHAL_DTLB_SET3_E0_ASID_CONST          0x01
+#define XCHAL_DTLB_SET3_E1_ASID_CONST          0x01
+/*  Constant VPN values for each entry of DTLB way set 3 (because VPN_CONSTMASK is non-zero):  */
+#define XCHAL_DTLB_SET3_E0_VPN_CONST           0xE0000000
+#define XCHAL_DTLB_SET3_E1_VPN_CONST           0xF0000000
+/*  Constant PPN values for each entry of DTLB way set 3 (because PPN_CONSTMASK is non-zero):  */
+#define XCHAL_DTLB_SET3_E0_PPN_CONST           0xF0000000
+#define XCHAL_DTLB_SET3_E1_PPN_CONST           0xF0000000
+/*  Constant CA values for each entry of DTLB way set 3 (because CA_CONSTMASK is non-zero):  */
+#define XCHAL_DTLB_SET3_E0_CA_CONST            0x07
+#define XCHAL_DTLB_SET3_E1_CA_CONST            0x03
+
+/*  DTLB way set 4 (group of ways 7 thru 9):  */
+#define XCHAL_DTLB_SET4_WAY                    7       /* index of first way in this way set */
+#define XCHAL_DTLB_SET4_WAYS                   3       /* number of (contiguous) ways in this way set */
+#define XCHAL_DTLB_SET4_ENTRIES_LOG2           0       /* log2(number of entries in this way) */
+#define XCHAL_DTLB_SET4_ENTRIES                        1       /* number of entries in this way (always a power of 2) */
+#define XCHAL_DTLB_SET4_ARF                    0       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_DTLB_SET4_PAGESIZES              1       /* number of supported page sizes in this way */
+#define XCHAL_DTLB_SET4_PAGESZ_BITS            0       /* number of bits to encode the page size */
+#define XCHAL_DTLB_SET4_PAGESZ_LOG2_MIN                12      /* log2(minimum supported page size) */
+#define XCHAL_DTLB_SET4_PAGESZ_LOG2_MAX                12      /* log2(maximum supported page size) */
+#define XCHAL_DTLB_SET4_PAGESZ_LOG2_LIST       12      /* list of log2(page size)s, separated by XCHAL_SEP;
+                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_DTLB_SET4_ASID_CONSTMASK         0       /* constant ASID bits; 0 if all writable */
+#define XCHAL_DTLB_SET4_VPN_CONSTMASK          0       /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET4_PPN_CONSTMASK          0       /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET4_CA_CONSTMASK           0       /* constant CA bits; 0 if all writable */
+#define XCHAL_DTLB_SET4_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET4_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET4_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET4_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
+
+/*  Indexing macros:  */
+#define _XCHAL_DTLB_SET(n,_what)       XCHAL_DTLB_SET ## n ## _what
+#define XCHAL_DTLB_SET(n,what)         _XCHAL_DTLB_SET(n, _ ## what )
+#define _XCHAL_DTLB_SET_E(n,i,_what)   XCHAL_DTLB_SET ## n ## _E ## i ## _what
+#define XCHAL_DTLB_SET_E(n,i,what)     _XCHAL_DTLB_SET_E(n,i, _ ## what )
+/*
+ *  Example use:  XCHAL_DTLB_SET(XCHAL_DTLB_ARF_SET0,ENTRIES)
+ *     to get the value of XCHAL_DTLB_SET<n>_ENTRIES where <n> is the first auto-refill set.
+ */
+
+
+/*
+ *  Determine whether we have a full MMU (with Page Table and Protection)
+ *  usable for an MMU-based OS:
+ */
+#if XCHAL_HAVE_TLBS && !XCHAL_HAVE_SPANNING_WAY && XCHAL_ITLB_ARF_WAYS > 0 && XCHAL_DTLB_ARF_WAYS > 0 && XCHAL_MMU_RINGS >= 2
+# define XCHAL_HAVE_PTP_MMU            1       /* have full MMU (with page table [autorefill] and protection) */
+#else
+# define XCHAL_HAVE_PTP_MMU            0       /* don't have full MMU */
+#endif
+
+/*
+ *  For full MMUs, report kernel RAM segment and kernel I/O segment static page mappings:
+ */
+#if XCHAL_HAVE_PTP_MMU
+#define XCHAL_KSEG_CACHED_VADDR                0xD0000000      /* virt.addr of kernel RAM cached static map */
+#define XCHAL_KSEG_CACHED_PADDR                0x00000000      /* phys.addr of kseg_cached */
+#define XCHAL_KSEG_CACHED_SIZE         0x08000000      /* size in bytes of kseg_cached (assumed power of 2!!!) */
+#define XCHAL_KSEG_BYPASS_VADDR                0xD8000000      /* virt.addr of kernel RAM bypass (uncached) static map */
+#define XCHAL_KSEG_BYPASS_PADDR                0x00000000      /* phys.addr of kseg_bypass */
+#define XCHAL_KSEG_BYPASS_SIZE         0x08000000      /* size in bytes of kseg_bypass (assumed power of 2!!!) */
+
+#define XCHAL_KIO_CACHED_VADDR         0xE0000000      /* virt.addr of kernel I/O cached static map */
+#define XCHAL_KIO_CACHED_PADDR         0xF0000000      /* phys.addr of kio_cached */
+#define XCHAL_KIO_CACHED_SIZE          0x10000000      /* size in bytes of kio_cached (assumed power of 2!!!) */
+#define XCHAL_KIO_BYPASS_VADDR         0xF0000000      /* virt.addr of kernel I/O bypass (uncached) static map */
+#define XCHAL_KIO_BYPASS_PADDR         0xF0000000      /* phys.addr of kio_bypass */
+#define XCHAL_KIO_BYPASS_SIZE          0x10000000      /* size in bytes of kio_bypass (assumed power of 2!!!) */
+
+#define XCHAL_SEG_MAPPABLE_VADDR       0x00000000      /* start of largest non-static-mapped virtual addr area */
+#define XCHAL_SEG_MAPPABLE_SIZE                0xD0000000      /* size in bytes of  "  */
+/* define XCHAL_SEG_MAPPABLE2_xxx if more areas present, sorted in order of descending size.  */
+#endif
+
+
+/*----------------------------------------------------------------------
+                               MISC
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_WRITEBUFFER_ENTRIES  4       /* number of write buffer entries */
+
+#define XCHAL_CORE_ID                  "linux_be"      /* configuration's alphanumeric core identifier
+                                                          (CoreID) set in the Xtensa Processor Generator */
+
+#define XCHAL_BUILD_UNIQUE_ID          0x00003256      /* software build-unique ID (22-bit) */
+
+/*  These definitions describe the hardware targeted by this software:  */
+#define XCHAL_HW_CONFIGID0             0xC103D1FF      /* config ID reg 0 value (upper 32 of 64 bits) */
+#define XCHAL_HW_CONFIGID1             0x00803256      /* config ID reg 1 value (lower 32 of 64 bits) */
+#define XCHAL_CONFIGID0                        XCHAL_HW_CONFIGID0      /* for backward compatibility only -- don't use! */
+#define XCHAL_CONFIGID1                        XCHAL_HW_CONFIGID1      /* for backward compatibility only -- don't use! */
+#define XCHAL_HW_RELEASE_MAJOR         1050    /* major release of targeted hardware */
+#define XCHAL_HW_RELEASE_MINOR         1       /* minor release of targeted hardware */
+#define XCHAL_HW_RELEASE_NAME          "T1050.1"       /* full release name of targeted hardware */
+#define XTHAL_HW_REL_T1050     1
+#define XTHAL_HW_REL_T1050_1   1
+#define XCHAL_HW_CONFIGID_RELIABLE     1
+
+
+/*
+ *  Miscellaneous special register fields:
+ */
+
+
+/*  DBREAKC (special register number 160):  */
+#define XCHAL_DBREAKC_VALIDMASK        0xC000003F      /* bits of DBREAKC that are defined */
+/*  MASK field:  */
+#define XCHAL_DBREAKC_MASK_BITS        6               /* number of bits in MASK field */
+#define XCHAL_DBREAKC_MASK_NUM         64              /* max number of possible causes (2^bits) */
+#define XCHAL_DBREAKC_MASK_SHIFT       0               /* position of MASK bits in DBREAKC, starting from lsbit */
+#define XCHAL_DBREAKC_MASK_MASK        0x0000003F      /* mask of bits in MASK field of DBREAKC */
+/*  LOADBREAK field:  */
+#define XCHAL_DBREAKC_LOADBREAK_BITS   1               /* number of bits in LOADBREAK field */
+#define XCHAL_DBREAKC_LOADBREAK_NUM    2               /* max number of possible causes (2^bits) */
+#define XCHAL_DBREAKC_LOADBREAK_SHIFT  30              /* position of LOADBREAK bits in DBREAKC, starting from lsbit */
+#define XCHAL_DBREAKC_LOADBREAK_MASK   0x40000000      /* mask of bits in LOADBREAK field of DBREAKC */
+/*  STOREBREAK field:  */
+#define XCHAL_DBREAKC_STOREBREAK_BITS  1               /* number of bits in STOREBREAK field */
+#define XCHAL_DBREAKC_STOREBREAK_NUM   2               /* max number of possible causes (2^bits) */
+#define XCHAL_DBREAKC_STOREBREAK_SHIFT 31              /* position of STOREBREAK bits in DBREAKC, starting from lsbit */
+#define XCHAL_DBREAKC_STOREBREAK_MASK  0x80000000      /* mask of bits in STOREBREAK field of DBREAKC */
+
+/*  PS (special register number 230):  */
+#define XCHAL_PS_VALIDMASK     0x00070FFF      /* bits of PS that are defined */
+/*  INTLEVEL field:  */
+#define XCHAL_PS_INTLEVEL_BITS         4               /* number of bits in INTLEVEL field */
+#define XCHAL_PS_INTLEVEL_NUM          16              /* max number of possible causes (2^bits) */
+#define XCHAL_PS_INTLEVEL_SHIFT        0               /* position of INTLEVEL bits in PS, starting from lsbit */
+#define XCHAL_PS_INTLEVEL_MASK         0x0000000F      /* mask of bits in INTLEVEL field of PS */
+/*  EXCM field:  */
+#define XCHAL_PS_EXCM_BITS     1               /* number of bits in EXCM field */
+#define XCHAL_PS_EXCM_NUM      2               /* max number of possible causes (2^bits) */
+#define XCHAL_PS_EXCM_SHIFT    4               /* position of EXCM bits in PS, starting from lsbit */
+#define XCHAL_PS_EXCM_MASK     0x00000010      /* mask of bits in EXCM field of PS */
+/*  PROGSTACK field:  */
+#define XCHAL_PS_PROGSTACK_BITS        1               /* number of bits in PROGSTACK field */
+#define XCHAL_PS_PROGSTACK_NUM         2               /* max number of possible causes (2^bits) */
+#define XCHAL_PS_PROGSTACK_SHIFT       5               /* position of PROGSTACK bits in PS, starting from lsbit */
+#define XCHAL_PS_PROGSTACK_MASK        0x00000020      /* mask of bits in PROGSTACK field of PS */
+/*  RING field:  */
+#define XCHAL_PS_RING_BITS     2               /* number of bits in RING field */
+#define XCHAL_PS_RING_NUM      4               /* max number of possible causes (2^bits) */
+#define XCHAL_PS_RING_SHIFT    6               /* position of RING bits in PS, starting from lsbit */
+#define XCHAL_PS_RING_MASK     0x000000C0      /* mask of bits in RING field of PS */
+/*  OWB field:  */
+#define XCHAL_PS_OWB_BITS      4               /* number of bits in OWB field */
+#define XCHAL_PS_OWB_NUM       16              /* max number of possible causes (2^bits) */
+#define XCHAL_PS_OWB_SHIFT     8               /* position of OWB bits in PS, starting from lsbit */
+#define XCHAL_PS_OWB_MASK      0x00000F00      /* mask of bits in OWB field of PS */
+/*  CALLINC field:  */
+#define XCHAL_PS_CALLINC_BITS  2               /* number of bits in CALLINC field */
+#define XCHAL_PS_CALLINC_NUM   4               /* max number of possible causes (2^bits) */
+#define XCHAL_PS_CALLINC_SHIFT 16              /* position of CALLINC bits in PS, starting from lsbit */
+#define XCHAL_PS_CALLINC_MASK  0x00030000      /* mask of bits in CALLINC field of PS */
+/*  WOE field:  */
+#define XCHAL_PS_WOE_BITS      1               /* number of bits in WOE field */
+#define XCHAL_PS_WOE_NUM       2               /* max number of possible causes (2^bits) */
+#define XCHAL_PS_WOE_SHIFT     18              /* position of WOE bits in PS, starting from lsbit */
+#define XCHAL_PS_WOE_MASK      0x00040000      /* mask of bits in WOE field of PS */
+
+/*  EXCCAUSE (special register number 232):  */
+#define XCHAL_EXCCAUSE_VALIDMASK       0x0000003F      /* bits of EXCCAUSE that are defined */
+/*  EXCCAUSE field:  */
+#define XCHAL_EXCCAUSE_BITS            6               /* number of bits in EXCCAUSE register */
+#define XCHAL_EXCCAUSE_NUM             64              /* max number of possible causes (2^bits) */
+#define XCHAL_EXCCAUSE_SHIFT           0               /* position of EXCCAUSE bits in register, starting from lsbit */
+#define XCHAL_EXCCAUSE_MASK            0x0000003F      /* mask of bits in EXCCAUSE register */
+
+/*  DEBUGCAUSE (special register number 233):  */
+#define XCHAL_DEBUGCAUSE_VALIDMASK     0x0000003F      /* bits of DEBUGCAUSE that are defined */
+/*  ICOUNT field:  */
+#define XCHAL_DEBUGCAUSE_ICOUNT_BITS   1               /* number of bits in ICOUNT field */
+#define XCHAL_DEBUGCAUSE_ICOUNT_NUM    2               /* max number of possible causes (2^bits) */
+#define XCHAL_DEBUGCAUSE_ICOUNT_SHIFT  0               /* position of ICOUNT bits in DEBUGCAUSE, starting from lsbit */
+#define XCHAL_DEBUGCAUSE_ICOUNT_MASK   0x00000001      /* mask of bits in ICOUNT field of DEBUGCAUSE */
+/*  IBREAK field:  */
+#define XCHAL_DEBUGCAUSE_IBREAK_BITS   1               /* number of bits in IBREAK field */
+#define XCHAL_DEBUGCAUSE_IBREAK_NUM    2               /* max number of possible causes (2^bits) */
+#define XCHAL_DEBUGCAUSE_IBREAK_SHIFT  1               /* position of IBREAK bits in DEBUGCAUSE, starting from lsbit */
+#define XCHAL_DEBUGCAUSE_IBREAK_MASK   0x00000002      /* mask of bits in IBREAK field of DEBUGCAUSE */
+/*  DBREAK field:  */
+#define XCHAL_DEBUGCAUSE_DBREAK_BITS   1               /* number of bits in DBREAK field */
+#define XCHAL_DEBUGCAUSE_DBREAK_NUM    2               /* max number of possible causes (2^bits) */
+#define XCHAL_DEBUGCAUSE_DBREAK_SHIFT  2               /* position of DBREAK bits in DEBUGCAUSE, starting from lsbit */
+#define XCHAL_DEBUGCAUSE_DBREAK_MASK   0x00000004      /* mask of bits in DBREAK field of DEBUGCAUSE */
+/*  BREAK field:  */
+#define XCHAL_DEBUGCAUSE_BREAK_BITS    1               /* number of bits in BREAK field */
+#define XCHAL_DEBUGCAUSE_BREAK_NUM     2               /* max number of possible causes (2^bits) */
+#define XCHAL_DEBUGCAUSE_BREAK_SHIFT   3               /* position of BREAK bits in DEBUGCAUSE, starting from lsbit */
+#define XCHAL_DEBUGCAUSE_BREAK_MASK    0x00000008      /* mask of bits in BREAK field of DEBUGCAUSE */
+/*  BREAKN field:  */
+#define XCHAL_DEBUGCAUSE_BREAKN_BITS   1               /* number of bits in BREAKN field */
+#define XCHAL_DEBUGCAUSE_BREAKN_NUM    2               /* max number of possible causes (2^bits) */
+#define XCHAL_DEBUGCAUSE_BREAKN_SHIFT  4               /* position of BREAKN bits in DEBUGCAUSE, starting from lsbit */
+#define XCHAL_DEBUGCAUSE_BREAKN_MASK   0x00000010      /* mask of bits in BREAKN field of DEBUGCAUSE */
+/*  DEBUGINT field:  */
+#define XCHAL_DEBUGCAUSE_DEBUGINT_BITS         1               /* number of bits in DEBUGINT field */
+#define XCHAL_DEBUGCAUSE_DEBUGINT_NUM          2               /* max number of possible causes (2^bits) */
+#define XCHAL_DEBUGCAUSE_DEBUGINT_SHIFT        5               /* position of DEBUGINT bits in DEBUGCAUSE, starting from lsbit */
+#define XCHAL_DEBUGCAUSE_DEBUGINT_MASK         0x00000020      /* mask of bits in DEBUGINT field of DEBUGCAUSE */
+
+
+
+/*----------------------------------------------------------------------
+                               ISA
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_DENSITY             1       /* 1 if density option configured, 0 otherwise */
+#define XCHAL_HAVE_LOOPS               1       /* 1 if zero-overhead loops option configured, 0 otherwise */
+/*  Misc instructions:  */
+#define XCHAL_HAVE_NSA                 0       /* 1 if NSA/NSAU instructions option configured, 0 otherwise */
+#define XCHAL_HAVE_MINMAX              0       /* 1 if MIN/MAX instructions option configured, 0 otherwise */
+#define XCHAL_HAVE_SEXT                        0       /* 1 if sign-extend instruction option configured, 0 otherwise */
+#define XCHAL_HAVE_CLAMPS              0       /* 1 if CLAMPS instruction option configured, 0 otherwise */
+#define XCHAL_HAVE_MAC16               0       /* 1 if MAC16 option configured, 0 otherwise */
+#define XCHAL_HAVE_MUL16               0       /* 1 if 16-bit integer multiply option configured, 0 otherwise */
+/*#define XCHAL_HAVE_POPC              0*/     /* 1 if CRC instruction option configured, 0 otherwise */
+/*#define XCHAL_HAVE_CRC               0*/     /* 1 if POPC instruction option configured, 0 otherwise */
+
+#define XCHAL_HAVE_SPECULATION         0       /* 1 if speculation option configured, 0 otherwise */
+/*#define XCHAL_HAVE_MP_SYNC           0*/     /* 1 if multiprocessor sync. option configured, 0 otherwise */
+#define XCHAL_HAVE_PRID                        0       /* 1 if processor ID register configured, 0 otherwise */
+
+#define XCHAL_NUM_MISC_REGS            2       /* number of miscellaneous registers (0..4) */
+
+/*  These relate a bit more to TIE:  */
+#define XCHAL_HAVE_BOOLEANS            0       /* 1 if booleans option configured, 0 otherwise */
+#define XCHAL_HAVE_MUL32               0       /* 1 if 32-bit integer multiply option configured, 0 otherwise */
+#define XCHAL_HAVE_MUL32_HIGH          0       /* 1 if MUL32 option includes MULUH and MULSH, 0 otherwise */
+#define XCHAL_HAVE_FP                  0       /* 1 if floating point option configured, 0 otherwise */
+
+
+/*----------------------------------------------------------------------
+                               DERIVED
+  ----------------------------------------------------------------------*/
+
+#if XCHAL_HAVE_BE
+#define XCHAL_INST_ILLN                        0xD60F          /* 2-byte illegal instruction, msb-first */
+#define XCHAL_INST_ILLN_BYTE0          0xD6            /* 2-byte illegal instruction, 1st byte */
+#define XCHAL_INST_ILLN_BYTE1          0x0F            /* 2-byte illegal instruction, 2nd byte */
+#else
+#define XCHAL_INST_ILLN                        0xF06D          /* 2-byte illegal instruction, lsb-first */
+#define XCHAL_INST_ILLN_BYTE0          0x6D            /* 2-byte illegal instruction, 1st byte */
+#define XCHAL_INST_ILLN_BYTE1          0xF0            /* 2-byte illegal instruction, 2nd byte */
+#endif
+/*  Belongs in xtensa/hal.h:  */
+#define XTHAL_INST_ILL                 0x000000        /* 3-byte illegal instruction */
+
+
+/*
+ *  Because information as to exactly which hardware release is targeted
+ *  by a given software build is not always available, compile-time HAL
+ *  Hardware-Release "_AT" macros are fuzzy (return 0, 1, or XCHAL_MAYBE):
+ */
+#ifndef XCHAL_HW_RELEASE_MAJOR
+# define XCHAL_HW_CONFIGID_RELIABLE    0
+#endif
+#if XCHAL_HW_CONFIGID_RELIABLE
+# define XCHAL_HW_RELEASE_AT_OR_BELOW(major,minor)     (XTHAL_REL_LE( XCHAL_HW_RELEASE_MAJOR,XCHAL_HW_RELEASE_MINOR, major,minor ) ? 1 : 0)
+# define XCHAL_HW_RELEASE_AT_OR_ABOVE(major,minor)     (XTHAL_REL_GE( XCHAL_HW_RELEASE_MAJOR,XCHAL_HW_RELEASE_MINOR, major,minor ) ? 1 : 0)
+# define XCHAL_HW_RELEASE_AT(major,minor)              (XTHAL_REL_EQ( XCHAL_HW_RELEASE_MAJOR,XCHAL_HW_RELEASE_MINOR, major,minor ) ? 1 : 0)
+# define XCHAL_HW_RELEASE_MAJOR_AT(major)              ((XCHAL_HW_RELEASE_MAJOR == (major)) ? 1 : 0)
+#else
+# define XCHAL_HW_RELEASE_AT_OR_BELOW(major,minor)     ( ((major) < 1040 && XCHAL_HAVE_XEA2) ? 0 \
+                                                       : ((major) > 1050 && XCHAL_HAVE_XEA1) ? 1 \
+                                                       : XTHAL_MAYBE )
+# define XCHAL_HW_RELEASE_AT_OR_ABOVE(major,minor)     ( ((major) >= 2000 && XCHAL_HAVE_XEA1) ? 0 \
+                                                       : (XTHAL_REL_LE(major,minor, 1040,0) && XCHAL_HAVE_XEA2) ? 1 \
+                                                       : XTHAL_MAYBE )
+# define XCHAL_HW_RELEASE_AT(major,minor)              ( (((major) < 1040 && XCHAL_HAVE_XEA2) || \
+                                                          ((major) >= 2000 && XCHAL_HAVE_XEA1)) ? 0 : XTHAL_MAYBE)
+# define XCHAL_HW_RELEASE_MAJOR_AT(major)              XCHAL_HW_RELEASE_AT(major,0)
+#endif
+
+/*
+ *  Specific errata:
+ */
+
+/*
+ *  Erratum T1020.H13, T1030.H7, T1040.H10, T1050.H4 (fixed in T1040.3 and T1050.1;
+ *  relevant only in XEA1, kernel-vector mode, level-one interrupts and overflows enabled):
+ */
+#define XCHAL_MAYHAVE_ERRATUM_XEA1KWIN (XCHAL_HAVE_XEA1 && \
+                                        (XCHAL_HW_RELEASE_AT_OR_BELOW(1040,2) != 0 \
+                                         || XCHAL_HW_RELEASE_AT(1050,0)))
+
+
+
+#endif /*XTENSA_CONFIG_CORE_H*/
+
diff --git a/include/asm-xtensa/xtensa/config-linux_be/defs.h b/include/asm-xtensa/xtensa/config-linux_be/defs.h
new file mode 100644 (file)
index 0000000..f7c58b2
--- /dev/null
@@ -0,0 +1,270 @@
+/* Definitions for Xtensa instructions, types, and protos. */
+
+/*
+ * Copyright (c) 2003 Tensilica, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ */
+
+/* Do not modify. This is automatically generated.*/
+
+#ifndef _XTENSA_BASE_HEADER
+#define _XTENSA_BASE_HEADER
+
+#ifdef __XTENSA__
+#if defined(__GNUC__) && !defined(__XCC__)
+
+#define L8UI_ASM(arr, ars, imm) { \
+  __asm__ volatile("l8ui %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
+}
+
+#define XT_L8UI(ars, imm) \
+({ \
+  unsigned char _arr; \
+  const unsigned char *_ars = ars; \
+  L8UI_ASM(_arr, _ars, imm); \
+  _arr; \
+})
+
+#define L16UI_ASM(arr, ars, imm) { \
+  __asm__ volatile("l16ui %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
+}
+
+#define XT_L16UI(ars, imm) \
+({ \
+  unsigned short _arr; \
+  const unsigned short *_ars = ars; \
+  L16UI_ASM(_arr, _ars, imm); \
+  _arr; \
+})
+
+#define L16SI_ASM(arr, ars, imm) {\
+  __asm__ volatile("l16si %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
+}
+
+#define XT_L16SI(ars, imm) \
+({ \
+  signed short _arr; \
+  const signed short *_ars = ars; \
+  L16SI_ASM(_arr, _ars, imm); \
+  _arr; \
+})
+
+#define L32I_ASM(arr, ars, imm) { \
+  __asm__ volatile("l32i %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
+}
+
+#define XT_L32I(ars, imm) \
+({ \
+  unsigned _arr; \
+  const unsigned *_ars = ars; \
+  L32I_ASM(_arr, _ars, imm); \
+  _arr; \
+})
+
+#define S8I_ASM(arr, ars, imm) {\
+  __asm__ volatile("s8i %0, %1, %2" : : "a" (arr), "a" (ars) , "i" (imm) : "memory" ); \
+}
+
+#define XT_S8I(arr, ars, imm) \
+({ \
+  signed char _arr = arr; \
+  const signed char *_ars = ars; \
+  S8I_ASM(_arr, _ars, imm); \
+})
+
+#define S16I_ASM(arr, ars, imm) {\
+  __asm__ volatile("s16i %0, %1, %2" : : "a" (arr), "a" (ars) , "i" (imm) : "memory" ); \
+}
+
+#define XT_S16I(arr, ars, imm) \
+({ \
+  signed short _arr = arr; \
+  const signed short *_ars = ars; \
+  S16I_ASM(_arr, _ars, imm); \
+})
+
+#define S32I_ASM(arr, ars, imm) { \
+  __asm__ volatile("s32i %0, %1, %2" : : "a" (arr), "a" (ars) , "i" (imm) : "memory" ); \
+}
+
+#define XT_S32I(arr, ars, imm) \
+({ \
+  signed int _arr = arr; \
+  const signed int *_ars = ars; \
+  S32I_ASM(_arr, _ars, imm); \
+})
+
+#define ADDI_ASM(art, ars, imm) {\
+   __asm__ ("addi %0, %1, %2" : "=a" (art) : "a" (ars), "i" (imm)); \
+}
+
+#define XT_ADDI(ars, imm) \
+({ \
+   unsigned _art; \
+   unsigned _ars = ars; \
+   ADDI_ASM(_art, _ars, imm); \
+   _art; \
+})
+
+#define ABS_ASM(arr, art) {\
+   __asm__ ("abs %0, %1" : "=a" (arr) : "a" (art)); \
+}
+
+#define XT_ABS(art) \
+({ \
+   unsigned _arr; \
+   signed _art = art; \
+   ABS_ASM(_arr, _art); \
+   _arr; \
+})
+
+/* Note: In the following macros that reference SAR, the magic "state"
+   register is used to capture the dependency on SAR.  This is because
+   SAR is a 5-bit register and thus there are no C types that can be
+   used to represent it.  It doesn't appear that the SAR register is
+   even relevant to GCC, but it is marked as "clobbered" just in
+   case.  */
+
+#define SRC_ASM(arr, ars, art) {\
+   register int _xt_sar __asm__ ("state"); \
+   __asm__ ("src %0, %1, %2" \
+           : "=a" (arr) : "a" (ars), "a" (art), "t" (_xt_sar)); \
+}
+
+#define XT_SRC(ars, art) \
+({ \
+   unsigned _arr; \
+   unsigned _ars = ars; \
+   unsigned _art = art; \
+   SRC_ASM(_arr, _ars, _art); \
+   _arr; \
+})
+
+#define SSR_ASM(ars) {\
+   register int _xt_sar __asm__ ("state"); \
+   __asm__ ("ssr %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
+}
+
+#define XT_SSR(ars) \
+({ \
+   unsigned _ars = ars; \
+   SSR_ASM(_ars); \
+})
+
+#define SSL_ASM(ars) {\
+   register int _xt_sar __asm__ ("state"); \
+   __asm__ ("ssl %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
+}
+
+#define XT_SSL(ars) \
+({ \
+   unsigned _ars = ars; \
+   SSL_ASM(_ars); \
+})
+
+#define SSA8B_ASM(ars) {\
+   register int _xt_sar __asm__ ("state"); \
+   __asm__ ("ssa8b %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
+}
+
+#define XT_SSA8B(ars) \
+({ \
+   unsigned _ars = ars; \
+   SSA8B_ASM(_ars); \
+})
+
+#define SSA8L_ASM(ars) {\
+   register int _xt_sar __asm__ ("state"); \
+   __asm__ ("ssa8l %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
+}
+
+#define XT_SSA8L(ars) \
+({ \
+   unsigned _ars = ars; \
+   SSA8L_ASM(_ars); \
+})
+
+#define SSAI_ASM(imm) {\
+   register int _xt_sar __asm__ ("state"); \
+   __asm__ ("ssai %1" : "=t" (_xt_sar) : "i" (imm) : "sar"); \
+}
+
+#define XT_SSAI(imm) \
+({ \
+   SSAI_ASM(imm); \
+})
+
+
+
+
+
+
+
+
+#endif /* __GNUC__ && !__XCC__ */
+
+#ifdef __XCC__
+
+/* Core load/store instructions */
+extern unsigned char _TIE_L8UI(const unsigned char * ars, immediate imm);
+extern unsigned short _TIE_L16UI(const unsigned short * ars, immediate imm);
+extern signed short _TIE_L16SI(const signed short * ars, immediate imm);
+extern unsigned _TIE_L32I(const unsigned * ars, immediate imm);
+extern void _TIE_S8I(unsigned char arr, unsigned char * ars, immediate imm);
+extern void _TIE_S16I(unsigned short arr, unsigned short * ars, immediate imm);
+extern void _TIE_S32I(unsigned arr, unsigned * ars, immediate imm);
+
+#define XT_L8UI  _TIE_L8UI
+#define XT_L16UI _TIE_L16UI
+#define XT_L16SI _TIE_L16SI
+#define XT_L32I  _TIE_L32I
+#define XT_S8I   _TIE_S8I
+#define XT_S16I  _TIE_S16I
+#define XT_S32I  _TIE_S32I
+
+/* Add-immediate instruction */
+extern unsigned _TIE_ADDI(unsigned ars, immediate imm);
+#define XT_ADDI  _TIE_ADDI
+
+/* Absolute value instruction */
+extern unsigned _TIE_ABS(int art);
+#define XT_ABS _TIE_ABS
+
+/* funnel shift instructions */
+extern unsigned _TIE_SRC(unsigned ars, unsigned art);
+#define XT_SRC _TIE_SRC
+extern void _TIE_SSR(unsigned ars);
+#define XT_SSR _TIE_SSR
+extern void _TIE_SSL(unsigned ars);
+#define XT_SSL _TIE_SSL
+extern void _TIE_SSA8B(unsigned ars);
+#define XT_SSA8B _TIE_SSA8B
+extern void _TIE_SSA8L(unsigned ars);
+#define XT_SSA8L _TIE_SSA8L
+extern void _TIE_SSAI(immediate imm);
+#define XT_SSAI _TIE_SSAI
+
+
+#endif /* __XCC__ */
+
+#endif /* __XTENSA__ */
+#endif /* !_XTENSA_BASE_HEADER */
diff --git a/include/asm-xtensa/xtensa/config-linux_be/specreg.h b/include/asm-xtensa/xtensa/config-linux_be/specreg.h
new file mode 100644 (file)
index 0000000..fa4106a
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Xtensa Special Register symbolic names
+ */
+
+/* $Id: specreg.h,v 1.2 2003/03/07 19:15:18 joetaylor Exp $ */
+
+/*
+ * Copyright (c) 2003 Tensilica, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ */
+
+#ifndef XTENSA_SPECREG_H
+#define XTENSA_SPECREG_H
+
+/*  Include these special register bitfield definitions, for historical reasons:  */
+#include <xtensa/corebits.h>
+
+
+/*  Special registers:  */
+#define LBEG           0
+#define LEND           1
+#define LCOUNT         2
+#define SAR            3
+#define WINDOWBASE     72
+#define WINDOWSTART    73
+#define PTEVADDR       83
+#define RASID          90
+#define ITLBCFG                91
+#define DTLBCFG                92
+#define IBREAKENABLE   96
+#define DDR            104
+#define IBREAKA_0      128
+#define IBREAKA_1      129
+#define DBREAKA_0      144
+#define DBREAKA_1      145
+#define DBREAKC_0      160
+#define DBREAKC_1      161
+#define EPC_1          177
+#define EPC_2          178
+#define EPC_3          179
+#define EPC_4          180
+#define DEPC           192
+#define EPS_2          194
+#define EPS_3          195
+#define EPS_4          196
+#define EXCSAVE_1      209
+#define EXCSAVE_2      210
+#define EXCSAVE_3      211
+#define EXCSAVE_4      212
+#define INTERRUPT      226
+#define INTENABLE      228
+#define PS             230
+#define EXCCAUSE       232
+#define DEBUGCAUSE     233
+#define CCOUNT         234
+#define ICOUNT         236
+#define ICOUNTLEVEL    237
+#define EXCVADDR       238
+#define CCOMPARE_0     240
+#define CCOMPARE_1     241
+#define CCOMPARE_2     242
+#define MISC_REG_0     244
+#define MISC_REG_1     245
+
+/*  Special cases (bases of special register series):  */
+#define IBREAKA                128
+#define DBREAKA                144
+#define DBREAKC                160
+#define EPC            176
+#define EPS            192
+#define EXCSAVE                208
+#define CCOMPARE       240
+
+/*  Special names for read-only and write-only interrupt registers:  */
+#define INTREAD                226
+#define INTSET         226
+#define INTCLEAR       227
+
+#endif /* XTENSA_SPECREG_H */
+
diff --git a/include/asm-xtensa/xtensa/config-linux_be/system.h b/include/asm-xtensa/xtensa/config-linux_be/system.h
new file mode 100644 (file)
index 0000000..cf9d4d3
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * xtensa/config/system.h -- HAL definitions that are dependent on SYSTEM configuration
+ *
+ *  NOTE: The location and contents of this file are highly subject to change.
+ *
+ *  Source for configuration-independent binaries (which link in a
+ *  configuration-specific HAL library) must NEVER include this file.
+ *  The HAL itself has historically included this file in some instances,
+ *  but this is not appropriate either, because the HAL is meant to be
+ *  core-specific but system independent.
+ */
+
+/*
+ * Copyright (c) 2003 Tensilica, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ */
+
+
+#ifndef XTENSA_CONFIG_SYSTEM_H
+#define XTENSA_CONFIG_SYSTEM_H
+
+/*#include <xtensa/hal.h>*/
+
+
+
+/*----------------------------------------------------------------------
+                               DEVICE ADDRESSES
+  ----------------------------------------------------------------------*/
+
+/*
+ *  Strange place to find these, but the configuration GUI
+ *  allows moving these around to account for various core
+ *  configurations.  Specific boards (and their BSP software)
+ *  will have specific meanings for these components.
+ */
+
+/*  I/O Block areas:  */
+#define XSHAL_IOBLOCK_CACHED_VADDR     0xE0000000
+#define XSHAL_IOBLOCK_CACHED_PADDR     0xF0000000
+#define XSHAL_IOBLOCK_CACHED_SIZE      0x0E000000
+
+#define XSHAL_IOBLOCK_BYPASS_VADDR     0xF0000000
+#define XSHAL_IOBLOCK_BYPASS_PADDR     0xF0000000
+#define XSHAL_IOBLOCK_BYPASS_SIZE      0x0E000000
+
+/*  System ROM:  */
+#define XSHAL_ROM_VADDR                0xEE000000
+#define XSHAL_ROM_PADDR                0xFE000000
+#define XSHAL_ROM_SIZE         0x00400000
+/*  Largest available area (free of vectors):  */
+#define XSHAL_ROM_AVAIL_VADDR  0xEE00052C
+#define XSHAL_ROM_AVAIL_VSIZE  0x003FFAD4
+
+/*  System RAM:  */
+#define XSHAL_RAM_VADDR                0xD0000000
+#define XSHAL_RAM_PADDR                0x00000000
+#define XSHAL_RAM_VSIZE                0x08000000
+#define XSHAL_RAM_PSIZE                0x10000000
+#define XSHAL_RAM_SIZE         XSHAL_RAM_PSIZE
+/*  Largest available area (free of vectors):  */
+#define XSHAL_RAM_AVAIL_VADDR  0xD0000370
+#define XSHAL_RAM_AVAIL_VSIZE  0x07FFFC90
+
+/*
+ *  Shadow system RAM (same device as system RAM, at different address).
+ *  (Emulation boards need this for the SONIC Ethernet driver
+ *   when data caches are configured for writeback mode.)
+ *  NOTE: on full MMU configs, this points to the BYPASS virtual address
+ *  of system RAM, ie. is the same as XSHAL_RAM_* except that virtual
+ *  addresses are viewed through the BYPASS static map rather than
+ *  the CACHED static map.
+ */
+#define XSHAL_RAM_BYPASS_VADDR         0xD8000000
+#define XSHAL_RAM_BYPASS_PADDR         0x00000000
+#define XSHAL_RAM_BYPASS_PSIZE         0x08000000
+
+/*  Alternate system RAM (different device than system RAM):  */
+#define XSHAL_ALTRAM_VADDR             0xCEE00000
+#define XSHAL_ALTRAM_PADDR             0xC0000000
+#define XSHAL_ALTRAM_SIZE              0x00200000
+
+
+/*----------------------------------------------------------------------
+ *                     DEVICE-ADDRESS DEPENDENT...
+ *
+ *  Values written to CACHEATTR special register (or its equivalent)
+ *  to enable and disable caches in various modes.
+ *----------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------
+                       BACKWARD COMPATIBILITY ...
+  ----------------------------------------------------------------------*/
+
+/*
+ *  NOTE:  the following two macros are DEPRECATED.  Use the latter
+ *  board-specific macros instead, which are specially tuned for the
+ *  particular target environments' memory maps.
+ */
+#define XSHAL_CACHEATTR_BYPASS         XSHAL_XT2000_CACHEATTR_BYPASS   /* disable caches in bypass mode */
+#define XSHAL_CACHEATTR_DEFAULT                XSHAL_XT2000_CACHEATTR_DEFAULT  /* default setting to enable caches (no writeback!) */
+
+/*----------------------------------------------------------------------
+                       ISS (Instruction Set Simulator) SPECIFIC ...
+  ----------------------------------------------------------------------*/
+
+#define XSHAL_ISS_CACHEATTR_WRITEBACK  0x1122222F      /* enable caches in write-back mode */
+#define XSHAL_ISS_CACHEATTR_WRITEALLOC 0x1122222F      /* enable caches in write-allocate mode */
+#define XSHAL_ISS_CACHEATTR_WRITETHRU  0x1122222F      /* enable caches in write-through mode */
+#define XSHAL_ISS_CACHEATTR_BYPASS     0x2222222F      /* disable caches in bypass mode */
+#define XSHAL_ISS_CACHEATTR_DEFAULT    XSHAL_ISS_CACHEATTR_WRITEBACK   /* default setting to enable caches */
+
+/*  For Coware only:  */
+#define XSHAL_COWARE_CACHEATTR_WRITEBACK       0x11222222      /* enable caches in write-back mode */
+#define XSHAL_COWARE_CACHEATTR_WRITEALLOC      0x11222222      /* enable caches in write-allocate mode */
+#define XSHAL_COWARE_CACHEATTR_WRITETHRU       0x11222222      /* enable caches in write-through mode */
+#define XSHAL_COWARE_CACHEATTR_BYPASS          0x22222222      /* disable caches in bypass mode */
+#define XSHAL_COWARE_CACHEATTR_DEFAULT         XSHAL_COWARE_CACHEATTR_WRITEBACK        /* default setting to enable caches */
+
+/*  For BFM and other purposes:  */
+#define XSHAL_ALLVALID_CACHEATTR_WRITEBACK     0x11222222      /* enable caches without any invalid regions */
+#define XSHAL_ALLVALID_CACHEATTR_DEFAULT       XSHAL_ALLVALID_CACHEATTR_WRITEBACK      /* default setting for caches without any invalid regions */
+
+#define XSHAL_ISS_PIPE_REGIONS 0
+#define XSHAL_ISS_SDRAM_REGIONS        0
+
+
+/*----------------------------------------------------------------------
+                       XT2000 BOARD SPECIFIC ...
+  ----------------------------------------------------------------------*/
+
+#define XSHAL_XT2000_CACHEATTR_WRITEBACK       0x22FFFFFF      /* enable caches in write-back mode */
+#define XSHAL_XT2000_CACHEATTR_WRITEALLOC      0x22FFFFFF      /* enable caches in write-allocate mode */
+#define XSHAL_XT2000_CACHEATTR_WRITETHRU       0x22FFFFFF      /* enable caches in write-through mode */
+#define XSHAL_XT2000_CACHEATTR_BYPASS          0x22FFFFFF      /* disable caches in bypass mode */
+#define XSHAL_XT2000_CACHEATTR_DEFAULT         XSHAL_XT2000_CACHEATTR_WRITEBACK        /* default setting to enable caches */
+
+#define XSHAL_XT2000_PIPE_REGIONS      0x00001000      /* BusInt pipeline regions */
+#define XSHAL_XT2000_SDRAM_REGIONS     0x00000005      /* BusInt SDRAM regions */
+
+
+/*----------------------------------------------------------------------
+                               VECTOR SIZES
+  ----------------------------------------------------------------------*/
+
+/*
+ *  Sizes allocated to vectors by the system (memory map) configuration.
+ *  These sizes are constrained by core configuration (eg. one vector's
+ *  code cannot overflow into another vector) but are dependent on the
+ *  system or board (or LSP) memory map configuration.
+ *
+ *  Whether or not each vector happens to be in a system ROM is also
+ *  a system configuration matter, sometimes useful, included here also:
+ */
+#define XSHAL_RESET_VECTOR_SIZE        0x000004E0
+#define XSHAL_RESET_VECTOR_ISROM       1
+#define XSHAL_USER_VECTOR_SIZE 0x0000001C
+#define XSHAL_USER_VECTOR_ISROM        0
+#define XSHAL_PROGRAMEXC_VECTOR_SIZE   XSHAL_USER_VECTOR_SIZE  /* for backward compatibility */
+#define XSHAL_USEREXC_VECTOR_SIZE      XSHAL_USER_VECTOR_SIZE  /* for backward compatibility */
+#define XSHAL_KERNEL_VECTOR_SIZE       0x0000001C
+#define XSHAL_KERNEL_VECTOR_ISROM      0
+#define XSHAL_STACKEDEXC_VECTOR_SIZE   XSHAL_KERNEL_VECTOR_SIZE        /* for backward compatibility */
+#define XSHAL_KERNELEXC_VECTOR_SIZE    XSHAL_KERNEL_VECTOR_SIZE        /* for backward compatibility */
+#define XSHAL_DOUBLEEXC_VECTOR_SIZE    0x000000E0
+#define XSHAL_DOUBLEEXC_VECTOR_ISROM   0
+#define XSHAL_WINDOW_VECTORS_SIZE      0x00000180
+#define XSHAL_WINDOW_VECTORS_ISROM     0
+#define XSHAL_INTLEVEL2_VECTOR_SIZE    0x0000000C
+#define XSHAL_INTLEVEL2_VECTOR_ISROM   0
+#define XSHAL_INTLEVEL3_VECTOR_SIZE    0x0000000C
+#define XSHAL_INTLEVEL3_VECTOR_ISROM   0
+#define XSHAL_INTLEVEL4_VECTOR_SIZE    0x0000000C
+#define XSHAL_INTLEVEL4_VECTOR_ISROM   1
+#define XSHAL_DEBUG_VECTOR_SIZE                XSHAL_INTLEVEL4_VECTOR_SIZE
+#define XSHAL_DEBUG_VECTOR_ISROM       XSHAL_INTLEVEL4_VECTOR_ISROM
+
+
+#endif /*XTENSA_CONFIG_SYSTEM_H*/
+
diff --git a/include/asm-xtensa/xtensa/config-linux_be/tie.h b/include/asm-xtensa/xtensa/config-linux_be/tie.h
new file mode 100644 (file)
index 0000000..3c2e514
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * xtensa/config/tie.h -- HAL definitions that are dependent on CORE and TIE configuration
+ *
+ *  This header file is sometimes referred to as the "compile-time HAL" or CHAL.
+ *  It was generated for a specific Xtensa processor configuration,
+ *  and furthermore for a specific set of TIE source files that extend
+ *  basic core functionality.
+ *
+ *  Source for configuration-independent binaries (which link in a
+ *  configuration-specific HAL library) must NEVER include this file.
+ *  It is perfectly normal, however, for the HAL source itself to include this file.
+ */
+
+/*
+ * Copyright (c) 2003 Tensilica, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ */
+
+
+#ifndef XTENSA_CONFIG_TIE_H
+#define XTENSA_CONFIG_TIE_H
+
+#include <xtensa/hal.h>
+
+
+/*----------------------------------------------------------------------
+                               GENERAL
+  ----------------------------------------------------------------------*/
+
+/*
+ *  Separators for macros that expand into arrays.
+ *  These can be predefined by files that #include this one,
+ *  when different separators are required.
+ */
+/*  Element separator for macros that expand into 1-dimensional arrays:  */
+#ifndef XCHAL_SEP
+#define XCHAL_SEP                      ,
+#endif
+/*  Array separator for macros that expand into 2-dimensional arrays:  */
+#ifndef XCHAL_SEP2
+#define XCHAL_SEP2                     },{
+#endif
+
+
+
+
+
+
+/*----------------------------------------------------------------------
+                       COPROCESSORS and EXTRA STATE
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_CP_NUM                   0       /* number of coprocessors */
+#define XCHAL_CP_MAX                   0       /* max coprocessor id plus one (0 if none) */
+#define XCHAL_CP_MASK                  0x00    /* bitmask of coprocessors by id */
+
+/*  Space for coprocessors' state save areas:  */
+#define XCHAL_CP0_SA_SIZE              0
+#define XCHAL_CP1_SA_SIZE              0
+#define XCHAL_CP2_SA_SIZE              0
+#define XCHAL_CP3_SA_SIZE              0
+#define XCHAL_CP4_SA_SIZE              0
+#define XCHAL_CP5_SA_SIZE              0
+#define XCHAL_CP6_SA_SIZE              0
+#define XCHAL_CP7_SA_SIZE              0
+/*  Minimum required alignments of CP state save areas:  */
+#define XCHAL_CP0_SA_ALIGN             1
+#define XCHAL_CP1_SA_ALIGN             1
+#define XCHAL_CP2_SA_ALIGN             1
+#define XCHAL_CP3_SA_ALIGN             1
+#define XCHAL_CP4_SA_ALIGN             1
+#define XCHAL_CP5_SA_ALIGN             1
+#define XCHAL_CP6_SA_ALIGN             1
+#define XCHAL_CP7_SA_ALIGN             1
+
+/*  Indexing macros:  */
+#define _XCHAL_CP_SA_SIZE(n)           XCHAL_CP ## n ## _SA_SIZE
+#define XCHAL_CP_SA_SIZE(n)            _XCHAL_CP_SA_SIZE(n)    /* n = 0 .. 7 */
+#define _XCHAL_CP_SA_ALIGN(n)          XCHAL_CP ## n ## _SA_ALIGN
+#define XCHAL_CP_SA_ALIGN(n)           _XCHAL_CP_SA_ALIGN(n)   /* n = 0 .. 7 */
+
+
+/*  Space for "extra" state (user special registers and non-cp TIE) save area:  */
+#define XCHAL_EXTRA_SA_SIZE            0
+#define XCHAL_EXTRA_SA_ALIGN           1
+
+/*  Total save area size (extra + all coprocessors)  */
+/*  (not useful until xthal_{save,restore}_all_extra() is implemented,  */
+/*   but included for Tor2 beta; doesn't account for alignment!):  */
+#define XCHAL_CPEXTRA_SA_SIZE_TOR2     0       /* Tor2Beta temporary definition -- do not use */
+
+/*  Combined required alignment for all CP and EXTRA state save areas  */
+/*  (does not include required alignment for any base config registers):  */
+#define XCHAL_CPEXTRA_SA_ALIGN         1
+
+/* ... */
+
+
+#ifdef _ASMLANGUAGE
+/*
+ *  Assembly-language specific definitions (assembly macros, etc.).
+ */
+#include <xtensa/config/specreg.h>
+
+/********************
+ *  Macros to save and restore the non-coprocessor TIE portion of EXTRA state.
+ */
+
+/* (none) */
+
+
+/********************
+ *  Macros to create functions that save and restore all EXTRA (non-coprocessor) state
+ *  (does not include zero-overhead loop registers and non-optional registers).
+ */
+
+       /*
+        *  Macro that expands to the body of a function that
+        *  stores the extra (non-coprocessor) optional/custom state.
+        *      Entry:  a2 = ptr to save area in which to save extra state
+        *      Exit:   any register a2-a15 (?) may have been clobbered.
+        */
+       .macro  xchal_extra_store_funcbody
+       .endm
+
+
+       /*
+        *  Macro that expands to the body of a function that
+        *  loads the extra (non-coprocessor) optional/custom state.
+        *      Entry:  a2 = ptr to save area from which to restore extra state
+        *      Exit:   any register a2-a15 (?) may have been clobbered.
+        */
+       .macro  xchal_extra_load_funcbody
+       .endm
+
+
+/********************
+ *  Macros to save and restore the state of each TIE coprocessor.
+ */
+
+
+
+/********************
+ *  Macros to create functions that save and restore the state of *any* TIE coprocessor.
+ */
+
+       /*
+        *  Macro that expands to the body of a function
+        *  that stores the selected coprocessor's state (registers etc).
+        *      Entry:  a2 = ptr to save area in which to save cp state
+        *              a3 = coprocessor number
+        *      Exit:   any register a2-a15 (?) may have been clobbered.
+        */
+       .macro  xchal_cpi_store_funcbody
+       .endm
+
+
+       /*
+        *  Macro that expands to the body of a function
+        *  that loads the selected coprocessor's state (registers etc).
+        *      Entry:  a2 = ptr to save area from which to restore cp state
+        *              a3 = coprocessor number
+        *      Exit:   any register a2-a15 (?) may have been clobbered.
+        */
+       .macro  xchal_cpi_load_funcbody
+       .endm
+
+#endif /*_ASMLANGUAGE*/
+
+
+/*
+ *  Contents of save areas in terms of libdb register numbers.
+ *  NOTE:  CONTENTS_LIBDB_{UREG,REGF} macros are not defined in this file;
+ *  it is up to the user of this header file to define these macros
+ *  usefully before each expansion of the CONTENTS_LIBDB macros.
+ *  (Fields rsv[123] are reserved for future additions; they are currently
+ *   set to zero but may be set to some useful values in the future.)
+ *
+ *     CONTENTS_LIBDB_SREG(libdbnum, offset, size, align, rsv1, name, sregnum, bitmask, rsv2, rsv3)
+ *     CONTENTS_LIBDB_UREG(libdbnum, offset, size, align, rsv1, name, uregnum, bitmask, rsv2, rsv3)
+ *     CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index, numentries, contentsize, regname_base, regfile_name, rsv2, rsv3)
+ */
+
+#define XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM      0
+#define XCHAL_EXTRA_SA_CONTENTS_LIBDB  /* empty */
+
+#define XCHAL_CP0_SA_CONTENTS_LIBDB_NUM        0
+#define XCHAL_CP0_SA_CONTENTS_LIBDB    /* empty */
+
+#define XCHAL_CP1_SA_CONTENTS_LIBDB_NUM        0
+#define XCHAL_CP1_SA_CONTENTS_LIBDB    /* empty */
+
+#define XCHAL_CP2_SA_CONTENTS_LIBDB_NUM        0
+#define XCHAL_CP2_SA_CONTENTS_LIBDB    /* empty */
+
+#define XCHAL_CP3_SA_CONTENTS_LIBDB_NUM        0
+#define XCHAL_CP3_SA_CONTENTS_LIBDB    /* empty */
+
+#define XCHAL_CP4_SA_CONTENTS_LIBDB_NUM        0
+#define XCHAL_CP4_SA_CONTENTS_LIBDB    /* empty */
+
+#define XCHAL_CP5_SA_CONTENTS_LIBDB_NUM        0
+#define XCHAL_CP5_SA_CONTENTS_LIBDB    /* empty */
+
+#define XCHAL_CP6_SA_CONTENTS_LIBDB_NUM        0
+#define XCHAL_CP6_SA_CONTENTS_LIBDB    /* empty */
+
+#define XCHAL_CP7_SA_CONTENTS_LIBDB_NUM        0
+#define XCHAL_CP7_SA_CONTENTS_LIBDB    /* empty */
+
+
+
+
+
+
+/*----------------------------------------------------------------------
+                               MISC
+  ----------------------------------------------------------------------*/
+
+#if 0  /* is there something equivalent for user TIE? */
+#define XCHAL_CORE_ID                  "linux_be"      /* configuration's alphanumeric core identifier
+                                                          (CoreID) set in the Xtensa Processor Generator */
+
+#define XCHAL_BUILD_UNIQUE_ID          0x00003256      /* software build-unique ID (22-bit) */
+
+/*  These definitions describe the hardware targeted by this software:  */
+#define XCHAL_HW_CONFIGID0             0xC103D1FF      /* config ID reg 0 value (upper 32 of 64 bits) */
+#define XCHAL_HW_CONFIGID1             0x00803256      /* config ID reg 1 value (lower 32 of 64 bits) */
+#define XCHAL_CONFIGID0                        XCHAL_HW_CONFIGID0      /* for backward compatibility only -- don't use! */
+#define XCHAL_CONFIGID1                        XCHAL_HW_CONFIGID1      /* for backward compatibility only -- don't use! */
+#define XCHAL_HW_RELEASE_MAJOR         1050    /* major release of targeted hardware */
+#define XCHAL_HW_RELEASE_MINOR         1       /* minor release of targeted hardware */
+#define XCHAL_HW_RELEASE_NAME          "T1050.1"       /* full release name of targeted hardware */
+#define XTHAL_HW_REL_T1050     1
+#define XTHAL_HW_REL_T1050_1   1
+#define XCHAL_HW_CONFIGID_RELIABLE     1
+#endif /*0*/
+
+
+
+/*----------------------------------------------------------------------
+                               ISA
+  ----------------------------------------------------------------------*/
+
+#if 0  /* these probably don't belong here, but are related to or implemented using TIE */
+#define XCHAL_HAVE_BOOLEANS            0       /* 1 if booleans option configured, 0 otherwise */
+/*  Misc instructions:  */
+#define XCHAL_HAVE_MUL32               0       /* 1 if 32-bit integer multiply option configured, 0 otherwise */
+#define XCHAL_HAVE_MUL32_HIGH          0       /* 1 if MUL32 option includes MULUH and MULSH, 0 otherwise */
+
+#define XCHAL_HAVE_FP                  0       /* 1 if floating point option configured, 0 otherwise */
+#endif /*0*/
+
+
+#endif /*XTENSA_CONFIG_TIE_H*/
+
diff --git a/include/asm-xtensa/xtensa/coreasm.h b/include/asm-xtensa/xtensa/coreasm.h
new file mode 100644 (file)
index 0000000..a8cfb54
--- /dev/null
@@ -0,0 +1,526 @@
+#ifndef XTENSA_COREASM_H
+#define XTENSA_COREASM_H
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * include/asm-xtensa/xtensa/coreasm.h -- assembler-specific
+ * definitions that depend on CORE configuration.
+ *
+ * Source for configuration-independent binaries (which link in a
+ * configuration-specific HAL library) must NEVER include this file.
+ * It is perfectly normal, however, for the HAL itself to include this
+ * file.
+ *
+ * This file must NOT include xtensa/config/system.h.  Any assembler
+ * header file that depends on system information should likely go in
+ * a new systemasm.h (or sysasm.h) header file.
+ *
+ *  NOTE: macro beqi32 is NOT configuration-dependent, and is placed
+ *        here til we will have configuration-independent header file.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2002 Tensilica Inc.
+ */
+
+
+#include <xtensa/config/core.h>
+#include <xtensa/config/specreg.h>
+
+/*
+ *  Assembly-language specific definitions (assembly macros, etc.).
+ */
+
+/*----------------------------------------------------------------------
+ *  find_ms_setbit
+ *
+ *  This macro finds the most significant bit that is set in <as>
+ *  and return its index + <base> in <ad>, or <base> - 1 if <as> is zero.
+ *  The index counts starting at zero for the lsbit, so the return
+ *  value ranges from <base>-1 (no bit set) to <base>+31 (msbit set).
+ *
+ *  Parameters:
+ *     <ad>    destination address register (any register)
+ *     <as>    source address register
+ *     <at>    temporary address register (must be different than <as>)
+ *     <base>  constant value added to result (usually 0 or 1)
+ *  On entry:
+ *     <ad> = undefined if different than <as>
+ *     <as> = value whose most significant set bit is to be found
+ *     <at> = undefined
+ *     no other registers are used by this macro.
+ *  On exit:
+ *     <ad> = <base> + index of msbit set in original <as>,
+ *          = <base> - 1 if original <as> was zero.
+ *     <as> clobbered (if not <ad>)
+ *     <at> clobbered (if not <ad>)
+ *  Example:
+ *     find_ms_setbit a0, a4, a0, 0            -- return in a0 index of msbit set in a4
+ */
+
+       .macro  find_ms_setbit ad, as, at, base
+#if XCHAL_HAVE_NSA
+       movi    \at, 31+\base
+       nsau    \as, \as        // get index of \as, numbered from msbit (32 if absent)
+       sub     \ad, \at, \as   // get numbering from lsbit (0..31, -1 if absent)
+#else /* XCHAL_HAVE_NSA */
+       movi    \at, \base      // start with result of 0 (point to lsbit of 32)
+
+       beqz    \as, 2f         // special case for zero argument: return -1
+       bltui   \as, 0x10000, 1f        // is it one of the 16 lsbits? (if so, check lower 16 bits)
+       addi    \at, \at, 16    // no, increment result to upper 16 bits (of 32)
+       //srli  \as, \as, 16    // check upper half (shift right 16 bits)
+       extui   \as, \as, 16, 16        // check upper half (shift right 16 bits)
+1:     bltui   \as, 0x100, 1f  // is it one of the 8 lsbits? (if so, check lower 8 bits)
+       addi    \at, \at, 8     // no, increment result to upper 8 bits (of 16)
+       srli    \as, \as, 8     // shift right to check upper 8 bits
+1:     bltui   \as, 0x10, 1f   // is it one of the 4 lsbits? (if so, check lower 4 bits)
+       addi    \at, \at, 4     // no, increment result to upper 4 bits (of 8)
+       srli    \as, \as, 4     // shift right 4 bits to check upper half
+1:     bltui   \as, 0x4, 1f    // is it one of the 2 lsbits? (if so, check lower 2 bits)
+       addi    \at, \at, 2     // no, increment result to upper 2 bits (of 4)
+       srli    \as, \as, 2     // shift right 2 bits to check upper half
+1:     bltui   \as, 0x2, 1f    // is it the lsbit?
+       addi    \at, \at, 2     // no, increment result to upper bit (of 2)
+2:     addi    \at, \at, -1    // (from just above: add 1;  from beqz: return -1)
+       //srli  \as, \as, 1
+1:                             // done! \at contains index of msbit set (or -1 if none set)
+       .if     0x\ad - 0x\at   // destination different than \at ? (works because regs are a0-a15)
+       mov     \ad, \at        // then move result to \ad
+       .endif
+#endif /* XCHAL_HAVE_NSA */
+       .endm   // find_ms_setbit
+
+/*----------------------------------------------------------------------
+ *  find_ls_setbit
+ *
+ *  This macro finds the least significant bit that is set in <as>,
+ *  and return its index in <ad>.
+ *  Usage is the same as for the find_ms_setbit macro.
+ *  Example:
+ *     find_ls_setbit a0, a4, a0, 0    -- return in a0 index of lsbit set in a4
+ */
+
+       .macro  find_ls_setbit ad, as, at, base
+       neg     \at, \as        // keep only the least-significant bit that is set...
+       and     \as, \at, \as   // ... in \as
+       find_ms_setbit  \ad, \as, \at, \base
+       .endm   // find_ls_setbit
+
+/*----------------------------------------------------------------------
+ *  find_ls_one
+ *
+ *  Same as find_ls_setbit with base zero.
+ *  Source (as) and destination (ad) registers must be different.
+ *  Provided for backward compatibility.
+ */
+
+       .macro  find_ls_one ad, as
+       find_ls_setbit  \ad, \as, \ad, 0
+       .endm   // find_ls_one
+
+/*----------------------------------------------------------------------
+ *  floop, floopnez, floopgtz, floopend
+ *
+ *  These macros are used for fast inner loops that
+ *  work whether or not the Loops options is configured.
+ *  If the Loops option is configured, they simply use
+ *  the zero-overhead LOOP instructions; otherwise
+ *  they use explicit decrement and branch instructions.
+ *
+ *  They are used in pairs, with floop, floopnez or floopgtz
+ *  at the beginning of the loop, and floopend at the end.
+ *
+ *  Each pair of loop macro calls must be given the loop count
+ *  address register and a unique label for that loop.
+ *
+ *  Example:
+ *
+ *     movi     a3, 16     // loop 16 times
+ *     floop    a3, myloop1
+ *     :
+ *     bnez     a7, end1       // exit loop if a7 != 0
+ *     :
+ *     floopend a3, myloop1
+ *  end1:
+ *
+ *  Like the LOOP instructions, these macros cannot be
+ *  nested, must include at least one instruction,
+ *  cannot call functions inside the loop, etc.
+ *  The loop can be exited by jumping to the instruction
+ *  following floopend (or elsewhere outside the loop),
+ *  or continued by jumping to a NOP instruction placed
+ *  immediately before floopend.
+ *
+ *  Unlike LOOP instructions, the register passed to floop*
+ *  cannot be used inside the loop, because it is used as
+ *  the loop counter if the Loops option is not configured.
+ *  And its value is undefined after exiting the loop.
+ *  And because the loop counter register is active inside
+ *  the loop, you can't easily use this construct to loop
+ *  across a register file using ROTW as you might with LOOP
+ *  instructions, unless you copy the loop register along.
+ */
+
+       /*  Named label version of the macros:  */
+
+       .macro  floop           ar, endlabel
+       floop_          \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
+       .endm
+
+       .macro  floopnez        ar, endlabel
+       floopnez_       \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
+       .endm
+
+       .macro  floopgtz        ar, endlabel
+       floopgtz_       \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
+       .endm
+
+       .macro  floopend        ar, endlabel
+       floopend_       \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
+       .endm
+
+       /*  Numbered local label version of the macros:  */
+#if 0 /*UNTESTED*/
+       .macro  floop89         ar
+       floop_          \ar, 8, 9f
+       .endm
+
+       .macro  floopnez89      ar
+       floopnez_       \ar, 8, 9f
+       .endm
+
+       .macro  floopgtz89      ar
+       floopgtz_       \ar, 8, 9f
+       .endm
+
+       .macro  floopend89      ar
+       floopend_       \ar, 8b, 9
+       .endm
+#endif /*0*/
+
+       /*  Underlying version of the macros:  */
+
+       .macro  floop_  ar, startlabel, endlabelref
+       .ifdef  _infloop_
+       .if     _infloop_
+       .err    // Error: floop cannot be nested
+       .endif
+       .endif
+       .set    _infloop_, 1
+#if XCHAL_HAVE_LOOPS
+       loop    \ar, \endlabelref
+#else /* XCHAL_HAVE_LOOPS */
+\startlabel:
+       addi    \ar, \ar, -1
+#endif /* XCHAL_HAVE_LOOPS */
+       .endm   // floop_
+
+       .macro  floopnez_       ar, startlabel, endlabelref
+       .ifdef  _infloop_
+       .if     _infloop_
+       .err    // Error: floopnez cannot be nested
+       .endif
+       .endif
+       .set    _infloop_, 1
+#if XCHAL_HAVE_LOOPS
+       loopnez \ar, \endlabelref
+#else /* XCHAL_HAVE_LOOPS */
+       beqz    \ar, \endlabelref
+\startlabel:
+       addi    \ar, \ar, -1
+#endif /* XCHAL_HAVE_LOOPS */
+       .endm   // floopnez_
+
+       .macro  floopgtz_       ar, startlabel, endlabelref
+       .ifdef  _infloop_
+       .if     _infloop_
+       .err    // Error: floopgtz cannot be nested
+       .endif
+       .endif
+       .set    _infloop_, 1
+#if XCHAL_HAVE_LOOPS
+       loopgtz \ar, \endlabelref
+#else /* XCHAL_HAVE_LOOPS */
+       bltz    \ar, \endlabelref
+       beqz    \ar, \endlabelref
+\startlabel:
+       addi    \ar, \ar, -1
+#endif /* XCHAL_HAVE_LOOPS */
+       .endm   // floopgtz_
+
+
+       .macro  floopend_       ar, startlabelref, endlabel
+       .ifndef _infloop_
+       .err    // Error: floopend without matching floopXXX
+       .endif
+       .ifeq   _infloop_
+       .err    // Error: floopend without matching floopXXX
+       .endif
+       .set    _infloop_, 0
+#if ! XCHAL_HAVE_LOOPS
+       bnez    \ar, \startlabelref
+#endif /* XCHAL_HAVE_LOOPS */
+\endlabel:
+       .endm   // floopend_
+
+/*----------------------------------------------------------------------
+ *  crsil  --  conditional RSIL (read/set interrupt level)
+ *
+ *  Executes the RSIL instruction if it exists, else just reads PS.
+ *  The RSIL instruction does not exist in the new exception architecture
+ *  if the interrupt option is not selected.
+ */
+
+       .macro  crsil   ar, newlevel
+#if XCHAL_HAVE_OLD_EXC_ARCH || XCHAL_HAVE_INTERRUPTS
+       rsil    \ar, \newlevel
+#else
+       rsr     \ar, PS
+#endif
+       .endm   // crsil
+
+/*----------------------------------------------------------------------
+ *  window_spill{4,8,12}
+ *
+ *  These macros spill callers' register windows to the stack.
+ *  They work for both privileged and non-privileged tasks.
+ *  Must be called from a windowed ABI context, eg. within
+ *  a windowed ABI function (ie. valid stack frame, window
+ *  exceptions enabled, not in exception mode, etc).
+ *
+ *  This macro requires a single invocation of the window_spill_common
+ *  macro in the same assembly unit and section.
+ *
+ *  Note that using window_spill{4,8,12} macros is more efficient
+ *  than calling a function implemented using window_spill_function,
+ *  because the latter needs extra code to figure out the size of
+ *  the call to the spilling function.
+ *
+ *  Example usage:
+ *
+ *             .text
+ *             .align  4
+ *             .global some_function
+ *             .type   some_function,@function
+ *     some_function:
+ *             entry   a1, 16
+ *             :
+ *             :
+ *
+ *             window_spill4   // spill windows of some_function's callers; preserves a0..a3 only;
+ *                             // to use window_spill{8,12} in this example function we'd have
+ *                             // to increase space allocated by the entry instruction, because
+ *                             // 16 bytes only allows call4; 32 or 48 bytes (+locals) are needed
+ *                             // for call8/window_spill8 or call12/window_spill12 respectively.
+ *             :
+ *
+ *             retw
+ *
+ *             window_spill_common     // instantiates code used by window_spill4
+ *
+ *
+ *  On entry:
+ *     none (if window_spill4)
+ *     stack frame has enough space allocated for call8 (if window_spill8)
+ *     stack frame has enough space allocated for call12 (if window_spill12)
+ *  On exit:
+ *      a4..a15 clobbered (if window_spill4)
+ *      a8..a15 clobbered (if window_spill8)
+ *     a12..a15 clobbered (if window_spill12)
+ *     no caller windows are in live registers
+ */
+
+       .macro  window_spill4
+#if XCHAL_HAVE_WINDOWED
+# if XCHAL_NUM_AREGS == 16
+       movi    a15, 0                  // for 16-register files, no need to call to reach the end
+# elif XCHAL_NUM_AREGS == 32
+       call4   .L__wdwspill_assist28   // call deep enough to clear out any live callers
+# elif XCHAL_NUM_AREGS == 64
+       call4   .L__wdwspill_assist60   // call deep enough to clear out any live callers
+# endif
+#endif
+       .endm   // window_spill4
+
+       .macro  window_spill8
+#if XCHAL_HAVE_WINDOWED
+# if XCHAL_NUM_AREGS == 16
+       movi    a15, 0                  // for 16-register files, no need to call to reach the end
+# elif XCHAL_NUM_AREGS == 32
+       call8   .L__wdwspill_assist24   // call deep enough to clear out any live callers
+# elif XCHAL_NUM_AREGS == 64
+       call8   .L__wdwspill_assist56   // call deep enough to clear out any live callers
+# endif
+#endif
+       .endm   // window_spill8
+
+       .macro  window_spill12
+#if XCHAL_HAVE_WINDOWED
+# if XCHAL_NUM_AREGS == 16
+       movi    a15, 0                  // for 16-register files, no need to call to reach the end
+# elif XCHAL_NUM_AREGS == 32
+       call12  .L__wdwspill_assist20   // call deep enough to clear out any live callers
+# elif XCHAL_NUM_AREGS == 64
+       call12  .L__wdwspill_assist52   // call deep enough to clear out any live callers
+# endif
+#endif
+       .endm   // window_spill12
+
+/*----------------------------------------------------------------------
+ *  window_spill_function
+ *
+ *  This macro outputs a function that will spill its caller's callers'
+ *  register windows to the stack.  Eg. it could be used to implement
+ *  a version of xthal_window_spill() that works in non-privileged tasks.
+ *  This works for both privileged and non-privileged tasks.
+ *
+ *  Typical usage:
+ *
+ *             .text
+ *             .align  4
+ *             .global my_spill_function
+ *             .type   my_spill_function,@function
+ *     my_spill_function:
+ *             window_spill_function
+ *
+ *  On entry to resulting function:
+ *     none
+ *  On exit from resulting function:
+ *     none (no caller windows are in live registers)
+ */
+
+       .macro  window_spill_function
+#if XCHAL_HAVE_WINDOWED
+# if XCHAL_NUM_AREGS == 32
+       entry   sp, 48
+       bbci.l  a0, 31, 1f              // branch if called with call4
+       bbsi.l  a0, 30, 2f              // branch if called with call12
+       call8   .L__wdwspill_assist16   // called with call8, only need another 8
+       retw
+1:     call12  .L__wdwspill_assist16   // called with call4, only need another 12
+       retw
+2:     call4   .L__wdwspill_assist16   // called with call12, only need another 4
+       retw
+# elif XCHAL_NUM_AREGS == 64
+       entry   sp, 48
+       bbci.l  a0, 31, 1f              // branch if called with call4
+       bbsi.l  a0, 30, 2f              // branch if called with call12
+       call4   .L__wdwspill_assist52   // called with call8, only need a call4
+       retw
+1:     call8   .L__wdwspill_assist52   // called with call4, only need a call8
+       retw
+2:     call12  .L__wdwspill_assist40   // called with call12, can skip a call12
+       retw
+# elif XCHAL_NUM_AREGS == 16
+       entry   sp, 16
+       bbci.l  a0, 31, 1f      // branch if called with call4
+       bbsi.l  a0, 30, 2f      // branch if called with call12
+       movi    a7, 0           // called with call8
+       retw
+1:     movi    a11, 0          // called with call4
+2:     retw                    // if called with call12, everything already spilled
+
+//     movi    a15, 0          // trick to spill all but the direct caller
+//     j       1f
+//     //  The entry instruction is magical in the assembler (gets auto-aligned)
+//     //  so we have to jump to it to avoid falling through the padding.
+//     //  We need entry/retw to know where to return.
+//1:   entry   sp, 16
+//     retw
+# else
+#  error "unrecognized address register file size"
+# endif
+#endif /* XCHAL_HAVE_WINDOWED */
+       window_spill_common
+       .endm   // window_spill_function
+
+/*----------------------------------------------------------------------
+ *  window_spill_common
+ *
+ *  Common code used by any number of invocations of the window_spill##
+ *  and window_spill_function macros.
+ *
+ *  Must be instantiated exactly once within a given assembly unit,
+ *  within call/j range of and same section as window_spill##
+ *  macro invocations for that assembly unit.
+ *  (Is automatically instantiated by the window_spill_function macro.)
+ */
+
+       .macro  window_spill_common
+#if XCHAL_HAVE_WINDOWED && (XCHAL_NUM_AREGS == 32 || XCHAL_NUM_AREGS == 64)
+       .ifndef .L__wdwspill_defined
+# if XCHAL_NUM_AREGS >= 64
+.L__wdwspill_assist60:
+       entry   sp, 32
+       call8   .L__wdwspill_assist52
+       retw
+.L__wdwspill_assist56:
+       entry   sp, 16
+       call4   .L__wdwspill_assist52
+       retw
+.L__wdwspill_assist52:
+       entry   sp, 48
+       call12  .L__wdwspill_assist40
+       retw
+.L__wdwspill_assist40:
+       entry   sp, 48
+       call12  .L__wdwspill_assist28
+       retw
+# endif
+.L__wdwspill_assist28:
+       entry   sp, 48
+       call12  .L__wdwspill_assist16
+       retw
+.L__wdwspill_assist24:
+       entry   sp, 32
+       call8   .L__wdwspill_assist16
+       retw
+.L__wdwspill_assist20:
+       entry   sp, 16
+       call4   .L__wdwspill_assist16
+       retw
+.L__wdwspill_assist16:
+       entry   sp, 16
+       movi    a15, 0
+       retw
+       .set    .L__wdwspill_defined, 1
+       .endif
+#endif /* XCHAL_HAVE_WINDOWED with 32 or 64 aregs */
+       .endm   // window_spill_common
+
+/*----------------------------------------------------------------------
+ *  beqi32
+ *
+ *  macro implements version of beqi for arbitrary 32-bit immidiate value
+ *
+ *     beqi32 ax, ay, imm32, label
+ *
+ *  Compares value in register ax with imm32 value and jumps to label if
+ *  equal. Clobberes register ay if needed
+ *
+ */
+   .macro beqi32       ax, ay, imm, label
+    .ifeq ((\imm-1) & ~7)      // 1..8 ?
+               beqi    \ax, \imm, \label
+    .else
+      .ifeq (\imm+1)           // -1 ?
+               beqi    \ax, \imm, \label
+      .else
+        .ifeq (\imm)           // 0 ?
+               beqz    \ax, \label
+        .else
+               //  We could also handle immediates 10,12,16,32,64,128,256
+               //  but it would be a long macro...
+               movi    \ay, \imm
+               beq     \ax, \ay, \label
+        .endif
+      .endif
+    .endif
+   .endm // beqi32
+
+#endif /*XTENSA_COREASM_H*/
+
diff --git a/include/asm-xtensa/xtensa/corebits.h b/include/asm-xtensa/xtensa/corebits.h
new file mode 100644 (file)
index 0000000..e578ade
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef XTENSA_COREBITS_H
+#define XTENSA_COREBITS_H
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * xtensa/corebits.h - Xtensa Special Register field positions and masks.
+ *
+ * (In previous releases, these were defined in specreg.h, a generated file.
+ *  This file is not generated, i.e. it is processor configuration independent.)
+ */
+
+
+/*  EXCCAUSE register fields:  */
+#define EXCCAUSE_EXCCAUSE_SHIFT        0
+#define EXCCAUSE_EXCCAUSE_MASK 0x3F
+/*  Exception causes (mostly incomplete!):  */
+#define EXCCAUSE_ILLEGAL               0
+#define EXCCAUSE_SYSCALL               1
+#define EXCCAUSE_IFETCHERROR           2
+#define EXCCAUSE_LOADSTOREERROR                3
+#define EXCCAUSE_LEVEL1INTERRUPT       4
+#define EXCCAUSE_ALLOCA                        5
+
+/*  PS register fields:  */
+#define PS_WOE_SHIFT           18
+#define PS_WOE_MASK            0x00040000
+#define PS_WOE                 PS_WOE_MASK
+#define PS_CALLINC_SHIFT       16
+#define PS_CALLINC_MASK                0x00030000
+#define PS_CALLINC(n)          (((n)&3)<<PS_CALLINC_SHIFT)     /* n = 0..3 */
+#define PS_OWB_SHIFT           8
+#define PS_OWB_MASK            0x00000F00
+#define PS_OWB(n)              (((n)&15)<<PS_OWB_SHIFT)        /* n = 0..15 (or 0..7) */
+#define PS_RING_SHIFT          6
+#define PS_RING_MASK           0x000000C0
+#define PS_RING(n)             (((n)&3)<<PS_RING_SHIFT)        /* n = 0..3 */
+#define PS_UM_SHIFT            5
+#define PS_UM_MASK             0x00000020
+#define PS_UM                  PS_UM_MASK
+#define PS_EXCM_SHIFT          4
+#define PS_EXCM_MASK           0x00000010
+#define PS_EXCM                        PS_EXCM_MASK
+#define PS_INTLEVEL_SHIFT      0
+#define PS_INTLEVEL_MASK       0x0000000F
+#define PS_INTLEVEL(n)         ((n)&PS_INTLEVEL_MASK)          /* n = 0..15 */
+/*  Backward compatibility (deprecated):  */
+#define PS_PROGSTACK_SHIFT     PS_UM_SHIFT
+#define PS_PROGSTACK_MASK      PS_UM_MASK
+#define PS_PROG_SHIFT          PS_UM_SHIFT
+#define PS_PROG_MASK           PS_UM_MASK
+#define PS_PROG                        PS_UM
+
+/*  DBREAKCn register fields:  */
+#define DBREAKC_MASK_SHIFT             0
+#define DBREAKC_MASK_MASK              0x0000003F
+#define DBREAKC_LOADBREAK_SHIFT                30
+#define DBREAKC_LOADBREAK_MASK         0x40000000
+#define DBREAKC_STOREBREAK_SHIFT       31
+#define DBREAKC_STOREBREAK_MASK                0x80000000
+
+/*  DEBUGCAUSE register fields:  */
+#define DEBUGCAUSE_DEBUGINT_SHIFT      5
+#define DEBUGCAUSE_DEBUGINT_MASK       0x20    /* debug interrupt */
+#define DEBUGCAUSE_BREAKN_SHIFT                4
+#define DEBUGCAUSE_BREAKN_MASK         0x10    /* BREAK.N instruction */
+#define DEBUGCAUSE_BREAK_SHIFT         3
+#define DEBUGCAUSE_BREAK_MASK          0x08    /* BREAK instruction */
+#define DEBUGCAUSE_DBREAK_SHIFT                2
+#define DEBUGCAUSE_DBREAK_MASK         0x04    /* DBREAK match */
+#define DEBUGCAUSE_IBREAK_SHIFT                1
+#define DEBUGCAUSE_IBREAK_MASK         0x02    /* IBREAK match */
+#define DEBUGCAUSE_ICOUNT_SHIFT                0
+#define DEBUGCAUSE_ICOUNT_MASK         0x01    /* ICOUNT would increment to zero */
+
+#endif /*XTENSA_COREBITS_H*/
+
diff --git a/include/asm-xtensa/xtensa/hal.h b/include/asm-xtensa/xtensa/hal.h
new file mode 100644 (file)
index 0000000..d104725
--- /dev/null
@@ -0,0 +1,822 @@
+#ifndef XTENSA_HAL_H
+#define XTENSA_HAL_H
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * include/asm-xtensa/xtensa/hal.h -- contains a definition of the
+ * Core HAL interface.
+ *
+ * All definitions in this header file are independent of any specific
+ * Xtensa processor configuration.  Thus an OS or other software can
+ * include this header file and be compiled into configuration-
+ * independent objects that can be distributed and eventually linked
+ * to the HAL library (libhal.a) to create a configuration-specific
+ * final executable.
+ *
+ * Certain definitions, however, are release-specific -- such as the
+ * XTHAL_RELEASE_xxx macros (or additions made in later releases).
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002 Tensilica Inc.
+ */
+
+
+/*----------------------------------------------------------------------
+                        Constant Definitions
+                       (shared with assembly)
+  ----------------------------------------------------------------------*/
+
+/*  Software release information (not configuration-specific!):  */
+#define XTHAL_RELEASE_MAJOR    1050
+#define XTHAL_RELEASE_MINOR    0
+#define XTHAL_RELEASE_NAME     "T1050.0-2002-08-06-eng0"
+#define XTHAL_RELEASE_INTERNAL "2002-08-06-eng0"
+#define XTHAL_REL_T1050        1
+#define XTHAL_REL_T1050_0      1
+#define XTHAL_REL_T1050_0_2002 1
+#define XTHAL_REL_T1050_0_2002_08      1
+#define XTHAL_REL_T1050_0_2002_08_06   1
+#define XTHAL_REL_T1050_0_2002_08_06_ENG0      1
+
+/*  HAL version numbers (these names are for backward compatibility):  */
+#define XTHAL_MAJOR_REV                XTHAL_RELEASE_MAJOR
+#define XTHAL_MINOR_REV                XTHAL_RELEASE_MINOR
+/*
+ *  A bit of software release history on values of XTHAL_{MAJOR,MINOR}_REV:
+ *
+ *     Release         MAJOR   MINOR           Comment
+ *     =======         =====   =====           =======
+ *     T1015.n         n/a     n/a             (HAL not yet available)
+ *     T1020.{0,1,2}   0       1               (HAL beta)
+ *     T1020.{3,4}     0       2               First release.
+ *     T1020.n (n>4)   0       2 or >3         (TBD)
+ *     T1030.0         0       1               (HAL beta)
+ *     T1030.{1,2}     0       3               Equivalent to first release.
+ *     T1030.n (n>=3)  0       >= 3            (TBD)
+ *     T1040.n         1040    n               Full CHAL available from T1040.2
+ *     T1050.n         1050    n               Current release.
+ *
+ *
+ *  Note:  there is a distinction between the software release with
+ *  which something is compiled (accessible using XTHAL_RELEASE_* macros)
+ *  and the software release with which the HAL library was compiled
+ *  (accessible using Xthal_release_* global variables).  This
+ *  distinction is particularly relevant for vendors that distribute
+ *  configuration-independent binaries (eg. an OS), where their customer
+ *  might link it with a HAL of a different Xtensa software release.
+ *  In this case, it may be appropriate for the OS to verify at run-time
+ *  whether XTHAL_RELEASE_* and Xthal_release_* are compatible.
+ *  [Guidelines as to which release is compatible with which are not
+ *  currently provided explicitly, but might be inferred from reading
+ *  OSKit documentation for all releases -- compatibility is also highly
+ *  dependent on which HAL features are used.  Each release is usually
+ *  backward compatible, with very few exceptions if any.]
+ *
+ *  Notes:
+ *     Tornado 2.0 supported in T1020.3+, T1030.1+, and T1040.{0,1} only.
+ *     Tornado 2.0.2 supported in T1040.2+, and T1050.
+ *     Compile-time HAL port of NucleusPlus supported by T1040.2+ and T1050.
+ */
+
+
+/*
+ *  Architectural limits, independent of configuration.
+ *  Note that these are ISA-defined limits, not micro-architecture implementation
+ *  limits enforced by the Xtensa Processor Generator (which may be stricter than
+ *  these below).
+ */
+#define XTHAL_MAX_CPS          8       /* max number of coprocessors (0..7) */
+#define XTHAL_MAX_INTERRUPTS   32      /* max number of interrupts (0..31) */
+#define XTHAL_MAX_INTLEVELS    16      /* max number of interrupt levels (0..15) */
+                                       /* (as of T1040, implementation limit is 7: 0..6) */
+#define XTHAL_MAX_TIMERS       4       /* max number of timers (CCOMPARE0..CCOMPARE3) */
+                                       /* (as of T1040, implementation limit is 3: 0..2) */
+
+/*  Misc:  */
+#define XTHAL_LITTLEENDIAN             0
+#define XTHAL_BIGENDIAN                        1
+
+
+/*  Interrupt types:  */
+#define XTHAL_INTTYPE_UNCONFIGURED     0
+#define XTHAL_INTTYPE_SOFTWARE         1
+#define XTHAL_INTTYPE_EXTERN_EDGE      2
+#define XTHAL_INTTYPE_EXTERN_LEVEL     3
+#define XTHAL_INTTYPE_TIMER            4
+#define XTHAL_INTTYPE_NMI              5
+#define XTHAL_MAX_INTTYPES             6       /* number of interrupt types */
+
+/*  Timer related:  */
+#define XTHAL_TIMER_UNCONFIGURED       -1      /* Xthal_timer_interrupt[] value for non-existent timers */
+#define XTHAL_TIMER_UNASSIGNED XTHAL_TIMER_UNCONFIGURED        /* (for backwards compatibility only) */
+
+
+/*  Access Mode bits (tentative):  */  /* bit abbr unit short_name       PPC equ - Description */
+#define XTHAL_AMB_EXCEPTION    0       /* 001 E EX fls: EXception        none    - generate exception on any access (aka "illegal") */
+#define XTHAL_AMB_HITCACHE     1       /* 002 C CH fls: use Cache on Hit ~(I CI) - use cache on hit -- way from tag match [or H HC, or U UC] (ISA: same, except for Isolate case) */
+#define XTHAL_AMB_ALLOCATE     2       /* 004 A AL fl?: ALlocate         none    - refill cache on miss -- way from LRU [or F FI fill] (ISA: Read/Write Miss Refill) */
+#define XTHAL_AMB_WRITETHRU    3       /* 008 W WT --s: WriteThrough     W WT    - store immediately to memory (ISA: same) */
+#define XTHAL_AMB_ISOLATE      4       /* 010 I IS fls: ISolate          none    - use cache regardless of hit-vs-miss -- way from vaddr (ISA: use-cache-on-miss+hit) */
+#define XTHAL_AMB_GUARD                5       /* 020 G GU ?l?: GUard            G *     - non-speculative; spec/replay refs not permitted */
+#if 0
+#define XTHAL_AMB_ORDERED      x       /* 000 O OR fls: ORdered          G *     - mem accesses cannot be out of order */
+#define XTHAL_AMB_FUSEWRITES   x       /* 000 F FW --s: FuseWrites       none    - allow combining/merging multiple writes (to same datapath data unit) into one (implied by writeback) */
+#define XTHAL_AMB_COHERENT     x       /* 000 M MC fl?: Mem/MP Coherent  M       - on reads, other CPUs/bus-masters may need to supply data */
+#define XTHAL_AMB_TRUSTED      x       /* 000 T TR ?l?: TRusted          none    - memory will not bus error (if it does, handle as fatal imprecise interrupt) */
+#define XTHAL_AMB_PREFETCH     x       /* 000 P PR fl?: PRefetch         none    - on refill, read line+1 into prefetch buffers */
+#define XTHAL_AMB_STREAM       x       /* 000 S ST ???: STreaming        none    - access one of N stream buffers */
+#endif /*0*/
+
+#define XTHAL_AM_EXCEPTION     (1<<XTHAL_AMB_EXCEPTION)
+#define XTHAL_AM_HITCACHE      (1<<XTHAL_AMB_HITCACHE)
+#define XTHAL_AM_ALLOCATE      (1<<XTHAL_AMB_ALLOCATE)
+#define XTHAL_AM_WRITETHRU     (1<<XTHAL_AMB_WRITETHRU)
+#define XTHAL_AM_ISOLATE       (1<<XTHAL_AMB_ISOLATE)
+#define XTHAL_AM_GUARD         (1<<XTHAL_AMB_GUARD)
+#if 0
+#define XTHAL_AM_ORDERED       (1<<XTHAL_AMB_ORDERED)
+#define XTHAL_AM_FUSEWRITES    (1<<XTHAL_AMB_FUSEWRITES)
+#define XTHAL_AM_COHERENT      (1<<XTHAL_AMB_COHERENT)
+#define XTHAL_AM_TRUSTED       (1<<XTHAL_AMB_TRUSTED)
+#define XTHAL_AM_PREFETCH      (1<<XTHAL_AMB_PREFETCH)
+#define XTHAL_AM_STREAM                (1<<XTHAL_AMB_STREAM)
+#endif /*0*/
+
+/*
+ *  Allowed Access Modes (bit combinations).
+ *
+ *  Columns are:
+ *  "FOGIWACE"
+ *     Access mode bits (see XTHAL_AMB_xxx above).
+ *     <letter> = bit is set
+ *     '-'      = bit is clear
+ *     '.'      = bit is irrelevant / don't care, as follows:
+ *                     E=1 makes all others irrelevant
+ *                     W,F relevant only for stores
+ *  "2345"
+ *     Indicates which Xtensa releases support the corresponding
+ *     access mode.  Releases for each character column are:
+ *             2 = prior to T1020.2:   T1015 (V1.5), T1020.0, T1020.1
+ *             3 = T1020.2 and later:  T1020.2+, T1030
+ *             4 = T1040
+ *             5 = T1050 (maybe)
+ *     And the character column contents are:
+ *             <number> = support by release(s)
+ *             "." = unsupported by release(s)
+ *             "?" = support unknown
+ */
+                                       /* FOGIWACE 2345 */
+/*  For instruction fetch:  */
+#define XTHAL_FAM_EXCEPTION    0x001   /* .......E 2345 exception */
+#define XTHAL_FAM_ISOLATE      0x012   /* .--I.-C- .... isolate */
+#define XTHAL_FAM_BYPASS       0x000   /* .---.--- 2345 bypass */
+#define XTHAL_FAM_NACACHED     0x002   /* .---.-C- .... cached no-allocate (frozen) */
+#define XTHAL_FAM_CACHED       0x006   /* .---.AC- 2345 cached */
+/*  For data load:  */
+#define XTHAL_LAM_EXCEPTION    0x001   /* .......E 2345 exception */
+#define XTHAL_LAM_ISOLATE      0x012   /* .--I.-C- 2345 isolate */
+#define XTHAL_LAM_BYPASS       0x000   /* .O--.--- 2... bypass speculative */
+#define XTHAL_LAM_BYPASSG      0x020   /* .OG-.--- .345 bypass guarded */
+#define XTHAL_LAM_NACACHED     0x002   /* .O--.-C- 2... cached no-allocate speculative */
+#define XTHAL_LAM_NACACHEDG    0x022   /* .OG-.-C- .345 cached no-allocate guarded */
+#define XTHAL_LAM_CACHED       0x006   /* .---.AC- 2345 cached speculative */
+#define XTHAL_LAM_CACHEDG      0x026   /* .?G-.AC- .... cached guarded */
+/*  For data store:  */
+#define XTHAL_SAM_EXCEPTION    0x001   /* .......E 2345 exception */
+#define XTHAL_SAM_ISOLATE      0x032   /* .-GI--C- 2345 isolate */
+#define XTHAL_SAM_BYPASS       0x028   /* -OG-W--- 2345 bypass */
+/*efine XTHAL_SAM_BYPASSF      0x028*/ /* F-G-W--- ...? bypass write-combined */
+#define XTHAL_SAM_WRITETHRU    0x02A   /* -OG-W-C- 234? writethrough */
+/*efine XTHAL_SAM_WRITETHRUF   0x02A*/ /* F-G-W-C- ...5 writethrough write-combined */
+#define XTHAL_SAM_WRITEALLOC   0x02E   /* -OG-WAC- ...? writethrough-allocate */
+/*efine XTHAL_SAM_WRITEALLOCF  0x02E*/ /* F-G-WAC- ...? writethrough-allocate write-combined */
+#define XTHAL_SAM_WRITEBACK    0x026   /* F-G--AC- ...5 writeback */
+
+#if 0
+/*
+    Cache attribute encoding for CACHEATTR (per ISA):
+    (Note:  if this differs from ISA Ref Manual, ISA has precedence)
+
+       Inst-fetches    Loads           Stores
+       -------------   ------------    -------------
+0x0    FCA_EXCEPTION  ?LCA_NACACHED_G* SCA_WRITETHRU   "uncached"
+0x1    FCA_CACHED      LCA_CACHED      SCA_WRITETHRU   cached
+0x2    FCA_BYPASS      LCA_BYPASS_G*   SCA_BYPASS      bypass
+0x3    FCA_CACHED      LCA_CACHED      SCA_WRITEALLOCF write-allocate
+                    or LCA_EXCEPTION   SCA_EXCEPTION   (if unimplemented)
+0x4    FCA_CACHED      LCA_CACHED      SCA_WRITEBACK   write-back
+                    or LCA_EXCEPTION   SCA_EXCEPTION   (if unimplemented)
+0x5..D FCA_EXCEPTION   LCA_EXCEPTION   SCA_EXCEPTION   (reserved)
+0xE    FCA_EXCEPTION   LCA_ISOLATE     SCA_ISOLATE     isolate
+0xF    FCA_EXCEPTION   LCA_EXCEPTION   SCA_EXCEPTION   illegal
+     *  Prior to T1020.2?, guard feature not supported, this defaulted to speculative (no _G)
+*/
+#endif /*0*/
+
+
+#if !defined(__ASSEMBLY__) && !defined(_NOCLANGUAGE)
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*----------------------------------------------------------------------
+                            HAL
+  ----------------------------------------------------------------------*/
+
+/* Constant to be checked in build = (XTHAL_MAJOR_REV<<16)|XTHAL_MINOR_REV */
+extern const unsigned int Xthal_rev_no;
+
+
+/*----------------------------------------------------------------------
+                       Processor State
+  ----------------------------------------------------------------------*/
+/* save & restore the extra processor state */
+extern void xthal_save_extra(void *base);
+extern void xthal_restore_extra(void *base);
+
+extern void xthal_save_cpregs(void *base, int);
+extern void xthal_restore_cpregs(void *base, int);
+
+/*extern void xthal_save_all_extra(void *base);*/
+/*extern void xthal_restore_all_extra(void *base);*/
+
+/* space for processor state */
+extern const unsigned int Xthal_extra_size;
+extern const unsigned int Xthal_extra_align;
+/* space for TIE register files */
+extern const unsigned int Xthal_cpregs_size[XTHAL_MAX_CPS];
+extern const unsigned int Xthal_cpregs_align[XTHAL_MAX_CPS];
+
+/* total of space for the processor state (for Tor2) */
+extern const unsigned int Xthal_all_extra_size;
+extern const unsigned int Xthal_all_extra_align;
+
+/* initialize the extra processor */
+/*extern void xthal_init_extra(void);*/
+/* initialize the TIE coprocessor */
+/*extern void xthal_init_cp(int);*/
+
+/* initialize the extra processor */
+extern void xthal_init_mem_extra(void *);
+/* initialize the TIE coprocessor */
+extern void xthal_init_mem_cp(void *, int);
+
+/* validate & invalidate the TIE register file */
+extern void xthal_validate_cp(int);
+extern void xthal_invalidate_cp(int);
+
+/* the number of TIE coprocessors contiguous from zero (for Tor2) */
+extern const unsigned int Xthal_num_coprocessors;
+
+/* actual number of coprocessors */
+extern const unsigned char Xthal_cp_num;
+/* index of highest numbered coprocessor, plus one */
+extern const unsigned char Xthal_cp_max;
+/* index of highest allowed coprocessor number, per cfg, plus one */
+/*extern const unsigned char Xthal_cp_maxcfg;*/
+/* bitmask of which coprocessors are present */
+extern const unsigned int  Xthal_cp_mask;
+
+/* read and write cpenable register */
+extern void xthal_set_cpenable(unsigned);
+extern unsigned xthal_get_cpenable(void);
+
+/* read & write extra state register */
+/*extern int xthal_read_extra(void *base, unsigned reg, unsigned *value);*/
+/*extern int xthal_write_extra(void *base, unsigned reg, unsigned value);*/
+
+/* read & write a TIE coprocessor register */
+/*extern int xthal_read_cpreg(void *base, int cp, unsigned reg, unsigned *value);*/
+/*extern int xthal_write_cpreg(void *base, int cp, unsigned reg, unsigned value);*/
+
+/* return coprocessor number based on register */
+/*extern int xthal_which_cp(unsigned reg);*/
+
+/*----------------------------------------------------------------------
+                               Interrupts
+  ----------------------------------------------------------------------*/
+
+/* the number of interrupt levels */
+extern const unsigned char Xthal_num_intlevels;
+/* the number of interrupts */
+extern const unsigned char Xthal_num_interrupts;
+
+/* mask for level of interrupts */
+extern const unsigned int Xthal_intlevel_mask[XTHAL_MAX_INTLEVELS];
+/* mask for level 0 to N interrupts */
+extern const unsigned int Xthal_intlevel_andbelow_mask[XTHAL_MAX_INTLEVELS];
+
+/* level of each interrupt */
+extern const unsigned char Xthal_intlevel[XTHAL_MAX_INTERRUPTS];
+
+/* type per interrupt */
+extern const unsigned char Xthal_inttype[XTHAL_MAX_INTERRUPTS];
+
+/* masks of each type of interrupt */
+extern const unsigned int Xthal_inttype_mask[XTHAL_MAX_INTTYPES];
+
+/* interrupt numbers assigned to each timer interrupt */
+extern const int Xthal_timer_interrupt[XTHAL_MAX_TIMERS];
+
+/***  Virtual interrupt prioritization:  ***/
+
+/*  Convert between interrupt levels (as per PS.INTLEVEL) and virtual interrupt priorities:  */
+extern unsigned        xthal_vpri_to_intlevel(unsigned vpri);
+extern unsigned        xthal_intlevel_to_vpri(unsigned intlevel);
+
+/*  Enables/disables given set (mask) of interrupts; returns previous enabled-mask of all ints:  */
+extern unsigned        xthal_int_enable(unsigned);
+extern unsigned        xthal_int_disable(unsigned);
+
+/*  Set/get virtual priority of an interrupt:  */
+extern int     xthal_set_int_vpri(int intnum, int vpri);
+extern int     xthal_get_int_vpri(int intnum);
+
+/*  Set/get interrupt lockout level for exclusive access to virtual priority data structures:  */
+extern void    xthal_set_vpri_locklevel(unsigned intlevel);
+extern unsigned        xthal_get_vpri_locklevel(void);
+
+/*  Set/get current virtual interrupt priority:  */
+extern unsigned        xthal_set_vpri(unsigned vpri);
+extern unsigned        xthal_get_vpri(unsigned vpri);
+extern unsigned        xthal_set_vpri_intlevel(unsigned intlevel);
+extern unsigned        xthal_set_vpri_lock(void);
+
+
+
+/*----------------------------------------------------------------------
+                       Generic Interrupt Trampolining Support
+  ----------------------------------------------------------------------*/
+
+typedef void (XtHalVoidFunc)(void);
+
+/*
+ *  Bitmask of interrupts currently trampolining down:
+ */
+extern unsigned Xthal_tram_pending;
+
+/*
+ *  Bitmask of which interrupts currently trampolining down
+ *  synchronously are actually enabled; this bitmask is necessary
+ *  because INTENABLE cannot hold that state (sync-trampolining
+ *  interrupts must be kept disabled while trampolining);
+ *  in the current implementation, any bit set here is not set
+ *  in INTENABLE, and vice-versa; once a sync-trampoline is
+ *  handled (at level one), its enable bit must be moved from
+ *  here to INTENABLE:
+ */
+extern unsigned Xthal_tram_enabled;
+
+/*
+ *  Bitmask of interrupts configured for sync trampolining:
+ */
+extern unsigned Xthal_tram_sync;
+
+
+/*  Trampoline support functions:  */
+extern unsigned  xthal_tram_pending_to_service( void );
+extern void      xthal_tram_done( unsigned serviced_mask );
+extern int       xthal_tram_set_sync( int intnum, int sync );
+extern XtHalVoidFunc* xthal_set_tram_trigger_func( XtHalVoidFunc *trigger_fn );
+
+/*  INTENABLE,INTREAD,INTSET,INTCLEAR register access functions:  */
+extern unsigned  xthal_get_intenable( void );
+extern void      xthal_set_intenable( unsigned );
+extern unsigned  xthal_get_intread( void );
+extern void      xthal_set_intset( unsigned );
+extern void      xthal_set_intclear( unsigned );
+
+
+/*----------------------------------------------------------------------
+                               Register Windows
+  ----------------------------------------------------------------------*/
+
+/* number of registers in register window */
+extern const unsigned int  Xthal_num_aregs;
+extern const unsigned char Xthal_num_aregs_log2;
+
+/*  This spill any live register windows (other than the caller's):  */
+extern void      xthal_window_spill( void );
+
+
+/*----------------------------------------------------------------------
+                               Cache
+  ----------------------------------------------------------------------*/
+
+/* size of the cache lines in log2(bytes) */
+extern const unsigned char Xthal_icache_linewidth;
+extern const unsigned char Xthal_dcache_linewidth;
+/* size of the cache lines in bytes */
+extern const unsigned short Xthal_icache_linesize;
+extern const unsigned short Xthal_dcache_linesize;
+/* number of cache sets in log2(lines per way) */
+extern const unsigned char Xthal_icache_setwidth;
+extern const unsigned char Xthal_dcache_setwidth;
+/* cache set associativity (number of ways) */
+extern const unsigned int  Xthal_icache_ways;
+extern const unsigned int  Xthal_dcache_ways;
+/* size of the caches in bytes (ways * 2^(linewidth + setwidth)) */
+extern const unsigned int  Xthal_icache_size;
+extern const unsigned int  Xthal_dcache_size;
+/* cache features */
+extern const unsigned char Xthal_dcache_is_writeback;
+extern const unsigned char Xthal_icache_line_lockable;
+extern const unsigned char Xthal_dcache_line_lockable;
+
+/* cache attribute register control (used by other HAL routines) */
+extern unsigned xthal_get_cacheattr( void );
+extern unsigned xthal_get_icacheattr( void );
+extern unsigned xthal_get_dcacheattr( void );
+extern void     xthal_set_cacheattr( unsigned );
+extern void     xthal_set_icacheattr( unsigned );
+extern void     xthal_set_dcacheattr( unsigned );
+
+/* initialize cache support (must be called once at startup, before all other cache calls) */
+/*extern void xthal_cache_startinit( void );*/
+/* reset caches */
+/*extern void xthal_icache_reset( void );*/
+/*extern void xthal_dcache_reset( void );*/
+/* enable caches */
+extern void xthal_icache_enable( void );       /* DEPRECATED */
+extern void xthal_dcache_enable( void );       /* DEPRECATED */
+/* disable caches */
+extern void xthal_icache_disable( void );      /* DEPRECATED */
+extern void xthal_dcache_disable( void );      /* DEPRECATED */
+
+/* invalidate the caches */
+extern void xthal_icache_all_invalidate( void );
+extern void xthal_dcache_all_invalidate( void );
+extern void xthal_icache_region_invalidate( void *addr, unsigned size );
+extern void xthal_dcache_region_invalidate( void *addr, unsigned size );
+extern void xthal_icache_line_invalidate(void *addr);
+extern void xthal_dcache_line_invalidate(void *addr);
+/* write dirty data back */
+extern void xthal_dcache_all_writeback( void );
+extern void xthal_dcache_region_writeback( void *addr, unsigned size );
+extern void xthal_dcache_line_writeback(void *addr);
+/* write dirty data back and invalidate */
+extern void xthal_dcache_all_writeback_inv( void );
+extern void xthal_dcache_region_writeback_inv( void *addr, unsigned size );
+extern void xthal_dcache_line_writeback_inv(void *addr);
+/* prefetch and lock specified memory range into cache */
+extern void xthal_icache_region_lock( void *addr, unsigned size );
+extern void xthal_dcache_region_lock( void *addr, unsigned size );
+extern void xthal_icache_line_lock(void *addr);
+extern void xthal_dcache_line_lock(void *addr);
+/* unlock from cache */
+extern void xthal_icache_all_unlock( void );
+extern void xthal_dcache_all_unlock( void );
+extern void xthal_icache_region_unlock( void *addr, unsigned size );
+extern void xthal_dcache_region_unlock( void *addr, unsigned size );
+extern void xthal_icache_line_unlock(void *addr);
+extern void xthal_dcache_line_unlock(void *addr);
+
+
+/* sync icache and memory */
+extern void xthal_icache_sync( void );
+/* sync dcache and memory */
+extern void xthal_dcache_sync( void );
+
+/*----------------------------------------------------------------------
+                               Debug
+  ----------------------------------------------------------------------*/
+
+/*  1 if debug option configured, 0 if not:  */
+extern const int Xthal_debug_configured;
+
+/*  Number of instruction and data break registers:  */
+extern const int Xthal_num_ibreak;
+extern const int Xthal_num_dbreak;
+
+/*  Set (plant) and remove software breakpoint, both synchronizing cache:  */
+extern unsigned int xthal_set_soft_break(void *addr);
+extern void         xthal_remove_soft_break(void *addr, unsigned int);
+
+
+/*----------------------------------------------------------------------
+                               Disassembler
+  ----------------------------------------------------------------------*/
+
+/*  Max expected size of the return buffer for a disassembled instruction (hint only):  */
+#define XTHAL_DISASM_BUFSIZE   80
+
+/*  Disassembly option bits for selecting what to return:  */
+#define XTHAL_DISASM_OPT_ADDR  0x0001  /* display address */
+#define XTHAL_DISASM_OPT_OPHEX 0x0002  /* display opcode bytes in hex */
+#define XTHAL_DISASM_OPT_OPCODE        0x0004  /* display opcode name (mnemonic) */
+#define XTHAL_DISASM_OPT_PARMS 0x0008  /* display parameters */
+#define XTHAL_DISASM_OPT_ALL   0x0FFF  /* display everything */
+
+/* routine to get a string for the disassembled instruction */
+extern int xthal_disassemble( unsigned char *instr_buf, void *tgt_addr,
+                      char *buffer, unsigned buflen, unsigned options );
+
+/* routine to get the size of the next instruction. Returns 0 for
+   illegal instruction */
+extern int xthal_disassemble_size( unsigned char *instr_buf );
+
+
+/*----------------------------------------------------------------------
+                               Core Counter
+  ----------------------------------------------------------------------*/
+
+/* counter info */
+extern const unsigned char Xthal_have_ccount;  /* set if CCOUNT register present */
+extern const unsigned char Xthal_num_ccompare; /* number of CCOMPAREn registers */
+
+/* get CCOUNT register (if not present return 0) */
+extern unsigned xthal_get_ccount(void);
+
+/* set and get CCOMPAREn registers (if not present, get returns 0) */
+extern void     xthal_set_ccompare(int, unsigned);
+extern unsigned xthal_get_ccompare(int);
+
+
+/*----------------------------------------------------------------------
+                       Instruction/Data RAM/ROM Access
+  ----------------------------------------------------------------------*/
+
+extern void* xthal_memcpy(void *dst, const void *src, unsigned len);
+extern void* xthal_bcopy(const void *src, void *dst, unsigned len);
+
+/*----------------------------------------------------------------------
+                           MP Synchronization
+  ----------------------------------------------------------------------*/
+extern int      xthal_compare_and_set( int *addr, int test_val, int compare_val );
+extern unsigned xthal_get_prid( void );
+
+/*extern const char  Xthal_have_s32c1i;*/
+extern const unsigned char Xthal_have_prid;
+
+
+/*----------------------------------------------------------------------
+                             Miscellaneous
+  ----------------------------------------------------------------------*/
+
+extern const unsigned int  Xthal_release_major;
+extern const unsigned int  Xthal_release_minor;
+extern const char * const  Xthal_release_name;
+extern const char * const  Xthal_release_internal;
+
+extern const unsigned char Xthal_memory_order;
+extern const unsigned char Xthal_have_windowed;
+extern const unsigned char Xthal_have_density;
+extern const unsigned char Xthal_have_booleans;
+extern const unsigned char Xthal_have_loops;
+extern const unsigned char Xthal_have_nsa;
+extern const unsigned char Xthal_have_minmax;
+extern const unsigned char Xthal_have_sext;
+extern const unsigned char Xthal_have_clamps;
+extern const unsigned char Xthal_have_mac16;
+extern const unsigned char Xthal_have_mul16;
+extern const unsigned char Xthal_have_fp;
+extern const unsigned char Xthal_have_speculation;
+extern const unsigned char Xthal_have_exceptions;
+extern const unsigned char Xthal_xea_version;
+extern const unsigned char Xthal_have_interrupts;
+extern const unsigned char Xthal_have_highlevel_interrupts;
+extern const unsigned char Xthal_have_nmi;
+
+extern const unsigned short Xthal_num_writebuffer_entries;
+
+extern const unsigned int  Xthal_build_unique_id;
+/*  Release info for hardware targeted by software upgrades:  */
+extern const unsigned int  Xthal_hw_configid0;
+extern const unsigned int  Xthal_hw_configid1;
+extern const unsigned int  Xthal_hw_release_major;
+extern const unsigned int  Xthal_hw_release_minor;
+extern const char * const  Xthal_hw_release_name;
+extern const char * const  Xthal_hw_release_internal;
+
+
+/*  Internal memories...  */
+
+extern const unsigned char Xthal_num_instrom;
+extern const unsigned char Xthal_num_instram;
+extern const unsigned char Xthal_num_datarom;
+extern const unsigned char Xthal_num_dataram;
+extern const unsigned char Xthal_num_xlmi;
+extern const unsigned int  Xthal_instrom_vaddr[1];
+extern const unsigned int  Xthal_instrom_paddr[1];
+extern const unsigned int  Xthal_instrom_size [1];
+extern const unsigned int  Xthal_instram_vaddr[1];
+extern const unsigned int  Xthal_instram_paddr[1];
+extern const unsigned int  Xthal_instram_size [1];
+extern const unsigned int  Xthal_datarom_vaddr[1];
+extern const unsigned int  Xthal_datarom_paddr[1];
+extern const unsigned int  Xthal_datarom_size [1];
+extern const unsigned int  Xthal_dataram_vaddr[1];
+extern const unsigned int  Xthal_dataram_paddr[1];
+extern const unsigned int  Xthal_dataram_size [1];
+extern const unsigned int  Xthal_xlmi_vaddr[1];
+extern const unsigned int  Xthal_xlmi_paddr[1];
+extern const unsigned int  Xthal_xlmi_size [1];
+
+
+
+/*----------------------------------------------------------------------
+                         Memory Management Unit
+  ----------------------------------------------------------------------*/
+
+extern const unsigned char Xthal_have_spanning_way;
+extern const unsigned char Xthal_have_identity_map;
+extern const unsigned char Xthal_have_mimic_cacheattr;
+extern const unsigned char Xthal_have_xlt_cacheattr;
+extern const unsigned char Xthal_have_cacheattr;
+extern const unsigned char Xthal_have_tlbs;
+
+extern const unsigned char Xthal_mmu_asid_bits;                /* 0 .. 8 */
+extern const unsigned char Xthal_mmu_asid_kernel;
+extern const unsigned char Xthal_mmu_rings;            /* 1 .. 4 (perhaps 0 if no MMU and/or no protection?) */
+extern const unsigned char Xthal_mmu_ring_bits;
+extern const unsigned char Xthal_mmu_sr_bits;
+extern const unsigned char Xthal_mmu_ca_bits;
+extern const unsigned int  Xthal_mmu_max_pte_page_size;
+extern const unsigned int  Xthal_mmu_min_pte_page_size;
+
+extern const unsigned char Xthal_itlb_way_bits;
+extern const unsigned char Xthal_itlb_ways;
+extern const unsigned char Xthal_itlb_arf_ways;
+extern const unsigned char Xthal_dtlb_way_bits;
+extern const unsigned char Xthal_dtlb_ways;
+extern const unsigned char Xthal_dtlb_arf_ways;
+
+/*  Convert between virtual and physical addresses (through static maps only):  */
+/*** WARNING: these two functions may go away in a future release; don't depend on them! ***/
+extern int  xthal_static_v2p( unsigned vaddr, unsigned *paddrp );
+extern int  xthal_static_p2v( unsigned paddr, unsigned *vaddrp, unsigned cached );
+
+#if 0
+/*******************   EXPERIMENTAL AND TENTATIVE ONLY   ********************/
+
+#define XTHAL_MMU_PAGESZ_COUNT_MAX     8       /* maximum number of different page sizes */
+extern const char      Xthal_mmu_pagesz_count;         /* 0 .. 8               number of different page sizes configured */
+
+/*  Note:  the following table doesn't necessarily have page sizes in increasing order: */
+extern const char      Xthal_mmu_pagesz_log2[XTHAL_MMU_PAGESZ_COUNT_MAX];      /* 10 .. 28 (0 past count) */
+
+/*  Sorted (increasing) table of page sizes, that indexes into the above table: */
+extern const char      Xthal_mmu_pagesz_sorted[XTHAL_MMU_PAGESZ_COUNT_MAX];    /* 0 .. 7 (0 past count) */
+
+/*u32  Xthal_virtual_exceptions;*/     /* bitmask of which exceptions execute in virtual mode... */
+
+extern const char      Xthal_mmu_pte_pagesz_log2_min;  /* ?? minimum page size in PTEs */
+extern const char      Xthal_mmu_pte_pagesz_log2_max;  /* ?? maximum page size in PTEs */
+
+/*  Cache Attribute Bits Implemented by the Cache (part of the cache abstraction) */
+extern const char      Xthal_icache_fca_bits_implemented;      /* ITLB/UTLB only! */
+extern const char      Xthal_dcache_lca_bits_implemented;      /* DTLB/UTLB only! */
+extern const char      Xthal_dcache_sca_bits_implemented;      /* DTLB/UTLB only! */
+
+/*  Per TLB Parameters (Instruction, Data, Unified)  */
+struct XtHalMmuTlb     Xthal_itlb;     /* description of MMU I-TLB generic features */
+struct XtHalMmuTlb     Xthal_dtlb;     /* description of MMU D-TLB generic features */
+struct XtHalMmuTlb     Xthal_utlb;     /* description of MMU U-TLB generic features */
+
+#define XTHAL_MMU_WAYS_MAX     8       /* maximum number of ways (associativities) for each TLB */
+
+/*  Structure for common information described for each possible TLB (instruction, data and unified): */
+typedef struct XtHalMmuTlb {
+    u8         va_bits;                /* 32           (number of virtual address bits) */
+    u8         pa_bits;                /* 32           (number of physical address bits) */
+    bool       tlb_va_indexed;         /* 1    (set if TLB is indexed by virtual address) */
+    bool       tlb_va_tagged;          /* 0    (set if TLB is tagged by virtual address) */
+    bool       cache_va_indexed;       /* 1    (set if cache is indexed by virtual address) */
+    bool       cache_va_tagged;        /* 0    (set if cache is tagged by virtual address) */
+    /*bool     (whether page tables are traversed in vaddr sorted order, paddr sorted order, ...) */
+    /*u8       (set of available page attribute bits, other than cache attribute bits defined above) */
+    /*u32      (various masks for pages, MMU table/TLB entries, etc.) */
+    u8         way_count;              /* 0 .. 8       (number of ways, a.k.a. associativities, for this TLB) */
+    XtHalMmuTlbWay *   ways[XTHAL_MMU_WAYS_MAX];       /* pointers to per-way parms for each way */
+} XtHalMmuTlb;
+
+/*  Per TLB Way (Per Associativity) Parameters  */
+typedef struct XtHalMmuTlbWay {
+     u32       index_count_log2;       /* 0 .. 4 */
+     u32       pagesz_mask;            /* 0 .. 2^pagesz_count - 1      (each bit corresponds to a size */
+                                       /*              defined in the Xthal_mmu_pagesz_log2[] table) */
+     u32       vpn_const_mask;
+     u32       vpn_const_value;
+     u64       ppn_const_mask;         /* future may support pa_bits > 32 */
+     u64       ppn_const_value;
+     u32       ppn_id_mask;            /* paddr bits taken directly from vaddr */
+     bool      backgnd_match;          /* 0 or 1 */
+     /*  These are defined in terms of the XTHAL_CACHE_xxx bits: */
+     u8        fca_const_mask;         /* ITLB/UTLB only! */
+     u8        fca_const_value;        /* ITLB/UTLB only! */
+     u8        lca_const_mask;         /* DTLB/UTLB only! */
+     u8        lca_const_value;        /* DTLB/UTLB only! */
+     u8        sca_const_mask;         /* DTLB/UTLB only! */
+     u8        sca_const_value;        /* DTLB/UTLB only! */
+     /*  These define an encoding that map 5 bits in TLB and PTE entries to */
+     /*  8 bits (FCA, ITLB), 16 bits (LCA+SCA, DTLB) or 24 bits (FCA+LCA+SCA, UTLB): */
+     /*  (they may be moved to struct XtHalMmuTlb) */
+     u8                ca_bits;                /* number of bits in TLB/PTE entries for cache attributes */
+     u32 *     ca_map;                 /* pointer to array of 2^ca_bits entries of FCA+LCA+SCA bits */
+} XtHalMmuTlbWay;
+
+/*
+ *  The way to determine whether protection support is present in core
+ *  is to [look at Xthal_mmu_rings ???].
+ *  Give info on memory requirements for MMU tables and other in-memory
+ *  data structures (globally, per task, base and per page, etc.) - whatever bounds can be calculated.
+ */
+
+
+/*  Default vectors:  */
+xthal_immu_fetch_miss_vector
+xthal_dmmu_load_miss_vector
+xthal_dmmu_store_miss_vector
+
+/*  Functions called when a fault is detected:  */
+typedef void (XtHalMmuFaultFunc)( unsigned vaddr, ...context... );
+/*  Or, */
+/*     a? = vaddr */
+/*     a? = context... */
+/*     PS.xxx = xxx */
+XtHalMMuFaultFunc *Xthal_immu_fetch_fault_func;
+XtHalMMuFaultFunc *Xthal_dmmu_load_fault_func;
+XtHalMMuFaultFunc *Xthal_dmmu_store_fault_func;
+
+/*  Default Handlers:  */
+/*  The user and/or kernel exception handlers may jump to these handlers to handle the relevant exceptions,
+ *  according to the value of EXCCAUSE.  The exact register state on entry to these handlers is TBD.  */
+/*  When multiple TLB entries match (hit) on the same access:  */
+xthal_immu_fetch_multihit_handler
+xthal_dmmu_load_multihit_handler
+xthal_dmmu_store_multihit_handler
+/*  Protection violations according to cache attributes, and other cache attribute mismatches:  */
+xthal_immu_fetch_attr_handler
+xthal_dmmu_load_attr_handler
+xthal_dmmu_store_attr_handler
+/*  Protection violations due to insufficient ring level:  */
+xthal_immu_fetch_priv_handler
+xthal_dmmu_load_priv_handler
+xthal_dmmu_store_priv_handler
+/*  Alignment exception handlers (if supported by the particular Xtensa MMU configuration):  */
+xthal_dmmu_load_align_handler
+xthal_dmmu_store_align_handler
+
+/*  Or, alternatively, the OS user and/or kernel exception handlers may simply jump to the
+ *  following entry points which will handle any values of EXCCAUSE not handled by the OS:  */
+xthal_user_exc_default_handler
+xthal_kernel_exc_default_handler
+
+#endif /*0*/
+
+#ifdef INCLUDE_DEPRECATED_HAL_CODE
+extern const unsigned char Xthal_have_old_exc_arch;
+extern const unsigned char Xthal_have_mmu;
+extern const unsigned int  Xthal_num_regs;
+extern const unsigned char Xthal_num_iroms;
+extern const unsigned char Xthal_num_irams;
+extern const unsigned char Xthal_num_droms;
+extern const unsigned char Xthal_num_drams;
+extern const unsigned int  Xthal_configid0;
+extern const unsigned int  Xthal_configid1;
+#endif
+
+#ifdef INCLUDE_DEPRECATED_HAL_DEBUG_CODE
+#define XTHAL_24_BIT_BREAK             0x80000000
+#define XTHAL_16_BIT_BREAK             0x40000000
+extern const unsigned short    Xthal_ill_inst_16[16];
+#define XTHAL_DEST_REG         0xf0000000      /* Mask for destination register */
+#define XTHAL_DEST_REG_INST    0x08000000      /* Branch address is in register */
+#define XTHAL_DEST_REL_INST    0x04000000      /* Branch address is relative */
+#define XTHAL_RFW_INST         0x00000800
+#define XTHAL_RFUE_INST                0x00000400
+#define XTHAL_RFI_INST         0x00000200
+#define XTHAL_RFE_INST         0x00000100
+#define XTHAL_RET_INST         0x00000080
+#define XTHAL_BREAK_INST       0x00000040
+#define XTHAL_SYSCALL_INST     0x00000020
+#define XTHAL_LOOP_END         0x00000010      /* Not set by xthal_inst_type */
+#define XTHAL_JUMP_INST                0x00000008      /* Call or jump instruction */
+#define XTHAL_BRANCH_INST      0x00000004      /* Branch instruction */
+#define XTHAL_24_BIT_INST      0x00000002
+#define XTHAL_16_BIT_INST   0x00000001
+typedef struct xthal_state {
+    unsigned   pc;
+    unsigned   ar[16];
+    unsigned   lbeg;
+    unsigned   lend;
+    unsigned   lcount;
+    unsigned   extra_ptr;
+    unsigned   cpregs_ptr[XTHAL_MAX_CPS];
+} XTHAL_STATE;
+extern unsigned int xthal_inst_type(void *addr);
+extern unsigned int xthal_branch_addr(void *addr);
+extern unsigned int xthal_get_npc(XTHAL_STATE *user_state);
+#endif /* INCLUDE_DEPRECATED_HAL_DEBUG_CODE */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*!__ASSEMBLY__ */
+
+#endif /*XTENSA_HAL_H*/
+
diff --git a/include/asm-xtensa/xtensa/simcall.h b/include/asm-xtensa/xtensa/simcall.h
new file mode 100644 (file)
index 0000000..a2b8689
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef SIMCALL_INCLUDED
+#define SIMCALL_INCLUDED
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * include/asm-xtensa/xtensa/simcall.h  -  Simulator call numbers
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2002 Tensilica Inc.
+ */
+
+
+/*
+ *  System call like services offered by the simulator host.
+ *  These are modeled after the Linux 2.4 kernel system calls
+ *  for Xtensa processors.  However not all system calls and
+ *  not all functionality of a given system call are implemented,
+ *  or necessarily have well defined or equivalent semantics in
+ *  the context of a simulation (as opposed to a Unix kernel).
+ *
+ *  These services behave largely as if they had been invoked
+ *  as a task in the simulator host's operating system
+ *  (eg. files accessed are those of the simulator host).
+ *  However, these SIMCALLs model a virtual operating system
+ *  so that various definitions, bit assignments etc
+ *  (eg. open mode bits, errno values, etc) are independent
+ *  of the host operating system used to run the simulation.
+ *  Rather these definitions are specific to the Xtensa ISS.
+ *  This way Xtensa ISA code written to use these SIMCALLs
+ *  can (in principle) be simulated on any host.
+ *
+ *  Up to 6 parameters are passed in registers a3 to a8
+ *  (note the 6th parameter isn't passed on the stack,
+ *   unlike windowed function calling conventions).
+ *  The return value is in a2.  A negative value in the
+ *  range -4096 to -1 indicates a negated error code to be
+ *  reported in errno with a return value of -1, otherwise
+ *  the value in a2 is returned as is.
+ */
+
+/* These #defines need to match what's in Xtensa/OS/vxworks/xtiss/simcalls.c */
+
+#define SYS_nop                0       /* n/a - setup; used to flush register windows */
+#define SYS_exit       1       /*x*/
+#define SYS_fork       2
+#define SYS_read       3       /*x*/
+#define SYS_write      4       /*x*/
+#define SYS_open       5       /*x*/
+#define SYS_close      6       /*x*/
+#define SYS_rename     7       /*x 38 - waitpid */
+#define SYS_creat      8       /*x*/
+#define SYS_link       9       /*x (not implemented on WIN32) */
+#define SYS_unlink     10      /*x*/
+#define SYS_execv      11      /* n/a - execve */
+#define SYS_execve     12      /* 11 - chdir */
+#define SYS_pipe       13      /* 42 - time */
+#define SYS_stat       14      /* 106 - mknod */
+#define SYS_chmod      15
+#define SYS_chown      16      /* 202 - lchown */
+#define SYS_utime      17      /* 30 - break */
+#define SYS_wait       18      /* n/a - oldstat */
+#define SYS_lseek      19      /*x*/
+#define SYS_getpid     20
+#define SYS_isatty     21      /* n/a - mount */
+#define SYS_fstat      22      /* 108 - oldumount */
+#define SYS_time       23      /* 13 - setuid */
+#define SYS_gettimeofday 24    /*x 78 - getuid (not implemented on WIN32) */
+#define SYS_times      25      /*X 43 - stime (Xtensa-specific implementation) */
+#define SYS_socket      26
+#define SYS_sendto      27
+#define SYS_recvfrom    28
+#define SYS_select_one  29      /* not compitible select, one file descriptor at the time */
+#define SYS_bind        30
+#define SYS_ioctl      31
+
+/*
+ *  Other...
+ */
+#define SYS_iss_argc      1000 /* returns value of argc */
+#define SYS_iss_argv_size 1001 /* bytes needed for argv & arg strings */
+#define SYS_iss_set_argv  1002 /* saves argv & arg strings at given addr */
+
+/*
+ * SIMCALLs for the ferret memory debugger. All are invoked by
+ * libferret.a ...  ( Xtensa/Target-Libs/ferret )
+ */
+#define SYS_ferret           1010
+#define SYS_malloc           1011
+#define SYS_free             1012
+#define SYS_more_heap        1013
+#define SYS_no_heap          1014
+
+
+/*
+ *  Extra SIMCALLs for GDB:
+ */
+#define SYS_gdb_break         -1       /* invoked by XTOS on user exceptions if EPC points
+                                          to a break.n/break, regardless of cause! */
+#define SYS_xmon_out          -2       /* invoked by XMON: ... */
+#define SYS_xmon_in           -3       /* invoked by XMON: ... */
+#define SYS_xmon_flush        -4       /* invoked by XMON: ... */
+#define SYS_gdb_abort         -5       /* invoked by XTOS in _xtos_panic() */
+#define SYS_gdb_illegal_inst  -6       /* invoked by XTOS for illegal instructions (too deeply) */
+#define SYS_xmon_init         -7       /* invoked by XMON: ... */
+#define SYS_gdb_enter_sktloop -8       /* invoked by XTOS on debug exceptions */
+
+/*
+ *  SIMCALLs for vxWorks xtiss BSP:
+ */
+#define SYS_setup_ppp_pipes   -83
+#define SYS_log_msg           -84
+
+/*
+ *  Test SIMCALLs:
+ */
+#define SYS_test_write_state  -100
+#define SYS_test_read_state   -101
+
+/*
+ * SYS_select_one specifiers
+ */
+#define  XTISS_SELECT_ONE_READ    1
+#define  XTISS_SELECT_ONE_WRITE   2
+#define  XTISS_SELECT_ONE_EXCEPT  3
+
+#endif /* !SIMCALL_INCLUDED */
diff --git a/include/asm-xtensa/xtensa/xt2000-uart.h b/include/asm-xtensa/xtensa/xt2000-uart.h
new file mode 100644 (file)
index 0000000..0154460
--- /dev/null
@@ -0,0 +1,155 @@
+#ifndef _uart_h_included_
+#define _uart_h_included_
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * include/asm-xtensa/xtensa/xt2000-uart.h -- NatSemi PC16552D DUART
+ * definitions
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002 Tensilica Inc.
+ */
+
+
+#include <xtensa/xt2000.h>
+
+
+/* 16550 UART DEVICE REGISTERS
+   The XT2000 board aligns each register to a 32-bit word but the UART device only uses
+   one byte of the word, which is the least-significant byte regardless of the
+   endianness of the core (ie. byte offset 0 for little-endian and 3 for big-endian).
+   So if using word accesses then endianness doesn't matter.
+   The macros provided here do that.
+*/
+struct uart_dev_s {
+  union {
+    unsigned int rxb;  /* DLAB=0: receive buffer, read-only */
+    unsigned int txb;  /* DLAB=0: transmit buffer, write-only */
+    unsigned int dll;  /* DLAB=1: divisor, least-significant byte latch (was write-only?) */
+  } w0;
+  union {
+    unsigned int ier;  /* DLAB=0: interrupt-enable register (was write-only?) */
+    unsigned int dlm;  /* DLAB=1: divisor, most-significant byte latch (was write-only?) */
+  } w1;
+
+  union {
+    unsigned int isr;  /* DLAB=0: interrupt status register, read-only */
+    unsigned int fcr;  /* DLAB=0: FIFO control register, write-only */
+    unsigned int afr;  /* DLAB=1: alternate function register */
+  } w2;
+
+  unsigned int lcr;    /* line control-register, write-only */
+  unsigned int mcr;    /* modem control-regsiter, write-only */
+  unsigned int lsr;    /* line status register, read-only */
+  unsigned int msr;    /* modem status register, read-only */
+  unsigned int scr;    /* scratch regsiter, read/write */
+};
+
+#define _RXB(u) ((u)->w0.rxb)
+#define _TXB(u) ((u)->w0.txb)
+#define _DLL(u) ((u)->w0.dll)
+#define _IER(u) ((u)->w1.ier)
+#define _DLM(u) ((u)->w1.dlm)
+#define _ISR(u) ((u)->w2.isr)
+#define _FCR(u) ((u)->w2.fcr)
+#define _AFR(u) ((u)->w2.afr)
+#define _LCR(u) ((u)->lcr)
+#define _MCR(u) ((u)->mcr)
+#define _LSR(u) ((u)->lsr)
+#define _MSR(u) ((u)->msr)
+#define _SCR(u) ((u)->scr)
+
+typedef volatile struct uart_dev_s uart_dev_t;
+
+/* IER bits */
+#define RCVR_DATA_REG_INTENABLE 0x01
+#define XMIT_HOLD_REG_INTENABLE    0x02
+#define RCVR_STATUS_INTENABLE   0x04
+#define MODEM_STATUS_INTENABLE     0x08
+
+/* FCR bits */
+#define _FIFO_ENABLE      0x01
+#define RCVR_FIFO_RESET  0x02
+#define XMIT_FIFO_RESET  0x04
+#define DMA_MODE_SELECT  0x08
+#define RCVR_TRIGGER_LSB 0x40
+#define RCVR_TRIGGER_MSB 0x80
+
+/* AFR bits */
+#define AFR_CONC_WRITE 0x01
+#define AFR_BAUDOUT_SEL        0x02
+#define AFR_RXRDY_SEL  0x04
+
+/* ISR bits */
+#define INT_STATUS(r)   ((r)&1)
+#define INT_PRIORITY(r) (((r)>>1)&0x7)
+
+/* LCR bits */
+#define WORD_LENGTH(n)  (((n)-5)&0x3)
+#define STOP_BIT_ENABLE 0x04
+#define PARITY_ENABLE   0x08
+#define EVEN_PARITY     0x10
+#define FORCE_PARITY    0x20
+#define XMIT_BREAK      0x40
+#define DLAB_ENABLE     0x80
+
+/* MCR bits */
+#define _DTR 0x01
+#define _RTS 0x02
+#define _OP1 0x04
+#define _OP2 0x08
+#define LOOP_BACK 0x10
+
+/* LSR Bits */
+#define RCVR_DATA_READY 0x01
+#define OVERRUN_ERROR   0x02
+#define PARITY_ERROR    0x04
+#define FRAMING_ERROR   0x08
+#define BREAK_INTERRUPT 0x10
+#define XMIT_HOLD_EMPTY 0x20
+#define XMIT_EMPTY      0x40
+#define FIFO_ERROR      0x80
+#define RCVR_READY(u)   (_LSR(u)&RCVR_DATA_READY)
+#define XMIT_READY(u)   (_LSR(u)&XMIT_HOLD_EMPTY)
+
+/* MSR bits */
+#define _RDR       0x01
+#define DELTA_DSR 0x02
+#define DELTA_RI  0x04
+#define DELTA_CD  0x08
+#define _CTS       0x10
+#define _DSR       0x20
+#define _RI        0x40
+#define _CD        0x80
+
+/* prototypes */
+void uart_init( uart_dev_t *u, int bitrate );
+void uart_out( uart_dev_t *u, char c );
+void uart_puts( uart_dev_t *u, char *s );
+char uart_in( uart_dev_t *u );
+void uart_enable_rcvr_int( uart_dev_t *u );
+void uart_disable_rcvr_int( uart_dev_t *u );
+
+#ifdef DUART16552_1_VADDR
+/*  DUART present.  */
+#define DUART_1_BASE   (*(uart_dev_t*)DUART16552_1_VADDR)
+#define DUART_2_BASE   (*(uart_dev_t*)DUART16552_2_VADDR)
+#define UART1_PUTS(s)  uart_puts( &DUART_1_BASE, s )
+#define UART2_PUTS(s)  uart_puts( &DUART_2_BASE, s )
+#else
+/*  DUART not configured, use dummy placeholders to allow compiles to work.  */
+#define DUART_1_BASE   (*(uart_dev_t*)0)
+#define DUART_2_BASE   (*(uart_dev_t*)0)
+#define UART1_PUTS(s)
+#define UART2_PUTS(s)
+#endif
+
+/*  Compute 16-bit divisor for baudrate generator, with rounding:  */
+#define DUART_DIVISOR(crystal,speed)   (((crystal)/16 + (speed)/2)/(speed))
+
+#endif /*_uart_h_included_*/
+
diff --git a/include/asm-xtensa/xtensa/xt2000.h b/include/asm-xtensa/xtensa/xt2000.h
new file mode 100644 (file)
index 0000000..703a450
--- /dev/null
@@ -0,0 +1,408 @@
+#ifndef _INC_XT2000_H_
+#define _INC_XT2000_H_
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * include/asm-xtensa/xtensa/xt2000.h - Definitions specific to the
+ * Tensilica XT2000 Emulation Board
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002 Tensilica Inc.
+ */
+
+
+#include <xtensa/config/core.h>
+#include <xtensa/config/system.h>
+
+
+/*
+ *  Default assignment of XT2000 devices to external interrupts.
+ */
+
+/*  Ethernet interrupt:  */
+#ifdef XCHAL_EXTINT3_NUM
+#define SONIC83934_INTNUM      XCHAL_EXTINT3_NUM
+#define SONIC83934_INTLEVEL    XCHAL_EXTINT3_LEVEL
+#define SONIC83934_INTMASK     XCHAL_EXTINT3_MASK
+#else
+#define SONIC83934_INTMASK     0
+#endif
+
+/*  DUART channel 1 interrupt (P1 - console):  */
+#ifdef XCHAL_EXTINT4_NUM
+#define DUART16552_1_INTNUM    XCHAL_EXTINT4_NUM
+#define DUART16552_1_INTLEVEL  XCHAL_EXTINT4_LEVEL
+#define DUART16552_1_INTMASK   XCHAL_EXTINT4_MASK
+#else
+#define DUART16552_1_INTMASK   0
+#endif
+
+/*  DUART channel 2 interrupt (P2 - 2nd serial port):  */
+#ifdef XCHAL_EXTINT5_NUM
+#define DUART16552_2_INTNUM    XCHAL_EXTINT5_NUM
+#define DUART16552_2_INTLEVEL  XCHAL_EXTINT5_LEVEL
+#define DUART16552_2_INTMASK   XCHAL_EXTINT5_MASK
+#else
+#define DUART16552_2_INTMASK   0
+#endif
+
+/*  FPGA-combined PCI/etc interrupts:  */
+#ifdef XCHAL_EXTINT6_NUM
+#define XT2000_FPGAPCI_INTNUM  XCHAL_EXTINT6_NUM
+#define XT2000_FPGAPCI_INTLEVEL        XCHAL_EXTINT6_LEVEL
+#define XT2000_FPGAPCI_INTMASK XCHAL_EXTINT6_MASK
+#else
+#define XT2000_FPGAPCI_INTMASK 0
+#endif
+
+
+
+/*
+ *  Device addresses.
+ *
+ *  Note:  for endianness-independence, use 32-bit loads and stores for all
+ *  register accesses to Ethernet, DUART and LED devices.  Undefined bits
+ *  may need to be masked out if needed when reading if the actual register
+ *  size is smaller than 32 bits.
+ *
+ *  Note:  XT2000 bus byte lanes are defined in terms of msbyte and lsbyte
+ *  relative to the processor.  So 32-bit registers are accessed consistently
+ *  from both big and little endian processors.  However, this means byte
+ *  sequences are not consistent between big and little endian processors.
+ *  This is fine for RAM, and for ROM if ROM is created for a specific
+ *  processor (and thus has correct byte sequences).  However this may be
+ *  unexpected for Flash, which might contain a file-system that one wants
+ *  to use for multiple processor configurations (eg. the Flash might contain
+ *  the Ethernet card's address, endianness-independent application data, etc).
+ *  That is, byte sequences written in Flash by a core of a given endianness
+ *  will be byte-swapped when seen by a core of the other endianness.
+ *  Someone implementing an endianness-independent Flash file system will
+ *  likely handle this byte-swapping issue in the Flash driver software.
+ */
+
+#define DUART16552_XTAL_FREQ   18432000        /* crystal frequency in Hz */
+#define XTBOARD_FLASH_MAXSIZE  0x4000000       /* 64 MB (max; depends on what is socketed!) */
+#define XTBOARD_EPROM_MAXSIZE  0x0400000       /* 4 MB (max; depends on what is socketed!) */
+#define XTBOARD_EEPROM_MAXSIZE 0x0080000       /* 512 kB (max; depends on what is socketed!) */
+#define XTBOARD_ASRAM_SIZE     0x0100000       /* 1 MB */
+#define XTBOARD_PCI_MEM_SIZE   0x8000000       /* 128 MB (allocated) */
+#define XTBOARD_PCI_IO_SIZE    0x1000000       /* 16 MB (allocated) */
+
+#ifdef XSHAL_IOBLOCK_BYPASS_PADDR
+/*  PCI memory space:  */
+# define XTBOARD_PCI_MEM_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0x0000000)
+/*  Socketed Flash (eg. 2 x 16-bit devices):  */
+# define XTBOARD_FLASH_PADDR   (XSHAL_IOBLOCK_BYPASS_PADDR+0x8000000)
+/*  PCI I/O space:  */
+# define XTBOARD_PCI_IO_PADDR  (XSHAL_IOBLOCK_BYPASS_PADDR+0xC000000)
+/*  V3 PCI interface chip register/config space:  */
+# define XTBOARD_V3PCI_PADDR   (XSHAL_IOBLOCK_BYPASS_PADDR+0xD000000)
+/*  Bus Interface registers:  */
+# define XTBOARD_BUSINT_PADDR  (XSHAL_IOBLOCK_BYPASS_PADDR+0xD010000)
+/*  FPGA registers:  */
+# define XT2000_FPGAREGS_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD020000)
+/*  SONIC SN83934 Ethernet controller/transceiver:  */
+# define SONIC83934_PADDR      (XSHAL_IOBLOCK_BYPASS_PADDR+0xD030000)
+/*  8-character bitmapped LED display:  */
+# define XTBOARD_LED_PADDR     (XSHAL_IOBLOCK_BYPASS_PADDR+0xD040000)
+/*  National-Semi PC16552D DUART:  */
+# define DUART16552_1_PADDR    (XSHAL_IOBLOCK_BYPASS_PADDR+0xD050020)  /* channel 1 (P1 - console) */
+# define DUART16552_2_PADDR    (XSHAL_IOBLOCK_BYPASS_PADDR+0xD050000)  /* channel 2 (P2) */
+/*  Asynchronous Static RAM:  */
+# define XTBOARD_ASRAM_PADDR   (XSHAL_IOBLOCK_BYPASS_PADDR+0xD400000)
+/*  8-bit EEPROM:  */
+# define XTBOARD_EEPROM_PADDR  (XSHAL_IOBLOCK_BYPASS_PADDR+0xD600000)
+/*  2 x 16-bit EPROMs:  */
+# define XTBOARD_EPROM_PADDR   (XSHAL_IOBLOCK_BYPASS_PADDR+0xD800000)
+#endif /* XSHAL_IOBLOCK_BYPASS_PADDR */
+
+/*  These devices might be accessed cached:  */
+#ifdef XSHAL_IOBLOCK_CACHED_PADDR
+# define XTBOARD_PCI_MEM_CACHED_PADDR  (XSHAL_IOBLOCK_CACHED_PADDR+0x0000000)
+# define XTBOARD_FLASH_CACHED_PADDR    (XSHAL_IOBLOCK_CACHED_PADDR+0x8000000)
+# define XTBOARD_ASRAM_CACHED_PADDR    (XSHAL_IOBLOCK_CACHED_PADDR+0xD400000)
+# define XTBOARD_EEPROM_CACHED_PADDR   (XSHAL_IOBLOCK_CACHED_PADDR+0xD600000)
+# define XTBOARD_EPROM_CACHED_PADDR    (XSHAL_IOBLOCK_CACHED_PADDR+0xD800000)
+#endif /* XSHAL_IOBLOCK_CACHED_PADDR */
+
+
+/***  Same thing over again, this time with virtual addresses:  ***/
+
+#ifdef XSHAL_IOBLOCK_BYPASS_VADDR
+/*  PCI memory space:  */
+# define XTBOARD_PCI_MEM_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0x0000000)
+/*  Socketed Flash (eg. 2 x 16-bit devices):  */
+# define XTBOARD_FLASH_VADDR   (XSHAL_IOBLOCK_BYPASS_VADDR+0x8000000)
+/*  PCI I/O space:  */
+# define XTBOARD_PCI_IO_VADDR  (XSHAL_IOBLOCK_BYPASS_VADDR+0xC000000)
+/*  V3 PCI interface chip register/config space:  */
+# define XTBOARD_V3PCI_VADDR   (XSHAL_IOBLOCK_BYPASS_VADDR+0xD000000)
+/*  Bus Interface registers:  */
+# define XTBOARD_BUSINT_VADDR  (XSHAL_IOBLOCK_BYPASS_VADDR+0xD010000)
+/*  FPGA registers:  */
+# define XT2000_FPGAREGS_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD020000)
+/*  SONIC SN83934 Ethernet controller/transceiver:  */
+# define SONIC83934_VADDR      (XSHAL_IOBLOCK_BYPASS_VADDR+0xD030000)
+/*  8-character bitmapped LED display:  */
+# define XTBOARD_LED_VADDR     (XSHAL_IOBLOCK_BYPASS_VADDR+0xD040000)
+/*  National-Semi PC16552D DUART:  */
+# define DUART16552_1_VADDR    (XSHAL_IOBLOCK_BYPASS_VADDR+0xD050020)  /* channel 1 (P1 - console) */
+# define DUART16552_2_VADDR    (XSHAL_IOBLOCK_BYPASS_VADDR+0xD050000)  /* channel 2 (P2) */
+/*  Asynchronous Static RAM:  */
+# define XTBOARD_ASRAM_VADDR   (XSHAL_IOBLOCK_BYPASS_VADDR+0xD400000)
+/*  8-bit EEPROM:  */
+# define XTBOARD_EEPROM_VADDR  (XSHAL_IOBLOCK_BYPASS_VADDR+0xD600000)
+/*  2 x 16-bit EPROMs:  */
+# define XTBOARD_EPROM_VADDR   (XSHAL_IOBLOCK_BYPASS_VADDR+0xD800000)
+#endif /* XSHAL_IOBLOCK_BYPASS_VADDR */
+
+/*  These devices might be accessed cached:  */
+#ifdef XSHAL_IOBLOCK_CACHED_VADDR
+# define XTBOARD_PCI_MEM_CACHED_VADDR  (XSHAL_IOBLOCK_CACHED_VADDR+0x0000000)
+# define XTBOARD_FLASH_CACHED_VADDR    (XSHAL_IOBLOCK_CACHED_VADDR+0x8000000)
+# define XTBOARD_ASRAM_CACHED_VADDR    (XSHAL_IOBLOCK_CACHED_VADDR+0xD400000)
+# define XTBOARD_EEPROM_CACHED_VADDR   (XSHAL_IOBLOCK_CACHED_VADDR+0xD600000)
+# define XTBOARD_EPROM_CACHED_VADDR    (XSHAL_IOBLOCK_CACHED_VADDR+0xD800000)
+#endif /* XSHAL_IOBLOCK_CACHED_VADDR */
+
+
+/*  System ROM:  */
+#define XTBOARD_ROM_SIZE               XSHAL_ROM_SIZE
+#ifdef XSHAL_ROM_VADDR
+#define XTBOARD_ROM_VADDR              XSHAL_ROM_VADDR
+#endif
+#ifdef XSHAL_ROM_PADDR
+#define XTBOARD_ROM_PADDR              XSHAL_ROM_PADDR
+#endif
+
+/*  System RAM:  */
+#define XTBOARD_RAM_SIZE               XSHAL_RAM_SIZE
+#ifdef XSHAL_RAM_VADDR
+#define XTBOARD_RAM_VADDR              XSHAL_RAM_VADDR
+#endif
+#ifdef XSHAL_RAM_PADDR
+#define XTBOARD_RAM_PADDR              XSHAL_RAM_PADDR
+#endif
+#define XTBOARD_RAM_BYPASS_VADDR       XSHAL_RAM_BYPASS_VADDR
+#define XTBOARD_RAM_BYPASS_PADDR       XSHAL_RAM_BYPASS_PADDR
+
+
+
+/*
+ *  Things that depend on device addresses.
+ */
+
+
+#define XTBOARD_CACHEATTR_WRITEBACK    XSHAL_XT2000_CACHEATTR_WRITEBACK
+#define XTBOARD_CACHEATTR_WRITEALLOC   XSHAL_XT2000_CACHEATTR_WRITEALLOC
+#define XTBOARD_CACHEATTR_WRITETHRU    XSHAL_XT2000_CACHEATTR_WRITETHRU
+#define XTBOARD_CACHEATTR_BYPASS       XSHAL_XT2000_CACHEATTR_BYPASS
+#define XTBOARD_CACHEATTR_DEFAULT      XSHAL_XT2000_CACHEATTR_DEFAULT
+
+#define XTBOARD_BUSINT_PIPE_REGIONS    XSHAL_XT2000_PIPE_REGIONS
+#define XTBOARD_BUSINT_SDRAM_REGIONS   XSHAL_XT2000_SDRAM_REGIONS
+
+
+
+/*
+ *  BusLogic (FPGA) registers.
+ *  All these registers are normally accessed using 32-bit loads/stores.
+ */
+
+/*  Register offsets:  */
+#define XT2000_DATECD_OFS      0x00    /* date code (read-only) */
+#define XT2000_STSREG_OFS      0x04    /* status (read-only) */
+#define XT2000_SYSLED_OFS      0x08    /* system LED */
+#define XT2000_WRPROT_OFS      0x0C    /* write protect */
+#define XT2000_SWRST_OFS       0x10    /* software reset */
+#define XT2000_SYSRST_OFS      0x14    /* system (peripherals) reset */
+#define XT2000_IMASK_OFS       0x18    /* interrupt mask */
+#define XT2000_ISTAT_OFS       0x1C    /* interrupt status */
+#define XT2000_V3CFG_OFS       0x20    /* V3 config (V320 PCI) */
+
+/*  Physical register addresses:  */
+#ifdef XT2000_FPGAREGS_PADDR
+#define XT2000_DATECD_PADDR    (XT2000_FPGAREGS_PADDR+XT2000_DATECD_OFS)
+#define XT2000_STSREG_PADDR    (XT2000_FPGAREGS_PADDR+XT2000_STSREG_OFS)
+#define XT2000_SYSLED_PADDR    (XT2000_FPGAREGS_PADDR+XT2000_SYSLED_OFS)
+#define XT2000_WRPROT_PADDR    (XT2000_FPGAREGS_PADDR+XT2000_WRPROT_OFS)
+#define XT2000_SWRST_PADDR     (XT2000_FPGAREGS_PADDR+XT2000_SWRST_OFS)
+#define XT2000_SYSRST_PADDR    (XT2000_FPGAREGS_PADDR+XT2000_SYSRST_OFS)
+#define XT2000_IMASK_PADDR     (XT2000_FPGAREGS_PADDR+XT2000_IMASK_OFS)
+#define XT2000_ISTAT_PADDR     (XT2000_FPGAREGS_PADDR+XT2000_ISTAT_OFS)
+#define XT2000_V3CFG_PADDR     (XT2000_FPGAREGS_PADDR+XT2000_V3CFG_OFS)
+#endif
+
+/*  Virtual register addresses:  */
+#ifdef XT2000_FPGAREGS_VADDR
+#define XT2000_DATECD_VADDR    (XT2000_FPGAREGS_VADDR+XT2000_DATECD_OFS)
+#define XT2000_STSREG_VADDR    (XT2000_FPGAREGS_VADDR+XT2000_STSREG_OFS)
+#define XT2000_SYSLED_VADDR    (XT2000_FPGAREGS_VADDR+XT2000_SYSLED_OFS)
+#define XT2000_WRPROT_VADDR    (XT2000_FPGAREGS_VADDR+XT2000_WRPROT_OFS)
+#define XT2000_SWRST_VADDR     (XT2000_FPGAREGS_VADDR+XT2000_SWRST_OFS)
+#define XT2000_SYSRST_VADDR    (XT2000_FPGAREGS_VADDR+XT2000_SYSRST_OFS)
+#define XT2000_IMASK_VADDR     (XT2000_FPGAREGS_VADDR+XT2000_IMASK_OFS)
+#define XT2000_ISTAT_VADDR     (XT2000_FPGAREGS_VADDR+XT2000_ISTAT_OFS)
+#define XT2000_V3CFG_VADDR     (XT2000_FPGAREGS_VADDR+XT2000_V3CFG_OFS)
+/*  Register access (for C code):  */
+#define XT2000_DATECD_REG      (*(volatile unsigned*) XT2000_DATECD_VADDR)
+#define XT2000_STSREG_REG      (*(volatile unsigned*) XT2000_STSREG_VADDR)
+#define XT2000_SYSLED_REG      (*(volatile unsigned*) XT2000_SYSLED_VADDR)
+#define XT2000_WRPROT_REG      (*(volatile unsigned*) XT2000_WRPROT_VADDR)
+#define XT2000_SWRST_REG       (*(volatile unsigned*) XT2000_SWRST_VADDR)
+#define XT2000_SYSRST_REG      (*(volatile unsigned*) XT2000_SYSRST_VADDR)
+#define XT2000_IMASK_REG       (*(volatile unsigned*) XT2000_IMASK_VADDR)
+#define XT2000_ISTAT_REG       (*(volatile unsigned*) XT2000_ISTAT_VADDR)
+#define XT2000_V3CFG_REG       (*(volatile unsigned*) XT2000_V3CFG_VADDR)
+#endif
+
+/*  DATECD (date code) bit fields:  */
+
+/*  BCD-coded month (01..12):  */
+#define XT2000_DATECD_MONTH_SHIFT      24
+#define XT2000_DATECD_MONTH_BITS       8
+#define XT2000_DATECD_MONTH_MASK       0xFF000000
+/*  BCD-coded day (01..31):  */
+#define XT2000_DATECD_DAY_SHIFT                16
+#define XT2000_DATECD_DAY_BITS         8
+#define XT2000_DATECD_DAY_MASK         0x00FF0000
+/*  BCD-coded year (2001..9999):  */
+#define XT2000_DATECD_YEAR_SHIFT       0
+#define XT2000_DATECD_YEAR_BITS                16
+#define XT2000_DATECD_YEAR_MASK                0x0000FFFF
+
+/*  STSREG (status) bit fields:  */
+
+/*  Switch SW3 setting bit fields (0=off/up, 1=on/down):  */
+#define XT2000_STSREG_SW3_SHIFT                0
+#define XT2000_STSREG_SW3_BITS         4
+#define XT2000_STSREG_SW3_MASK         0x0000000F
+/*  Boot-select bits of switch SW3:  */
+#define XT2000_STSREG_BOOTSEL_SHIFT    0
+#define XT2000_STSREG_BOOTSEL_BITS     2
+#define XT2000_STSREG_BOOTSEL_MASK     0x00000003
+/*  Boot-select values:  */
+#define XT2000_STSREG_BOOTSEL_FLASH    0
+#define XT2000_STSREG_BOOTSEL_EPROM16  1
+#define XT2000_STSREG_BOOTSEL_PROM8    2
+#define XT2000_STSREG_BOOTSEL_ASRAM    3
+/*  User-defined bits of switch SW3:  */
+#define XT2000_STSREG_SW3_2_SHIFT      2
+#define XT2000_STSREG_SW3_2_MASK       0x00000004
+#define XT2000_STSREG_SW3_3_SHIFT      3
+#define XT2000_STSREG_SW3_3_MASK       0x00000008
+
+/*  SYSLED (system LED) bit fields:  */
+
+/*  LED control bit (0=off, 1=on):  */
+#define XT2000_SYSLED_LEDON_SHIFT      0
+#define XT2000_SYSLED_LEDON_MASK       0x00000001
+
+/*  WRPROT (write protect) bit fields (0=writable, 1=write-protected [default]):  */
+
+/*  Flash write protect:  */
+#define XT2000_WRPROT_FLWP_SHIFT       0
+#define XT2000_WRPROT_FLWP_MASK                0x00000001
+/*  Reserved but present write protect bits:  */
+#define XT2000_WRPROT_WRP_SHIFT                1
+#define XT2000_WRPROT_WRP_BITS         7
+#define XT2000_WRPROT_WRP_MASK         0x000000FE
+
+/*  SWRST (software reset; allows s/w to generate power-on equivalent reset):  */
+
+/*  Software reset bits:  */
+#define XT2000_SWRST_SWR_SHIFT         0
+#define XT2000_SWRST_SWR_BITS          16
+#define XT2000_SWRST_SWR_MASK          0x0000FFFF
+/*  Software reset value -- writing this value resets the board:  */
+#define XT2000_SWRST_RESETVALUE                0x0000DEAD
+
+/*  SYSRST (system reset; controls reset of individual peripherals):  */
+
+/*  All-device reset:  */
+#define XT2000_SYSRST_ALL_SHIFT                0
+#define XT2000_SYSRST_ALL_BITS         4
+#define XT2000_SYSRST_ALL_MASK         0x0000000F
+/*  HDSP-2534 LED display reset (1=reset, 0=nothing):  */
+#define XT2000_SYSRST_LED_SHIFT                0
+#define XT2000_SYSRST_LED_MASK         0x00000001
+/*  Sonic DP83934 Ethernet controller reset (1=reset, 0=nothing):  */
+#define XT2000_SYSRST_SONIC_SHIFT      1
+#define XT2000_SYSRST_SONIC_MASK       0x00000002
+/*  DP16552 DUART reset (1=reset, 0=nothing):  */
+#define XT2000_SYSRST_DUART_SHIFT      2
+#define XT2000_SYSRST_DUART_MASK       0x00000004
+/*  V3 V320 PCI bridge controller reset (1=reset, 0=nothing):  */
+#define XT2000_SYSRST_V3_SHIFT         3
+#define XT2000_SYSRST_V3_MASK          0x00000008
+
+/*  IMASK (interrupt mask; 0=disable, 1=enable):  */
+/*  ISTAT (interrupt status; 0=inactive, 1=pending):  */
+
+/*  PCI INTP interrupt:  */
+#define XT2000_INTMUX_PCI_INTP_SHIFT   2
+#define XT2000_INTMUX_PCI_INTP_MASK    0x00000004
+/*  PCI INTS interrupt:  */
+#define XT2000_INTMUX_PCI_INTS_SHIFT   3
+#define XT2000_INTMUX_PCI_INTS_MASK    0x00000008
+/*  PCI INTD interrupt:  */
+#define XT2000_INTMUX_PCI_INTD_SHIFT   4
+#define XT2000_INTMUX_PCI_INTD_MASK    0x00000010
+/*  V320 PCI controller interrupt:  */
+#define XT2000_INTMUX_V3_SHIFT         5
+#define XT2000_INTMUX_V3_MASK          0x00000020
+/*  PCI ENUM interrupt:  */
+#define XT2000_INTMUX_PCI_ENUM_SHIFT   6
+#define XT2000_INTMUX_PCI_ENUM_MASK    0x00000040
+/*  PCI DEG interrupt:  */
+#define XT2000_INTMUX_PCI_DEG_SHIFT    7
+#define XT2000_INTMUX_PCI_DEG_MASK     0x00000080
+
+/*  V3CFG (V3 config, V320 PCI controller):  */
+
+/*  V3 address control (0=pass-thru, 1=V3 address bits 31:28 set to 4'b0001 [default]):  */
+#define XT2000_V3CFG_V3ADC_SHIFT       0
+#define XT2000_V3CFG_V3ADC_MASK                0x00000001
+
+/* I2C Devices */
+
+#define        XT2000_I2C_RTC_ID               0x68
+#define        XT2000_I2C_NVRAM0_ID            0x56    /* 1st 256 byte block */
+#define        XT2000_I2C_NVRAM1_ID            0x57    /* 2nd 256 byte block */
+
+/*  NVRAM Board Info structure:  */
+
+#define XT2000_NVRAM_SIZE              512
+
+#define XT2000_NVRAM_BINFO_START       0x100
+#define XT2000_NVRAM_BINFO_SIZE                0x20
+#define XT2000_NVRAM_BINFO_VERSION     0x10    /* version 1.0 */
+#if 0
+#define XT2000_NVRAM_BINFO_VERSION_OFFSET      0x00
+#define XT2000_NVRAM_BINFO_VERSION_SIZE                        0x1
+#define XT2000_NVRAM_BINFO_ETH_ADDR_OFFSET     0x02
+#define XT2000_NVRAM_BINFO_ETH_ADDR_SIZE               0x6
+#define XT2000_NVRAM_BINFO_SN_OFFSET           0x10
+#define XT2000_NVRAM_BINFO_SN_SIZE                     0xE
+#define        XT2000_NVRAM_BINFO_CRC_OFFSET           0x1E
+#define        XT2000_NVRAM_BINFO_CRC_SIZE                     0x2
+#endif /*0*/
+
+#if !defined(__ASSEMBLY__) && !defined(_NOCLANGUAGE)
+typedef struct xt2000_nvram_binfo {
+    unsigned char      version;
+    unsigned char      reserved1;
+    unsigned char      eth_addr[6];
+    unsigned char      reserved8[8];
+    unsigned char      serialno[14];
+    unsigned char      crc[2];         /* 16-bit CRC */
+} xt2000_nvram_binfo;
+#endif /*!__ASSEMBLY__ && !_NOCLANGUAGE*/
+
+
+#endif /*_INC_XT2000_H_*/
+
diff --git a/include/asm-xtensa/xtensa/xtboard.h b/include/asm-xtensa/xtensa/xtboard.h
new file mode 100644 (file)
index 0000000..22469c1
--- /dev/null
@@ -0,0 +1,120 @@
+#ifndef _xtboard_h_included_
+#define _xtboard_h_included_
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ *  xtboard.h  --  Routines for getting useful information from the board.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002 Tensilica Inc.
+ */
+
+
+#include <xtensa/xt2000.h>
+
+#define        XTBOARD_RTC_ERROR       -1
+#define        XTBOARD_RTC_STOPPED     -2
+
+
+/*  xt2000-i2cdev.c:  */
+typedef void XtboardDelayFunc( unsigned );
+extern XtboardDelayFunc* xtboard_set_nsdelay_func( XtboardDelayFunc *delay_fn );
+extern int xtboard_i2c_read (unsigned id, unsigned char *buf, unsigned addr, unsigned size);
+extern int xtboard_i2c_write(unsigned id, unsigned char *buf, unsigned addr, unsigned size);
+extern int xtboard_i2c_wait_nvram_ack(unsigned id, unsigned swtimer);
+
+/*  xtboard.c:  */
+extern int xtboard_nvram_read (unsigned addr, unsigned len, unsigned char *buf);
+extern int xtboard_nvram_write(unsigned addr, unsigned len, unsigned char *buf);
+extern int xtboard_nvram_binfo_read (xt2000_nvram_binfo *buf);
+extern int xtboard_nvram_binfo_write(xt2000_nvram_binfo *buf);
+extern int xtboard_nvram_binfo_valid(xt2000_nvram_binfo *buf);
+extern int xtboard_ethermac_get(unsigned char *buf);
+extern int xtboard_ethermac_set(unsigned char *buf);
+
+/*+*----------------------------------------------------------------------------
+/ Function: xtboard_get_rtc_time
+/
+/ Description:  Get time stored in real-time clock.
+/
+/ Returns: time in seconds stored in real-time clock.
+/-**----------------------------------------------------------------------------*/
+
+extern unsigned xtboard_get_rtc_time(void);
+
+/*+*----------------------------------------------------------------------------
+/ Function: xtboard_set_rtc_time
+/
+/ Description:  Set time stored in real-time clock.
+/
+/ Parameters:  time -- time in seconds to store to real-time clock
+/
+/ Returns: 0 on success, xtboard_i2c_write() error code otherwise.
+/-**----------------------------------------------------------------------------*/
+
+extern int xtboard_set_rtc_time(unsigned time);
+
+
+/*  xtfreq.c:  */
+/*+*----------------------------------------------------------------------------
+/ Function: xtboard_measure_sys_clk
+/
+/ Description:  Get frequency of system clock.
+/
+/ Parameters:  none
+/
+/ Returns: frequency of system clock.
+/-**----------------------------------------------------------------------------*/
+
+extern unsigned xtboard_measure_sys_clk(void);
+
+
+#if 0  /* old stuff from xtboard.c: */
+
+/*+*----------------------------------------------------------------------------
+/ Function: xtboard_nvram valid
+/
+/ Description:  Determines if data in NVRAM is valid.
+/
+/ Parameters:  delay -- 10us delay function
+/
+/ Returns: 1 if NVRAM is valid, 0 otherwise
+/-**----------------------------------------------------------------------------*/
+
+extern unsigned xtboard_nvram_valid(void (*delay)( void ));
+
+/*+*----------------------------------------------------------------------------
+/ Function: xtboard_get_nvram_contents
+/
+/ Description:  Returns contents of NVRAM.
+/
+/ Parameters:  buf -- buffer to NVRAM contents.
+/              delay -- 10us delay function
+/
+/ Returns: 1 if NVRAM is valid, 0 otherwise
+/-**----------------------------------------------------------------------------*/
+
+extern unsigned xtboard_get_nvram_contents(unsigned char *buf, void (*delay)( void ));
+
+/*+*----------------------------------------------------------------------------
+/ Function: xtboard_get_ether_addr
+/
+/ Description:  Returns ethernet address of board.
+/
+/ Parameters:  buf -- buffer to store ethernet address
+/              delay -- 10us delay function
+/
+/ Returns: nothing.
+/-**----------------------------------------------------------------------------*/
+
+extern void xtboard_get_ether_addr(unsigned char *buf, void (*delay)( void ));
+
+#endif /*0*/
+
+
+#endif /*_xtboard_h_included_*/
+
index af8a1dfa5c329dd2dcdbbefc11238e413c3c08a8..f913cc3e1b0da141d273522c751e4003cfc7ec18 100644 (file)
@@ -138,7 +138,7 @@ enum machine_type {
 #endif
 #endif
 
-#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1))
+#define _N_SEGMENT_ROUND(x) ALIGN(x, SEGMENT_SIZE)
 
 #define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
 
index b123cc08773d30fccf89c1d0a0aa4e79fcaa2512..ef8483673aa3a87cc7f2608f77e2cf87ab1c019f 100644 (file)
@@ -342,11 +342,19 @@ struct acpi_table_ecdt {
 
 /* PCI MMCONFIG */
 
+/* Defined in PCI Firmware Specification 3.0 */
+struct acpi_table_mcfg_config {
+       u32                             base_address;
+       u32                             base_reserved;
+       u16                             pci_segment_group_number;
+       u8                              start_bus_number;
+       u8                              end_bus_number;
+       u8                              reserved[4];
+} __attribute__ ((packed));
 struct acpi_table_mcfg {
        struct acpi_table_header        header;
        u8                              reserved[8];
-       u32                             base_address;
-       u32                             base_reserved;
+       struct acpi_table_mcfg_config   config[0];
 } __attribute__ ((packed));
 
 /* Table Handlers */
@@ -391,6 +399,7 @@ int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler);
 int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header);
 int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries);
 int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries);
+int acpi_parse_mcfg (unsigned long phys_addr, unsigned long size);
 void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr);
 void acpi_table_print_madt_entry (acpi_table_entry_header *madt);
 void acpi_table_print_srat_entry (acpi_table_entry_header *srat);
@@ -407,9 +416,13 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu);
 int acpi_unmap_lsapic(int cpu);
 #endif /* CONFIG_ACPI_HOTPLUG_CPU */
 
+int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base);
+int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base);
+
 extern int acpi_mp_config;
 
-extern u32 pci_mmcfg_base_addr;
+extern struct acpi_table_mcfg_config *pci_mmcfg_config;
+extern int pci_mmcfg_config_num;
 
 extern int sbf_port ;
 
index 09a1451c1159575c2ca94b6c247eb9e0b0a187e0..911c09cb9bf922ea48583dfd7dbac8ee330cfc88 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __LINUX_ATALK_H__
 #define __LINUX_ATALK_H__
 
+#include <asm/byteorder.h>
+
 /*
  * AppleTalk networking structures
  *
index 038022763f09535e97525cd531c17c9352fffda4..36ef29fa0d8b64a1cc2e2406bd9a8b30f83ab026 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/highmem.h>
 #include <linux/mempool.h>
+#include <linux/ioprio.h>
 
 /* Platforms may set this to teach the BIO layer about IOMMU hardware. */
 #include <asm/io.h>
@@ -149,6 +150,19 @@ struct bio {
 #define BIO_RW_FAILFAST        3
 #define BIO_RW_SYNC    4
 
+/*
+ * upper 16 bits of bi_rw define the io priority of this bio
+ */
+#define BIO_PRIO_SHIFT (8 * sizeof(unsigned long) - IOPRIO_BITS)
+#define bio_prio(bio)  ((bio)->bi_rw >> BIO_PRIO_SHIFT)
+#define bio_prio_valid(bio)    ioprio_valid(bio_prio(bio))
+
+#define bio_set_prio(bio, prio)                do {                    \
+       WARN_ON(prio >= (1 << IOPRIO_BITS));                    \
+       (bio)->bi_rw &= ((1UL << BIO_PRIO_SHIFT) - 1);          \
+       (bio)->bi_rw |= ((unsigned long) (prio) << BIO_PRIO_SHIFT);     \
+} while (0)
+
 /*
  * various member access, note that bio_data should of course not be used
  * on highmem page vectors
index 60272141ff1976c57c3f4f58daf514d2f79d0e52..0881b5cdee3d443c4aca06bd1c4d3c6652c9a5bc 100644 (file)
@@ -54,16 +54,23 @@ struct as_io_context {
 
 struct cfq_queue;
 struct cfq_io_context {
-       void (*dtor)(struct cfq_io_context *);
-       void (*exit)(struct cfq_io_context *);
-
-       struct io_context *ioc;
-
        /*
         * circular list of cfq_io_contexts belonging to a process io context
         */
        struct list_head list;
        struct cfq_queue *cfqq;
+       void *key;
+
+       struct io_context *ioc;
+
+       unsigned long last_end_request;
+       unsigned long last_queue;
+       unsigned long ttime_total;
+       unsigned long ttime_samples;
+       unsigned long ttime_mean;
+
+       void (*dtor)(struct cfq_io_context *);
+       void (*exit)(struct cfq_io_context *);
 };
 
 /*
@@ -73,7 +80,9 @@ struct cfq_io_context {
  */
 struct io_context {
        atomic_t refcount;
-       pid_t pid;
+       struct task_struct *task;
+
+       int (*set_ioprio)(struct io_context *, unsigned int);
 
        /*
         * For request batching
@@ -81,14 +90,13 @@ struct io_context {
        unsigned long last_waited; /* Time last woken after wait for request */
        int nr_batch_requests;     /* Number of requests left in the batch */
 
-       spinlock_t lock;
-
        struct as_io_context *aic;
        struct cfq_io_context *cic;
 };
 
 void put_io_context(struct io_context *ioc);
 void exit_io_context(void);
+struct io_context *current_io_context(int gfp_flags);
 struct io_context *get_io_context(int gfp_flags);
 void copy_io_context(struct io_context **pdst, struct io_context **psrc);
 void swap_io_context(struct io_context **ioc1, struct io_context **ioc2);
@@ -134,6 +142,8 @@ struct request {
 
        void *elevator_private;
 
+       unsigned short ioprio;
+
        int rq_status;  /* should split this into a few status bits */
        struct gendisk *rq_disk;
        int errors;
@@ -539,15 +549,12 @@ extern void generic_make_request(struct bio *bio);
 extern void blk_put_request(struct request *);
 extern void blk_end_sync_rq(struct request *rq);
 extern void blk_attempt_remerge(request_queue_t *, struct request *);
-extern void __blk_attempt_remerge(request_queue_t *, struct request *);
 extern struct request *blk_get_request(request_queue_t *, int, int);
 extern void blk_insert_request(request_queue_t *, struct request *, int, void *);
 extern void blk_requeue_request(request_queue_t *, struct request *);
 extern void blk_plug_device(request_queue_t *);
 extern int blk_remove_plug(request_queue_t *);
 extern void blk_recount_segments(request_queue_t *, struct bio *);
-extern int blk_phys_contig_segment(request_queue_t *q, struct bio *, struct bio *);
-extern int blk_hw_contig_segment(request_queue_t *q, struct bio *, struct bio *);
 extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *);
 extern void blk_start_queue(request_queue_t *q);
 extern void blk_stop_queue(request_queue_t *q);
@@ -631,7 +638,6 @@ extern void blk_queue_dma_alignment(request_queue_t *, int);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 extern void blk_queue_ordered(request_queue_t *, int);
 extern void blk_queue_issue_flush_fn(request_queue_t *, issue_flush_fn *);
-extern int blkdev_scsi_issue_flush_fn(request_queue_t *, struct gendisk *, sector_t *);
 extern struct request *blk_start_pre_flush(request_queue_t *,struct request *);
 extern int blk_complete_barrier_rq(request_queue_t *, struct request *, int);
 extern int blk_complete_barrier_rq_locked(request_queue_t *, struct request *, int);
@@ -675,8 +681,6 @@ extern int blkdev_issue_flush(struct block_device *, sector_t *);
 
 #define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist)
 
-extern void drive_stat_acct(struct request *, int, int);
-
 static inline int queue_hardsect_size(request_queue_t *q)
 {
        int retval = 512;
index 500f451ce0c0012dfe533ddd4f05b2a28db5b78f..82bd8842d11cfe3a01e704aaec3aab947b917c08 100644 (file)
@@ -22,6 +22,10 @@ extern unsigned long min_low_pfn;
  */
 extern unsigned long max_pfn;
 
+#ifdef CONFIG_CRASH_DUMP
+extern unsigned long saved_max_pfn;
+#endif
+
 /*
  * node_bootmem_map is a map pointer - the bits represent all physical 
  * memory pages (including holes) on the node.
index d28d9a804d3bc0c92e2dcde511e430b4c7a681ef..d5f2a320510930ce7d673ed11ed2f30c96d5994f 100644 (file)
 #endif /* OPTIMIZE */
 
 
-static __inline__ __const__ __u32 __fswahw32(__u32 x)
+static inline __u32 __fswahw32(__u32 x)
 {
        return __arch__swahw32(x);
 }
-static __inline__ __u32 __swahw32p(__u32 *x)
+
+static inline __u32 __swahw32p(__u32 *x)
 {
        return __arch__swahw32p(x);
 }
-static __inline__ void __swahw32s(__u32 *addr)
+
+static inline void __swahw32s(__u32 *addr)
 {
        __arch__swahw32s(addr);
 }
 
-
-static __inline__ __const__ __u32 __fswahb32(__u32 x)
+static inline __u32 __fswahb32(__u32 x)
 {
        return __arch__swahb32(x);
 }
-static __inline__ __u32 __swahb32p(__u32 *x)
+
+static inline __u32 __swahb32p(__u32 *x)
 {
        return __arch__swahb32p(x);
 }
-static __inline__ void __swahb32s(__u32 *addr)
+
+static inline void __swahb32s(__u32 *addr)
 {
        __arch__swahb32s(addr);
 }
index ee0c6e8995dafd198f257cdea54fd48b65edb09b..424d5e622b4331ba31b7cc83002a3f97aa5aec3f 100644 (file)
@@ -10,6 +10,7 @@
 typedef struct _cciss_pci_info_struct
 {
        unsigned char   bus;
+       unsigned short  domain;
        unsigned char   dev_fn;
        __u32           board_id;
 } cciss_pci_info_struct; 
index fe0298e5dae1563b165f60aac60164cf13766121..e8904c0da686e0f347c5fe35a8603fa6e581de31 100644 (file)
@@ -69,6 +69,7 @@ extern struct semaphore cpucontrol;
        register_cpu_notifier(&fn##_nb);                        \
 }
 int cpu_down(unsigned int cpu);
+extern int __attribute__((weak)) smp_prepare_cpu(int cpu);
 #define cpu_is_offline(cpu) unlikely(!cpu_online(cpu))
 #else
 #define lock_cpu_hotplug()     do { } while (0)
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
new file mode 100644 (file)
index 0000000..534d750
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef LINUX_CRASH_DUMP_H
+#define LINUX_CRASH_DUMP_H
+
+#ifdef CONFIG_CRASH_DUMP
+#include <linux/kexec.h>
+#include <linux/smp_lock.h>
+#include <linux/device.h>
+#include <linux/proc_fs.h>
+
+#define ELFCORE_ADDR_MAX       (-1ULL)
+extern unsigned long long elfcorehdr_addr;
+extern ssize_t copy_oldmem_page(unsigned long, char *, size_t,
+                                               unsigned long, int);
+extern struct file_operations proc_vmcore_operations;
+extern struct proc_dir_entry *proc_vmcore;
+
+#endif /* CONFIG_CRASH_DUMP */
+#endif /* LINUX_CRASHDUMP_H */
index 7b781a72b2931ce05ed4fb49a6c83fe38c4d7f40..f378c846e6d52fee3b058a20f8d9d2b03f96e4e5 100644 (file)
@@ -69,7 +69,7 @@ struct bus_type {
 extern int bus_register(struct bus_type * bus);
 extern void bus_unregister(struct bus_type * bus);
 
-extern int bus_rescan_devices(struct bus_type * bus);
+extern void bus_rescan_devices(struct bus_type * bus);
 
 extern struct bus_type * get_bus(struct bus_type * bus);
 extern void put_bus(struct bus_type * bus);
@@ -80,6 +80,8 @@ extern struct bus_type * find_bus(char * name);
 
 int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data,
                     int (*fn)(struct device *, void *));
+struct device * bus_find_device(struct bus_type *bus, struct device *start,
+                               void *data, int (*match)(struct device *, void *));
 
 int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, 
                     void * data, int (*fn)(struct device_driver *, void *));
@@ -142,6 +144,9 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute *
 
 extern int driver_for_each_device(struct device_driver * drv, struct device * start,
                                  void * data, int (*fn)(struct device *, void *));
+struct device * driver_find_device(struct device_driver *drv,
+                                  struct device *start, void *data,
+                                  int (*match)(struct device *, void *));
 
 
 /*
index d2bcf556088b99a58ead0a44c883a5c88df19c84..5e93e6dce9a4751b7107d24e4e241a1eb1989651 100644 (file)
@@ -9,6 +9,7 @@ enum dmi_field {
        DMI_SYS_VENDOR,
        DMI_PRODUCT_NAME,
        DMI_PRODUCT_VERSION,
+       DMI_PRODUCT_SERIAL,
        DMI_BOARD_VENDOR,
        DMI_BOARD_NAME,
        DMI_BOARD_VERSION,
index 42fbf47971568014ddec85872c7668079908c9b9..57f1250d5a526c88e8d30ebbd277c878b60c6e6c 100644 (file)
 /* Root squash turned on */
 #define V1_DQF_RSQUASH 1
 
+/* Numbers of blocks needed for updates */
+#define V1_INIT_ALLOC 1
+#define V1_INIT_REWRITE 1
+#define V1_DEL_ALLOC 0
+#define V1_DEL_REWRITE 2
+
 /* Special information about quotafile */
 struct v1_mem_dqinfo {
 };
index 4a6c5f6867bb0d0abf980058f5cdcc1fcdde177c..4f853322cb7fa0db9a6a73f266b01b825b6f37c7 100644 (file)
 /* id numbers of quota format */
 #define QFMT_VFS_V0 2
 
+/* Numbers of blocks needed for updates */
+#define V2_INIT_ALLOC 4
+#define V2_INIT_REWRITE 2
+#define V2_DEL_ALLOC 0
+#define V2_DEL_REWRITE 6
+
 /* Inmemory copy of version specific information */
 struct v2_mem_dqinfo {
        unsigned int dqi_blocks;
index ee54f81faad506ea5db9f94ceaa71dd15669b7d1..ea6bbc2d7407e9fb48de7c67756e4463bba82970 100644 (file)
@@ -16,9 +16,9 @@ typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *);
 typedef void (elevator_requeue_req_fn) (request_queue_t *, struct request *);
 typedef struct request *(elevator_request_list_fn) (request_queue_t *, struct request *);
 typedef void (elevator_completed_req_fn) (request_queue_t *, struct request *);
-typedef int (elevator_may_queue_fn) (request_queue_t *, int);
+typedef int (elevator_may_queue_fn) (request_queue_t *, int, struct bio *);
 
-typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, int);
+typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, struct bio *, int);
 typedef void (elevator_put_req_fn) (request_queue_t *, struct request *);
 typedef void (elevator_deactivate_req_fn) (request_queue_t *, struct request *);
 
@@ -96,9 +96,9 @@ extern struct request *elv_former_request(request_queue_t *, struct request *);
 extern struct request *elv_latter_request(request_queue_t *, struct request *);
 extern int elv_register_queue(request_queue_t *q);
 extern void elv_unregister_queue(request_queue_t *q);
-extern int elv_may_queue(request_queue_t *, int);
+extern int elv_may_queue(request_queue_t *, int, struct bio *);
 extern void elv_completed_request(request_queue_t *, struct request *);
-extern int elv_set_request(request_queue_t *, struct request *, int);
+extern int elv_set_request(request_queue_t *, struct request *, struct bio *, int);
 extern void elv_put_request(request_queue_t *, struct request *);
 
 /*
index a1478258d00243c93fec79a8e66b07739caeea92..cf3847edc50f6c0199965d338b6e687d36786b74 100644 (file)
@@ -25,6 +25,7 @@
 #define _LINUX_ETHERDEVICE_H
 
 #include <linux/if_ether.h>
+#include <linux/netdevice.h>
 #include <linux/random.h>
 
 #ifdef __KERNEL__
@@ -65,7 +66,7 @@ static inline int is_zero_ether_addr(const u8 *addr)
  */
 static inline int is_multicast_ether_addr(const u8 *addr)
 {
-       return addr[0] & 0x01;
+       return ((addr[0] != 0xff) && (0x01 & addr[0]));
 }
 
 /**
index fab43527e597402da88de4d6777216e685076e0d..a657130ba03ae576df96b8e6ec4539d64dc6df3f 100644 (file)
@@ -300,18 +300,19 @@ struct ext2_inode {
 /*
  * Mount flags
  */
-#define EXT2_MOUNT_CHECK               0x0001  /* Do mount-time checks */
-#define EXT2_MOUNT_OLDALLOC            0x0002  /* Don't use the new Orlov allocator */
-#define EXT2_MOUNT_GRPID               0x0004  /* Create files with directory's group */
-#define EXT2_MOUNT_DEBUG               0x0008  /* Some debugging messages */
-#define EXT2_MOUNT_ERRORS_CONT         0x0010  /* Continue on errors */
-#define EXT2_MOUNT_ERRORS_RO           0x0020  /* Remount fs ro on errors */
-#define EXT2_MOUNT_ERRORS_PANIC                0x0040  /* Panic on errors */
-#define EXT2_MOUNT_MINIX_DF            0x0080  /* Mimics the Minix statfs */
-#define EXT2_MOUNT_NOBH                        0x0100  /* No buffer_heads */
-#define EXT2_MOUNT_NO_UID32            0x0200  /* Disable 32-bit UIDs */
-#define EXT2_MOUNT_XATTR_USER          0x4000  /* Extended user attributes */
-#define EXT2_MOUNT_POSIX_ACL           0x8000  /* POSIX Access Control Lists */
+#define EXT2_MOUNT_CHECK               0x000001  /* Do mount-time checks */
+#define EXT2_MOUNT_OLDALLOC            0x000002  /* Don't use the new Orlov allocator */
+#define EXT2_MOUNT_GRPID               0x000004  /* Create files with directory's group */
+#define EXT2_MOUNT_DEBUG               0x000008  /* Some debugging messages */
+#define EXT2_MOUNT_ERRORS_CONT         0x000010  /* Continue on errors */
+#define EXT2_MOUNT_ERRORS_RO           0x000020  /* Remount fs ro on errors */
+#define EXT2_MOUNT_ERRORS_PANIC                0x000040  /* Panic on errors */
+#define EXT2_MOUNT_MINIX_DF            0x000080  /* Mimics the Minix statfs */
+#define EXT2_MOUNT_NOBH                        0x000100  /* No buffer_heads */
+#define EXT2_MOUNT_NO_UID32            0x000200  /* Disable 32-bit UIDs */
+#define EXT2_MOUNT_XATTR_USER          0x004000  /* Extended user attributes */
+#define EXT2_MOUNT_POSIX_ACL           0x008000  /* POSIX Access Control Lists */
+#define EXT2_MOUNT_XIP                 0x010000  /* Execute in place */
 
 #define clear_opt(o, opt)              o &= ~EXT2_MOUNT_##opt
 #define set_opt(o, opt)                        o |= EXT2_MOUNT_##opt
index 74ad31781e3ea7241b174b90c84d4cb86c3568bc..4b6e1ab216a5414135f734c784ef117baf154837 100644 (file)
@@ -358,6 +358,7 @@ struct ext3_inode {
 #define EXT3_MOUNT_RESERVATION         0x10000 /* Preallocation */
 #define EXT3_MOUNT_BARRIER             0x20000 /* Use block barriers */
 #define EXT3_MOUNT_NOBH                        0x40000 /* No bufferheads */
+#define EXT3_MOUNT_QUOTA               0x80000 /* Some quota option set */
 
 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
 #ifndef _LINUX_EXT2_FS_H
index e8292af9033bfffa3b6b1ec02dbae22b5b38c1bd..c8307c02dd07103c19bfd2dd38ece06470d12278 100644 (file)
  * superblock only gets updated once, of course, so don't bother
  * counting that again for the quota updates. */
 
-#define EXT3_DATA_TRANS_BLOCKS         (EXT3_SINGLEDATA_TRANS_BLOCKS + \
+#define EXT3_DATA_TRANS_BLOCKS(sb)     (EXT3_SINGLEDATA_TRANS_BLOCKS + \
                                         EXT3_XATTR_TRANS_BLOCKS - 2 + \
-                                        2*EXT3_QUOTA_TRANS_BLOCKS)
+                                        2*EXT3_QUOTA_TRANS_BLOCKS(sb))
 
 /* Delete operations potentially hit one directory's namespace plus an
  * entire inode, plus arbitrary amounts of bitmap/indirection data.  Be
  * generous.  We can grow the delete transaction later if necessary. */
 
-#define EXT3_DELETE_TRANS_BLOCKS       (2 * EXT3_DATA_TRANS_BLOCKS + 64)
+#define EXT3_DELETE_TRANS_BLOCKS(sb)   (2 * EXT3_DATA_TRANS_BLOCKS(sb) + 64)
 
 /* Define an arbitrary limit for the amount of data we will anticipate
  * writing to any given transaction.  For unbounded transactions such as
 #ifdef CONFIG_QUOTA
 /* Amount of blocks needed for quota update - we know that the structure was
  * allocated so we need to update only inode+data */
-#define EXT3_QUOTA_TRANS_BLOCKS 2
+#define EXT3_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0)
 /* Amount of blocks needed for quota insert/delete - we do some block writes
  * but inode, sb and group updates are done only once */
-#define EXT3_QUOTA_INIT_BLOCKS (DQUOT_MAX_WRITES*\
-                               (EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3)
+#define EXT3_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\
+               (EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_INIT_REWRITE) : 0)
+#define EXT3_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\
+               (EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_DEL_REWRITE) : 0)
 #else
-#define EXT3_QUOTA_TRANS_BLOCKS 0
-#define EXT3_QUOTA_INIT_BLOCKS 0
+#define EXT3_QUOTA_TRANS_BLOCKS(sb) 0
+#define EXT3_QUOTA_INIT_BLOCKS(sb) 0
+#define EXT3_QUOTA_DEL_BLOCKS(sb) 0
 #endif
 
 int
index 517bf4966bf523b688e0480870dec0c23e6abae2..047bde30836ac0c1278e289bbff500dae39f570b 100644 (file)
@@ -213,6 +213,7 @@ extern int dir_notify_enable;
 #include <linux/radix-tree.h>
 #include <linux/prio_tree.h>
 #include <linux/init.h>
+#include <linux/sched.h>
 
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
@@ -220,6 +221,7 @@ extern int dir_notify_enable;
 
 struct iovec;
 struct nameidata;
+struct kiocb;
 struct pipe_inode_info;
 struct poll_table_struct;
 struct kstatfs;
@@ -240,7 +242,7 @@ typedef int (get_block_t)(struct inode *inode, sector_t iblock,
 typedef int (get_blocks_t)(struct inode *inode, sector_t iblock,
                        unsigned long max_blocks,
                        struct buffer_head *bh_result, int create);
-typedef void (dio_iodone_t)(struct inode *inode, loff_t offset,
+typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
                        ssize_t bytes, void *private);
 
 /*
@@ -302,7 +304,6 @@ struct iattr {
 struct page;
 struct address_space;
 struct writeback_control;
-struct kiocb;
 
 struct address_space_operations {
        int (*writepage)(struct page *page, struct writeback_control *wbc);
@@ -330,6 +331,8 @@ struct address_space_operations {
        int (*releasepage) (struct page *, int);
        ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
                        loff_t offset, unsigned long nr_segs);
+       struct page* (*get_xip_page)(struct address_space *, sector_t,
+                       int);
 };
 
 struct backing_dev_info;
@@ -820,16 +823,34 @@ enum {
 #define vfs_check_frozen(sb, level) \
        wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level)))
 
+static inline void get_fs_excl(void)
+{
+       atomic_inc(&current->fs_excl);
+}
+
+static inline void put_fs_excl(void)
+{
+       atomic_dec(&current->fs_excl);
+}
+
+static inline int has_fs_excl(void)
+{
+       return atomic_read(&current->fs_excl);
+}
+
+
 /*
  * Superblock locking.
  */
 static inline void lock_super(struct super_block * sb)
 {
+       get_fs_excl();
        down(&sb->s_lock);
 }
 
 static inline void unlock_super(struct super_block * sb)
 {
+       put_fs_excl();
        up(&sb->s_lock);
 }
 
@@ -885,6 +906,7 @@ struct block_device_operations {
        int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
        long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
        long (*compat_ioctl) (struct file *, unsigned, unsigned long);
+       int (*direct_access) (struct block_device *, sector_t, unsigned long *);
        int (*media_changed) (struct gendisk *);
        int (*revalidate_disk) (struct gendisk *);
        struct module *owner;
@@ -1496,6 +1518,23 @@ extern loff_t remote_llseek(struct file *file, loff_t offset, int origin);
 extern int generic_file_open(struct inode * inode, struct file * filp);
 extern int nonseekable_open(struct inode * inode, struct file * filp);
 
+#ifdef CONFIG_FS_XIP
+extern ssize_t xip_file_read(struct file *filp, char __user *buf, size_t len,
+                            loff_t *ppos);
+extern ssize_t xip_file_sendfile(struct file *in_file, loff_t *ppos,
+                                size_t count, read_actor_t actor,
+                                void *target);
+extern int xip_file_mmap(struct file * file, struct vm_area_struct * vma);
+extern ssize_t xip_file_write(struct file *filp, const char __user *buf,
+                             size_t len, loff_t *ppos);
+extern int xip_truncate_page(struct address_space *mapping, loff_t from);
+#else
+static inline int xip_truncate_page(struct address_space *mapping, loff_t from)
+{
+       return 0;
+}
+#endif
+
 static inline void do_generic_file_read(struct file * filp, loff_t *ppos,
                                        read_descriptor_t * desc,
                                        read_actor_t actor)
index 2a7e6c65c882f6b17b1d4037ed1c8a25637d7455..6bece9280eb779cf673e9f700ccc64ccc28d543a 100644 (file)
@@ -28,6 +28,7 @@ static inline void *kmap(struct page *page)
 
 #define kmap_atomic(page, idx)         page_address(page)
 #define kunmap_atomic(addr, idx)       do { } while (0)
+#define kmap_atomic_pfn(pfn, idx)      page_address(pfn_to_page(pfn))
 #define kmap_atomic_to_page(ptr)       virt_to_page(ptr)
 
 #endif /* CONFIG_HIGHMEM */
index d228230ffe5d05d308c4b2e79bd48342a55a6c0d..541695679762c39fffcec3d1228efacb05a51e2d 100644 (file)
@@ -25,6 +25,7 @@
 #define _LINUX_I2C_DEV_H
 
 #include <linux/types.h>
+#include <linux/compiler.h>
 
 /* Some IOCTL commands are defined in <linux/i2c.h> */
 /* Note: 10-bit addresses are NOT supported! */
index ef7f644dd8736ae6802dd610dfd1aa31db5f0931..36fd18cdad2897f6f0f3ff38ad4770db29227c13 100644 (file)
 #define MAX_I2O_CONTROLLERS    32
 
 //#include <linux/ioctl.h>
+#ifndef __KERNEL__
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+#endif                         /* __KERNEL__ */
 
 /*
  * I2O Control IOCTLs and structures
@@ -113,6 +120,10 @@ struct i2o_evt_get {
        int lost;
 };
 
+typedef struct i2o_sg_io_hdr {
+       unsigned int flags;     /* see I2O_DPT_SG_IO_FLAGS */
+} i2o_sg_io_hdr_t;
+
 /**************************************************************************
  * HRT related constants and structures
  **************************************************************************/
@@ -126,14 +137,6 @@ struct i2o_evt_get {
 #define I2O_BUS_CARDBUS 7
 #define I2O_BUS_UNKNOWN 0x80
 
-#ifndef __KERNEL__
-
-typedef unsigned char u8;
-typedef unsigned short u16;
-typedef unsigned int u32;
-
-#endif                         /* __KERNEL__ */
-
 typedef struct _i2o_pci_bus {
        u8 PciFunctionNumber;
        u8 PciDeviceNumber;
@@ -333,7 +336,7 @@ typedef struct _i2o_status_block {
 #define I2O_CLASS_ATE_PERIPHERAL               0x061
 #define I2O_CLASS_FLOPPY_CONTROLLER            0x070
 #define I2O_CLASS_FLOPPY_DEVICE                0x071
-#define I2O_CLASS_BUS_ADAPTER_PORT             0x080
+#define I2O_CLASS_BUS_ADAPTER                  0x080
 #define I2O_CLASS_PEER_TRANSPORT_AGENT         0x090
 #define I2O_CLASS_PEER_TRANSPORT               0x091
 #define        I2O_CLASS_END                           0xfff
@@ -399,4 +402,26 @@ typedef struct _i2o_status_block {
 #define ADAPTER_STATE_FAILED                   0x10
 #define ADAPTER_STATE_FAULTED                  0x11
 
+/*
+ *     Software module types
+ */
+#define I2O_SOFTWARE_MODULE_IRTOS              0x11
+#define I2O_SOFTWARE_MODULE_IOP_PRIVATE                0x22
+#define I2O_SOFTWARE_MODULE_IOP_CONFIG         0x23
+
+/*
+ *     Vendors
+ */
+#define I2O_VENDOR_DPT                         0x001b
+
+/*
+ * DPT / Adaptec specific values for i2o_sg_io_hdr flags.
+ */
+#define I2O_DPT_SG_FLAG_INTERPRET              0x00010000
+#define I2O_DPT_SG_FLAG_PHYSICAL               0x00020000
+
+#define I2O_DPT_FLASH_FRAG_SIZE                        0x10000
+#define I2O_DPT_FLASH_READ                     0x0101
+#define I2O_DPT_FLASH_WRITE                    0x0102
+
 #endif                         /* _I2O_DEV_H */
index ea9a3ad4b67fc2296eeba96bddca8294032ac8bf..bdc286ec947c13b2017a9dcc3dd5f49f0ed60533 100644 (file)
@@ -119,12 +119,21 @@ struct i2o_driver {
 };
 
 /*
- *     Contains all information which are necessary for DMA operations
+ *     Contains DMA mapped address information
  */
 struct i2o_dma {
        void *virt;
        dma_addr_t phys;
-       u32 len;
+       size_t len;
+};
+
+/*
+ *     Contains IO mapped address information
+ */
+struct i2o_io {
+       void __iomem *virt;
+       unsigned long phys;
+       unsigned long len;
 };
 
 /*
@@ -147,28 +156,25 @@ struct i2o_controller {
 
        struct pci_dev *pdev;   /* PCI device */
 
-       unsigned int short_req:1;       /* use small block sizes */
+       unsigned int promise:1; /* Promise controller */
+       unsigned int adaptec:1; /* DPT / Adaptec controller */
+       unsigned int raptor:1;  /* split bar */
        unsigned int no_quiesce:1;      /* dont quiesce before reset */
-       unsigned int raptor:1;          /* split bar */
-       unsigned int promise:1;         /* Promise controller */
-
-#ifdef CONFIG_MTRR
-       int mtrr_reg0;
-       int mtrr_reg1;
-#endif
+       unsigned int short_req:1;       /* use small block sizes */
+       unsigned int limit_sectors:1;   /* limit number of sectors / request */
+       unsigned int pae_support:1;     /* controller has 64-bit SGL support */
 
        struct list_head devices;       /* list of I2O devices */
-
-       struct notifier_block *event_notifer;   /* Events */
-       atomic_t users;
        struct list_head list;  /* Controller list */
-       void __iomem *post_port;        /* Inbout port address */
-       void __iomem *reply_port;       /* Outbound port address */
-       void __iomem *irq_mask;         /* Interrupt register address */
+
+       void __iomem *in_port;  /* Inbout port address */
+       void __iomem *out_port; /* Outbound port address */
+       void __iomem *irq_status;       /* Interrupt status register address */
+       void __iomem *irq_mask; /* Interrupt mask register address */
 
        /* Dynamic LCT related data */
 
-       struct i2o_dma status;  /* status of IOP */
+       struct i2o_dma status;  /* IOP status block */
 
        struct i2o_dma hrt;     /* HW Resource Table */
        i2o_lct *lct;           /* Logical Config Table */
@@ -176,21 +182,19 @@ struct i2o_controller {
        struct semaphore lct_lock;      /* Lock for LCT updates */
        struct i2o_dma status_block;    /* IOP status block */
 
-       struct i2o_dma base;    /* controller messaging unit */
-       struct i2o_dma in_queue;        /* inbound message queue Host->IOP */
+       struct i2o_io base;     /* controller messaging unit */
+       struct i2o_io in_queue; /* inbound message queue Host->IOP */
        struct i2o_dma out_queue;       /* outbound message queue IOP->Host */
 
-       unsigned int battery:1;         /* Has a battery backup */
+       unsigned int battery:1; /* Has a battery backup */
        unsigned int io_alloc:1;        /* An I/O resource was allocated */
        unsigned int mem_alloc:1;       /* A memory resource was allocated */
 
        struct resource io_resource;    /* I/O resource allocated to the IOP */
        struct resource mem_resource;   /* Mem resource allocated to the IOP */
 
-       struct proc_dir_entry *proc_entry;      /* /proc dir */
-
-       struct list_head bus_list;      /* list of busses on IOP */
        struct device device;
+       struct class_device classdev;   /* I2O controller class */
        struct i2o_device *exec;        /* Executive */
 #if BITS_PER_LONG == 64
        spinlock_t context_list_lock;   /* lock for context_list */
@@ -241,9 +245,10 @@ struct i2o_sys_tbl {
 extern struct list_head i2o_controllers;
 
 /* Message functions */
-static inline u32 i2o_msg_get(struct i2o_controller *, struct i2o_message __iomem **);
-extern u32 i2o_msg_get_wait(struct i2o_controller *, struct i2o_message __iomem **,
-                           int);
+static inline u32 i2o_msg_get(struct i2o_controller *,
+                             struct i2o_message __iomem **);
+extern u32 i2o_msg_get_wait(struct i2o_controller *,
+                           struct i2o_message __iomem **, int);
 static inline void i2o_msg_post(struct i2o_controller *, u32);
 static inline int i2o_msg_post_wait(struct i2o_controller *, u32,
                                    unsigned long);
@@ -252,15 +257,6 @@ extern int i2o_msg_post_wait_mem(struct i2o_controller *, u32, unsigned long,
 extern void i2o_msg_nop(struct i2o_controller *, u32);
 static inline void i2o_flush_reply(struct i2o_controller *, u32);
 
-/* DMA handling functions */
-static inline int i2o_dma_alloc(struct device *, struct i2o_dma *, size_t,
-                               unsigned int);
-static inline void i2o_dma_free(struct device *, struct i2o_dma *);
-int i2o_dma_realloc(struct device *, struct i2o_dma *, size_t, unsigned int);
-
-static inline int i2o_dma_map(struct device *, struct i2o_dma *);
-static inline void i2o_dma_unmap(struct device *, struct i2o_dma *);
-
 /* IOP functions */
 extern int i2o_status_get(struct i2o_controller *);
 
@@ -285,6 +281,16 @@ static inline u32 i2o_ptr_high(void *ptr)
 {
        return (u32) ((u64) ptr >> 32);
 };
+
+static inline u32 i2o_dma_low(dma_addr_t dma_addr)
+{
+       return (u32) (u64) dma_addr;
+};
+
+static inline u32 i2o_dma_high(dma_addr_t dma_addr)
+{
+       return (u32) ((u64) dma_addr >> 32);
+};
 #else
 static inline u32 i2o_cntxt_list_add(struct i2o_controller *c, void *ptr)
 {
@@ -315,8 +321,246 @@ static inline u32 i2o_ptr_high(void *ptr)
 {
        return 0;
 };
+
+static inline u32 i2o_dma_low(dma_addr_t dma_addr)
+{
+       return (u32) dma_addr;
+};
+
+static inline u32 i2o_dma_high(dma_addr_t dma_addr)
+{
+       return 0;
+};
 #endif
 
+/**
+ *     i2o_sg_tablesize - Calculate the maximum number of elements in a SGL
+ *     @c: I2O controller for which the calculation should be done
+ *     @body_size: maximum body size used for message in 32-bit words.
+ *
+ *     Return the maximum number of SG elements in a SG list.
+ */
+static inline u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size)
+{
+       i2o_status_block *sb = c->status_block.virt;
+       u16 sg_count =
+           (sb->inbound_frame_size - sizeof(struct i2o_message) / 4) -
+           body_size;
+
+       if (c->pae_support) {
+               /*
+                * for 64-bit a SG attribute element must be added and each
+                * SG element needs 12 bytes instead of 8.
+                */
+               sg_count -= 2;
+               sg_count /= 3;
+       } else
+               sg_count /= 2;
+
+       if (c->short_req && (sg_count > 8))
+               sg_count = 8;
+
+       return sg_count;
+};
+
+/**
+ *     i2o_dma_map_single - Map pointer to controller and fill in I2O message.
+ *     @c: I2O controller
+ *     @ptr: pointer to the data which should be mapped
+ *     @size: size of data in bytes
+ *     @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
+ *     @sg_ptr: pointer to the SG list inside the I2O message
+ *
+ *     This function does all necessary DMA handling and also writes the I2O
+ *     SGL elements into the I2O message. For details on DMA handling see also
+ *     dma_map_single(). The pointer sg_ptr will only be set to the end of the
+ *     SG list if the allocation was successful.
+ *
+ *     Returns DMA address which must be checked for failures using
+ *     dma_mapping_error().
+ */
+static inline dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr,
+                                           size_t size,
+                                           enum dma_data_direction direction,
+                                           u32 __iomem ** sg_ptr)
+{
+       u32 sg_flags;
+       u32 __iomem *mptr = *sg_ptr;
+       dma_addr_t dma_addr;
+
+       switch (direction) {
+       case DMA_TO_DEVICE:
+               sg_flags = 0xd4000000;
+               break;
+       case DMA_FROM_DEVICE:
+               sg_flags = 0xd0000000;
+               break;
+       default:
+               return 0;
+       }
+
+       dma_addr = dma_map_single(&c->pdev->dev, ptr, size, direction);
+       if (!dma_mapping_error(dma_addr)) {
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+               if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
+                       writel(0x7C020002, mptr++);
+                       writel(PAGE_SIZE, mptr++);
+               }
+#endif
+
+               writel(sg_flags | size, mptr++);
+               writel(i2o_dma_low(dma_addr), mptr++);
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+               if ((sizeof(dma_addr_t) > 4) && c->pae_support)
+                       writel(i2o_dma_high(dma_addr), mptr++);
+#endif
+               *sg_ptr = mptr;
+       }
+       return dma_addr;
+};
+
+/**
+ *     i2o_dma_map_sg - Map a SG List to controller and fill in I2O message.
+ *     @c: I2O controller
+ *     @sg: SG list to be mapped
+ *     @sg_count: number of elements in the SG list
+ *     @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
+ *     @sg_ptr: pointer to the SG list inside the I2O message
+ *
+ *     This function does all necessary DMA handling and also writes the I2O
+ *     SGL elements into the I2O message. For details on DMA handling see also
+ *     dma_map_sg(). The pointer sg_ptr will only be set to the end of the SG
+ *     list if the allocation was successful.
+ *
+ *     Returns 0 on failure or 1 on success.
+ */
+static inline int i2o_dma_map_sg(struct i2o_controller *c,
+                                struct scatterlist *sg, int sg_count,
+                                enum dma_data_direction direction,
+                                u32 __iomem ** sg_ptr)
+{
+       u32 sg_flags;
+       u32 __iomem *mptr = *sg_ptr;
+
+       switch (direction) {
+       case DMA_TO_DEVICE:
+               sg_flags = 0x14000000;
+               break;
+       case DMA_FROM_DEVICE:
+               sg_flags = 0x10000000;
+               break;
+       default:
+               return 0;
+       }
+
+       sg_count = dma_map_sg(&c->pdev->dev, sg, sg_count, direction);
+       if (!sg_count)
+               return 0;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+       if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
+               writel(0x7C020002, mptr++);
+               writel(PAGE_SIZE, mptr++);
+       }
+#endif
+
+       while (sg_count-- > 0) {
+               if (!sg_count)
+                       sg_flags |= 0xC0000000;
+               writel(sg_flags | sg_dma_len(sg), mptr++);
+               writel(i2o_dma_low(sg_dma_address(sg)), mptr++);
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+               if ((sizeof(dma_addr_t) > 4) && c->pae_support)
+                       writel(i2o_dma_high(sg_dma_address(sg)), mptr++);
+#endif
+               sg++;
+       }
+       *sg_ptr = mptr;
+
+       return 1;
+};
+
+/**
+ *     i2o_dma_alloc - Allocate DMA memory
+ *     @dev: struct device pointer to the PCI device of the I2O controller
+ *     @addr: i2o_dma struct which should get the DMA buffer
+ *     @len: length of the new DMA memory
+ *     @gfp_mask: GFP mask
+ *
+ *     Allocate a coherent DMA memory and write the pointers into addr.
+ *
+ *     Returns 0 on success or -ENOMEM on failure.
+ */
+static inline int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr,
+                               size_t len, unsigned int gfp_mask)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       int dma_64 = 0;
+
+       if ((sizeof(dma_addr_t) > 4) && (pdev->dma_mask == DMA_64BIT_MASK)) {
+               dma_64 = 1;
+               if (pci_set_dma_mask(pdev, DMA_32BIT_MASK))
+                       return -ENOMEM;
+       }
+
+       addr->virt = dma_alloc_coherent(dev, len, &addr->phys, gfp_mask);
+
+       if ((sizeof(dma_addr_t) > 4) && dma_64)
+               if (pci_set_dma_mask(pdev, DMA_64BIT_MASK))
+                       printk(KERN_WARNING "i2o: unable to set 64-bit DMA");
+
+       if (!addr->virt)
+               return -ENOMEM;
+
+       memset(addr->virt, 0, len);
+       addr->len = len;
+
+       return 0;
+};
+
+/**
+ *     i2o_dma_free - Free DMA memory
+ *     @dev: struct device pointer to the PCI device of the I2O controller
+ *     @addr: i2o_dma struct which contains the DMA buffer
+ *
+ *     Free a coherent DMA memory and set virtual address of addr to NULL.
+ */
+static inline void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
+{
+       if (addr->virt) {
+               if (addr->phys)
+                       dma_free_coherent(dev, addr->len, addr->virt,
+                                         addr->phys);
+               else
+                       kfree(addr->virt);
+               addr->virt = NULL;
+       }
+};
+
+/**
+ *     i2o_dma_realloc - Realloc DMA memory
+ *     @dev: struct device pointer to the PCI device of the I2O controller
+ *     @addr: pointer to a i2o_dma struct DMA buffer
+ *     @len: new length of memory
+ *     @gfp_mask: GFP mask
+ *
+ *     If there was something allocated in the addr, free it first. If len > 0
+ *     than try to allocate it and write the addresses back to the addr
+ *     structure. If len == 0 set the virtual address to NULL.
+ *
+ *     Returns the 0 on success or negative error code on failure.
+ */
+static inline int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr,
+                                 size_t len, unsigned int gfp_mask)
+{
+       i2o_dma_free(dev, addr);
+
+       if (len)
+               return i2o_dma_alloc(dev, addr, len, gfp_mask);
+
+       return 0;
+};
+
 /* I2O driver (OSM) functions */
 extern int i2o_driver_register(struct i2o_driver *);
 extern void i2o_driver_unregister(struct i2o_driver *);
@@ -385,49 +629,11 @@ extern int i2o_device_claim_release(struct i2o_device *);
 /* Exec OSM functions */
 extern int i2o_exec_lct_get(struct i2o_controller *);
 
-/* device to i2o_device and driver to i2o_driver convertion functions */
+/* device / driver / kobject conversion functions */
 #define to_i2o_driver(drv) container_of(drv,struct i2o_driver, driver)
 #define to_i2o_device(dev) container_of(dev, struct i2o_device, device)
-
-/*
- *     Messenger inlines
- */
-static inline u32 I2O_POST_READ32(struct i2o_controller *c)
-{
-       rmb();
-       return readl(c->post_port);
-};
-
-static inline void I2O_POST_WRITE32(struct i2o_controller *c, u32 val)
-{
-       wmb();
-       writel(val, c->post_port);
-};
-
-static inline u32 I2O_REPLY_READ32(struct i2o_controller *c)
-{
-       rmb();
-       return readl(c->reply_port);
-};
-
-static inline void I2O_REPLY_WRITE32(struct i2o_controller *c, u32 val)
-{
-       wmb();
-       writel(val, c->reply_port);
-};
-
-static inline u32 I2O_IRQ_READ32(struct i2o_controller *c)
-{
-       rmb();
-       return readl(c->irq_mask);
-};
-
-static inline void I2O_IRQ_WRITE32(struct i2o_controller *c, u32 val)
-{
-       wmb();
-       writel(val, c->irq_mask);
-       wmb();
-};
+#define to_i2o_controller(dev) container_of(dev, struct i2o_controller, device)
+#define kobj_to_i2o_device(kobj) to_i2o_device(container_of(kobj, struct device, kobj))
 
 /**
  *     i2o_msg_get - obtain an I2O message from the IOP
@@ -443,11 +649,11 @@ static inline void I2O_IRQ_WRITE32(struct i2o_controller *c, u32 val)
  *     available returns I2O_QUEUE_EMPTY and msg is leaved untouched.
  */
 static inline u32 i2o_msg_get(struct i2o_controller *c,
-                             struct i2o_message __iomem **msg)
+                             struct i2o_message __iomem ** msg)
 {
-       u32 m;
+       u32 m = readl(c->in_port);
 
-       if ((m = I2O_POST_READ32(c)) != I2O_QUEUE_EMPTY)
+       if (m != I2O_QUEUE_EMPTY)
                *msg = c->in_queue.virt + m;
 
        return m;
@@ -462,7 +668,7 @@ static inline u32 i2o_msg_get(struct i2o_controller *c,
  */
 static inline void i2o_msg_post(struct i2o_controller *c, u32 m)
 {
-       I2O_POST_WRITE32(c, m);
+       writel(m, c->in_port);
 };
 
 /**
@@ -491,12 +697,10 @@ static inline int i2o_msg_post_wait(struct i2o_controller *c, u32 m,
  *     The I2O controller must be informed that the reply message is not needed
  *     anymore. If you forget to flush the reply, the message frame can't be
  *     used by the controller anymore and is therefore lost.
- *
- *     FIXME: is there a timeout after which the controller reuse the message?
  */
 static inline void i2o_flush_reply(struct i2o_controller *c, u32 m)
 {
-       I2O_REPLY_WRITE32(c, m);
+       writel(m, c->out_port);
 };
 
 /**
@@ -530,97 +734,13 @@ static inline struct i2o_message *i2o_msg_out_to_virt(struct i2o_controller *c,
  *     work for receive side messages as they are kmalloc objects
  *     in a different pool.
  */
-static inline struct i2o_message __iomem *i2o_msg_in_to_virt(struct i2o_controller *c,
-                                                    u32 m)
+static inline struct i2o_message __iomem *i2o_msg_in_to_virt(struct
+                                                            i2o_controller *c,
+                                                            u32 m)
 {
        return c->in_queue.virt + m;
 };
 
-/**
- *     i2o_dma_alloc - Allocate DMA memory
- *     @dev: struct device pointer to the PCI device of the I2O controller
- *     @addr: i2o_dma struct which should get the DMA buffer
- *     @len: length of the new DMA memory
- *     @gfp_mask: GFP mask
- *
- *     Allocate a coherent DMA memory and write the pointers into addr.
- *
- *     Returns 0 on success or -ENOMEM on failure.
- */
-static inline int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr,
-                               size_t len, unsigned int gfp_mask)
-{
-       addr->virt = dma_alloc_coherent(dev, len, &addr->phys, gfp_mask);
-       if (!addr->virt)
-               return -ENOMEM;
-
-       memset(addr->virt, 0, len);
-       addr->len = len;
-
-       return 0;
-};
-
-/**
- *     i2o_dma_free - Free DMA memory
- *     @dev: struct device pointer to the PCI device of the I2O controller
- *     @addr: i2o_dma struct which contains the DMA buffer
- *
- *     Free a coherent DMA memory and set virtual address of addr to NULL.
- */
-static inline void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
-{
-       if (addr->virt) {
-               if (addr->phys)
-                       dma_free_coherent(dev, addr->len, addr->virt,
-                                         addr->phys);
-               else
-                       kfree(addr->virt);
-               addr->virt = NULL;
-       }
-};
-
-/**
- *     i2o_dma_map - Map the memory to DMA
- *     @dev: struct device pointer to the PCI device of the I2O controller
- *     @addr: i2o_dma struct which should be mapped
- *
- *     Map the memory in addr->virt to coherent DMA memory and write the
- *     physical address into addr->phys.
- *
- *     Returns 0 on success or -ENOMEM on failure.
- */
-static inline int i2o_dma_map(struct device *dev, struct i2o_dma *addr)
-{
-       if (!addr->virt)
-               return -EFAULT;
-
-       if (!addr->phys)
-               addr->phys = dma_map_single(dev, addr->virt, addr->len,
-                                           DMA_BIDIRECTIONAL);
-       if (!addr->phys)
-               return -ENOMEM;
-
-       return 0;
-};
-
-/**
- *     i2o_dma_unmap - Unmap the DMA memory
- *     @dev: struct device pointer to the PCI device of the I2O controller
- *     @addr: i2o_dma struct which should be unmapped
- *
- *     Unmap the memory in addr->virt from DMA memory.
- */
-static inline void i2o_dma_unmap(struct device *dev, struct i2o_dma *addr)
-{
-       if (!addr->virt)
-               return;
-
-       if (addr->phys) {
-               dma_unmap_single(dev, addr->phys, addr->len, DMA_BIDIRECTIONAL);
-               addr->phys = 0;
-       }
-};
-
 /*
  *     Endian handling wrapped into the macro - keeps the core code
  *     cleaner.
@@ -772,6 +892,14 @@ extern void i2o_debug_state(struct i2o_controller *c);
 #define I2O_CMD_SCSI_ABORT             0x83
 #define I2O_CMD_SCSI_BUSRESET          0x27
 
+/*
+ * Bus Adapter Class
+ */
+#define I2O_CMD_BUS_ADAPTER_RESET      0x85
+#define I2O_CMD_BUS_RESET              0x87
+#define I2O_CMD_BUS_SCAN               0x89
+#define I2O_CMD_BUS_QUIESCE            0x8b
+
 /*
  * Random Block Storage Class
  */
@@ -784,7 +912,7 @@ extern void i2o_debug_state(struct i2o_controller *c);
 #define I2O_CMD_BLOCK_MEJECT           0x43
 #define I2O_CMD_BLOCK_POWER            0x70
 
-#define I2O_PRIVATE_MSG                        0xFF
+#define I2O_CMD_PRIVATE                        0xFF
 
 /* Command status values  */
 
@@ -922,7 +1050,7 @@ extern void i2o_debug_state(struct i2o_controller *c);
 #define I2OVER15       0x0001
 #define I2OVER20       0x0002
 
-/* Default is 1.5, FIXME: Need support for both 1.5 and 2.0 */
+/* Default is 1.5 */
 #define I2OVERSION     I2OVER15
 
 #define SGL_OFFSET_0    I2OVERSION
@@ -933,9 +1061,9 @@ extern void i2o_debug_state(struct i2o_controller *c);
 #define SGL_OFFSET_8    (0x0080 | I2OVERSION)
 #define SGL_OFFSET_9    (0x0090 | I2OVERSION)
 #define SGL_OFFSET_10   (0x00A0 | I2OVERSION)
-
-#define TRL_OFFSET_5    (0x0050 | I2OVERSION)
-#define TRL_OFFSET_6    (0x0060 | I2OVERSION)
+#define SGL_OFFSET_11   (0x00B0 | I2OVERSION)
+#define SGL_OFFSET_12   (0x00C0 | I2OVERSION)
+#define SGL_OFFSET(x)   (((x)<<4) | I2OVERSION)
 
 /* Transaction Reply Lists (TRL) Control Word structure */
 #define TRL_SINGLE_FIXED_LENGTH                0x00
@@ -962,17 +1090,13 @@ extern void i2o_debug_state(struct i2o_controller *c);
 #define ELEVEN_WORD_MSG_SIZE   0x000B0000
 #define I2O_MESSAGE_SIZE(x)    ((x)<<16)
 
-/* Special TID Assignments */
-
+/* special TID assignments */
 #define ADAPTER_TID            0
 #define HOST_TID               1
 
-#define MSG_FRAME_SIZE         128     /* i2o_scsi assumes >= 32 */
-#define REPLY_FRAME_SIZE       17
-#define SG_TABLESIZE           30
-#define NMBR_MSG_FRAMES                128
-
-#define MSG_POOL_SIZE          (MSG_FRAME_SIZE*NMBR_MSG_FRAMES*sizeof(u32))
+/* outbound queue defines */
+#define I2O_MAX_OUTBOUND_MSG_FRAMES    128
+#define I2O_OUTBOUND_MSG_FRAME_SIZE    128     /* in 32-bit words */
 
 #define I2O_POST_WAIT_OK       0
 #define I2O_POST_WAIT_TIMEOUT  -ETIMEDOUT
@@ -993,11 +1117,10 @@ extern void i2o_debug_state(struct i2o_controller *c);
 #define I2O_HRT_GET_TRIES              3
 #define I2O_LCT_GET_TRIES              3
 
-/* request queue sizes */
+/* defines for max_sectors and max_phys_segments */
 #define I2O_MAX_SECTORS                        1024
-#define I2O_MAX_SEGMENTS               128
-
-#define I2O_REQ_MEMPOOL_SIZE           32
+#define I2O_MAX_SECTORS_LIMITED                256
+#define I2O_MAX_PHYS_SEGMENTS          MAX_PHYS_SEGMENTS
 
 #endif                         /* __KERNEL__ */
 #endif                         /* _I2O_H */
index 57024ce2c74f558e818cd24e9c568bf14244231f..84598fa2e9de4c8aebe8ebf625bb667bfa505b18 100644 (file)
@@ -35,6 +35,9 @@
  *
  * 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
  *     - Code cleanup and style changes
+ *
+ * 2005/05/05 - Jason Gabler <jygabler at lbl dot gov>
+ *      - added definitions for various XOR hashing policies
  */
 
 #ifndef _LINUX_IF_BONDING_H
 
 #define BOND_DEFAULT_MAX_BONDS  1   /* Default maximum number of devices to support */
 
+/* hashing types */
+#define BOND_XMIT_POLICY_LAYER2                0 /* layer 2 (MAC only), default */
+#define BOND_XMIT_POLICY_LAYER34       1 /* layer 3+4 (IP ^ MAC) */
+
 typedef struct ifbond {
        __s32 bond_mode;
        __s32 num_slaves;
index f8256c582845399c47f2818e2b9900115e5aa528..dcf5720ffcbb3419c524140bfbc02945c53f3e47 100644 (file)
@@ -156,7 +156,7 @@ struct in6_flowlabel_req
 #define IPV6_CHECKSUM          7
 #define IPV6_HOPLIMIT          8
 #define IPV6_NEXTHOP           9
-#define IPV6_AUTHHDR           10
+#define IPV6_AUTHHDR           10      /* obsolete */
 #define IPV6_FLOWINFO          11
 
 #define IPV6_UNICAST_HOPS      16
index 05c83e0521ca6290638a22a6d22cd68c90a3d6ef..59008c3826cf790806f1f68bd007fa172e89fc5f 100644 (file)
@@ -229,6 +229,18 @@ void __init parse_early_param(void);
 #define __devexitdata __exitdata
 #endif
 
+#ifdef CONFIG_HOTPLUG_CPU
+#define __cpuinit
+#define __cpuinitdata
+#define __cpuexit
+#define __cpuexitdata
+#else
+#define __cpuinit      __init
+#define __cpuinitdata __initdata
+#define __cpuexit __exit
+#define __cpuexitdata  __exitdata
+#endif
+
 /* Functions marked as __devexit may be discarded at kernel link time, depending
    on config options.  Newer versions of binutils detect references from
    retained sections to discarded sections and flag an error.  Pointers to
index a6a8c1a38d5e4278a8472132d70b44a6589ae654..c727c195a91a87cc0015abb05d7ed8660cf63453 100644 (file)
@@ -81,6 +81,7 @@ extern struct group_info init_groups;
        .mm             = NULL,                                         \
        .active_mm      = &init_mm,                                     \
        .run_list       = LIST_HEAD_INIT(tsk.run_list),                 \
+       .ioprio         = 0,                                            \
        .time_slice     = HZ,                                           \
        .tasks          = LIST_HEAD_INIT(tsk.tasks),                    \
        .ptrace_children= LIST_HEAD_INIT(tsk.ptrace_children),          \
@@ -108,9 +109,9 @@ extern struct group_info init_groups;
        .blocked        = {{0}},                                        \
        .alloc_lock     = SPIN_LOCK_UNLOCKED,                           \
        .proc_lock      = SPIN_LOCK_UNLOCKED,                           \
-       .switch_lock    = SPIN_LOCK_UNLOCKED,                           \
        .journal_info   = NULL,                                         \
        .cpu_timers     = INIT_CPU_TIMERS(tsk.cpu_timers),              \
+       .fs_excl        = ATOMIC_INIT(0),                               \
 }
 
 
index 9d9598ed760de2a7a4f2081f62dc41b11a6e81c8..b9cc0ac71f44db7b6e361bca0a789defacdd8886 100644 (file)
@@ -859,6 +859,10 @@ struct input_dev {
        int (*erase_effect)(struct input_dev *dev, int effect_id);
 
        struct input_handle *grab;
+
+       struct semaphore sem;   /* serializes open and close operations */
+       unsigned int users;
+
        struct device *dev;
 
        struct list_head        h_list;
diff --git a/include/linux/ioprio.h b/include/linux/ioprio.h
new file mode 100644 (file)
index 0000000..8a453a0
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef IOPRIO_H
+#define IOPRIO_H
+
+#include <linux/sched.h>
+
+/*
+ * Gives us 8 prio classes with 13-bits of data for each class
+ */
+#define IOPRIO_BITS            (16)
+#define IOPRIO_CLASS_SHIFT     (13)
+#define IOPRIO_PRIO_MASK       ((1UL << IOPRIO_CLASS_SHIFT) - 1)
+
+#define IOPRIO_PRIO_CLASS(mask)        ((mask) >> IOPRIO_CLASS_SHIFT)
+#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
+#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data)
+
+#define ioprio_valid(mask)     (IOPRIO_PRIO_CLASS((mask)) != IOPRIO_CLASS_NONE)
+
+/*
+ * These are the io priority groups as implemented by CFQ. RT is the realtime
+ * class, it always gets premium service. BE is the best-effort scheduling
+ * class, the default for any process. IDLE is the idle scheduling class, it
+ * is only served when no one else is using the disk.
+ */
+enum {
+       IOPRIO_CLASS_NONE,
+       IOPRIO_CLASS_RT,
+       IOPRIO_CLASS_BE,
+       IOPRIO_CLASS_IDLE,
+};
+
+/*
+ * 8 best effort priority levels are supported
+ */
+#define IOPRIO_BE_NR   (8)
+
+asmlinkage int sys_ioprio_set(int, int, int);
+asmlinkage int sys_ioprio_get(int, int);
+
+enum {
+       IOPRIO_WHO_PROCESS = 1,
+       IOPRIO_WHO_PGRP,
+       IOPRIO_WHO_USER,
+};
+
+/*
+ * if process has set io priority explicitly, use that. if not, convert
+ * the cpu scheduler nice value to an io priority
+ */
+#define IOPRIO_NORM    (4)
+static inline int task_ioprio(struct task_struct *task)
+{
+       WARN_ON(!ioprio_valid(task->ioprio));
+       return IOPRIO_PRIO_DATA(task->ioprio);
+}
+
+static inline int task_nice_ioprio(struct task_struct *task)
+{
+       return (task_nice(task) + 20) / 5;
+}
+
+/*
+ * For inheritance, return the highest of the two given priorities
+ */
+static inline int ioprio_best(unsigned short aprio, unsigned short bprio)
+{
+       unsigned short aclass = IOPRIO_PRIO_CLASS(aprio);
+       unsigned short bclass = IOPRIO_PRIO_CLASS(bprio);
+
+       if (!ioprio_valid(aprio))
+               return bprio;
+       if (!ioprio_valid(bprio))
+               return aprio;
+
+       if (aclass == IOPRIO_CLASS_NONE)
+               aclass = IOPRIO_CLASS_BE;
+       if (bclass == IOPRIO_CLASS_NONE)
+               bclass = IOPRIO_CLASS_BE;
+
+       if (aclass == bclass)
+               return min(aprio, bprio);
+       if (aclass > bclass)
+               return bprio;
+       else
+               return aprio;
+}
+
+#endif
index 2ec265e1045faf49392ac2f852ae8683c38ca0cc..596ca6130159f749036cf15860ba275c2122a6d3 100644 (file)
@@ -209,6 +209,11 @@ struct kernel_ipmi_msg
 #include <linux/list.h>
 #include <linux/module.h>
 
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+extern struct proc_dir_entry *proc_ipmi_root;
+#endif /* CONFIG_PROC_FS */
+
 /* Opaque type for a IPMI message user.  One of these is needed to
    send and receive messages. */
 typedef struct ipmi_user *ipmi_user_t;
index 7fc1022be9ee13254dbfd7a2f6bf67e9c20cb1f6..069d3b84d311b442ffbbe2074733b78f5e894b7b 100644 (file)
@@ -85,10 +85,10 @@ extern int no_irq_affinity;
 extern int noirqdebug_setup(char *str);
 
 extern fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
-                                      struct irqaction *action);
+                                       struct irqaction *action);
 extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs);
-extern void note_interrupt(unsigned int irq, irq_desc_t *desc, int action_ret);
-extern void report_bad_irq(unsigned int irq, irq_desc_t *desc, int action_ret);
+extern void note_interrupt(unsigned int irq, irq_desc_t *desc,
+                                       int action_ret, struct pt_regs *regs);
 extern int can_request_irq(unsigned int irq, unsigned long irqflags);
 
 extern void init_irq_proc(void);
index b7e0ab622cd7c377ff5980ff6067058b580c3900..06b9af77eb7f8eca71b6476013ea69ed32ee909e 100644 (file)
@@ -111,18 +111,35 @@ struct js_corr {
 #define JS_SET_ALL             8
 
 struct JS_DATA_TYPE {
-       int buttons;
-       int x;
-       int y;
+       __s32 buttons;
+       __s32 x;
+       __s32 y;
 };
 
-struct JS_DATA_SAVE_TYPE {
-       int JS_TIMEOUT;
-       int BUSY;
-       long JS_EXPIRETIME;
-       long JS_TIMELIMIT;
+struct JS_DATA_SAVE_TYPE_32 {
+       __s32 JS_TIMEOUT;
+       __s32 BUSY;
+       __s32 JS_EXPIRETIME;
+       __s32 JS_TIMELIMIT;
        struct JS_DATA_TYPE JS_SAVE;
        struct JS_DATA_TYPE JS_CORR;
 };
 
+struct JS_DATA_SAVE_TYPE_64 {
+       __s32 JS_TIMEOUT;
+       __s32 BUSY;
+       __s64 JS_EXPIRETIME;
+       __s64 JS_TIMELIMIT;
+       struct JS_DATA_TYPE JS_SAVE;
+       struct JS_DATA_TYPE JS_CORR;
+};
+
+#if BITS_PER_LONG == 64
+#define JS_DATA_SAVE_TYPE JS_DATA_SAVE_TYPE_64
+#elif BITS_PER_LONG == 32
+#define JS_DATA_SAVE_TYPE JS_DATA_SAVE_TYPE_32
+#else
+#error Unexpected BITS_PER_LONG
+#endif
+
 #endif /* _LINUX_JOYSTICK_H */
index e25b97062ce1ac942d14301335584bd66e3d331d..687ba8c9973de2d30d97e234817a52e6b2d2f993 100644 (file)
@@ -58,15 +58,23 @@ struct completion;
  * be biten later when the calling function happens to sleep when it is not
  * supposed to.
  */
+#ifdef CONFIG_PREEMPT_VOLUNTARY
+extern int cond_resched(void);
+# define might_resched() cond_resched()
+#else
+# define might_resched() do { } while (0)
+#endif
+
 #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
-#define might_sleep() __might_sleep(__FILE__, __LINE__)
-#define might_sleep_if(cond) do { if (unlikely(cond)) might_sleep(); } while (0)
-void __might_sleep(char *file, int line);
+  void __might_sleep(char *file, int line);
+# define might_sleep() \
+       do { __might_sleep(__FILE__, __LINE__); might_resched(); } while (0)
 #else
-#define might_sleep() do {} while(0)
-#define might_sleep_if(cond) do {} while (0)
+# define might_sleep() do { might_resched(); } while (0)
 #endif
 
+#define might_sleep_if(cond) do { if (unlikely(cond)) might_sleep(); } while (0)
+
 #define abs(x) ({                              \
                int __x = (x);                  \
                (__x < 0) ? -__x : __x;         \
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
new file mode 100644 (file)
index 0000000..c846847
--- /dev/null
@@ -0,0 +1,135 @@
+#ifndef LINUX_KEXEC_H
+#define LINUX_KEXEC_H
+
+#ifdef CONFIG_KEXEC
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/linkage.h>
+#include <linux/compat.h>
+#include <asm/kexec.h>
+
+/* Verify architecture specific macros are defined */
+
+#ifndef KEXEC_SOURCE_MEMORY_LIMIT
+#error KEXEC_SOURCE_MEMORY_LIMIT not defined
+#endif
+
+#ifndef KEXEC_DESTINATION_MEMORY_LIMIT
+#error KEXEC_DESTINATION_MEMORY_LIMIT not defined
+#endif
+
+#ifndef KEXEC_CONTROL_MEMORY_LIMIT
+#error KEXEC_CONTROL_MEMORY_LIMIT not defined
+#endif
+
+#ifndef KEXEC_CONTROL_CODE_SIZE
+#error KEXEC_CONTROL_CODE_SIZE not defined
+#endif
+
+#ifndef KEXEC_ARCH
+#error KEXEC_ARCH not defined
+#endif
+
+/*
+ * This structure is used to hold the arguments that are used when loading
+ * kernel binaries.
+ */
+
+typedef unsigned long kimage_entry_t;
+#define IND_DESTINATION  0x1
+#define IND_INDIRECTION  0x2
+#define IND_DONE         0x4
+#define IND_SOURCE       0x8
+
+#define KEXEC_SEGMENT_MAX 8
+struct kexec_segment {
+       void __user *buf;
+       size_t bufsz;
+       unsigned long mem;      /* User space sees this as a (void *) ... */
+       size_t memsz;
+};
+
+#ifdef CONFIG_COMPAT
+struct compat_kexec_segment {
+       compat_uptr_t buf;
+       compat_size_t bufsz;
+       compat_ulong_t mem;     /* User space sees this as a (void *) ... */
+       compat_size_t memsz;
+};
+#endif
+
+struct kimage {
+       kimage_entry_t head;
+       kimage_entry_t *entry;
+       kimage_entry_t *last_entry;
+
+       unsigned long destination;
+
+       unsigned long start;
+       struct page *control_code_page;
+
+       unsigned long nr_segments;
+       struct kexec_segment segment[KEXEC_SEGMENT_MAX];
+
+       struct list_head control_pages;
+       struct list_head dest_pages;
+       struct list_head unuseable_pages;
+
+       /* Address of next control page to allocate for crash kernels. */
+       unsigned long control_page;
+
+       /* Flags to indicate special processing */
+       unsigned int type : 1;
+#define KEXEC_TYPE_DEFAULT 0
+#define KEXEC_TYPE_CRASH   1
+};
+
+
+
+/* kexec interface functions */
+extern NORET_TYPE void machine_kexec(struct kimage *image) ATTRIB_NORET;
+extern int machine_kexec_prepare(struct kimage *image);
+extern void machine_kexec_cleanup(struct kimage *image);
+extern asmlinkage long sys_kexec_load(unsigned long entry,
+                                       unsigned long nr_segments,
+                                       struct kexec_segment __user *segments,
+                                       unsigned long flags);
+#ifdef CONFIG_COMPAT
+extern asmlinkage long compat_sys_kexec_load(unsigned long entry,
+                               unsigned long nr_segments,
+                               struct compat_kexec_segment __user *segments,
+                               unsigned long flags);
+#endif
+extern struct page *kimage_alloc_control_pages(struct kimage *image,
+                                               unsigned int order);
+extern void crash_kexec(struct pt_regs *);
+int kexec_should_crash(struct task_struct *);
+extern struct kimage *kexec_image;
+
+#define KEXEC_ON_CRASH  0x00000001
+#define KEXEC_ARCH_MASK 0xffff0000
+
+/* These values match the ELF architecture values.
+ * Unless there is a good reason that should continue to be the case.
+ */
+#define KEXEC_ARCH_DEFAULT ( 0 << 16)
+#define KEXEC_ARCH_386     ( 3 << 16)
+#define KEXEC_ARCH_X86_64  (62 << 16)
+#define KEXEC_ARCH_PPC     (20 << 16)
+#define KEXEC_ARCH_PPC64   (21 << 16)
+#define KEXEC_ARCH_IA_64   (50 << 16)
+#define KEXEC_ARCH_S390    (22 << 16)
+
+#define KEXEC_FLAGS    (KEXEC_ON_CRASH)  /* List of defined/legal kexec flags */
+
+/* Location of a reserved region to hold the crash kernel.
+ */
+extern struct resource crashk_res;
+
+#else /* !CONFIG_KEXEC */
+struct pt_regs;
+struct task_struct;
+static inline void crash_kexec(struct pt_regs *regs) { }
+static inline int kexec_should_crash(struct task_struct *p) { return 0; }
+#endif /* CONFIG_KEXEC */
+#endif /* LINUX_KEXEC_H */
index 60cc7b762e78da106729b02925c8c98d00b0d603..cc326174a80886d8c6aba40e11055455de84a60f 100644 (file)
@@ -1,4 +1,4 @@
-/* key-ui.h: key userspace interface stuff for use by keyfs
+/* key-ui.h: key userspace interface stuff
  *
  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -31,8 +31,10 @@ extern spinlock_t key_serial_lock;
  * subscribed
  */
 struct keyring_list {
-       unsigned        maxkeys;        /* max keys this list can hold */
-       unsigned        nkeys;          /* number of keys currently held */
+       struct rcu_head rcu;            /* RCU deletion hook */
+       unsigned short  maxkeys;        /* max keys this list can hold */
+       unsigned short  nkeys;          /* number of keys currently held */
+       unsigned short  delkey;         /* key to be unlinked by RCU */
        struct key      *keys[0];
 };
 
@@ -82,8 +84,45 @@ static inline int key_any_permission(const struct key *key, key_perm_t perm)
        return kperm != 0;
 }
 
+static inline int key_task_groups_search(struct task_struct *tsk, gid_t gid)
+{
+       int ret;
+
+       task_lock(tsk);
+       ret = groups_search(tsk->group_info, gid);
+       task_unlock(tsk);
+       return ret;
+}
+
+static inline int key_task_permission(const struct key *key,
+                                     struct task_struct *context,
+                                     key_perm_t perm)
+{
+       key_perm_t kperm;
+
+       if (key->uid == context->fsuid) {
+               kperm = key->perm >> 16;
+       }
+       else if (key->gid != -1 &&
+                key->perm & KEY_GRP_ALL && (
+                        key->gid == context->fsgid ||
+                        key_task_groups_search(context, key->gid)
+                        )
+                ) {
+               kperm = key->perm >> 8;
+       }
+       else {
+               kperm = key->perm;
+       }
+
+       kperm = kperm & perm & KEY_ALL;
+
+       return kperm == perm;
+
+}
 
-extern struct key *lookup_user_key(key_serial_t id, int create, int part,
+extern struct key *lookup_user_key(struct task_struct *context,
+                                  key_serial_t id, int create, int partial,
                                   key_perm_t perm);
 
 extern long join_session_keyring(const char *name);
index 6aa46d0e812f974540ef788401def920da72d77c..970bbd916cf44a4b32bf5b1ea0005483b1f52c32 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/rbtree.h>
-#include <linux/spinlock.h>
+#include <linux/rcupdate.h>
 #include <asm/atomic.h>
 
 #ifdef __KERNEL__
@@ -78,7 +78,6 @@ struct key {
        key_serial_t            serial;         /* key serial number */
        struct rb_node          serial_node;
        struct key_type         *type;          /* type of key */
-       rwlock_t                lock;           /* examination vs change lock */
        struct rw_semaphore     sem;            /* change vs change sem */
        struct key_user         *user;          /* owner of this key */
        time_t                  expiry;         /* time at which key expires (or 0) */
@@ -86,14 +85,10 @@ struct key {
        gid_t                   gid;
        key_perm_t              perm;           /* access permissions */
        unsigned short          quotalen;       /* length added to quota */
-       unsigned short          datalen;        /* payload data length */
-       unsigned short          flags;          /* status flags (change with lock writelocked) */
-#define KEY_FLAG_INSTANTIATED  0x00000001      /* set if key has been instantiated */
-#define KEY_FLAG_DEAD          0x00000002      /* set if key type has been deleted */
-#define KEY_FLAG_REVOKED       0x00000004      /* set if key had been revoked */
-#define KEY_FLAG_IN_QUOTA      0x00000008      /* set if key consumes quota */
-#define KEY_FLAG_USER_CONSTRUCT        0x00000010      /* set if key is being constructed in userspace */
-#define KEY_FLAG_NEGATIVE      0x00000020      /* set if key is negative */
+       unsigned short          datalen;        /* payload data length
+                                                * - may not match RCU dereferenced payload
+                                                * - payload should contain own length
+                                                */
 
 #ifdef KEY_DEBUGGING
        unsigned                magic;
@@ -101,6 +96,14 @@ struct key {
 #define KEY_DEBUG_MAGIC_X      0xf8e9dacbu
 #endif
 
+       unsigned long           flags;          /* status flags (change with bitops) */
+#define KEY_FLAG_INSTANTIATED  0       /* set if key has been instantiated */
+#define KEY_FLAG_DEAD          1       /* set if key type has been deleted */
+#define KEY_FLAG_REVOKED       2       /* set if key had been revoked */
+#define KEY_FLAG_IN_QUOTA      3       /* set if key consumes quota */
+#define KEY_FLAG_USER_CONSTRUCT        4       /* set if key is being constructed in userspace */
+#define KEY_FLAG_NEGATIVE      5       /* set if key is negative */
+
        /* the description string
         * - this is used to match a key against search criteria
         * - this should be a printable string
@@ -196,10 +199,12 @@ extern int key_payload_reserve(struct key *key, size_t datalen);
 extern int key_instantiate_and_link(struct key *key,
                                    const void *data,
                                    size_t datalen,
-                                   struct key *keyring);
+                                   struct key *keyring,
+                                   struct key *instkey);
 extern int key_negate_and_link(struct key *key,
                               unsigned timeout,
-                              struct key *keyring);
+                              struct key *keyring,
+                              struct key *instkey);
 extern void key_revoke(struct key *key);
 extern void key_put(struct key *key);
 
@@ -242,14 +247,13 @@ extern struct key *keyring_search(struct key *keyring,
                                  struct key_type *type,
                                  const char *description);
 
-extern struct key *search_process_keyrings(struct key_type *type,
-                                          const char *description);
-
 extern int keyring_add_key(struct key *keyring,
                           struct key *key);
 
 extern struct key *key_lookup(key_serial_t id);
 
+extern void keyring_replace_payload(struct key *key, void *replacement);
+
 #define key_serial(key) ((key) ? (key)->serial : 0)
 
 /*
@@ -268,14 +272,22 @@ extern void key_fsuid_changed(struct task_struct *tsk);
 extern void key_fsgid_changed(struct task_struct *tsk);
 extern void key_init(void);
 
+#define __install_session_keyring(tsk, keyring)                        \
+({                                                             \
+       struct key *old_session = tsk->signal->session_keyring; \
+       tsk->signal->session_keyring = keyring;                 \
+       old_session;                                            \
+})
+
 #else /* CONFIG_KEYS */
 
 #define key_validate(k)                        0
 #define key_serial(k)                  0
-#define key_get(k)                     NULL
+#define key_get(k)                     ({ NULL; })
 #define key_put(k)                     do { } while(0)
 #define alloc_uid_keyring(u)           0
 #define switch_uid_keyring(u)          do { } while(0)
+#define __install_session_keyring(t, k)        ({ NULL; })
 #define copy_keys(f,t)                 0
 #define copy_thread_group_keys(t)      0
 #define exit_keys(t)                   do { } while(0)
index 381dedc370a32e4e80c597d8d2d796fbc7c65aaf..8d7c59a29e094f1e040b603496f335e8d38ec86c 100644 (file)
 #define KEY_SPEC_USER_SESSION_KEYRING  -5      /* - key ID for UID-session keyring */
 #define KEY_SPEC_GROUP_KEYRING         -6      /* - key ID for GID-specific keyring */
 
+/* request-key default keyrings */
+#define KEY_REQKEY_DEFL_NO_CHANGE              -1
+#define KEY_REQKEY_DEFL_DEFAULT                        0
+#define KEY_REQKEY_DEFL_THREAD_KEYRING         1
+#define KEY_REQKEY_DEFL_PROCESS_KEYRING                2
+#define KEY_REQKEY_DEFL_SESSION_KEYRING                3
+#define KEY_REQKEY_DEFL_USER_KEYRING           4
+#define KEY_REQKEY_DEFL_USER_SESSION_KEYRING   5
+#define KEY_REQKEY_DEFL_GROUP_KEYRING          6
+
 /* keyctl commands */
 #define KEYCTL_GET_KEYRING_ID          0       /* ask for a keyring's ID */
 #define KEYCTL_JOIN_SESSION_KEYRING    1       /* join or start named session keyring */
@@ -35,5 +45,6 @@
 #define KEYCTL_READ                    11      /* read a key or keyring's contents */
 #define KEYCTL_INSTANTIATE             12      /* instantiate a partially constructed key */
 #define KEYCTL_NEGATE                  13      /* negate a partially constructed key */
+#define KEYCTL_SET_REQKEY_KEYRING      14      /* set default request-key keyring */
 
 #endif /*  _LINUX_KEYCTL_H */
index 95d0e4b0814daa4b77b0df7b0d3e2418607726b4..e4a231549407817c285bb2a6b18c78fdcd31652f 100644 (file)
@@ -19,6 +19,7 @@
  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/stddef.h>
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/compiler.h>
@@ -34,7 +35,17 @@ static inline int request_module(const char * name, ...) { return -ENOSYS; }
 #endif
 
 #define try_then_request_module(x, mod...) ((x) ?: (request_module(mod), (x)))
-extern int call_usermodehelper(char *path, char *argv[], char *envp[], int wait);
+
+struct key;
+extern int call_usermodehelper_keys(char *path, char *argv[], char *envp[],
+                                   struct key *session_keyring, int wait);
+
+static inline int
+call_usermodehelper(char *path, char **argv, char **envp, int wait)
+{
+       return call_usermodehelper_keys(path, argv, envp, NULL, wait);
+}
+
 extern void usermodehelper_init(void);
 
 #endif /* __LINUX_KMOD_H__ */
index 5e1a7b0d7b3f7b6286d02ce6416848c1c7025118..b7a194c4362ac80056efeee5b677af75be2e85b5 100644 (file)
@@ -104,33 +104,12 @@ struct jprobe {
 };
 
 #ifdef ARCH_SUPPORTS_KRETPROBES
-extern int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs);
-extern void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs,
-                                                       unsigned long flags);
-extern struct task_struct *arch_get_kprobe_task(void *ptr);
 extern void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs);
-extern void arch_kprobe_flush_task(struct task_struct *tk);
 #else /* ARCH_SUPPORTS_KRETPROBES */
-static inline void kretprobe_trampoline(void)
-{
-}
-static inline int trampoline_probe_handler(struct kprobe *p,
-                                               struct pt_regs *regs)
-{
-       return 0;
-}
-static inline void trampoline_post_handler(struct kprobe *p,
-                               struct pt_regs *regs, unsigned long flags)
-{
-}
 static inline void arch_prepare_kretprobe(struct kretprobe *rp,
                                        struct pt_regs *regs)
 {
 }
-static inline void arch_kprobe_flush_task(struct task_struct *tk)
-{
-}
-#define arch_get_kprobe_task(ptr) ((struct task_struct *)NULL)
 #endif /* ARCH_SUPPORTS_KRETPROBES */
 /*
  * Function-return probe -
@@ -155,8 +134,8 @@ struct kretprobe_instance {
        struct hlist_node uflist; /* either on free list or used list */
        struct hlist_node hlist;
        struct kretprobe *rp;
-       void *ret_addr;
-       void *stack_addr;
+       kprobe_opcode_t *ret_addr;
+       struct task_struct *task;
 };
 
 #ifdef CONFIG_KPROBES
@@ -176,7 +155,10 @@ extern void arch_copy_kprobe(struct kprobe *p);
 extern void arch_arm_kprobe(struct kprobe *p);
 extern void arch_disarm_kprobe(struct kprobe *p);
 extern void arch_remove_kprobe(struct kprobe *p);
+extern int arch_init(void);
 extern void show_registers(struct pt_regs *regs);
+extern kprobe_opcode_t *get_insn_slot(void);
+extern void free_insn_slot(kprobe_opcode_t *slot);
 
 /* Get the kprobe at this addr (if any).  Must have called lock_kprobes */
 struct kprobe *get_kprobe(void *addr);
@@ -194,8 +176,6 @@ int register_kretprobe(struct kretprobe *rp);
 void unregister_kretprobe(struct kretprobe *rp);
 
 struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp);
-struct kretprobe_instance *get_rp_inst(void *sara);
-struct kretprobe_instance *get_rp_inst_tsk(struct task_struct *tk);
 void add_rp_inst(struct kretprobe_instance *ri);
 void kprobe_flush_task(struct task_struct *tk);
 void recycle_rp_inst(struct kretprobe_instance *ri);
index 923bdbc6d9e40da0b83a659f4e743f03a18ab851..a710bddda4ebaade343bd925bf7f9c7fb9fc20a5 100644 (file)
@@ -41,6 +41,7 @@ struct ps2dev {
 
 void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
 int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout);
+void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout);
 int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
 int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command);
 int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);
index 399b51d1721880e6eac3d8b293a140938bf7eb17..aab2db21b013e438c672dbfe4fcceb065bf578d3 100644 (file)
@@ -185,7 +185,7 @@ static inline void list_del(struct list_head *entry)
  * list_for_each_entry_rcu().
  *
  * Note that the caller is not permitted to immediately free
- * the newly deleted entry.  Instead, either synchronize_kernel()
+ * the newly deleted entry.  Instead, either synchronize_rcu()
  * or call_rcu() must be used to defer freeing until an RCU
  * grace period has elapsed.
  */
index d6eb7b2efc04301f3be2c047107b5c2e5b17056a..9b6d05172ed45ba62618a10a6b2e635105f5b3a5 100644 (file)
@@ -175,4 +175,50 @@ struct serio_device_id {
 };
 
 
+/* PCMCIA */
+
+struct pcmcia_device_id {
+       __u16           match_flags;
+
+       __u16           manf_id;
+       __u16           card_id;
+
+       __u8            func_id;
+
+       /* for real multi-function devices */
+       __u8            function;
+
+       /* for pseude multi-function devices */
+       __u8            device_no;
+
+       __u32           prod_id_hash[4];
+
+       /* not matched against in kernelspace*/
+#ifdef __KERNEL__
+       const char *    prod_id[4];
+#else
+       kernel_ulong_t  prod_id[4];
+#endif
+
+       /* not matched against */
+       kernel_ulong_t  driver_info;
+#ifdef __KERNEL__
+       char *          cisfile;
+#else
+       kernel_ulong_t  cisfile;
+#endif
+};
+
+#define PCMCIA_DEV_ID_MATCH_MANF_ID    0x0001
+#define PCMCIA_DEV_ID_MATCH_CARD_ID    0x0002
+#define PCMCIA_DEV_ID_MATCH_FUNC_ID    0x0004
+#define PCMCIA_DEV_ID_MATCH_FUNCTION   0x0008
+#define PCMCIA_DEV_ID_MATCH_PROD_ID1   0x0010
+#define PCMCIA_DEV_ID_MATCH_PROD_ID2   0x0020
+#define PCMCIA_DEV_ID_MATCH_PROD_ID3   0x0040
+#define PCMCIA_DEV_ID_MATCH_PROD_ID4   0x0080
+#define PCMCIA_DEV_ID_MATCH_DEVICE_NO  0x0100
+#define PCMCIA_DEV_ID_MATCH_FAKE_CIS   0x0200
+#define PCMCIA_DEV_ID_MATCH_ANONYMOUS  0x0400
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
index 0e432a0f4aee305945e8c7ef9513b9807424c7a1..f05372b7fe7746a48a838a310b18e3115c0e55ef 100644 (file)
@@ -51,6 +51,9 @@ struct module_attribute {
         ssize_t (*show)(struct module_attribute *, struct module *, char *);
         ssize_t (*store)(struct module_attribute *, struct module *,
                         const char *, size_t count);
+       void (*setup)(struct module *, const char *);
+       int (*test)(struct module *);
+       void (*free)(struct module *);
 };
 
 struct module_kobject
@@ -239,6 +242,8 @@ struct module
        /* Sysfs stuff. */
        struct module_kobject mkobj;
        struct module_param_attrs *param_attrs;
+       const char *version;
+       const char *srcversion;
 
        /* Exported symbols */
        const struct kernel_symbol *syms;
index 9eca1558d72f4df6fbeb97fb35a68031b1d71390..697991b69f9b6d09e7d18f087490e66b018a78d1 100644 (file)
@@ -12,7 +12,6 @@ struct namespace {
        struct rw_semaphore     sem;
 };
 
-extern void umount_tree(struct vfsmount *);
 extern int copy_namespace(int, struct task_struct *);
 extern void __put_namespace(struct namespace *namespace);
 
index d89816ad642fa0890dec4a35cada88bbd96b69c2..3a0ed7f9e8015bb3165fb1e55eaf44493d9521e2 100644 (file)
@@ -164,12 +164,6 @@ struct netif_rx_stats
        unsigned total;
        unsigned dropped;
        unsigned time_squeeze;
-       unsigned throttled;
-       unsigned fastroute_hit;
-       unsigned fastroute_success;
-       unsigned fastroute_defer;
-       unsigned fastroute_deferred_out;
-       unsigned fastroute_latency_reduction;
        unsigned cpu_collision;
 };
 
@@ -562,12 +556,9 @@ static inline int unregister_gifconf(unsigned int family)
 
 struct softnet_data
 {
-       int                     throttle;
-       int                     cng_level;
-       int                     avg_blog;
+       struct net_device       *output_queue;
        struct sk_buff_head     input_pkt_queue;
        struct list_head        poll_list;
-       struct net_device       *output_queue;
        struct sk_buff          *completion_queue;
 
        struct net_device       backlog_dev;    /* Sorry. 8) */
index 3029cad63a013b5301c9f026b9771e156f229816..27e4d164a1081bab8581957a46a293b7462477b6 100644 (file)
@@ -168,6 +168,7 @@ __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags)
        nlh->nlmsg_flags = flags;
        nlh->nlmsg_pid = pid;
        nlh->nlmsg_seq = seq;
+       memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size);
        return nlh;
 }
 
index 5bb5b2fd7ba21edb9585b6495754239cecfa7cb3..0c1c306cdaec7e77749319f68978e8785d2486dd 100644 (file)
@@ -28,7 +28,7 @@
 #define NFS4_ACCESS_DELETE      0x0010
 #define NFS4_ACCESS_EXECUTE     0x0020
 
-#define NFS4_FH_PERISTENT              0x0000
+#define NFS4_FH_PERSISTENT             0x0000
 #define NFS4_FH_NOEXPIRE_WITH_OPEN     0x0001
 #define NFS4_FH_VOLATILE_ANY           0x0002
 #define NFS4_FH_VOL_MIGRATION          0x0004
index 4bf931d5ff56097ed98d521d0af7f4e718660323..5791dfd30dd02854a9ba0b1a163c3dba75ebb9a6 100644 (file)
@@ -145,15 +145,19 @@ int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
  * NFSv4 State
  */
 #ifdef CONFIG_NFSD_V4
-int nfs4_state_init(void);
+void nfs4_state_init(void);
+int nfs4_state_start(void);
 void nfs4_state_shutdown(void);
 time_t nfs4_lease_time(void);
 void nfs4_reset_lease(time_t leasetime);
+int nfs4_reset_recoverydir(char *recdir);
 #else
-static inline int nfs4_state_init(void){return 0;}
+static inline void nfs4_state_init(void){};
+static inline int nfs4_state_start(void){return 0;}
 static inline void nfs4_state_shutdown(void){}
 static inline time_t nfs4_lease_time(void){return 0;}
 static inline void nfs4_reset_lease(time_t leasetime){}
+static inline int nfs4_reset_recoverydir(char *recdir) {return 0;}
 #endif
 
 /*
index b6b2fe1e7c63f38a70223911365bcb48d544ee98..a84a3fa99be1b03a3102677ea31a28240389d419 100644 (file)
@@ -61,11 +61,6 @@ typedef struct {
 #define si_stateownerid   si_opaque.so_stateownerid
 #define si_fileid         si_opaque.so_fileid
 
-extern stateid_t zerostateid;
-extern stateid_t onestateid;
-
-#define ZERO_STATEID(stateid)       (!memcmp((stateid), &zerostateid, sizeof(stateid_t)))
-#define ONE_STATEID(stateid)        (!memcmp((stateid), &onestateid, sizeof(stateid_t)))
 
 struct nfs4_cb_recall {
        u32                     cbr_ident;
@@ -77,8 +72,8 @@ struct nfs4_cb_recall {
 };
 
 struct nfs4_delegation {
-       struct list_head        dl_del_perfile; /* nfs4_file->fi_del_perfile */
-       struct list_head        dl_del_perclnt; /* nfs4_client->cl_del_perclnt*/
+       struct list_head        dl_perfile;
+       struct list_head        dl_perclnt;
        struct list_head        dl_recall_lru;  /* delegation recalled */
        atomic_t                dl_count;       /* ref count */
        struct nfs4_client      *dl_client;
@@ -97,7 +92,6 @@ struct nfs4_delegation {
 /* client delegation callback info */
 struct nfs4_callback {
        /* SETCLIENTID info */
-       u32                     cb_parsed;  /* addr parsed */
        u32                     cb_addr;
        unsigned short          cb_port;
        u32                     cb_prog;
@@ -109,6 +103,8 @@ struct nfs4_callback {
        struct rpc_clnt *       cb_client;
 };
 
+#define HEXDIR_LEN     33 /* hex version of 16 byte md5 of cl_name plus '\0' */
+
 /*
  * struct nfs4_client - one per client.  Clientids live here.
  *     o Each nfs4_client is hashed by clientid.
@@ -122,10 +118,11 @@ struct nfs4_callback {
 struct nfs4_client {
        struct list_head        cl_idhash;      /* hash by cl_clientid.id */
        struct list_head        cl_strhash;     /* hash by cl_name */
-       struct list_head        cl_perclient;   /* list: stateowners */
-       struct list_head        cl_del_perclnt; /* list: delegations */
+       struct list_head        cl_openowners;
+       struct list_head        cl_delegations;
        struct list_head        cl_lru;         /* tail queue */
        struct xdr_netobj       cl_name;        /* id generated by client */
+       char                    cl_recdir[HEXDIR_LEN]; /* recovery dir */
        nfs4_verifier           cl_verifier;    /* generated by client */
        time_t                  cl_time;        /* time of last lease renewal */
        u32                     cl_addr;        /* client ipaddress */
@@ -134,6 +131,7 @@ struct nfs4_client {
        nfs4_verifier           cl_confirm;     /* generated by server */
        struct nfs4_callback    cl_callback;    /* callback info */
        atomic_t                cl_count;       /* ref count */
+       u32                     cl_firststate;  /* recovery dir creation */
 };
 
 /* struct nfs4_client_reset
@@ -143,7 +141,7 @@ struct nfs4_client {
  */
 struct nfs4_client_reclaim {
        struct list_head        cr_strhash;     /* hash by cr_name */
-       struct xdr_netobj       cr_name;        /* id generated by client */
+       char                    cr_recdir[HEXDIR_LEN]; /* recover dir */
 };
 
 static inline void
@@ -197,9 +195,9 @@ struct nfs4_stateowner {
        struct kref             so_ref;
        struct list_head        so_idhash;   /* hash by so_id */
        struct list_head        so_strhash;   /* hash by op_name */
-       struct list_head        so_perclient; /* nfs4_client->cl_perclient */
-       struct list_head        so_perfilestate; /* list: nfs4_stateid */
-       struct list_head        so_perlockowner; /* nfs4_stateid->st_perlockowner */
+       struct list_head        so_perclient;
+       struct list_head        so_stateids;
+       struct list_head        so_perstateid; /* for lockowners only */
        struct list_head        so_close_lru; /* tail queue */
        time_t                  so_time; /* time of placement on so_close_lru */
        int                     so_is_open_owner; /* 1=openowner,0=lockowner */
@@ -217,9 +215,10 @@ struct nfs4_stateowner {
 *      share_acces, share_deny on the file.
 */
 struct nfs4_file {
+       struct kref             fi_ref;
        struct list_head        fi_hash;    /* hash by "struct inode *" */
-       struct list_head        fi_perfile; /* list: nfs4_stateid */
-       struct list_head        fi_del_perfile; /* list: nfs4_delegation */
+       struct list_head        fi_stateids;
+       struct list_head        fi_delegations;
        struct inode            *fi_inode;
        u32                     fi_id;      /* used with stateowner->so_id 
                                             * for stateid_hashtbl hash */
@@ -241,8 +240,8 @@ struct nfs4_file {
 struct nfs4_stateid {
        struct list_head              st_hash; 
        struct list_head              st_perfile;
-       struct list_head              st_perfilestate; 
-       struct list_head              st_perlockowner;
+       struct list_head              st_perstateowner;
+       struct list_head              st_lockowners;
        struct nfs4_stateowner      * st_stateowner;
        struct nfs4_file            * st_file;
        stateid_t                     st_stateid;
@@ -267,12 +266,9 @@ struct nfs4_stateid {
        ((err) != nfserr_stale_stateid) &&      \
        ((err) != nfserr_bad_stateid))
 
-extern time_t nfs4_laundromat(void);
 extern int nfsd4_renew(clientid_t *clid);
 extern int nfs4_preprocess_stateid_op(struct svc_fh *current_fh, 
                stateid_t *stateid, int flags, struct file **filp);
-extern int nfs4_share_conflict(struct svc_fh *current_fh, 
-               unsigned int deny_type);
 extern void nfs4_lock_state(void);
 extern void nfs4_unlock_state(void);
 extern int nfs4_in_grace(void);
@@ -282,6 +278,15 @@ extern void nfs4_free_stateowner(struct kref *kref);
 extern void nfsd4_probe_callback(struct nfs4_client *clp);
 extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
 extern void nfs4_put_delegation(struct nfs4_delegation *dp);
+extern int nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
+extern void nfsd4_init_recdir(char *recdir_name);
+extern int nfsd4_recdir_load(void);
+extern void nfsd4_shutdown_recdir(void);
+extern int nfs4_client_to_reclaim(const char *name);
+extern int nfs4_has_reclaimed_state(const char *name);
+extern void nfsd4_recdir_purge_old(void);
+extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
+extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
 
 static inline void
 nfs4_put_stateowner(struct nfs4_stateowner *so)
index a1f5ad0be1bf0a17473c36d6e057662fa6b7120b..4d24d65c0e88ae44abd098ee1b6aa25fc75f8a40 100644 (file)
@@ -210,6 +210,7 @@ struct nfsd4_open {
        u32             op_share_access;    /* request */
        u32             op_share_deny;      /* request */
        stateid_t       op_stateid;         /* response */
+       u32             op_recall;          /* recall */
        struct nfsd4_change_info  op_cinfo; /* response */
        u32             op_rflags;          /* response */
        int             op_truncate;        /* used during processing */
index 9bb7f30e923b1012d51e105a0fa4e6809a7ddd76..e82746fcad14551ab7aaf46157e3aba04c27e6b1 100644 (file)
 /* XXX from linux/nfs_idmap.h */
 #define IDMAP_NAMESZ 128
 
+#ifdef CONFIG_NFSD_V4
 void nfsd_idmap_init(void);
 void nfsd_idmap_shutdown(void);
+#else
+static inline void nfsd_idmap_init(void) {};
+static inline void nfsd_idmap_shutdown(void) {};
+#endif
 
 int nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *);
 int nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, __u32 *);
index b031e41b5e0d106d620e7184f5fafd4773ab5a06..9189829c131c3051a0b3087b1d1596dcfa292954 100644 (file)
@@ -20,8 +20,6 @@ extern void __nvram_write_byte(unsigned char c, int i);
 extern void nvram_write_byte(unsigned char c, int i);
 extern int __nvram_check_checksum(void);
 extern int nvram_check_checksum(void);
-extern void __nvram_set_checksum(void);
-extern void nvram_set_checksum(void);
 #endif
 
 #endif  /* _LINUX_NVRAM_H */
index b5238bd188302be2bf941a11594a61814c40120f..66798b46f3081e33d2a2aa7bc03fb3fb6aef2ba1 100644 (file)
@@ -734,16 +734,20 @@ void pcibios_update_irq(struct pci_dev *, int irq);
 /* Generic PCI functions used internally */
 
 extern struct pci_bus *pci_find_bus(int domain, int busnr);
+void pci_bus_add_devices(struct pci_bus *bus);
 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)
 {
-       return pci_scan_bus_parented(NULL, bus, ops, sysdata);
+       struct pci_bus *root_bus;
+       root_bus = pci_scan_bus_parented(NULL, bus, ops, sysdata);
+       if (root_bus)
+               pci_bus_add_devices(root_bus);
+       return root_bus;
 }
 int pci_scan_slot(struct pci_bus *bus, int devfn);
 struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn);
 unsigned int pci_scan_child_bus(struct pci_bus *bus);
 void pci_bus_add_device(struct pci_dev *dev);
-void pci_bus_add_devices(struct pci_bus *bus);
 void pci_name_device(struct pci_dev *dev);
 char *pci_class_name(u32 class);
 void pci_read_bridge_bases(struct pci_bus *child);
@@ -870,6 +874,15 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass
 #define        pci_pool_alloc(pool, flags, handle) dma_pool_alloc(pool, flags, handle)
 #define        pci_pool_free(pool, vaddr, addr) dma_pool_free(pool, vaddr, addr)
 
+enum pci_dma_burst_strategy {
+       PCI_DMA_BURST_INFINITY, /* make bursts as large as possible,
+                                  strategy_parameter is N/A */
+       PCI_DMA_BURST_BOUNDARY, /* disconnect at every strategy_parameter
+                                  byte boundaries */
+       PCI_DMA_BURST_MULTIPLE, /* disconnect at some multiple of
+                                  strategy_parameter byte boundaries */
+};
+
 #if defined(CONFIG_ISA) || defined(CONFIG_EISA)
 extern struct pci_dev *isa_bridge;
 #endif
@@ -972,6 +985,8 @@ static inline int pci_proc_domain(struct pci_bus *bus)
 }
 #endif
 
+#define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0)
+
 #endif /* !CONFIG_PCI */
 
 /* these helpers provide future and backwards compatibility
@@ -1016,6 +1031,20 @@ static inline char *pci_name(struct pci_dev *pdev)
 #define pci_pretty_name(dev) ""
 #endif
 
+
+/* Some archs don't want to expose struct resource to userland as-is
+ * in sysfs and /proc
+ */
+#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, u64 *start, u64 *end)
+{
+       *start = rsrc->start;
+       *end = rsrc->end;
+}
+#endif /* HAVE_ARCH_PCI_RESOURCE_TO_USER */
+
+
 /*
  *  The world is not perfect and supplies us with broken PCI devices.
  *  For at least a part of these bugs we need a work-around, so both
index 63e89e47b8e98b118bd7f8f088ea2f54c2ec37a9..c3ee1ae4545a9fa2a0038bda58308f08af8e72ab 100644 (file)
@@ -62,6 +62,8 @@
 
 #define PCI_BASE_CLASS_SYSTEM          0x08
 #define PCI_CLASS_SYSTEM_PIC           0x0800
+#define PCI_CLASS_SYSTEM_PIC_IOAPIC    0x080010
+#define PCI_CLASS_SYSTEM_PIC_IOXAPIC   0x080020
 #define PCI_CLASS_SYSTEM_DMA           0x0801
 #define PCI_CLASS_SYSTEM_TIMER         0x0802
 #define PCI_CLASS_SYSTEM_RTC           0x0803
 #define PCI_DEVICE_ID_HP_DIVA_AUX      0x1290
 #define PCI_DEVICE_ID_HP_DIVA_RMP3     0x1301
 #define PCI_DEVICE_ID_HP_CISSA         0x3220
-#define PCI_DEVICE_ID_HP_CISSB         0x3230
+#define PCI_DEVICE_ID_HP_CISSB         0x3222
 #define PCI_DEVICE_ID_HP_ZX2_IOC       0x4031
+#define PCI_DEVICE_ID_HP_CISSC         0x3230
 
 #define PCI_VENDOR_ID_PCTECH           0x1042
 #define PCI_DEVICE_ID_PCTECH_RZ1000    0x1000
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2    0x0348
 #define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000       0x034C
 #define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100         0x034E
+#define PCI_DEVICE_ID_NVIDIA_NVENET_14              0x0372
+#define PCI_DEVICE_ID_NVIDIA_NVENET_15              0x0373
 
 #define PCI_VENDOR_ID_IMS              0x10e0
 #define PCI_DEVICE_ID_IMS_8849         0x8849
 #define PCI_DEVICE_ID_SERVERWORKS_OSB4USB 0x0220
 #define PCI_DEVICE_ID_SERVERWORKS_CSB5USB PCI_DEVICE_ID_SERVERWORKS_OSB4USB
 #define PCI_DEVICE_ID_SERVERWORKS_CSB6USB 0x0221
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227
 #define PCI_DEVICE_ID_SERVERWORKS_GCLE    0x0225
 #define PCI_DEVICE_ID_SERVERWORKS_GCLE2   0x0227
 #define PCI_DEVICE_ID_SERVERWORKS_CSB5ISA 0x0230
 #define PCI_VENDOR_ID_ITE              0x1283
 #define PCI_DEVICE_ID_ITE_IT8172G      0x8172
 #define PCI_DEVICE_ID_ITE_IT8172G_AUDIO 0x0801
+#define PCI_DEVICE_ID_ITE_8211         0x8211
+#define PCI_DEVICE_ID_ITE_8212         0x8212
 #define PCI_DEVICE_ID_ITE_8872         0x8872
 #define PCI_DEVICE_ID_ITE_IT8330G_0    0xe886
 
index d2aa214d68032fb2d70c51b939257cf762f32e21..bd2c5a2bbbf523596130be188879d81238424705 100644 (file)
@@ -276,6 +276,7 @@ struct tc_rsvp_pinfo
        __u8    protocol;
        __u8    tunnelid;
        __u8    tunnelhdr;
+       __u8    pad;
 };
 
 /* ROUTE filter */
@@ -408,6 +409,7 @@ enum
        TCF_EM_NBYTE,
        TCF_EM_U32,
        TCF_EM_META,
+       TCF_EM_TEXT,
        __TCF_EM_MAX
 };
 
index 1d9da36eb9db2f76488f1cdb86acf320809172f1..60ffcb9c5791aef695ce0a48f02f66057ec06c88 100644 (file)
@@ -221,9 +221,11 @@ struct tc_gred_qopt
 /* gred setup */
 struct tc_gred_sopt
 {
-       __u32           DPs;
-       __u32           def_DP;
-       __u8            grio;
+       __u32           DPs;
+       __u32           def_DP;
+       __u8            grio;
+       __u8            pad1;
+       __u16           pad2;
 };
 
 /* HTB section */
@@ -351,6 +353,7 @@ struct tc_cbq_ovl
 #define        TC_CBQ_OVL_DROP         3
 #define        TC_CBQ_OVL_RCLASSIC     4
        unsigned char   priority2;
+       __u16           pad;
        __u32           penalty;
 };
 
index ed2b76e75199256e0ad037a5db8ff10966eaa67f..14479325e3f38d35a8e4ca36835254bbcb376114 100644 (file)
@@ -103,7 +103,8 @@ extern int pm_active;
 /*
  * Register a device with power management
  */
-struct pm_dev __deprecated *pm_register(pm_dev_t type, unsigned long id, pm_callback callback);
+struct pm_dev __deprecated *
+pm_register(pm_dev_t type, unsigned long id, pm_callback callback);
 
 /*
  * Unregister a device with power management
@@ -190,17 +191,18 @@ typedef u32 __bitwise pm_message_t;
 /*
  * There are 4 important states driver can be in:
  * ON     -- driver is working
- * FREEZE -- stop operations and apply whatever policy is applicable to a suspended driver
- *           of that class, freeze queues for block like IDE does, drop packets for
- *           ethernet, etc... stop DMA engine too etc... so a consistent image can be
- *           saved; but do not power any hardware down.
- * SUSPEND - like FREEZE, but hardware is doing as much powersaving as possible. Roughly
- *           pci D3.
+ * FREEZE -- stop operations and apply whatever policy is applicable to a
+ *           suspended driver of that class, freeze queues for block like IDE
+ *           does, drop packets for ethernet, etc... stop DMA engine too etc...
+ *           so a consistent image can be saved; but do not power any hardware
+ *           down.
+ * SUSPEND - like FREEZE, but hardware is doing as much powersaving as
+ *           possible. Roughly pci D3.
  *
- * Unfortunately, current drivers only recognize numeric values 0 (ON) and 3 (SUSPEND).
- * We'll need to fix the drivers. So yes, putting 3 to all diferent defines is intentional,
- * and will go away as soon as drivers are fixed. Also note that typedef is neccessary,
- * we'll probably want to switch to
+ * Unfortunately, current drivers only recognize numeric values 0 (ON) and 3
+ * (SUSPEND).  We'll need to fix the drivers. So yes, putting 3 to all different
+ * defines is intentional, and will go away as soon as drivers are fixed.  Also
+ * note that typedef is neccessary, we'll probably want to switch to
  *   typedef struct pm_message_t { int event; int flags; } pm_message_t
  * or something similar soon.
  */
@@ -222,11 +224,18 @@ struct dev_pm_info {
 
 extern void device_pm_set_parent(struct device * dev, struct device * parent);
 
-extern int device_suspend(pm_message_t state);
 extern int device_power_down(pm_message_t state);
 extern void device_power_up(void);
 extern void device_resume(void);
 
+#ifdef CONFIG_PM
+extern int device_suspend(pm_message_t state);
+#else
+static inline int device_suspend(pm_message_t state)
+{
+       return 0;
+}
+#endif
 
 #endif /* __KERNEL__ */
 
index 6d73eada277e34acb74391ba5b0eb323e4707679..373bd3b9b330f2db82c06d3ef59ec0f9e1829834 100644 (file)
@@ -166,7 +166,7 @@ extern int pmu_i2c_simple_read(int bus, int addr,  u8* data, int len);
 extern int pmu_i2c_simple_write(int bus, int addr,  u8* data, int len);
 
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 /*
  * Stuff for putting the powerbook to sleep and waking it again.
  *
@@ -208,6 +208,8 @@ struct pmu_sleep_notifier
 int pmu_register_sleep_notifier(struct pmu_sleep_notifier* notifier);
 int pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* notifier);
 
+#endif /* CONFIG_PM */
+
 #define PMU_MAX_BATTERIES      2
 
 /* values for pmu_power_flags */
@@ -235,6 +237,4 @@ extern int pmu_battery_count;
 extern struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
 extern unsigned int pmu_power_flags;
 
-#endif /* CONFIG_PMAC_PBOOK */
-
 #endif /* __KERNEL__ */
index 59e505261fd677deb989ada1ca68b5f57af71319..0563581e3a0289b7c4ff9ce2868609cf2d39dda4 100644 (file)
@@ -74,6 +74,13 @@ struct kcore_list {
        size_t size;
 };
 
+struct vmcore {
+       struct list_head list;
+       unsigned long long paddr;
+       unsigned long size;
+       loff_t offset;
+};
+
 #ifdef CONFIG_PROC_FS
 
 extern struct proc_dir_entry proc_root;
index 22ba580b0ae89045d54f2b262f2e67437dbbc12e..fc610bb0f73397421ba88804236d950a2a4d9c7d 100644 (file)
@@ -46,11 +46,11 @@ struct qnx4_inode_entry {
        char            di_fname[QNX4_SHORT_NAME_MAX];
        qnx4_off_t      di_size;
        qnx4_xtnt_t     di_first_xtnt;
-       __u32           di_xblk;
-       __s32           di_ftime;
-       __s32           di_mtime;
-       __s32           di_atime;
-       __s32           di_ctime;
+       __le32          di_xblk;
+       __le32          di_ftime;
+       __le32          di_mtime;
+       __le32          di_atime;
+       __le32          di_ctime;
        qnx4_nxtnt_t    di_num_xtnts;
        qnx4_mode_t     di_mode;
        qnx4_muid_t     di_uid;
@@ -63,18 +63,18 @@ struct qnx4_inode_entry {
 
 struct qnx4_link_info {
        char            dl_fname[QNX4_NAME_MAX];
-       __u32           dl_inode_blk;
+       __le32          dl_inode_blk;
        __u8            dl_inode_ndx;
        __u8            dl_spare[10];
        __u8            dl_status;
 };
 
 struct qnx4_xblk {
-       __u32           xblk_next_xblk;
-       __u32           xblk_prev_xblk;
+       __le32          xblk_next_xblk;
+       __le32          xblk_prev_xblk;
        __u8            xblk_num_xtnts;
        __u8            xblk_spare[3];
-       __s32           xblk_num_blocks;
+       __le32          xblk_num_blocks;
        qnx4_xtnt_t     xblk_xtnts[QNX4_MAX_XTNTS_PER_XBLK];
        char            xblk_signature[8];
        qnx4_xtnt_t     xblk_first_xtnt;
index fb518e318c7c6209c57240a4a9517375884c3c9f..a3eb1137857b15ab616ab6a5e1352fe7e5a87eaf 100644 (file)
 #ifndef _QNX4TYPES_H
 #define _QNX4TYPES_H
 
-typedef __u16 qnx4_nxtnt_t;
+typedef __le16 qnx4_nxtnt_t;
 typedef __u8  qnx4_ftype_t;
 
 typedef struct {
-       __u32 xtnt_blk;
-       __u32 xtnt_size;
+       __le32 xtnt_blk;
+       __le32 xtnt_size;
 } qnx4_xtnt_t;
 
-typedef __u16 qnx4_mode_t;
-typedef __u16 qnx4_muid_t;
-typedef __u16 qnx4_mgid_t;
-typedef __u32 qnx4_off_t;
-typedef __u16 qnx4_nlink_t;
+typedef __le16 qnx4_mode_t;
+typedef __le16 qnx4_muid_t;
+typedef __le16 qnx4_mgid_t;
+typedef __le32 qnx4_off_t;
+typedef __le16 qnx4_nlink_t;
 
 #endif
index ac5b90f4f25645dd241665220fc248573a42e284..700ead45084fd4694ec5925bf318aa4ad0634621 100644 (file)
@@ -138,8 +138,11 @@ struct if_dqinfo {
 #include <linux/dqblk_v2.h>
 
 /* Maximal numbers of writes for quota operation (insert/delete/update)
- * (over all formats) - info block, 4 pointer blocks, data block */
-#define DQUOT_MAX_WRITES       6
+ * (over VFS all formats) */
+#define DQUOT_INIT_ALLOC max(V1_INIT_ALLOC, V2_INIT_ALLOC)
+#define DQUOT_INIT_REWRITE max(V1_INIT_REWRITE, V2_INIT_REWRITE)
+#define DQUOT_DEL_ALLOC max(V1_DEL_ALLOC, V2_DEL_ALLOC)
+#define DQUOT_DEL_REWRITE max(V1_DEL_REWRITE, V2_DEL_REWRITE)
 
 /*
  * Data for one user/group kept in memory
index d60fafc8bdc584e73662a1e51f2876b09b13c9f1..2d4dd23168dd2dac2470f3d169742cd297975bc2 100644 (file)
@@ -51,6 +51,10 @@ extern void machine_restart(char *cmd);
 extern void machine_halt(void);
 extern void machine_power_off(void);
 
+extern void machine_shutdown(void);
+struct pt_regs;
+extern void machine_crash_shutdown(struct pt_regs *);
+
 #endif
 
 #endif /* _LINUX_REBOOT_H */
index 32148625fc2f0b025a9070fc93650c2fd84903dc..4c7c5689ad9357d096d99403157d19ab009b9545 100644 (file)
@@ -1644,11 +1644,18 @@ struct reiserfs_journal_header {
 #define JOURNAL_MAX_TRANS_AGE 30
 #define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9)
 #ifdef CONFIG_QUOTA
-#define REISERFS_QUOTA_TRANS_BLOCKS 2  /* We need to update data and inode (atime) */
-#define REISERFS_QUOTA_INIT_BLOCKS (DQUOT_MAX_WRITES*(JOURNAL_PER_BALANCE_CNT+2)+1)    /* 1 balancing, 1 bitmap, 1 data per write + stat data update */
+/* We need to update data and inode (atime) */
+#define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? 2 : 0)
+/* 1 balancing, 1 bitmap, 1 data per write + stat data update */
+#define REISERFS_QUOTA_INIT_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? \
+(DQUOT_INIT_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_INIT_REWRITE+1) : 0)
+/* same as with INIT */
+#define REISERFS_QUOTA_DEL_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? \
+(DQUOT_DEL_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_DEL_REWRITE+1) : 0)
 #else
-#define REISERFS_QUOTA_TRANS_BLOCKS 0
-#define REISERFS_QUOTA_INIT_BLOCKS 0
+#define REISERFS_QUOTA_TRANS_BLOCKS(s) 0
+#define REISERFS_QUOTA_INIT_BLOCKS(s) 0
+#define REISERFS_QUOTA_DEL_BLOCKS(s) 0
 #endif
 
 /* both of these can be as low as 1, or as high as you want.  The min is the
index 37a3a7afbec7e100daa5d05ca08220c4edccc87d..31c709d0fe18d5cb4a69672a45e42ab45f94271e 100644 (file)
@@ -467,6 +467,8 @@ enum reiserfs_mount_options {
     REISERFS_ERROR_RO,
     REISERFS_ERROR_CONTINUE,
 
+    REISERFS_QUOTA,            /* Some quota option specified */
+
     REISERFS_TEST1,
     REISERFS_TEST2,
     REISERFS_TEST3,
index 11b484e37ac94fcd2308a354d372f00faff8a736..e80fb7ee6efdf5617f49f439ac4eafe28e86dfc1 100644 (file)
@@ -92,6 +92,12 @@ static inline void page_dup_rmap(struct page *page)
 int page_referenced(struct page *, int is_locked, int ignore_token);
 int try_to_unmap(struct page *);
 
+/*
+ * Called from mm/filemap_xip.c to unmap empty zero page
+ */
+pte_t *page_check_address(struct page *, struct mm_struct *, unsigned long);
+
+
 /*
  * Used by swapoff to help locate where page is expected in vma.
  */
index e68dbf0bf5791f1e0a4e08098fdbf2e9995195e1..657c05ab8f9eb79c63422d495f105e7c91bb489b 100644 (file)
@@ -363,6 +363,8 @@ enum
 struct rta_session
 {
        __u8    proto;
+       __u8    pad1;
+       __u16   pad2;
 
        union {
                struct {
@@ -635,10 +637,13 @@ struct ifinfomsg
 struct prefixmsg
 {
        unsigned char   prefix_family;
+       unsigned char   prefix_pad1;
+       unsigned short  prefix_pad2;
        int             prefix_ifindex;
        unsigned char   prefix_type;
        unsigned char   prefix_len;
        unsigned char   prefix_flags;
+       unsigned char   prefix_pad3;
 };
 
 enum 
@@ -892,10 +897,15 @@ extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const voi
                 goto rtattr_failure; \
        __rta_fill(skb, attrtype, attrlen, data); }) 
 
-#define RTA_PUT_NOHDR(skb, attrlen, data) \
+#define RTA_APPEND(skb, attrlen, data) \
 ({     if (unlikely(skb_tailroom(skb) < (int)(attrlen))) \
                goto rtattr_failure; \
-       memcpy(skb_put(skb, RTA_ALIGN(attrlen)), data, attrlen); })
+       memcpy(skb_put(skb, attrlen), data, attrlen); })
+
+#define RTA_PUT_NOHDR(skb, attrlen, data) \
+({     RTA_APPEND(skb, RTA_ALIGN(attrlen), data); \
+       memset(skb->tail - (RTA_ALIGN(attrlen) - attrlen), 0, \
+              RTA_ALIGN(attrlen) - attrlen); })
 
 #define RTA_PUT_U8(skb, attrtype, value) \
 ({     u8 _tmp = (value); \
@@ -975,6 +985,7 @@ __rta_reserve(struct sk_buff *skb, int attrtype, int attrlen)
        rta = (struct rtattr*)skb_put(skb, RTA_ALIGN(size));
        rta->rta_type = attrtype;
        rta->rta_len = size;
+       memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size);
        return rta;
 }
 
index 901742f92389f273723ecad9767768bdd3fff293..ff48815bd3a2374600b0fce516f48ce3941599b1 100644 (file)
@@ -368,6 +368,11 @@ struct signal_struct {
 #endif
 };
 
+/* Context switch must be unlocked if interrupts are to be enabled */
+#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
+# define __ARCH_WANT_UNLOCKED_CTXSW
+#endif
+
 /*
  * Bits in flags field of signal_struct.
  */
@@ -460,10 +465,11 @@ enum idle_type
 #define SD_LOAD_BALANCE                1       /* Do load balancing on this domain. */
 #define SD_BALANCE_NEWIDLE     2       /* Balance when about to become idle */
 #define SD_BALANCE_EXEC                4       /* Balance on exec */
-#define SD_WAKE_IDLE           8       /* Wake to idle CPU on task wakeup */
-#define SD_WAKE_AFFINE         16      /* Wake task to waking CPU */
-#define SD_WAKE_BALANCE                32      /* Perform balancing at task wakeup */
-#define SD_SHARE_CPUPOWER      64      /* Domain members share cpu power */
+#define SD_BALANCE_FORK                8       /* Balance on fork, clone */
+#define SD_WAKE_IDLE           16      /* Wake to idle CPU on task wakeup */
+#define SD_WAKE_AFFINE         32      /* Wake task to waking CPU */
+#define SD_WAKE_BALANCE                64      /* Perform balancing at task wakeup */
+#define SD_SHARE_CPUPOWER      128     /* Domain members share cpu power */
 
 struct sched_group {
        struct sched_group *next;       /* Must be a circular list */
@@ -488,6 +494,11 @@ struct sched_domain {
        unsigned long long cache_hot_time; /* Task considered cache hot (ns) */
        unsigned int cache_nice_tries;  /* Leave cache hot tasks for # tries */
        unsigned int per_cpu_gain;      /* CPU % gained by adding domain cpus */
+       unsigned int busy_idx;
+       unsigned int idle_idx;
+       unsigned int newidle_idx;
+       unsigned int wake_idx;
+       unsigned int forkexec_idx;
        int flags;                      /* See SD_* */
 
        /* Runtime fields. */
@@ -511,10 +522,16 @@ struct sched_domain {
        unsigned long alb_failed;
        unsigned long alb_pushed;
 
-       /* sched_balance_exec() stats */
-       unsigned long sbe_attempts;
+       /* SD_BALANCE_EXEC stats */
+       unsigned long sbe_cnt;
+       unsigned long sbe_balanced;
        unsigned long sbe_pushed;
 
+       /* SD_BALANCE_FORK stats */
+       unsigned long sbf_cnt;
+       unsigned long sbf_balanced;
+       unsigned long sbf_pushed;
+
        /* try_to_wake_up() stats */
        unsigned long ttwu_wake_remote;
        unsigned long ttwu_move_affine;
@@ -522,6 +539,8 @@ struct sched_domain {
 #endif
 };
 
+extern void partition_sched_domains(cpumask_t *partition1,
+                                   cpumask_t *partition2);
 #ifdef ARCH_HAS_SCHED_DOMAIN
 /* Useful helpers that arch setup code may use. Defined in kernel/sched.c */
 extern cpumask_t cpu_isolated_map;
@@ -561,9 +580,10 @@ struct group_info {
                groups_free(group_info); \
 } while (0)
 
-struct group_info *groups_alloc(int gidsetsize);
-void groups_free(struct group_info *group_info);
-int set_current_groups(struct group_info *group_info);
+extern struct group_info *groups_alloc(int gidsetsize);
+extern void groups_free(struct group_info *group_info);
+extern int set_current_groups(struct group_info *group_info);
+extern int groups_search(struct group_info *group_info, gid_t grp);
 /* access the groups "array" with this macro */
 #define GROUP_AT(gi, i) \
     ((gi)->blocks[(i)/NGROUPS_PER_BLOCK][(i)%NGROUPS_PER_BLOCK])
@@ -581,10 +601,15 @@ struct task_struct {
 
        int lock_depth;         /* BKL lock depth */
 
+#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
+       int oncpu;
+#endif
        int prio, static_prio;
        struct list_head run_list;
        prio_array_t *array;
 
+       unsigned short ioprio;
+
        unsigned long sleep_avg;
        unsigned long long timestamp, last_ran;
        unsigned long long sched_time; /* sched_clock time spent running */
@@ -660,6 +685,7 @@ struct task_struct {
        struct user_struct *user;
 #ifdef CONFIG_KEYS
        struct key *thread_keyring;     /* keyring private to this thread */
+       unsigned char jit_keyring;      /* default keyring to attach requested keys to */
 #endif
        int oomkilladj; /* OOM kill score adjustment (bit shift). */
        char comm[TASK_COMM_LEN]; /* executable name excluding path
@@ -702,8 +728,6 @@ struct task_struct {
        spinlock_t alloc_lock;
 /* Protection of proc_dentry: nesting proc_lock, dcache_lock, write_lock_irq(&tasklist_lock); */
        spinlock_t proc_lock;
-/* context-switch lock */
-       spinlock_t switch_lock;
 
 /* journalling filesystem info */
        void *journal_info;
@@ -741,6 +765,7 @@ struct task_struct {
        nodemask_t mems_allowed;
        int cpuset_mems_generation;
 #endif
+       atomic_t fs_excl;       /* holding fs exclusive resources */
 };
 
 static inline pid_t process_group(struct task_struct *tsk)
@@ -910,7 +935,7 @@ extern void FASTCALL(wake_up_new_task(struct task_struct * tsk,
 #else
  static inline void kick_process(struct task_struct *tsk) { }
 #endif
-extern void FASTCALL(sched_fork(task_t * p));
+extern void FASTCALL(sched_fork(task_t * p, int clone_flags));
 extern void FASTCALL(sched_exit(task_t * p));
 
 extern int in_group_p(gid_t);
@@ -1090,7 +1115,8 @@ extern void unhash_process(struct task_struct *p);
 
 /*
  * Protects ->fs, ->files, ->mm, ->ptrace, ->group_info, ->comm, keyring
- * subscriptions and synchronises with wait4().  Also used in procfs.
+ * subscriptions and synchronises with wait4().  Also used in procfs.  Also
+ * pins the final release of task.io_context.
  *
  * Nests both inside and outside of read_lock(&tasklist_lock).
  * It must not be nested with write_lock_irq(&tasklist_lock),
@@ -1243,33 +1269,78 @@ extern void normalize_rt_tasks(void);
 
 #endif
 
-/* try_to_freeze
- *
- * Checks whether we need to enter the refrigerator
- * and returns 1 if we did so.
- */
 #ifdef CONFIG_PM
-extern void refrigerator(unsigned long);
+/*
+ * Check if a process has been frozen
+ */
+static inline int frozen(struct task_struct *p)
+{
+       return p->flags & PF_FROZEN;
+}
+
+/*
+ * Check if there is a request to freeze a process
+ */
+static inline int freezing(struct task_struct *p)
+{
+       return p->flags & PF_FREEZE;
+}
+
+/*
+ * Request that a process be frozen
+ * FIXME: SMP problem. We may not modify other process' flags!
+ */
+static inline void freeze(struct task_struct *p)
+{
+       p->flags |= PF_FREEZE;
+}
+
+/*
+ * Wake up a frozen process
+ */
+static inline int thaw_process(struct task_struct *p)
+{
+       if (frozen(p)) {
+               p->flags &= ~PF_FROZEN;
+               wake_up_process(p);
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * freezing is complete, mark process as frozen
+ */
+static inline void frozen_process(struct task_struct *p)
+{
+       p->flags = (p->flags & ~PF_FREEZE) | PF_FROZEN;
+}
+
+extern void refrigerator(void);
 extern int freeze_processes(void);
 extern void thaw_processes(void);
 
-static inline int try_to_freeze(unsigned long refrigerator_flags)
+static inline int try_to_freeze(void)
 {
-       if (unlikely(current->flags & PF_FREEZE)) {
-               refrigerator(refrigerator_flags);
+       if (freezing(current)) {
+               refrigerator();
                return 1;
        } else
                return 0;
 }
 #else
-static inline void refrigerator(unsigned long flag) {}
+static inline int frozen(struct task_struct *p) { return 0; }
+static inline int freezing(struct task_struct *p) { return 0; }
+static inline void freeze(struct task_struct *p) { BUG(); }
+static inline int thaw_process(struct task_struct *p) { return 1; }
+static inline void frozen_process(struct task_struct *p) { BUG(); }
+
+static inline void refrigerator(void) {}
 static inline int freeze_processes(void) { BUG(); return 0; }
 static inline void thaw_processes(void) {}
 
-static inline int try_to_freeze(unsigned long refrigerator_flags)
-{
-       return 0;
-}
+static inline int try_to_freeze(void) { return 0; }
+
 #endif /* CONFIG_PM */
 #endif /* __KERNEL__ */
 
index 3a2702bbb1d67dc177544c294db50677a50015e4..dc89116bb1ca997bef56f6e938f4f6080ee4f878 100644 (file)
@@ -19,6 +19,11 @@ static inline void secure_computing(int this_syscall)
                __secure_computing(this_syscall);
 }
 
+static inline int has_secure_computing(struct thread_info *ti)
+{
+       return unlikely(test_ti_thread_flag(ti, TIF_SECCOMP));
+}
+
 #else /* CONFIG_SECCOMP */
 
 #if (__GNUC__ > 2)
@@ -28,6 +33,11 @@ static inline void secure_computing(int this_syscall)
 #endif
 
 #define secure_computing(x) do { } while (0)
+/* static inline to preserve typechecking */
+static inline int has_secure_computing(struct thread_info *ti)
+{
+       return 0;
+}
 
 #endif /* CONFIG_SECCOMP */
 
index 823181af6ddfbfec26e3c42af6c19599f8d69745..3e3c1fa35b06cc2eafa509f2cf1d2b4dcf04e7e4 100644 (file)
@@ -22,6 +22,7 @@ struct plat_serial8250_port {
        unsigned int    uartclk;        /* UART clock rate */
        unsigned char   regshift;       /* register shift */
        unsigned char   iotype;         /* UPIO_* */
+       unsigned char   hub6;
        unsigned int    flags;          /* UPF_* flags */
 };
 
index a2d3b9ae06f4976439edd8045e714435849b27aa..aa4d6493a034b605d429bf237fd9a37c36fe9fff 100644 (file)
@@ -83,6 +83,7 @@ static inline void serio_register_port(struct serio *serio)
 }
 
 void serio_unregister_port(struct serio *serio);
+void serio_unregister_child_port(struct serio *serio);
 void __serio_unregister_port_delayed(struct serio *serio, struct module *owner);
 static inline void serio_unregister_port_delayed(struct serio *serio)
 {
@@ -153,6 +154,11 @@ static inline int serio_pin_driver(struct serio *serio)
        return down_interruptible(&serio->drv_sem);
 }
 
+static inline void serio_pin_driver_uninterruptible(struct serio *serio)
+{
+       down(&serio->drv_sem);
+}
+
 static inline void serio_unpin_driver(struct serio *serio)
 {
        up(&serio->drv_sem);
index d7c839a21842ca03f360a0e16320bab6c8253f76..416a2e4024b21b082a573740052002e815e6bd10 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/highmem.h>
 #include <linux/poll.h>
 #include <linux/net.h>
+#include <linux/textsearch.h>
 #include <net/checksum.h>
 
 #define HAVE_ALLOC_SKB         /* For the drivers to know */
@@ -321,6 +322,28 @@ extern void              skb_over_panic(struct sk_buff *skb, int len,
 extern void          skb_under_panic(struct sk_buff *skb, int len,
                                      void *here);
 
+struct skb_seq_state
+{
+       __u32           lower_offset;
+       __u32           upper_offset;
+       __u32           frag_idx;
+       __u32           stepped_offset;
+       struct sk_buff  *root_skb;
+       struct sk_buff  *cur_skb;
+       __u8            *frag_data;
+};
+
+extern void          skb_prepare_seq_read(struct sk_buff *skb,
+                                          unsigned int from, unsigned int to,
+                                          struct skb_seq_state *st);
+extern unsigned int   skb_seq_read(unsigned int consumed, const u8 **data,
+                                  struct skb_seq_state *st);
+extern void          skb_abort_seq_read(struct skb_seq_state *st);
+
+extern unsigned int   skb_find_text(struct sk_buff *skb, unsigned int from,
+                                   unsigned int to, struct ts_config *config,
+                                   struct ts_state *state);
+
 /* Internal */
 #define skb_shinfo(SKB)                ((struct skb_shared_info *)((SKB)->end))
 
index 2bf0d5fabcdb9592adfa3f182ba5a90ad5aa5782..f2e96fdfaae01604e207fc9362f55d9286b1b95c 100644 (file)
@@ -58,7 +58,7 @@ static inline int software_suspend(void)
 }
 #endif
 
-#ifdef CONFIG_SMP
+#ifdef CONFIG_SUSPEND_SMP
 extern void disable_nonboot_cpus(void);
 extern void enable_nonboot_cpus(void);
 #else
index c39f6f72cbbc3f0a53ae8e8a31b0749e2c8ea747..52830b6d94e5c8fc926f291452b29bef4dcee91e 100644 (file)
@@ -159,8 +159,9 @@ asmlinkage long sys_shutdown(int, int);
 asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd,
                                void __user *arg);
 asmlinkage long sys_restart_syscall(void);
-asmlinkage long sys_kexec_load(void *entry, unsigned long nr_segments,
-                       struct kexec_segment *segments, unsigned long flags);
+asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments,
+                               struct kexec_segment __user *segments,
+                               unsigned long flags);
 
 asmlinkage long sys_exit(int error_code);
 asmlinkage void sys_exit_group(int error_code);
index 72965bfe6cfb97e3fe375bdc886f399df505a7df..5b5f434ac9a08e96634564ae77a06f1dfe570fda 100644 (file)
@@ -243,6 +243,7 @@ enum
        NET_CORE_MOD_CONG=16,
        NET_CORE_DEV_WEIGHT=17,
        NET_CORE_SOMAXCONN=18,
+       NET_CORE_BUDGET=19,
 };
 
 /* /proc/sys/net/ethernet */
@@ -640,6 +641,7 @@ enum {
        NET_SCTP_ADDIP_ENABLE            = 13,
        NET_SCTP_PRSCTP_ENABLE           = 14,
        NET_SCTP_SNDBUF_POLICY           = 15,
+       NET_SCTP_SACK_TIMEOUT            = 16,
 };
 
 /* /proc/sys/net/bridge */
diff --git a/include/linux/tc_ematch/tc_em_text.h b/include/linux/tc_ematch/tc_em_text.h
new file mode 100644 (file)
index 0000000..7cd43e9
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __LINUX_TC_EM_TEXT_H
+#define __LINUX_TC_EM_TEXT_H
+
+#include <linux/pkt_cls.h>
+
+#define TC_EM_TEXT_ALGOSIZ     16
+
+struct tcf_em_text
+{
+       char            algo[TC_EM_TEXT_ALGOSIZ];
+       __u16           from_offset;
+       __u16           to_offset;
+       __u16           pattern_len;
+       __u8            from_layer:4;
+       __u8            to_layer:4;
+       __u8            pad;
+};
+
+#endif
index 3ea75dd6640a8cb825dd69c9c9718cb6fd2f23f8..dfd93d03f5d28df6bd112e590ae30c43a2f32a85 100644 (file)
@@ -127,6 +127,7 @@ enum {
 #define TCP_WINDOW_CLAMP       10      /* Bound advertised window */
 #define TCP_INFO               11      /* Information about this connection. */
 #define TCP_QUICKACK           12      /* Block/reenable quick acks */
+#define TCP_CONGESTION         13      /* Congestion control algorithm */
 
 #define TCPI_OPT_TIMESTAMPS    1
 #define TCPI_OPT_SACK          2
diff --git a/include/linux/textsearch.h b/include/linux/textsearch.h
new file mode 100644 (file)
index 0000000..941f45a
--- /dev/null
@@ -0,0 +1,180 @@
+#ifndef __LINUX_TEXTSEARCH_H
+#define __LINUX_TEXTSEARCH_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+struct ts_config;
+
+/**
+ * TS_AUTOLOAD - Automatically load textsearch modules when needed
+ */
+#define TS_AUTOLOAD    1
+
+/**
+ * struct ts_state - search state
+ * @offset: offset for next match
+ * @cb: control buffer, for persistant variables of get_next_block()
+ */
+struct ts_state
+{
+       unsigned int            offset;
+       char                    cb[40];
+};
+
+/**
+ * struct ts_ops - search module operations
+ * @name: name of search algorithm
+ * @init: initialization function to prepare a search
+ * @find: find the next occurrence of the pattern
+ * @destroy: destroy algorithm specific parts of a search configuration
+ * @get_pattern: return head of pattern
+ * @get_pattern_len: return length of pattern
+ * @owner: module reference to algorithm
+ */
+struct ts_ops
+{
+       const char              *name;
+       struct ts_config *      (*init)(const void *, unsigned int, int);
+       unsigned int            (*find)(struct ts_config *,
+                                       struct ts_state *);
+       void                    (*destroy)(struct ts_config *);
+       void *                  (*get_pattern)(struct ts_config *);
+       unsigned int            (*get_pattern_len)(struct ts_config *);
+       struct module           *owner;
+       struct list_head        list;
+};
+
+/**
+ * struct ts_config - search configuration
+ * @ops: operations of chosen algorithm
+ * @get_next_block: callback to fetch the next block to search in
+ * @finish: callback to finalize a search
+ */
+struct ts_config
+{
+       struct ts_ops           *ops;
+
+       /**
+        * get_next_block - fetch next block of data
+        * @consumed: number of bytes consumed by the caller
+        * @dst: destination buffer
+        * @conf: search configuration
+        * @state: search state
+        *
+        * Called repeatedly until 0 is returned. Must assign the
+        * head of the next block of data to &*dst and return the length
+        * of the block or 0 if at the end. consumed == 0 indicates
+        * a new search. May store/read persistant values in state->cb.
+        */
+       unsigned int            (*get_next_block)(unsigned int consumed,
+                                                 const u8 **dst,
+                                                 struct ts_config *conf,
+                                                 struct ts_state *state);
+
+       /**
+        * finish - finalize/clean a series of get_next_block() calls
+        * @conf: search configuration
+        * @state: search state
+        *
+        * Called after the last use of get_next_block(), may be used
+        * to cleanup any leftovers.
+        */
+       void                    (*finish)(struct ts_config *conf,
+                                         struct ts_state *state);
+};
+
+/**
+ * textsearch_next - continue searching for a pattern
+ * @conf: search configuration
+ * @state: search state
+ *
+ * Continues a search looking for more occurrences of the pattern.
+ * textsearch_find() must be called to find the first occurrence
+ * in order to reset the state.
+ *
+ * Returns the position of the next occurrence of the pattern or
+ * UINT_MAX if not match was found.
+ */ 
+static inline unsigned int textsearch_next(struct ts_config *conf,
+                                          struct ts_state *state)
+{
+       unsigned int ret = conf->ops->find(conf, state);
+
+       if (conf->finish)
+               conf->finish(conf, state);
+
+       return ret;
+}
+
+/**
+ * textsearch_find - start searching for a pattern
+ * @conf: search configuration
+ * @state: search state
+ *
+ * Returns the position of first occurrence of the pattern or
+ * UINT_MAX if no match was found.
+ */ 
+static inline unsigned int textsearch_find(struct ts_config *conf,
+                                          struct ts_state *state)
+{
+       state->offset = 0;
+       return textsearch_next(conf, state);
+}
+
+/**
+ * textsearch_get_pattern - return head of the pattern
+ * @conf: search configuration
+ */
+static inline void *textsearch_get_pattern(struct ts_config *conf)
+{
+       return conf->ops->get_pattern(conf);
+}
+
+/**
+ * textsearch_get_pattern_len - return length of the pattern
+ * @conf: search configuration
+ */
+static inline unsigned int textsearch_get_pattern_len(struct ts_config *conf)
+{
+       return conf->ops->get_pattern_len(conf);
+}
+
+extern int textsearch_register(struct ts_ops *);
+extern int textsearch_unregister(struct ts_ops *);
+extern struct ts_config *textsearch_prepare(const char *, const void *,
+                                           unsigned int, int, int);
+extern void textsearch_destroy(struct ts_config *conf);
+extern unsigned int textsearch_find_continuous(struct ts_config *,
+                                              struct ts_state *,
+                                              const void *, unsigned int);
+
+
+#define TS_PRIV_ALIGNTO        8
+#define TS_PRIV_ALIGN(len) (((len) + TS_PRIV_ALIGNTO-1) & ~(TS_PRIV_ALIGNTO-1))
+
+static inline struct ts_config *alloc_ts_config(size_t payload, int gfp_mask)
+{
+       struct ts_config *conf;
+
+       conf = kmalloc(TS_PRIV_ALIGN(sizeof(*conf)) + payload, gfp_mask);
+       if (conf == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       memset(conf, 0, TS_PRIV_ALIGN(sizeof(*conf)) + payload);
+       return conf;
+}
+
+static inline void *ts_config_priv(struct ts_config *conf)
+{
+       return ((u8 *) conf + TS_PRIV_ALIGN(sizeof(struct ts_config)));
+}
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/include/linux/textsearch_fsm.h b/include/linux/textsearch_fsm.h
new file mode 100644 (file)
index 0000000..fdfa078
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef __LINUX_TEXTSEARCH_FSM_H
+#define __LINUX_TEXTSEARCH_FSM_H
+
+#include <linux/types.h>
+
+enum {
+       TS_FSM_SPECIFIC,        /* specific character */
+       TS_FSM_WILDCARD,        /* any character */
+       TS_FSM_DIGIT,           /* isdigit() */
+       TS_FSM_XDIGIT,          /* isxdigit() */
+       TS_FSM_PRINT,           /* isprint() */
+       TS_FSM_ALPHA,           /* isalpha() */
+       TS_FSM_ALNUM,           /* isalnum() */
+       TS_FSM_ASCII,           /* isascii() */
+       TS_FSM_CNTRL,           /* iscntrl() */
+       TS_FSM_GRAPH,           /* isgraph() */
+       TS_FSM_LOWER,           /* islower() */
+       TS_FSM_UPPER,           /* isupper() */
+       TS_FSM_PUNCT,           /* ispunct() */
+       TS_FSM_SPACE,           /* isspace() */
+       __TS_FSM_TYPE_MAX,
+};
+#define TS_FSM_TYPE_MAX (__TS_FSM_TYPE_MAX - 1)
+
+enum {
+       TS_FSM_SINGLE,          /* 1 occurrence */
+       TS_FSM_PERHAPS,         /* 1 or 0 occurrence */
+       TS_FSM_ANY,             /* 0..n occurrences */
+       TS_FSM_MULTI,           /* 1..n occurrences */
+       TS_FSM_HEAD_IGNORE,     /* 0..n ignored occurrences at head */
+       __TS_FSM_RECUR_MAX,
+};
+#define TS_FSM_RECUR_MAX (__TS_FSM_RECUR_MAX - 1)
+
+/**
+ * struct ts_fsm_token - state machine token (state)
+ * @type: type of token
+ * @recur: number of recurrences
+ * @value: character value for TS_FSM_SPECIFIC
+ */
+struct ts_fsm_token
+{
+       __u16           type;
+       __u8            recur;
+       __u8            value;
+};
+
+#endif
index d70e8972c67f5c3857b9e8df7ecfb99fd74ed9fd..0320225e96da5b6b24bc5e3d5107fc55527e6aab 100644 (file)
        .cache_hot_time         = 0,                    \
        .cache_nice_tries       = 0,                    \
        .per_cpu_gain           = 25,                   \
+       .busy_idx               = 0,                    \
+       .idle_idx               = 0,                    \
+       .newidle_idx            = 1,                    \
+       .wake_idx               = 0,                    \
+       .forkexec_idx           = 0,                    \
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_NEWIDLE    \
                                | SD_BALANCE_EXEC       \
        .cache_hot_time         = (5*1000000/2),        \
        .cache_nice_tries       = 1,                    \
        .per_cpu_gain           = 100,                  \
+       .busy_idx               = 2,                    \
+       .idle_idx               = 1,                    \
+       .newidle_idx            = 2,                    \
+       .wake_idx               = 1,                    \
+       .forkexec_idx           = 1,                    \
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_NEWIDLE    \
                                | SD_BALANCE_EXEC       \
-                               | SD_WAKE_AFFINE        \
-                               | SD_WAKE_IDLE          \
-                               | SD_WAKE_BALANCE,      \
+                               | SD_WAKE_AFFINE,       \
        .last_balance           = jiffies,              \
        .balance_interval       = 1,                    \
        .nr_balance_failed      = 0,                    \
index f5fe94e09a033fbf5ebba0ac167c9bc2fc22f65a..ee21e6bf3867a8bff6d2ac30a32ce6f4743a9536 100644 (file)
@@ -6,17 +6,20 @@
  *
  * - the master/host side Linux-USB kernel driver API;
  * - the "usbfs" user space API; and
- * - (eventually) a Linux "gadget" slave/device side driver API.
+ * - the Linux "gadget" slave/device/peripheral side driver API.
  *
  * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
  * act either as a USB master/host or as a USB slave/device.  That means
- * the master and slave side APIs will benefit from working well together.
+ * the master and slave side APIs benefit from working well together.
+ *
+ * There's also "Wireless USB", using low power short range radios for
+ * peripheral interconnection but otherwise building on the USB framework.
  */
 
 #ifndef __LINUX_USB_CH9_H
 #define __LINUX_USB_CH9_H
 
-#include <asm/types.h>         /* __u8 etc */
+#include <linux/types.h>       /* __u8 etc */
 
 /*-------------------------------------------------------------------------*/
 
 #define USB_REQ_SET_INTERFACE          0x0B
 #define USB_REQ_SYNCH_FRAME            0x0C
 
+#define USB_REQ_SET_ENCRYPTION         0x0D    /* Wireless USB */
+#define USB_REQ_GET_ENCRYPTION         0x0E
+#define USB_REQ_SET_HANDSHAKE          0x0F
+#define USB_REQ_GET_HANDSHAKE          0x10
+#define USB_REQ_SET_CONNECTION         0x11
+#define USB_REQ_SET_SECURITY_DATA      0x12
+#define USB_REQ_GET_SECURITY_DATA      0x13
+#define USB_REQ_SET_WUSB_DATA          0x14
+#define USB_REQ_LOOPBACK_DATA_WRITE    0x15
+#define USB_REQ_LOOPBACK_DATA_READ     0x16
+#define USB_REQ_SET_INTERFACE_DS       0x17
+
 /*
  * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
  * are read as a bit array returned by USB_REQ_GET_STATUS.  (So there
  */
 #define USB_DEVICE_SELF_POWERED                0       /* (read only) */
 #define USB_DEVICE_REMOTE_WAKEUP       1       /* dev may initiate wakeup */
-#define USB_DEVICE_TEST_MODE           2       /* (high speed only) */
-#define USB_DEVICE_B_HNP_ENABLE                3       /* dev may initiate HNP */
-#define USB_DEVICE_A_HNP_SUPPORT       4       /* RH port supports HNP */
-#define USB_DEVICE_A_ALT_HNP_SUPPORT   5       /* other RH port does */
+#define USB_DEVICE_TEST_MODE           2       /* (wired high speed only) */
+#define USB_DEVICE_BATTERY             2       /* (wireless) */
+#define USB_DEVICE_B_HNP_ENABLE                3       /* (otg) dev may initiate HNP */
+#define USB_DEVICE_WUSB_DEVICE         3       /* (wireless)*/
+#define USB_DEVICE_A_HNP_SUPPORT       4       /* (otg) RH port supports HNP */
+#define USB_DEVICE_A_ALT_HNP_SUPPORT   5       /* (otg) other RH port does */
 #define USB_DEVICE_DEBUG_MODE          6       /* (special devices only) */
 
 #define USB_ENDPOINT_HALT              0       /* IN/OUT will STALL */
@@ -135,6 +152,13 @@ struct usb_ctrlrequest {
 #define USB_DT_OTG                     0x09
 #define USB_DT_DEBUG                   0x0a
 #define USB_DT_INTERFACE_ASSOCIATION   0x0b
+/* these are from the Wireless USB spec */
+#define USB_DT_SECURITY                        0x0c
+#define USB_DT_KEY                     0x0d
+#define USB_DT_ENCRYPTION_TYPE         0x0e
+#define USB_DT_BOS                     0x0f
+#define USB_DT_DEVICE_CAPABILITY       0x10
+#define USB_DT_WIRELESS_ENDPOINT_COMP  0x11
 
 /* conventional codes for class-specific descriptors */
 #define USB_DT_CS_DEVICE               0x21
@@ -192,6 +216,7 @@ struct usb_device_descriptor {
 #define USB_CLASS_CSCID                        0x0b    /* chip+ smart card */
 #define USB_CLASS_CONTENT_SEC          0x0d    /* content security */
 #define USB_CLASS_VIDEO                        0x0e
+#define USB_CLASS_WIRELESS_CONTROLLER  0xe0
 #define USB_CLASS_APP_SPEC             0xfe
 #define USB_CLASS_VENDOR_SPEC          0xff
 
@@ -223,6 +248,7 @@ struct usb_config_descriptor {
 #define USB_CONFIG_ATT_ONE             (1 << 7)        /* must be set */
 #define USB_CONFIG_ATT_SELFPOWER       (1 << 6)        /* self powered */
 #define USB_CONFIG_ATT_WAKEUP          (1 << 5)        /* can wakeup */
+#define USB_CONFIG_ATT_BATTERY         (1 << 4)        /* battery powered */
 
 /*-------------------------------------------------------------------------*/
 
@@ -268,8 +294,8 @@ struct usb_endpoint_descriptor {
        __le16 wMaxPacketSize;
        __u8  bInterval;
 
-       // NOTE:  these two are _only_ in audio endpoints.
-       // use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof.
+       /* NOTE:  these two are _only_ in audio endpoints. */
+       /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
        __u8  bRefresh;
        __u8  bSynchAddress;
 } __attribute__ ((packed));
@@ -289,6 +315,7 @@ struct usb_endpoint_descriptor {
 #define USB_ENDPOINT_XFER_ISOC         1
 #define USB_ENDPOINT_XFER_BULK         2
 #define USB_ENDPOINT_XFER_INT          3
+#define USB_ENDPOINT_MAX_ADJUSTABLE    0x80
 
 
 /*-------------------------------------------------------------------------*/
@@ -350,6 +377,147 @@ struct usb_interface_assoc_descriptor {
 } __attribute__ ((packed));
 
 
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_SECURITY:  group of wireless security descriptors, including
+ * encryption types available for setting up a CC/association.
+ */
+struct usb_security_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __le16 wTotalLength;
+       __u8  bNumEncryptionTypes;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_KEY:  used with {GET,SET}_SECURITY_DATA; only public keys
+ * may be retrieved.
+ */
+struct usb_key_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  tTKID[3];
+       __u8  bReserved;
+       __u8  bKeyData[0];
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_ENCRYPTION_TYPE:  bundled in DT_SECURITY groups */
+struct usb_encryption_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bEncryptionType;
+#define        USB_ENC_TYPE_UNSECURE           0
+#define        USB_ENC_TYPE_WIRED              1       /* non-wireless mode */
+#define        USB_ENC_TYPE_CCM_1              2       /* aes128/cbc session */
+#define        USB_ENC_TYPE_RSA_1              3       /* rsa3072/sha1 auth */
+       __u8  bEncryptionValue;         /* use in SET_ENCRYPTION */
+       __u8  bAuthKeyIndex;
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_BOS:  group of wireless capabilities */
+struct usb_bos_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __le16 wTotalLength;
+       __u8  bNumDeviceCaps;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE_CAPABILITY:  grouped with BOS */
+struct usb_dev_cap_header {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDevCapabilityType;
+};
+
+#define        USB_CAP_TYPE_WIRELESS_USB       1
+
+struct usb_wireless_cap_descriptor {   /* Ultra Wide Band */
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDevCapabilityType;
+
+       __u8  bmAttributes;
+#define        USB_WIRELESS_P2P_DRD            (1 << 1)
+#define        USB_WIRELESS_BEACON_MASK        (3 << 2)
+#define        USB_WIRELESS_BEACON_SELF        (1 << 2)
+#define        USB_WIRELESS_BEACON_DIRECTED    (2 << 2)
+#define        USB_WIRELESS_BEACON_NONE        (3 << 2)
+       __le16 wPHYRates;       /* bit rates, Mbps */
+#define        USB_WIRELESS_PHY_53             (1 << 0)        /* always set */
+#define        USB_WIRELESS_PHY_80             (1 << 1)
+#define        USB_WIRELESS_PHY_107            (1 << 2)        /* always set */
+#define        USB_WIRELESS_PHY_160            (1 << 3)
+#define        USB_WIRELESS_PHY_200            (1 << 4)        /* always set */
+#define        USB_WIRELESS_PHY_320            (1 << 5)
+#define        USB_WIRELESS_PHY_400            (1 << 6)
+#define        USB_WIRELESS_PHY_480            (1 << 7)
+       __u8  bmTFITXPowerInfo; /* TFI power levels */
+       __u8  bmFFITXPowerInfo; /* FFI power levels */
+       __le16 bmBandGroup;
+       __u8  bReserved;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_WIRELESS_ENDPOINT_COMP:  companion descriptor associated with
+ * each endpoint descriptor for a wireless device
+ */
+struct usb_wireless_ep_comp_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bMaxBurst;
+       __u8  bMaxSequence;
+       __le16 wMaxStreamDelay;
+       __le16 wOverTheAirPacketSize;
+       __u8  bOverTheAirInterval;
+       __u8  bmCompAttributes;
+#define USB_ENDPOINT_SWITCH_MASK       0x03    /* in bmCompAttributes */
+#define USB_ENDPOINT_SWITCH_NO         0
+#define USB_ENDPOINT_SWITCH_SWITCH     1
+#define USB_ENDPOINT_SWITCH_SCALE      2
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless
+ * host and a device for connection set up, mutual authentication, and
+ * exchanging short lived session keys.  The handshake depends on a CC.
+ */
+struct usb_handshake {
+       __u8 bMessageNumber;
+       __u8 bStatus;
+       __u8 tTKID[3];
+       __u8 bReserved;
+       __u8 CDID[16];
+       __u8 nonce[16];
+       __u8 MIC[8];
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC).
+ * A CC may also be set up using non-wireless secure channels (including
+ * wired USB!), and some devices may support CCs with multiple hosts.
+ */
+struct usb_connection_context {
+       __u8 CHID[16];          /* persistent host id */
+       __u8 CDID[16];          /* device id (unique w/in host context) */
+       __u8 CK[16];            /* connection key */
+};
+
 /*-------------------------------------------------------------------------*/
 
 /* USB 2.0 defines three speeds, here's how Linux identifies them */
@@ -357,7 +525,8 @@ struct usb_interface_assoc_descriptor {
 enum usb_device_speed {
        USB_SPEED_UNKNOWN = 0,                  /* enumerating */
        USB_SPEED_LOW, USB_SPEED_FULL,          /* usb 1.1 */
-       USB_SPEED_HIGH                          /* usb 2.0 */
+       USB_SPEED_HIGH,                         /* usb 2.0 */
+       USB_SPEED_VARIABLE,                     /* wireless (usb 2.5) */
 };
 
 enum usb_device_state {
index 9bba9997947bcd6c4a5b39e7847cd58186d635fb..b00f127cb4472ea05b7198a698673756dfa10c09 100644 (file)
@@ -711,7 +711,7 @@ usb_gadget_disconnect (struct usb_gadget *gadget)
  *     the hardware level driver. Most calls must be handled by
  *     the gadget driver, including descriptor and configuration
  *     management.  The 16 bit members of the setup data are in
- *     cpu order. Called in_interrupt; this may not sleep.  Driver
+ *     USB byte order. Called in_interrupt; this may not sleep.  Driver
  *     queues a response to ep0, or returns negative to stall.
  * @disconnect: Invoked after all transfers have been stopped,
  *     when the host is disconnected.  May be called in_interrupt; this
diff --git a/include/linux/usb_isp116x.h b/include/linux/usb_isp116x.h
new file mode 100644 (file)
index 0000000..5f5a9d9
--- /dev/null
@@ -0,0 +1,47 @@
+
+/*
+ * Board initialization code should put one of these into dev->platform_data
+ * and place the isp116x onto platform_bus.
+ */
+
+struct isp116x_platform_data {
+       /* Enable internal resistors on downstream ports */
+       unsigned sel15Kres:1;
+       /* Chip's internal clock won't be stopped in suspended state.
+          Setting/unsetting this bit takes effect only if
+          'remote_wakeup_enable' below is not set. */
+       unsigned clknotstop:1;
+       /* On-chip overcurrent protection */
+       unsigned oc_enable:1;
+       /* INT output polarity */
+       unsigned int_act_high:1;
+       /* INT edge or level triggered */
+       unsigned int_edge_triggered:1;
+       /* WAKEUP pin connected - NOT SUPPORTED  */
+       /* unsigned remote_wakeup_connected:1; */
+       /* Wakeup by devices on usb bus enabled */
+       unsigned remote_wakeup_enable:1;
+       /* Switch or not to switch (keep always powered) */
+       unsigned no_power_switching:1;
+       /* Ganged port power switching (0) or individual port
+          power switching (1) */
+       unsigned power_switching_mode:1;
+       /* Given port_power, msec/2 after power on till power good */
+       u8 potpg;
+       /* Hardware reset set/clear. If implemented, this function must:
+          if set == 0,   deassert chip's HW reset pin
+          otherwise,     assert chip's HW reset pin       */
+       void (*reset) (struct device * dev, int set);
+       /* Hardware clock start/stop. If implemented, this function must:
+          if start == 0,    stop the external clock
+          otherwise,        start the external clock
+        */
+       void (*clock) (struct device * dev, int start);
+       /* Inter-io delay (ns). The chip is picky about access timings; it
+          expects at least:
+          150ns delay between consecutive accesses to DATA_REG,
+          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);
+};
index 4e0edce537601ce1ef7d0cce6b983a4d62f2bcfa..acbfc525576df3eb2cb7803bf866e38a2d2ea2bb 100644 (file)
@@ -221,6 +221,8 @@ struct v4l2_pix_format
 /*  Vendor-specific formats   */
 #define V4L2_PIX_FMT_WNVA     v4l2_fourcc('W','N','V','A') /* Winnov hw compress */
 #define V4L2_PIX_FMT_SN9C10X  v4l2_fourcc('S','9','1','0') /* SN9C10x compression */
+#define V4L2_PIX_FMT_PWC1     v4l2_fourcc('P','W','C','1') /* pwc older webcam */
+#define V4L2_PIX_FMT_PWC2     v4l2_fourcc('P','W','C','2') /* pwc newer webcam */
 
 /*
  *     F O R M A T   E N U M E R A T I O N
index 1262cb43c3abcd78553e0b819adf0548fb2c0c33..542dbaee65129480867593be885ab71c05be8796 100644 (file)
@@ -14,11 +14,13 @@ extern struct list_head inode_unused;
  * Yes, writeback.h requires sched.h
  * No, sched.h is not included from here.
  */
-static inline int current_is_pdflush(void)
+static inline int task_is_pdflush(struct task_struct *task)
 {
-       return current->flags & PF_FLUSHER;
+       return task->flags & PF_FLUSHER;
 }
 
+#define current_is_pdflush()   task_is_pdflush(current)
+
 /*
  * fs/fs-writeback.c
  */
@@ -83,7 +85,7 @@ static inline void wait_on_inode(struct inode *inode)
 /*
  * mm/page-writeback.c
  */
-int wakeup_bdflush(long nr_pages);
+int wakeup_pdflush(long nr_pages);
 void laptop_io_completion(void);
 void laptop_sync_completion(void);
 void throttle_vm_writeout(void);
diff --git a/include/linux/xattr_acl.h b/include/linux/xattr_acl.h
deleted file mode 100644 (file)
index 7a1f9b9..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-  File: linux/xattr_acl.h
-
-  (extended attribute representation of access control lists)
-
-  (C) 2000 Andreas Gruenbacher, <a.gruenbacher@computer.org>
-*/
-
-#ifndef _LINUX_XATTR_ACL_H
-#define _LINUX_XATTR_ACL_H
-
-#include <linux/posix_acl.h>
-
-#define XATTR_NAME_ACL_ACCESS  "system.posix_acl_access"
-#define XATTR_NAME_ACL_DEFAULT "system.posix_acl_default"
-
-#define XATTR_ACL_VERSION      0x0002
-
-typedef struct {
-       __u16           e_tag;
-       __u16           e_perm;
-       __u32           e_id;
-} xattr_acl_entry;
-
-typedef struct {
-       __u32           a_version;
-       xattr_acl_entry a_entries[0];
-} xattr_acl_header;
-
-static inline size_t xattr_acl_size(int count)
-{
-       return sizeof(xattr_acl_header) + count * sizeof(xattr_acl_entry);
-}
-
-static inline int xattr_acl_count(size_t size)
-{
-       if (size < sizeof(xattr_acl_header))
-               return -1;
-       size -= sizeof(xattr_acl_header);
-       if (size % sizeof(xattr_acl_entry))
-               return -1;
-       return size / sizeof(xattr_acl_entry);
-}
-
-struct posix_acl * posix_acl_from_xattr(const void *value, size_t size);
-int posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size);
-
-
-
-#endif /* _LINUX_XATTR_ACL_H */
index d3e9e30608dc811b4fd9d78f252dfa98dddc634a..f345a61c3bdbcdc9e72d5873224ad06199ee6787 100644 (file)
@@ -1,3 +1,7 @@
+/*
+ * $Id: audiochip.h,v 1.3 2005/06/12 04:19:19 mchehab Exp $
+ */
+
 #ifndef AUDIOCHIP_H
 #define AUDIOCHIP_H
 
index 1b0320dc8f73cd79fa9ec09f1c1541369df9953e..a39a6423914bc553f8b79e9139ba7221c0710380 100644 (file)
@@ -1,3 +1,7 @@
+/*
+ * $Id: id.h,v 1.4 2005/06/12 04:19:19 mchehab Exp $
+ */
+
 /* FIXME: this temporarely, until these are included in linux/i2c-id.h */
 
 /* drivers */
index 62c963a52d8639658e3bcfe810f8e2f24115f060..698670547f1684679a28c0fbc601cdeefc9f6c33 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ir-common.h,v 1.8 2005/02/22 12:28:40 kraxel Exp $
+ * $Id: ir-common.h,v 1.9 2005/05/15 19:01:26 mchehab Exp $
  *
  * some common structs and functions to handle infrared remotes via
  * input layer ...
@@ -50,6 +50,7 @@ extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE];
 
 void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
                   int ir_type, IR_KEYTAB_TYPE *ir_codes);
index 156a9c51ffec92b9070ff24ff7e84c227f4e519d..4794c563236085d25670f0f3b3931f554e37df64 100644 (file)
@@ -1,5 +1,6 @@
 
-/*
+/* $Id: tuner.h,v 1.33 2005/06/21 14:58:08 mkrufky Exp $
+ *
     tuner.h - definition for different tuners
 
     Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de)
 #ifndef _TUNER_H
 #define _TUNER_H
 
+#include <linux/videodev2.h>
+
 #include "id.h"
 
+#define ADDR_UNSET (255)
+
 #define TUNER_TEMIC_PAL     0        /* 4002 FH5 (3X 7756, 9483) */
 #define TUNER_PHILIPS_PAL_I 1
 #define TUNER_PHILIPS_NTSC  2
@@ -86,7 +91,7 @@
 #define TUNER_LG_NTSC_TAPE       47
 
 #define TUNER_TNF_8831BGFF       48
-#define TUNER_MICROTUNE_4042FI5  49    /* FusionHDTV 3 Gold - 4042 FI5 (3X 8147) */
+#define TUNER_MICROTUNE_4042FI5  49    /* DViCO FusionHDTV 3 Gold-Q - 4042 FI5 (3X 8147) */
 #define TUNER_TCL_2002N          50
 #define TUNER_PHILIPS_FM1256_IH3   51
 
 #define TUNER_LG_PAL_TAPE        55    /* Hauppauge PVR-150 PAL */
 
 #define TUNER_PHILIPS_FQ1216AME_MK4 56 /* Hauppauge PVR-150 PAL */
-#define TUNER_PHILIPS_FQ1236A_MK4 57   /* Hauppauge PVR-500MCE NTSC */
+#define TUNER_PHILIPS_FQ1236A_MK4   57   /* Hauppauge PVR-500MCE NTSC */
+
+#define TUNER_YMEC_TVF_8531MF 58
+#define TUNER_YMEC_TVF_5533MF 59       /* Pixelview Pro Ultra NTSC */
+#define TUNER_THOMSON_DTT7611 60       /* DViCO FusionHDTV 3 Gold-T */
+#define TUNER_TENA_9533_DI    61
+
+#define TUNER_TEA5767         62       /* Only FM Radio Tuner */
+#define TUNER_PHILIPS_FMD1216ME_MK3 63
+
+#define TEA5767_TUNER_NAME "Philips TEA5767HN FM Radio"
 
 #define NOTUNER 0
 #define PAL     1      /* PAL_BG */
 #define NTSC    3
 #define SECAM   4
 #define ATSC    5
+#define RADIO  6
 
 #define NoTuner 0
 #define Philips 1
 #define TCL     11
 #define THOMSON 12
 
+enum v4l_radio_tuner {
+        TEA5767_LOW_LO_32768    = 0,
+        TEA5767_HIGH_LO_32768   = 1,
+        TEA5767_LOW_LO_13MHz    = 2,
+        TEA5767_HIGH_LO_13MHz   = 3,
+};
+
+
 #define TUNER_SET_TYPE               _IOW('t',1,int)    /* set tuner type */
 #define TUNER_SET_TVFREQ             _IOW('t',2,int)    /* set tv freq */
+#define TUNER_SET_TYPE_ADDR          _IOW('T',3,int)   /* set tuner type and I2C addr */
 
 #define  TDA9887_SET_CONFIG          _IOW('t',5,int)
+
 /* tv card specific */
 # define TDA9887_PRESENT             (1<<0)
 # define TDA9887_PORT1_INACTIVE      (1<<1)
 #define I2C_ADDR_TDA8290        0x4b
 #define I2C_ADDR_TDA8275        0x61
 
+struct tuner_addr {
+       enum v4l2_tuner_type    v4l2_tuner;
+       unsigned int            type;
+       unsigned short          addr;
+};
+
 struct tuner {
        /* device */
        struct i2c_client i2c;
@@ -165,11 +197,15 @@ struct tuner {
        unsigned char i2c_easy_mode[2];
        unsigned char i2c_set_freq[8];
 
+       /* used to keep track of audmode */
+       unsigned int audmode;
+
        /* function ptrs */
        void (*tv_freq)(struct i2c_client *c, unsigned int freq);
        void (*radio_freq)(struct i2c_client *c, unsigned int freq);
        int  (*has_signal)(struct i2c_client *c);
        int  (*is_stereo)(struct i2c_client *c);
+       int  (*set_tuner)(struct i2c_client *c, struct v4l2_tuner *v);
 };
 
 extern unsigned int tuner_debug;
@@ -177,6 +213,7 @@ extern unsigned const int tuner_count;
 
 extern int microtune_init(struct i2c_client *c);
 extern int tda8290_init(struct i2c_client *c);
+extern int tea5767_tuner_init(struct i2c_client *c);
 extern int default_tuner_init(struct i2c_client *c);
 
 #define tuner_warn(fmt, arg...) \
index 627603e561a689d89815fe9d3c86f45d873c4536..5c4fe30e8d1dd95da9d31a99416d5cddb380a662 100644 (file)
@@ -1,3 +1,7 @@
+/*
+ * $Id: tveeprom.h,v 1.2 2005/06/12 04:19:19 mchehab Exp $
+ */
+
 struct tveeprom {
        u32 has_radio;
 
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
new file mode 100644 (file)
index 0000000..db09580
--- /dev/null
@@ -0,0 +1,856 @@
+/*
+ * Merged with mainline ieee80211.h in Aug 2004.  Original ieee802_11
+ * remains copyright by the original authors
+ *
+ * Portions of the merged code are based on Host AP (software wireless
+ * LAN access point) driver for Intersil Prism2/2.5/3.
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * Adaption to a generic IEEE 802.11 stack by James Ketrenos
+ * <jketreno@linux.intel.com>
+ * Copyright (c) 2004, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+ */
+#ifndef IEEE80211_H
+#define IEEE80211_H
+
+#include <linux/if_ether.h> /* ETH_ALEN */
+#include <linux/kernel.h>   /* ARRAY_SIZE */
+
+#if WIRELESS_EXT < 17
+#define IW_QUAL_QUAL_INVALID   0x10
+#define IW_QUAL_LEVEL_INVALID  0x20
+#define IW_QUAL_NOISE_INVALID  0x40
+#define IW_QUAL_QUAL_UPDATED   0x1
+#define IW_QUAL_LEVEL_UPDATED  0x2
+#define IW_QUAL_NOISE_UPDATED  0x4
+#endif
+
+#define IEEE80211_DATA_LEN             2304
+/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
+   6.2.1.1.2.
+
+   The figure in section 7.1.2 suggests a body size of up to 2312
+   bytes is allowed, which is a bit confusing, I suspect this
+   represents the 2304 bytes of real data, plus a possible 8 bytes of
+   WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+
+
+#define IEEE80211_HLEN                 30
+#define IEEE80211_FRAME_LEN            (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+struct ieee80211_hdr {
+       u16 frame_ctl;
+       u16 duration_id;
+       u8 addr1[ETH_ALEN];
+       u8 addr2[ETH_ALEN];
+       u8 addr3[ETH_ALEN];
+       u16 seq_ctl;
+       u8 addr4[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct ieee80211_hdr_3addr {
+       u16 frame_ctl;
+       u16 duration_id;
+       u8 addr1[ETH_ALEN];
+       u8 addr2[ETH_ALEN];
+       u8 addr3[ETH_ALEN];
+       u16 seq_ctl;
+} __attribute__ ((packed));
+
+enum eap_type {
+       EAP_PACKET = 0,
+       EAPOL_START,
+       EAPOL_LOGOFF,
+       EAPOL_KEY,
+       EAPOL_ENCAP_ASF_ALERT
+};
+
+static const char *eap_types[] = {
+       [EAP_PACKET]            = "EAP-Packet",
+       [EAPOL_START]           = "EAPOL-Start",
+       [EAPOL_LOGOFF]          = "EAPOL-Logoff",
+       [EAPOL_KEY]             = "EAPOL-Key",
+       [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert"
+};
+
+static inline const char *eap_get_type(int type)
+{
+       return (type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type];
+}
+
+struct eapol {
+       u8 snap[6];
+       u16 ethertype;
+       u8 version;
+       u8 type;
+       u16 length;
+} __attribute__ ((packed));
+
+#define IEEE80211_1ADDR_LEN 10
+#define IEEE80211_2ADDR_LEN 16
+#define IEEE80211_3ADDR_LEN 24
+#define IEEE80211_4ADDR_LEN 30
+#define IEEE80211_FCS_LEN    4
+
+#define MIN_FRAG_THRESHOLD     256U
+#define        MAX_FRAG_THRESHOLD     2346U
+
+/* Frame control field constants */
+#define IEEE80211_FCTL_VERS            0x0002
+#define IEEE80211_FCTL_FTYPE           0x000c
+#define IEEE80211_FCTL_STYPE           0x00f0
+#define IEEE80211_FCTL_TODS            0x0100
+#define IEEE80211_FCTL_FROMDS          0x0200
+#define IEEE80211_FCTL_MOREFRAGS       0x0400
+#define IEEE80211_FCTL_RETRY           0x0800
+#define IEEE80211_FCTL_PM              0x1000
+#define IEEE80211_FCTL_MOREDATA        0x2000
+#define IEEE80211_FCTL_WEP             0x4000
+#define IEEE80211_FCTL_ORDER           0x8000
+
+#define IEEE80211_FTYPE_MGMT           0x0000
+#define IEEE80211_FTYPE_CTL            0x0004
+#define IEEE80211_FTYPE_DATA           0x0008
+
+/* management */
+#define IEEE80211_STYPE_ASSOC_REQ      0x0000
+#define IEEE80211_STYPE_ASSOC_RESP     0x0010
+#define IEEE80211_STYPE_REASSOC_REQ    0x0020
+#define IEEE80211_STYPE_REASSOC_RESP   0x0030
+#define IEEE80211_STYPE_PROBE_REQ      0x0040
+#define IEEE80211_STYPE_PROBE_RESP     0x0050
+#define IEEE80211_STYPE_BEACON         0x0080
+#define IEEE80211_STYPE_ATIM           0x0090
+#define IEEE80211_STYPE_DISASSOC       0x00A0
+#define IEEE80211_STYPE_AUTH           0x00B0
+#define IEEE80211_STYPE_DEAUTH         0x00C0
+
+/* control */
+#define IEEE80211_STYPE_PSPOLL         0x00A0
+#define IEEE80211_STYPE_RTS            0x00B0
+#define IEEE80211_STYPE_CTS            0x00C0
+#define IEEE80211_STYPE_ACK            0x00D0
+#define IEEE80211_STYPE_CFEND          0x00E0
+#define IEEE80211_STYPE_CFENDACK       0x00F0
+
+/* data */
+#define IEEE80211_STYPE_DATA           0x0000
+#define IEEE80211_STYPE_DATA_CFACK     0x0010
+#define IEEE80211_STYPE_DATA_CFPOLL    0x0020
+#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030
+#define IEEE80211_STYPE_NULLFUNC       0x0040
+#define IEEE80211_STYPE_CFACK          0x0050
+#define IEEE80211_STYPE_CFPOLL         0x0060
+#define IEEE80211_STYPE_CFACKPOLL      0x0070
+
+#define IEEE80211_SCTL_FRAG            0x000F
+#define IEEE80211_SCTL_SEQ             0xFFF0
+
+
+/* debug macros */
+
+#ifdef CONFIG_IEEE80211_DEBUG
+extern u32 ieee80211_debug_level;
+#define IEEE80211_DEBUG(level, fmt, args...) \
+do { if (ieee80211_debug_level & (level)) \
+  printk(KERN_DEBUG "ieee80211: %c %s " fmt, \
+         in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+#else
+#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0)
+#endif /* CONFIG_IEEE80211_DEBUG */
+
+/*
+ * To use the debug system;
+ *
+ * If you are defining a new debug classification, simply add it to the #define
+ * list here in the form of:
+ *
+ * #define IEEE80211_DL_xxxx VALUE
+ *
+ * shifting value to the left one bit from the previous entry.  xxxx should be
+ * the name of the classification (for example, WEP)
+ *
+ * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your
+ * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want
+ * to send output to that classification.
+ *
+ * To add your debug level to the list of levels seen when you perform
+ *
+ * % cat /proc/net/ipw/debug_level
+ *
+ * you simply need to add your entry to the ipw_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/ipw then you do not have
+ * CONFIG_IEEE80211_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IEEE80211_DL_INFO          (1<<0)
+#define IEEE80211_DL_WX            (1<<1)
+#define IEEE80211_DL_SCAN          (1<<2)
+#define IEEE80211_DL_STATE         (1<<3)
+#define IEEE80211_DL_MGMT          (1<<4)
+#define IEEE80211_DL_FRAG          (1<<5)
+#define IEEE80211_DL_EAP           (1<<6)
+#define IEEE80211_DL_DROP          (1<<7)
+
+#define IEEE80211_DL_TX            (1<<8)
+#define IEEE80211_DL_RX            (1<<9)
+
+#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a)
+#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a)
+#define IEEE80211_DEBUG_INFO(f, a...)   IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a)
+
+#define IEEE80211_DEBUG_WX(f, a...)     IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a)
+#define IEEE80211_DEBUG_SCAN(f, a...)   IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a)
+#define IEEE80211_DEBUG_STATE(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a)
+#define IEEE80211_DEBUG_MGMT(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a)
+#define IEEE80211_DEBUG_FRAG(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a)
+#define IEEE80211_DEBUG_EAP(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a)
+#define IEEE80211_DEBUG_DROP(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a)
+#define IEEE80211_DEBUG_TX(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a)
+#define IEEE80211_DEBUG_RX(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a)
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/if_arp.h> /* ARPHRD_ETHER */
+
+#ifndef WIRELESS_SPY
+#define WIRELESS_SPY           // enable iwspy support
+#endif
+#include <net/iw_handler.h>    // new driver API
+
+#ifndef ETH_P_PAE
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#endif /* ETH_P_PAE */
+
+#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
+
+#ifndef ETH_P_80211_RAW
+#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
+#endif
+
+/* IEEE 802.11 defines */
+
+#define P80211_OUI_LEN 3
+
+struct ieee80211_snap_hdr {
+
+        u8    dsap;   /* always 0xAA */
+        u8    ssap;   /* always 0xAA */
+        u8    ctrl;   /* always 0x03 */
+        u8    oui[P80211_OUI_LEN];    /* organizational universal id */
+
+} __attribute__ ((packed));
+
+#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
+
+#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
+#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
+
+#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
+#define WLAN_GET_SEQ_SEQ(seq)  ((seq) & IEEE80211_SCTL_SEQ)
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN 0
+#define WLAN_AUTH_SHARED_KEY 1
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_BSS (1<<0)
+#define WLAN_CAPABILITY_IBSS (1<<1)
+#define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
+#define WLAN_CAPABILITY_PRIVACY (1<<4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
+#define WLAN_CAPABILITY_PBCC (1<<6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
+
+/* Status codes */
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_CAPS_UNSUPPORTED 10
+#define WLAN_STATUS_REASSOC_NO_ASSOC 11
+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
+#define WLAN_STATUS_CHALLENGE_FAIL 15
+#define WLAN_STATUS_AUTH_TIMEOUT 16
+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
+#define WLAN_STATUS_ASSOC_DENIED_RATES 18
+/* 802.11b */
+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+
+/* Reason codes */
+#define WLAN_REASON_UNSPECIFIED 1
+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define WLAN_REASON_DEAUTH_LEAVING 3
+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define WLAN_REASON_DISASSOC_AP_BUSY 5
+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+
+
+#define IEEE80211_STATMASK_SIGNAL (1<<0)
+#define IEEE80211_STATMASK_RSSI (1<<1)
+#define IEEE80211_STATMASK_NOISE (1<<2)
+#define IEEE80211_STATMASK_RATE (1<<3)
+#define IEEE80211_STATMASK_WEMASK 0x7
+
+
+#define IEEE80211_CCK_MODULATION    (1<<0)
+#define IEEE80211_OFDM_MODULATION   (1<<1)
+
+#define IEEE80211_24GHZ_BAND     (1<<0)
+#define IEEE80211_52GHZ_BAND     (1<<1)
+
+#define IEEE80211_CCK_RATE_1MB                 0x02
+#define IEEE80211_CCK_RATE_2MB                 0x04
+#define IEEE80211_CCK_RATE_5MB                 0x0B
+#define IEEE80211_CCK_RATE_11MB                        0x16
+#define IEEE80211_OFDM_RATE_6MB                        0x0C
+#define IEEE80211_OFDM_RATE_9MB                        0x12
+#define IEEE80211_OFDM_RATE_12MB               0x18
+#define IEEE80211_OFDM_RATE_18MB               0x24
+#define IEEE80211_OFDM_RATE_24MB               0x30
+#define IEEE80211_OFDM_RATE_36MB               0x48
+#define IEEE80211_OFDM_RATE_48MB               0x60
+#define IEEE80211_OFDM_RATE_54MB               0x6C
+#define IEEE80211_BASIC_RATE_MASK              0x80
+
+#define IEEE80211_CCK_RATE_1MB_MASK            (1<<0)
+#define IEEE80211_CCK_RATE_2MB_MASK            (1<<1)
+#define IEEE80211_CCK_RATE_5MB_MASK            (1<<2)
+#define IEEE80211_CCK_RATE_11MB_MASK           (1<<3)
+#define IEEE80211_OFDM_RATE_6MB_MASK           (1<<4)
+#define IEEE80211_OFDM_RATE_9MB_MASK           (1<<5)
+#define IEEE80211_OFDM_RATE_12MB_MASK          (1<<6)
+#define IEEE80211_OFDM_RATE_18MB_MASK          (1<<7)
+#define IEEE80211_OFDM_RATE_24MB_MASK          (1<<8)
+#define IEEE80211_OFDM_RATE_36MB_MASK          (1<<9)
+#define IEEE80211_OFDM_RATE_48MB_MASK          (1<<10)
+#define IEEE80211_OFDM_RATE_54MB_MASK          (1<<11)
+
+#define IEEE80211_CCK_RATES_MASK               0x0000000F
+#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \
+       IEEE80211_CCK_RATE_2MB_MASK)
+#define IEEE80211_CCK_DEFAULT_RATES_MASK       (IEEE80211_CCK_BASIC_RATES_MASK | \
+        IEEE80211_CCK_RATE_5MB_MASK | \
+        IEEE80211_CCK_RATE_11MB_MASK)
+
+#define IEEE80211_OFDM_RATES_MASK              0x00000FF0
+#define IEEE80211_OFDM_BASIC_RATES_MASK        (IEEE80211_OFDM_RATE_6MB_MASK | \
+       IEEE80211_OFDM_RATE_12MB_MASK | \
+       IEEE80211_OFDM_RATE_24MB_MASK)
+#define IEEE80211_OFDM_DEFAULT_RATES_MASK      (IEEE80211_OFDM_BASIC_RATES_MASK | \
+       IEEE80211_OFDM_RATE_9MB_MASK  | \
+       IEEE80211_OFDM_RATE_18MB_MASK | \
+       IEEE80211_OFDM_RATE_36MB_MASK | \
+       IEEE80211_OFDM_RATE_48MB_MASK | \
+       IEEE80211_OFDM_RATE_54MB_MASK)
+#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \
+                                IEEE80211_CCK_DEFAULT_RATES_MASK)
+
+#define IEEE80211_NUM_OFDM_RATES           8
+#define IEEE80211_NUM_CCK_RATES                    4
+#define IEEE80211_OFDM_SHIFT_MASK_A         4
+
+
+
+
+/* NOTE: This data is for statistical purposes; not all hardware provides this
+ *       information for frames received.  Not setting these will not cause
+ *       any adverse affects. */
+struct ieee80211_rx_stats {
+       u32 mac_time;
+       s8 rssi;
+       u8 signal;
+       u8 noise;
+       u16 rate; /* in 100 kbps */
+       u8 received_channel;
+       u8 control;
+       u8 mask;
+       u8 freq;
+       u16 len;
+};
+
+/* IEEE 802.11 requires that STA supports concurrent reception of at least
+ * three fragmented frames. This define can be increased to support more
+ * concurrent frames, but it should be noted that each entry can consume about
+ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
+#define IEEE80211_FRAG_CACHE_LEN 4
+
+struct ieee80211_frag_entry {
+       unsigned long first_frag_time;
+       unsigned int seq;
+       unsigned int last_frag;
+       struct sk_buff *skb;
+       u8 src_addr[ETH_ALEN];
+       u8 dst_addr[ETH_ALEN];
+};
+
+struct ieee80211_stats {
+       unsigned int tx_unicast_frames;
+       unsigned int tx_multicast_frames;
+       unsigned int tx_fragments;
+       unsigned int tx_unicast_octets;
+       unsigned int tx_multicast_octets;
+       unsigned int tx_deferred_transmissions;
+       unsigned int tx_single_retry_frames;
+       unsigned int tx_multiple_retry_frames;
+       unsigned int tx_retry_limit_exceeded;
+       unsigned int tx_discards;
+       unsigned int rx_unicast_frames;
+       unsigned int rx_multicast_frames;
+       unsigned int rx_fragments;
+       unsigned int rx_unicast_octets;
+       unsigned int rx_multicast_octets;
+       unsigned int rx_fcs_errors;
+       unsigned int rx_discards_no_buffer;
+       unsigned int tx_discards_wrong_sa;
+       unsigned int rx_discards_undecryptable;
+       unsigned int rx_message_in_msg_fragments;
+       unsigned int rx_message_in_bad_msg_fragments;
+};
+
+struct ieee80211_device;
+
+#if 0 /* for later */
+#include "ieee80211_crypt.h"
+#endif
+
+#define SEC_KEY_1         (1<<0)
+#define SEC_KEY_2         (1<<1)
+#define SEC_KEY_3         (1<<2)
+#define SEC_KEY_4         (1<<3)
+#define SEC_ACTIVE_KEY    (1<<4)
+#define SEC_AUTH_MODE     (1<<5)
+#define SEC_UNICAST_GROUP (1<<6)
+#define SEC_LEVEL         (1<<7)
+#define SEC_ENABLED       (1<<8)
+
+#define SEC_LEVEL_0      0 /* None */
+#define SEC_LEVEL_1      1 /* WEP 40 and 104 bit */
+#define SEC_LEVEL_2      2 /* Level 1 + TKIP */
+#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
+#define SEC_LEVEL_3      4 /* Level 2 + CCMP */
+
+#define WEP_KEYS 4
+#define WEP_KEY_LEN 13
+
+struct ieee80211_security {
+       u16 active_key:2,
+            enabled:1,
+           auth_mode:2,
+            auth_algo:4,
+            unicast_uses_group:1;
+       u8 key_sizes[WEP_KEYS];
+       u8 keys[WEP_KEYS][WEP_KEY_LEN];
+       u8 level;
+       u16 flags;
+} __attribute__ ((packed));
+
+
+/*
+
+ 802.11 data frame from AP
+
+      ,-------------------------------------------------------------------.
+Bytes |  2   |  2   |    6    |    6    |    6    |  2   | 0..2312 |   4  |
+      |------|------|---------|---------|---------|------|---------|------|
+Desc. | ctrl | dura |  DA/RA  |   TA    |    SA   | Sequ |  frame  |  fcs |
+      |      | tion | (BSSID) |         |         | ence |  data   |      |
+      `-------------------------------------------------------------------'
+
+Total: 28-2340 bytes
+
+*/
+
+#define BEACON_PROBE_SSID_ID_POSITION 12
+
+/* Management Frame Information Element Types */
+#define MFIE_TYPE_SSID       0
+#define MFIE_TYPE_RATES      1
+#define MFIE_TYPE_FH_SET     2
+#define MFIE_TYPE_DS_SET     3
+#define MFIE_TYPE_CF_SET     4
+#define MFIE_TYPE_TIM        5
+#define MFIE_TYPE_IBSS_SET   6
+#define MFIE_TYPE_CHALLENGE  16
+#define MFIE_TYPE_RSN       48
+#define MFIE_TYPE_RATES_EX   50
+#define MFIE_TYPE_GENERIC    221
+
+struct ieee80211_info_element_hdr {
+       u8 id;
+       u8 len;
+} __attribute__ ((packed));
+
+struct ieee80211_info_element {
+       u8 id;
+       u8 len;
+       u8 data[0];
+} __attribute__ ((packed));
+
+/*
+ * These are the data types that can make up management packets
+ *
+       u16 auth_algorithm;
+       u16 auth_sequence;
+       u16 beacon_interval;
+       u16 capability;
+       u8 current_ap[ETH_ALEN];
+       u16 listen_interval;
+       struct {
+               u16 association_id:14, reserved:2;
+       } __attribute__ ((packed));
+       u32 time_stamp[2];
+       u16 reason;
+       u16 status;
+*/
+
+struct ieee80211_authentication {
+       struct ieee80211_hdr_3addr header;
+       u16 algorithm;
+       u16 transaction;
+       u16 status;
+       struct ieee80211_info_element info_element;
+} __attribute__ ((packed));
+
+
+struct ieee80211_probe_response {
+       struct ieee80211_hdr_3addr header;
+       u32 time_stamp[2];
+       u16 beacon_interval;
+       u16 capability;
+       struct ieee80211_info_element info_element;
+} __attribute__ ((packed));
+
+struct ieee80211_assoc_request_frame {
+       u16 capability;
+       u16 listen_interval;
+       u8 current_ap[ETH_ALEN];
+       struct ieee80211_info_element info_element;
+} __attribute__ ((packed));
+
+struct ieee80211_assoc_response_frame {
+       struct ieee80211_hdr_3addr header;
+       u16 capability;
+       u16 status;
+       u16 aid;
+       struct ieee80211_info_element info_element; /* supported rates */
+} __attribute__ ((packed));
+
+
+struct ieee80211_txb {
+       u8 nr_frags;
+       u8 encrypted;
+       u16 reserved;
+       u16 frag_size;
+       u16 payload_size;
+       struct sk_buff *fragments[0];
+};
+
+
+/* SWEEP TABLE ENTRIES NUMBER*/
+#define MAX_SWEEP_TAB_ENTRIES            42
+#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET  7
+/* MAX_RATES_LENGTH needs to be 12.  The spec says 8, and many APs
+ * only use 8, and then use extended rates for the remaining supported
+ * rates.  Other APs, however, stick all of their supported rates on the
+ * main rates information element... */
+#define MAX_RATES_LENGTH                  ((u8)12)
+#define MAX_RATES_EX_LENGTH               ((u8)16)
+#define MAX_NETWORK_COUNT                  128
+
+#define CRC_LENGTH                 4U
+
+#define MAX_WPA_IE_LEN 64
+
+#define NETWORK_EMPTY_ESSID (1<<0)
+#define NETWORK_HAS_OFDM    (1<<1)
+#define NETWORK_HAS_CCK     (1<<2)
+
+struct ieee80211_network {
+       /* These entries are used to identify a unique network */
+       u8 bssid[ETH_ALEN];
+       u8 channel;
+       /* Ensure null-terminated for any debug msgs */
+       u8 ssid[IW_ESSID_MAX_SIZE + 1];
+       u8 ssid_len;
+
+       /* These are network statistics */
+       struct ieee80211_rx_stats stats;
+       u16 capability;
+       u8 rates[MAX_RATES_LENGTH];
+       u8 rates_len;
+       u8 rates_ex[MAX_RATES_EX_LENGTH];
+       u8 rates_ex_len;
+       unsigned long last_scanned;
+       u8 mode;
+       u8 flags;
+       u32 last_associate;
+       u32 time_stamp[2];
+       u16 beacon_interval;
+       u16 listen_interval;
+       u16 atim_window;
+       u8 wpa_ie[MAX_WPA_IE_LEN];
+       size_t wpa_ie_len;
+       u8 rsn_ie[MAX_WPA_IE_LEN];
+       size_t rsn_ie_len;
+       struct list_head list;
+};
+
+enum ieee80211_state {
+       IEEE80211_UNINITIALIZED = 0,
+       IEEE80211_INITIALIZED,
+       IEEE80211_ASSOCIATING,
+       IEEE80211_ASSOCIATED,
+       IEEE80211_AUTHENTICATING,
+       IEEE80211_AUTHENTICATED,
+       IEEE80211_SHUTDOWN
+};
+
+#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
+#define DEFAULT_FTS 2346
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
+
+
+#define CFG_IEEE80211_RESERVE_FCS (1<<0)
+#define CFG_IEEE80211_COMPUTE_FCS (1<<1)
+
+struct ieee80211_device {
+       struct net_device *dev;
+
+       /* Bookkeeping structures */
+       struct net_device_stats stats;
+       struct ieee80211_stats ieee_stats;
+
+       /* Probe / Beacon management */
+       struct list_head network_free_list;
+       struct list_head network_list;
+       struct ieee80211_network *networks;
+       int scans;
+       int scan_age;
+
+       int iw_mode; /* operating mode (IW_MODE_*) */
+
+       spinlock_t lock;
+
+       int tx_headroom; /* Set to size of any additional room needed at front
+                         * of allocated Tx SKBs */
+       u32 config;
+
+       /* WEP and other encryption related settings at the device level */
+       int open_wep; /* Set to 1 to allow unencrypted frames */
+
+       int reset_on_keychange; /* Set to 1 if the HW needs to be reset on
+                                * WEP key changes */
+
+       /* If the host performs {en,de}cryption, then set to 1 */
+       int host_encrypt;
+       int host_decrypt;
+       int ieee802_1x; /* is IEEE 802.1X used */
+
+       /* WPA data */
+       int wpa_enabled;
+       int drop_unencrypted;
+       int tkip_countermeasures;
+       int privacy_invoked;
+       size_t wpa_ie_len;
+       u8 *wpa_ie;
+
+       struct list_head crypt_deinit_list;
+       struct ieee80211_crypt_data *crypt[WEP_KEYS];
+       int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
+       struct timer_list crypt_deinit_timer;
+
+       int bcrx_sta_key; /* use individual keys to override default keys even
+                          * with RX of broad/multicast frames */
+
+       /* Fragmentation structures */
+       struct ieee80211_frag_entry frag_cache[IEEE80211_FRAG_CACHE_LEN];
+       unsigned int frag_next_idx;
+       u16 fts; /* Fragmentation Threshold */
+
+       /* Association info */
+       u8 bssid[ETH_ALEN];
+
+       enum ieee80211_state state;
+
+       int mode;       /* A, B, G */
+       int modulation; /* CCK, OFDM */
+       int freq_band;  /* 2.4Ghz, 5.2Ghz, Mixed */
+       int abg_ture;   /* ABG flag              */
+
+       /* Callback functions */
+       void (*set_security)(struct net_device *dev,
+                            struct ieee80211_security *sec);
+       int (*hard_start_xmit)(struct ieee80211_txb *txb,
+                              struct net_device *dev);
+       int (*reset_port)(struct net_device *dev);
+
+       /* This must be the last item so that it points to the data
+        * allocated beyond this structure by alloc_ieee80211 */
+       u8 priv[0];
+};
+
+#define IEEE_A            (1<<0)
+#define IEEE_B            (1<<1)
+#define IEEE_G            (1<<2)
+#define IEEE_MODE_MASK    (IEEE_A|IEEE_B|IEEE_G)
+
+extern inline void *ieee80211_priv(struct net_device *dev)
+{
+       return ((struct ieee80211_device *)netdev_priv(dev))->priv;
+}
+
+extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len)
+{
+       /* Single white space is for Linksys APs */
+       if (essid_len == 1 && essid[0] == ' ')
+               return 1;
+
+       /* Otherwise, if the entire essid is 0, we assume it is hidden */
+       while (essid_len) {
+               essid_len--;
+               if (essid[essid_len] != '\0')
+                       return 0;
+       }
+
+       return 1;
+}
+
+extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode)
+{
+       /*
+        * It is possible for both access points and our device to support
+        * combinations of modes, so as long as there is one valid combination
+        * of ap/device supported modes, then return success
+        *
+        */
+       if ((mode & IEEE_A) &&
+           (ieee->modulation & IEEE80211_OFDM_MODULATION) &&
+           (ieee->freq_band & IEEE80211_52GHZ_BAND))
+               return 1;
+
+       if ((mode & IEEE_G) &&
+           (ieee->modulation & IEEE80211_OFDM_MODULATION) &&
+           (ieee->freq_band & IEEE80211_24GHZ_BAND))
+               return 1;
+
+       if ((mode & IEEE_B) &&
+           (ieee->modulation & IEEE80211_CCK_MODULATION) &&
+           (ieee->freq_band & IEEE80211_24GHZ_BAND))
+               return 1;
+
+       return 0;
+}
+
+extern inline int ieee80211_get_hdrlen(u16 fc)
+{
+       int hdrlen = IEEE80211_3ADDR_LEN;
+
+       switch (WLAN_FC_GET_TYPE(fc)) {
+       case IEEE80211_FTYPE_DATA:
+               if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
+                       hdrlen = IEEE80211_4ADDR_LEN;
+               break;
+       case IEEE80211_FTYPE_CTL:
+               switch (WLAN_FC_GET_STYPE(fc)) {
+               case IEEE80211_STYPE_CTS:
+               case IEEE80211_STYPE_ACK:
+                       hdrlen = IEEE80211_1ADDR_LEN;
+                       break;
+               default:
+                       hdrlen = IEEE80211_2ADDR_LEN;
+                       break;
+               }
+               break;
+       }
+
+       return hdrlen;
+}
+
+
+
+/* ieee80211.c */
+extern void free_ieee80211(struct net_device *dev);
+extern struct net_device *alloc_ieee80211(int sizeof_priv);
+
+extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
+
+/* ieee80211_tx.c */
+
+
+extern int ieee80211_xmit(struct sk_buff *skb,
+                         struct net_device *dev);
+extern void ieee80211_txb_free(struct ieee80211_txb *);
+
+
+/* ieee80211_rx.c */
+extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+                       struct ieee80211_rx_stats *rx_stats);
+extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
+                            struct ieee80211_hdr *header,
+                            struct ieee80211_rx_stats *stats);
+
+/* iee80211_wx.c */
+extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
+                                struct iw_request_info *info,
+                                union iwreq_data *wrqu, char *key);
+extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
+                                  struct iw_request_info *info,
+                                  union iwreq_data *wrqu, char *key);
+extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
+                                  struct iw_request_info *info,
+                                  union iwreq_data *wrqu, char *key);
+
+
+extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee)
+{
+       ieee->scans++;
+}
+
+extern inline int ieee80211_get_scans(struct ieee80211_device *ieee)
+{
+       return ieee->scans;
+}
+
+static inline const char *escape_essid(const char *essid, u8 essid_len) {
+       static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+       const char *s = essid;
+       char *d = escaped;
+
+       if (ieee80211_is_empty_essid(essid, essid_len)) {
+               memcpy(escaped, "<hidden>", sizeof("<hidden>"));
+               return escaped;
+       }
+
+       essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE);
+       while (essid_len--) {
+               if (*s == '\0') {
+                       *d++ = '\\';
+                       *d++ = '0';
+                       s++;
+               } else {
+                       *d++ = *s++;
+               }
+       }
+       *d = '\0';
+       return escaped;
+}
+
+#endif /* IEEE80211_H */
index 771b47e30f86eed68fb3c9d221847704b81572a7..69324465e8b357fd1d10e90eac83630319f6dac8 100644 (file)
@@ -183,7 +183,6 @@ struct ipv6_txoptions
        struct ipv6_opt_hdr     *hopopt;
        struct ipv6_opt_hdr     *dst0opt;
        struct ipv6_rt_hdr      *srcrt; /* Routing Header */
-       struct ipv6_opt_hdr     *auth;
        struct ipv6_opt_hdr     *dst1opt;
 
        /* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */
index 4868c7f7749dab76a2abbffdf81ca28e2d0609b8..5999e5684bbfc5136f36964fb3ebe2c0e669f9b1 100644 (file)
@@ -263,23 +263,11 @@ enum { SCTP_MIN_PMTU = 576 };
 enum { SCTP_MAX_DUP_TSNS = 16 };
 enum { SCTP_MAX_GABS = 16 };
 
-/* Here we define the default timers.  */
+/* Heartbeat interval - 30 secs */
+#define SCTP_DEFAULT_TIMEOUT_HEARTBEAT (30 * HZ)
 
-/* cookie timer def = ? seconds */
-#define SCTP_DEFAULT_TIMEOUT_T1_COOKIE (3 * HZ)
-
-/* init timer def = 3 seconds  */
-#define SCTP_DEFAULT_TIMEOUT_T1_INIT   (3 * HZ)
-
-/* shutdown timer def = 300 ms */
-#define SCTP_DEFAULT_TIMEOUT_T2_SHUTDOWN ((300 * HZ) / 1000)
-
-/* 0 seconds + RTO */
-#define SCTP_DEFAULT_TIMEOUT_HEARTBEAT (10 * HZ)
-
-/* recv timer def = 200ms (in usec) */
+/* Delayed sack timer - 200ms */
 #define SCTP_DEFAULT_TIMEOUT_SACK      ((200 * HZ) / 1000)
-#define SCTP_DEFAULT_TIMEOUT_SACK_MAX  ((500 * HZ) / 1000) /* 500 ms */
 
 /* RTO.Initial              - 3  seconds
  * RTO.Min                  - 1  second
index a53e08a45e32fb8e3c271f30d5792b1a7e567cf1..88d9fe5975d50fc27ea1bb87eb38b30b63ea64da 100644 (file)
@@ -131,7 +131,6 @@ sctp_state_fn_t sctp_sf_do_ecne;
 sctp_state_fn_t sctp_sf_ootb;
 sctp_state_fn_t sctp_sf_pdiscard;
 sctp_state_fn_t sctp_sf_violation;
-sctp_state_fn_t sctp_sf_violation_chunklen;
 sctp_state_fn_t sctp_sf_discard_chunk;
 sctp_state_fn_t sctp_sf_do_5_2_1_siminit;
 sctp_state_fn_t sctp_sf_do_5_2_2_dupinit;
@@ -259,11 +258,6 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
 void sctp_chunk_assign_tsn(struct sctp_chunk *);
 void sctp_chunk_assign_ssn(struct sctp_chunk *);
 
-sctp_disposition_t  sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
-                                          __u16 error,
-                                          const struct sctp_association *asoc,
-                                          struct sctp_transport *transport);
-
 /* Prototypes for statetable processing. */
 
 int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
index dfad4d3c581c483c149321df4346b6e52532cacb..47727c7cc628abe7af68a9c69defdb7f11343ee0 100644 (file)
@@ -161,6 +161,9 @@ extern struct sctp_globals {
         */
        int sndbuf_policy;
 
+       /* Delayed SACK timeout  200ms default*/
+       int sack_timeout;
+
        /* HB.interval              - 30 seconds  */
        int hb_interval;
 
@@ -217,6 +220,7 @@ extern struct sctp_globals {
 #define sctp_sndbuf_policy             (sctp_globals.sndbuf_policy)
 #define sctp_max_retrans_path          (sctp_globals.max_retrans_path)
 #define sctp_max_retrans_init          (sctp_globals.max_retrans_init)
+#define sctp_sack_timeout              (sctp_globals.sack_timeout)
 #define sctp_hb_interval               (sctp_globals.hb_interval)
 #define sctp_max_instreams             (sctp_globals.max_instreams)
 #define sctp_max_outstreams            (sctp_globals.max_outstreams)
index e427cf35915c23476570e1097c57c634923ec929..ec9e20c27179af1f6446ece3e97b0dfb090b8403 100644 (file)
@@ -1162,12 +1162,14 @@ extern void tcp_init_congestion_control(struct tcp_sock *tp);
 extern void tcp_cleanup_congestion_control(struct tcp_sock *tp);
 extern int tcp_set_default_congestion_control(const char *name);
 extern void tcp_get_default_congestion_control(char *name);
+extern int tcp_set_congestion_control(struct tcp_sock *tp, const char *name);
 
-extern struct tcp_congestion_ops tcp_reno;
+extern struct tcp_congestion_ops tcp_init_congestion_ops;
 extern u32 tcp_reno_ssthresh(struct tcp_sock *tp);
 extern void tcp_reno_cong_avoid(struct tcp_sock *tp, u32 ack,
                                u32 rtt, u32 in_flight, int flag);
 extern u32 tcp_reno_min_cwnd(struct tcp_sock *tp);
+extern struct tcp_congestion_ops tcp_reno;
 
 static inline void tcp_set_ca_state(struct tcp_sock *tp, u8 ca_state)
 {
index 2000b43ece9184161a632d0c16e30eecc7abcdf5..da19c297dd657c6cac5b9a7f4e7a0b7653c863e6 100644 (file)
 
 #define MANFID_TDK                     0x0105
 #define PRODID_TDK_CF010               0x0900
+#define PRODID_TDK_NP9610              0x0d0a
+#define PRODID_TDK_MN3200              0x0e0a
 #define PRODID_TDK_GN3410              0x4815
 
 #define MANFID_TOSHIBA                 0x0098
index 8d8643adc7866e6bab8ac96580b4ddefdff91ec2..b42ddc0c1143348b896adb42c707fed132b5525e 100644 (file)
@@ -396,7 +396,6 @@ struct pcmcia_socket;
 int pcmcia_access_configuration_register(client_handle_t handle, conf_reg_t *reg);
 int pcmcia_deregister_client(client_handle_t handle);
 int pcmcia_get_configuration_info(client_handle_t handle, config_info_t *config);
-int pcmcia_get_card_services_info(servinfo_t *info);
 int pcmcia_get_first_window(window_handle_t *win, win_req_t *req);
 int pcmcia_get_next_window(window_handle_t *win, win_req_t *req);
 int pcmcia_get_status(client_handle_t handle, cs_status_t *status);
@@ -417,7 +416,6 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt);
 int pcmcia_resume_card(struct pcmcia_socket *skt);
 int pcmcia_eject_card(struct pcmcia_socket *skt);
 int pcmcia_insert_card(struct pcmcia_socket *skt);
-int pcmcia_report_error(client_handle_t handle, error_info_t *err);
 
 struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt);
 void pcmcia_put_socket(struct pcmcia_socket *skt);
diff --git a/include/pcmcia/device_id.h b/include/pcmcia/device_id.h
new file mode 100644 (file)
index 0000000..346d81e
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright (2003-2004)       Dominik Brodowski <linux@brodo.de>
+ *                             David Woodhouse
+ *
+ * License: GPL v2
+ */
+
+#define PCMCIA_DEVICE_MANF_CARD(manf, card) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
+                       PCMCIA_DEV_ID_MATCH_CARD_ID, \
+       .manf_id = (manf), \
+       .card_id = (card), }
+
+#define PCMCIA_DEVICE_FUNC_ID(func) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_FUNC_ID, \
+       .func_id = (func), }
+
+#define PCMCIA_DEVICE_PROD_ID1(v1, vh1) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1, \
+       .prod_id = { (v1), NULL, NULL, NULL }, \
+       .prod_id_hash = { (vh1), 0, 0, 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID2(v2, vh2) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+       .prod_id = { NULL, (v2), NULL, NULL },  \
+       .prod_id_hash = { 0, (vh2), 0, 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID12(v1, v2, vh1, vh2) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+       .prod_id = { (v1), (v2), NULL, NULL }, \
+       .prod_id_hash = { (vh1), (vh2), 0, 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID13(v1, v3, vh1, vh3) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3, \
+       .prod_id = { (v1), NULL, (v3), NULL }, \
+       .prod_id_hash = { (vh1), 0, (vh3), 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID14(v1, v4, vh1, vh4) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID4, \
+       .prod_id = { (v1), NULL, NULL, (v4) }, \
+       .prod_id_hash = { (vh1), 0, 0, (vh4) }, }
+
+#define PCMCIA_DEVICE_PROD_ID123(v1, v2, v3, vh1, vh2, vh3) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3, \
+       .prod_id = { (v1), (v2), (v3), NULL },\
+       .prod_id_hash = { (vh1), (vh2), (vh3), 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID124(v1, v2, v4, vh1, vh2, vh4) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID4, \
+       .prod_id = { (v1), (v2), NULL, (v4) }, \
+       .prod_id_hash = { (vh1), (vh2), 0, (vh4) }, }
+
+#define PCMCIA_DEVICE_PROD_ID134(v1, v3, v4, vh1, vh3, vh4) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID4, \
+       .prod_id = { (v1), NULL, (v3), (v4) }, \
+       .prod_id_hash = { (vh1), 0, (vh3), (vh4) }, }
+
+#define PCMCIA_DEVICE_PROD_ID1234(v1, v2, v3, v4, vh1, vh2, vh3, vh4) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID4, \
+       .prod_id = { (v1), (v2), (v3), (v4) }, \
+       .prod_id_hash = { (vh1), (vh2), (vh3), (vh4) }, }
+
+
+/* multi-function devices */
+
+#define PCMCIA_MFC_DEVICE_MANF_CARD(mfc, manf, card) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
+                       PCMCIA_DEV_ID_MATCH_CARD_ID| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .manf_id = (manf), \
+       .card_id = (card), \
+       .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID1(mfc, v1, vh1) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .prod_id = { (v1), NULL, NULL, NULL }, \
+       .prod_id_hash = { (vh1), 0, 0, 0 }, \
+       .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID2(mfc, v2, vh2) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .prod_id = { NULL, (v2), NULL, NULL },  \
+       .prod_id_hash = { 0, (vh2), 0, 0 }, \
+       .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID12(mfc, v1, v2, vh1, vh2) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .prod_id = { (v1), (v2), NULL, NULL }, \
+       .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+       .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID13(mfc, v1, v3, vh1, vh3) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .prod_id = { (v1), NULL, (v3), NULL }, \
+       .prod_id_hash = { (vh1), 0, (vh3), 0 }, \
+       .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID123(mfc, v1, v2, v3, vh1, vh2, vh3) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .prod_id = { (v1), (v2), (v3), NULL },\
+       .prod_id_hash = { (vh1), (vh2), (vh3), 0 }, \
+       .function = (mfc), }
+
+/* pseudo multi-function devices */
+
+#define PCMCIA_PFC_DEVICE_MANF_CARD(mfc, manf, card) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
+                       PCMCIA_DEV_ID_MATCH_CARD_ID| \
+                       PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+       .manf_id = (manf), \
+       .card_id = (card), \
+       .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID1(mfc, v1, vh1) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+       .prod_id = { (v1), NULL, NULL, NULL }, \
+       .prod_id_hash = { (vh1), 0, 0, 0 }, \
+       .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID2(mfc, v2, vh2) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+       .prod_id = { NULL, (v2), NULL, NULL },  \
+       .prod_id_hash = { 0, (vh2), 0, 0 }, \
+       .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID12(mfc, v1, v2, vh1, vh2) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+       .prod_id = { (v1), (v2), NULL, NULL }, \
+       .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+       .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID13(mfc, v1, v3, vh1, vh3) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+                       PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+       .prod_id = { (v1), NULL, (v3), NULL }, \
+       .prod_id_hash = { (vh1), 0, (vh3), 0 }, \
+       .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID123(mfc, v1, v2, v3, vh1, vh2, vh3) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+                       PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+       .prod_id = { (v1), (v2), (v3), NULL },\
+       .prod_id_hash = { (vh1), (vh2), (vh3), 0 }, \
+       .device_no = (mfc), }
+
+/* cards needing a CIS override */
+
+#define PCMCIA_DEVICE_CIS_MANF_CARD(manf, card, _cisfile) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_MANF_ID| \
+                       PCMCIA_DEV_ID_MATCH_CARD_ID, \
+       .manf_id = (manf), \
+       .card_id = (card), \
+       .cisfile = (_cisfile)}
+
+#define PCMCIA_DEVICE_CIS_PROD_ID12(v1, v2, vh1, vh2, _cisfile) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+       .prod_id = { (v1), (v2), NULL, NULL }, \
+       .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+       .cisfile = (_cisfile)}
+
+#define PCMCIA_DEVICE_CIS_PROD_ID123(v1, v2, v3, vh1, vh2, vh3, _cisfile) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3, \
+       .prod_id = { (v1), (v2), (v3), NULL },\
+       .prod_id_hash = { (vh1), (vh2), (vh3), 0 }, \
+       .cisfile = (_cisfile)}
+
+
+#define PCMCIA_DEVICE_CIS_PROD_ID2(v2, vh2, _cisfile) { \
+       .match_flags =  PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+       .prod_id = { NULL, (v2), NULL, NULL },  \
+       .prod_id_hash = { 0, (vh2), 0, 0 }, \
+       .cisfile = (_cisfile)}
+
+#define PCMCIA_PFC_DEVICE_CIS_PROD_ID12(mfc, v1, v2, vh1, vh2, _cisfile) { \
+       .match_flags =  PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+       .prod_id = { (v1), (v2), NULL, NULL }, \
+       .prod_id_hash = { (vh1), (vh2), 0, 0 },\
+       .device_no = (mfc), \
+       .cisfile = (_cisfile)}
+
+#define PCMCIA_MFC_DEVICE_CIS_MANF_CARD(mfc, manf, card, _cisfile) { \
+       .match_flags =  PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_MANF_ID| \
+                       PCMCIA_DEV_ID_MATCH_CARD_ID| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .manf_id = (manf), \
+       .card_id = (card), \
+       .function = (mfc), \
+       .cisfile = (_cisfile)}
+
+#define PCMCIA_MFC_DEVICE_CIS_PROD_ID12(mfc, v1, v2, vh1, vh2, _cisfile) { \
+       .match_flags =  PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .prod_id = { (v1), (v2), NULL, NULL }, \
+       .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+       .function = (mfc), \
+       .cisfile = (_cisfile)}
+
+#define PCMCIA_MFC_DEVICE_CIS_PROD_ID4(mfc, v4, vh4, _cisfile) { \
+       .match_flags =  PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID4| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .prod_id = { NULL, NULL, NULL, (v4) }, \
+       .prod_id_hash = { 0, 0, 0, (vh4) }, \
+       .function = (mfc), \
+       .cisfile = (_cisfile)}
+
+
+#define PCMCIA_DEVICE_NULL { .match_flags = 0, }
index 312fd958c9014de44bf2dbb0c8f80d7e4b22d726..2b52553f2d945d3ff7c65ecdfb838b440745b1c5 100644 (file)
@@ -18,6 +18,8 @@
 
 #include <pcmcia/bulkmem.h>
 #include <pcmcia/cs_types.h>
+#include <pcmcia/device_id.h>
+#include <linux/mod_devicetable.h>
 
 typedef struct tuple_parse_t {
     tuple_t            tuple;
@@ -129,12 +131,11 @@ typedef struct dev_link_t {
 
 struct pcmcia_socket;
 
-extern struct bus_type pcmcia_bus_type;
-
 struct pcmcia_driver {
        dev_link_t              *(*attach)(void);
        void                    (*detach)(dev_link_t *);
        struct module           *owner;
+       struct pcmcia_device_id *id_table;
        struct device_driver    drv;
 };
 
@@ -173,7 +174,9 @@ struct pcmcia_device {
        u8                      has_manf_id:1;
        u8                      has_card_id:1;
        u8                      has_func_id:1;
-       u8                      reserved:5;
+
+       u8                      allow_func_id_match:1;
+       u8                      reserved:4;
 
        u8                      func_id;
        u16                     manf_id;
index 67b867f31fe48b9fc78c2185169ba7fc608191f3..0f7aacc33fe95d68b24efefe69886e03679e9e34 100644 (file)
 #ifndef _LINUX_SS_H
 #define _LINUX_SS_H
 
+#include <linux/config.h>
+#include <linux/device.h>
+
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/bulkmem.h>
-#include <linux/device.h>
 
 /* Definitions for card status flags for GetStatus */
 #define SS_WRPROT      0x0001
@@ -171,7 +173,7 @@ typedef struct window_t {
 
 struct config_t;
 struct pcmcia_callback;
-
+struct user_info_t;
 
 struct pcmcia_socket {
        struct module                   *owner;
@@ -216,8 +218,9 @@ struct pcmcia_socket {
 
        /* is set to one if resource setup is done using adjust_resource_info() */
        u8                              resource_setup_old:1;
+       u8                              resource_setup_new:1;
 
-       u8                              reserved:6;
+       u8                              reserved:5;
 
        /* socket operations */
        struct pccard_operations *      ops;
@@ -241,9 +244,32 @@ struct pcmcia_socket {
        unsigned int                    thread_events;
 
        /* pcmcia (16-bit) */
-       struct pcmcia_bus_socket        *pcmcia;
        struct pcmcia_callback          *callback;
 
+#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
+       struct list_head                devices_list;   /*  PCMCIA devices */
+       u8                              device_count;   /* the number of devices, used
+                                                        * only internally and subject
+                                                        * to incorrectness and change */
+
+       struct {
+               u8                      present:1,      /* PCMCIA card is present in socket */
+                                       busy:1,         /* "master" ioctl is used */
+                                       dead:1,         /* pcmcia module is being unloaded */
+                                       device_add_pending:1, /* a pseudo-multifunction-device
+                                                              * add event is pending */
+                                       reserved:4;
+       }                               pcmcia_state;
+
+       struct work_struct              device_add;     /* for adding further pseudo-multifunction
+                                                        * devices */
+
+#ifdef CONFIG_PCMCIA_IOCTL
+       struct user_info_t              *user;
+       wait_queue_head_t               queue;
+#endif
+#endif
+
        /* cardbus (32-bit) */
 #ifdef CONFIG_CARDBUS
        struct resource *               cb_cis_res;
diff --git a/include/scsi/sg_request.h b/include/scsi/sg_request.h
new file mode 100644 (file)
index 0000000..57ff525
--- /dev/null
@@ -0,0 +1,26 @@
+typedef struct scsi_request Scsi_Request;
+
+static Scsi_Request *dummy_cmdp;       /* only used for sizeof */
+
+typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */
+       unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */
+       unsigned short sglist_len; /* size of malloc'd scatter-gather list ++ */
+       unsigned bufflen;       /* Size of (aggregate) data buffer */
+       unsigned b_malloc_len;  /* actual len malloc'ed in buffer */
+       void *buffer;           /* Data buffer or scatter list (k_use_sg>0) */
+       char dio_in_use;        /* 0->indirect IO (or mmap), 1->dio */
+       unsigned char cmd_opcode; /* first byte of command */
+} Sg_scatter_hold;
+
+typedef struct sg_request {    /* SG_MAX_QUEUE requests outstanding per file */
+       Scsi_Request *my_cmdp;  /* != 0  when request with lower levels */
+       struct sg_request *nextrp;      /* NULL -> tail request (slist) */
+       struct sg_fd *parentfp; /* NULL -> not in use */
+       Sg_scatter_hold data;   /* hold buffer, perhaps scatter list */
+       sg_io_hdr_t header;     /* scsi command+info, see <scsi/sg.h> */
+       unsigned char sense_b[sizeof (dummy_cmdp->sr_sense_buffer)];
+       char res_used;          /* 1 -> using reserve buffer, 0 -> not ... */
+       char orphan;            /* 1 -> drop on sight, 0 -> normal */
+       char sg_io_owned;       /* 1 -> packet belongs to SG_IO */
+       volatile char done;     /* 0->before bh, 1->before read, 2->read */
+} Sg_request;
index 07e7d31f2d0b09000e7bb9dcce72541d9e89d85d..a05cabd0fd10420a20c6192b989cb8dd23629346 100644 (file)
@@ -41,7 +41,7 @@ static int __init do_linuxrc(void * shell)
 static void __init handle_initrd(void)
 {
        int error;
-       int i, pid;
+       int pid;
 
        real_root_dev = new_encode_dev(ROOT_DEV);
        create_dev("/dev/root.old", Root_RAM0, NULL);
@@ -58,7 +58,7 @@ static void __init handle_initrd(void)
 
        pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
        if (pid > 0) {
-               while (pid != sys_wait4(-1, &i, 0, NULL))
+               while (pid != sys_wait4(-1, NULL, 0, NULL))
                        yield();
        }
 
@@ -86,7 +86,10 @@ static void __init handle_initrd(void)
                printk("okay\n");
        else {
                int fd = sys_open("/dev/root.old", O_RDWR, 0);
-               printk("failed\n");
+               if (error == -ENOENT)
+                       printk("/initrd does not exist. Ignored.\n");
+               else
+                       printk("failed\n");
                printk(KERN_NOTICE "Unmounting old root\n");
                sys_umount("/old", MNT_DETACH);
                printk(KERN_NOTICE "Trying to free ramdisk memory ... ");
index d324801729ba713938481fd4f3a8199fdc2eb6e9..b5e421e39ede7ec40d61da8345e8115a749dc0df 100644 (file)
@@ -383,6 +383,13 @@ static void noinline rest_init(void)
        numa_default_policy();
        unlock_kernel();
        preempt_enable_no_resched();
+
+       /*
+        * The boot idle thread must execute schedule()
+        * at least one to get things moving:
+        */
+       schedule();
+
        cpu_idle();
 } 
 
diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt
new file mode 100644 (file)
index 0000000..0b46a5d
--- /dev/null
@@ -0,0 +1,65 @@
+
+choice
+       prompt "Preemption Model"
+       default PREEMPT_NONE
+
+config PREEMPT_NONE
+       bool "No Forced Preemption (Server)"
+       help
+         This is the traditional Linux preemption model, geared towards
+         throughput. It will still provide good latencies most of the
+         time, but there are no guarantees and occasional longer delays
+         are possible.
+
+         Select this option if you are building a kernel for a server or
+         scientific/computation system, or if you want to maximize the
+         raw processing power of the kernel, irrespective of scheduling
+         latencies.
+
+config PREEMPT_VOLUNTARY
+       bool "Voluntary Kernel Preemption (Desktop)"
+       help
+         This option reduces the latency of the kernel by adding more
+         "explicit preemption points" to the kernel code. These new
+         preemption points have been selected to reduce the maximum
+         latency of rescheduling, providing faster application reactions,
+         at the cost of slighly lower throughput.
+
+         This allows reaction to interactive events by allowing a
+         low priority process to voluntarily preempt itself even if it
+         is in kernel mode executing a system call. This allows
+         applications to run more 'smoothly' even when the system is
+         under load.
+
+         Select this if you are building a kernel for a desktop system.
+
+config PREEMPT
+       bool "Preemptible Kernel (Low-Latency Desktop)"
+       help
+         This option reduces the latency of the kernel by making
+         all kernel code (that is not executing in a critical section)
+         preemptible.  This allows reaction to interactive events by
+         permitting a low priority process to be preempted involuntarily
+         even if it is in kernel mode executing a system call and would
+         otherwise not be about to reach a natural preemption point.
+         This allows applications to run more 'smoothly' even when the
+         system is under load, at the cost of slighly lower throughput
+         and a slight runtime overhead to kernel code.
+
+         Select this if you are building a kernel for a desktop or
+         embedded system with latency requirements in the milliseconds
+         range.
+
+endchoice
+
+config PREEMPT_BKL
+       bool "Preempt The Big Kernel Lock"
+       depends on SMP || PREEMPT
+       default y
+       help
+         This option reduces the latency of the kernel by making the
+         big kernel lock preemptible.
+
+         Say Y here if you are building a kernel for a desktop system.
+         Say N if you are unsure.
+
index b01d26fe8db71abdd0397bcb25eb4e47d3f8c45e..cb05cd05d2374b1ae316adb437ec14da370bd8a5 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PM) += power/
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
+obj-$(CONFIG_KEXEC) += kexec.o
 obj-$(CONFIG_COMPAT) += compat.o
 obj-$(CONFIG_CPUSETS) += cpuset.o
 obj-$(CONFIG_IKCONFIG) += configs.o
@@ -27,6 +28,7 @@ obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
 obj-$(CONFIG_KPROBES) += kprobes.o
 obj-$(CONFIG_SYSFS) += ksysfs.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
+obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
 obj-$(CONFIG_SECCOMP) += seccomp.o
 
 ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
index 628f4ccda12790da9663a4bde4ac897607a8ebd2..53d8263ae12ebc00483a3ad999177799003467e2 100644 (file)
@@ -63,19 +63,15 @@ static int take_cpu_down(void *unused)
 {
        int err;
 
-       /* Take offline: makes arch_cpu_down somewhat easier. */
-       cpu_clear(smp_processor_id(), cpu_online_map);
-
        /* Ensure this CPU doesn't handle any more interrupts. */
        err = __cpu_disable();
        if (err < 0)
-               cpu_set(smp_processor_id(), cpu_online_map);
-       else
-               /* Force idle task to run as soon as we yield: it should
-                  immediately notice cpu is offline and die quickly. */
-               sched_idle_next();
+               return err;
 
-       return err;
+       /* Force idle task to run as soon as we yield: it should
+          immediately notice cpu is offline and die quickly. */
+       sched_idle_next();
+       return 0;
 }
 
 int cpu_down(unsigned int cpu)
index 79dd929f4084395ff82dd6fa8f8065dcc111b16f..984c0bf3807fcc7e56bf339c0620205f79e0205b 100644 (file)
@@ -595,10 +595,62 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
        return 0;
 }
 
+/*
+ * For a given cpuset cur, partition the system as follows
+ * a. All cpus in the parent cpuset's cpus_allowed that are not part of any
+ *    exclusive child cpusets
+ * b. All cpus in the current cpuset's cpus_allowed that are not part of any
+ *    exclusive child cpusets
+ * Build these two partitions by calling partition_sched_domains
+ *
+ * Call with cpuset_sem held.  May nest a call to the
+ * lock_cpu_hotplug()/unlock_cpu_hotplug() pair.
+ */
+static void update_cpu_domains(struct cpuset *cur)
+{
+       struct cpuset *c, *par = cur->parent;
+       cpumask_t pspan, cspan;
+
+       if (par == NULL || cpus_empty(cur->cpus_allowed))
+               return;
+
+       /*
+        * Get all cpus from parent's cpus_allowed not part of exclusive
+        * children
+        */
+       pspan = par->cpus_allowed;
+       list_for_each_entry(c, &par->children, sibling) {
+               if (is_cpu_exclusive(c))
+                       cpus_andnot(pspan, pspan, c->cpus_allowed);
+       }
+       if (is_removed(cur) || !is_cpu_exclusive(cur)) {
+               cpus_or(pspan, pspan, cur->cpus_allowed);
+               if (cpus_equal(pspan, cur->cpus_allowed))
+                       return;
+               cspan = CPU_MASK_NONE;
+       } else {
+               if (cpus_empty(pspan))
+                       return;
+               cspan = cur->cpus_allowed;
+               /*
+                * Get all cpus from current cpuset's cpus_allowed not part
+                * of exclusive children
+                */
+               list_for_each_entry(c, &cur->children, sibling) {
+                       if (is_cpu_exclusive(c))
+                               cpus_andnot(cspan, cspan, c->cpus_allowed);
+               }
+       }
+
+       lock_cpu_hotplug();
+       partition_sched_domains(&pspan, &cspan);
+       unlock_cpu_hotplug();
+}
+
 static int update_cpumask(struct cpuset *cs, char *buf)
 {
        struct cpuset trialcs;
-       int retval;
+       int retval, cpus_unchanged;
 
        trialcs = *cs;
        retval = cpulist_parse(buf, trialcs.cpus_allowed);
@@ -608,9 +660,13 @@ static int update_cpumask(struct cpuset *cs, char *buf)
        if (cpus_empty(trialcs.cpus_allowed))
                return -ENOSPC;
        retval = validate_change(cs, &trialcs);
-       if (retval == 0)
-               cs->cpus_allowed = trialcs.cpus_allowed;
-       return retval;
+       if (retval < 0)
+               return retval;
+       cpus_unchanged = cpus_equal(cs->cpus_allowed, trialcs.cpus_allowed);
+       cs->cpus_allowed = trialcs.cpus_allowed;
+       if (is_cpu_exclusive(cs) && !cpus_unchanged)
+               update_cpu_domains(cs);
+       return 0;
 }
 
 static int update_nodemask(struct cpuset *cs, char *buf)
@@ -646,7 +702,7 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf)
 {
        int turning_on;
        struct cpuset trialcs;
-       int err;
+       int err, cpu_exclusive_changed;
 
        turning_on = (simple_strtoul(buf, NULL, 10) != 0);
 
@@ -657,13 +713,18 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf)
                clear_bit(bit, &trialcs.flags);
 
        err = validate_change(cs, &trialcs);
-       if (err == 0) {
-               if (turning_on)
-                       set_bit(bit, &cs->flags);
-               else
-                       clear_bit(bit, &cs->flags);
-       }
-       return err;
+       if (err < 0)
+               return err;
+       cpu_exclusive_changed =
+               (is_cpu_exclusive(cs) != is_cpu_exclusive(&trialcs));
+       if (turning_on)
+               set_bit(bit, &cs->flags);
+       else
+               clear_bit(bit, &cs->flags);
+
+       if (cpu_exclusive_changed)
+                update_cpu_domains(cs);
+       return 0;
 }
 
 static int attach_task(struct cpuset *cs, char *buf)
@@ -1309,12 +1370,14 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry)
                up(&cpuset_sem);
                return -EBUSY;
        }
-       spin_lock(&cs->dentry->d_lock);
        parent = cs->parent;
        set_bit(CS_REMOVED, &cs->flags);
+       if (is_cpu_exclusive(cs))
+               update_cpu_domains(cs);
        list_del(&cs->sibling); /* delete my sibling from parent->children */
        if (list_empty(&parent->children))
                check_for_release(parent);
+       spin_lock(&cs->dentry->d_lock);
        d = dget(cs->dentry);
        cs->dentry = NULL;
        spin_unlock(&d->d_lock);
diff --git a/kernel/crash_dump.c b/kernel/crash_dump.c
new file mode 100644 (file)
index 0000000..459ba49
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *     kernel/crash_dump.c - Memory preserving reboot related code.
+ *
+ *     Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
+ *     Copyright (C) IBM Corporation, 2004. All rights reserved
+ */
+
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/bootmem.h>
+#include <linux/highmem.h>
+#include <linux/crash_dump.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+/* Stores the physical address of elf header of crash image. */
+unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
+
+/*
+ * Copy a page from "oldmem". For this page, there is no pte mapped
+ * in the current kernel. We stitch up a pte, similar to kmap_atomic.
+ */
+ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
+                               size_t csize, unsigned long offset, int userbuf)
+{
+       void *page, *vaddr;
+
+       if (!csize)
+               return 0;
+
+       page = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!page)
+               return -ENOMEM;
+
+       vaddr = kmap_atomic_pfn(pfn, KM_PTE0);
+       copy_page(page, vaddr);
+       kunmap_atomic(vaddr, KM_PTE0);
+
+       if (userbuf) {
+               if (copy_to_user(buf, (page + offset), csize)) {
+                       kfree(page);
+                       return -EFAULT;
+               }
+       } else {
+               memcpy(buf, (page + offset), csize);
+       }
+
+       kfree(page);
+       return csize;
+}
index 3ebcd60a19c69e76bab6d9b70cbd0d75508b3422..9d1b10ed0135139b8514f829f345c6525699db50 100644 (file)
@@ -784,6 +784,8 @@ fastcall NORET_TYPE void do_exit(long code)
 
        profile_task_exit(tsk);
 
+       WARN_ON(atomic_read(&tsk->fs_excl));
+
        if (unlikely(in_interrupt()))
                panic("Aiee, killing interrupt handler!");
        if (unlikely(!tsk->pid))
index a28d11e10877d07ebdd1ccde6006493122873b28..cdef6cea8900d67910bb1199ca7728c045a1737b 100644 (file)
@@ -1003,9 +1003,6 @@ static task_t *copy_process(unsigned long clone_flags,
        p->pdeath_signal = 0;
        p->exit_state = 0;
 
-       /* Perform scheduler related setup */
-       sched_fork(p);
-
        /*
         * Ok, make it visible to the rest of the system.
         * We dont wake it up yet.
@@ -1014,18 +1011,24 @@ static task_t *copy_process(unsigned long clone_flags,
        INIT_LIST_HEAD(&p->ptrace_children);
        INIT_LIST_HEAD(&p->ptrace_list);
 
+       /* Perform scheduler related setup. Assign this task to a CPU. */
+       sched_fork(p, clone_flags);
+
        /* Need tasklist lock for parent etc handling! */
        write_lock_irq(&tasklist_lock);
 
        /*
-        * The task hasn't been attached yet, so cpus_allowed mask cannot
-        * have changed. The cpus_allowed mask of the parent may have
-        * changed after it was copied first time, and it may then move to
-        * another CPU - so we re-copy it here and set the child's CPU to
-        * the parent's CPU. This avoids alot of nasty races.
+        * The task hasn't been attached yet, so its cpus_allowed mask will
+        * not be changed, nor will its assigned CPU.
+        *
+        * The cpus_allowed mask of the parent may have changed after it was
+        * copied first time - so re-copy it here, then check the child's CPU
+        * to ensure it is on a valid CPU (and if not, just force it back to
+        * parent's CPU). This avoids alot of nasty races.
         */
        p->cpus_allowed = current->cpus_allowed;
-       set_task_cpu(p, smp_processor_id());
+       if (unlikely(!cpu_isset(task_cpu(p), p->cpus_allowed)))
+               set_task_cpu(p, smp_processor_id());
 
        /*
         * Check for pending SIGKILL! The new thread should not be allowed
@@ -1087,6 +1090,11 @@ static task_t *copy_process(unsigned long clone_flags,
                spin_unlock(&current->sighand->siglock);
        }
 
+       /*
+        * inherit ioprio
+        */
+       p->ioprio = current->ioprio;
+
        SET_LINKS(p);
        if (unlikely(p->ptrace & PT_PTRACED))
                __ptrace_link(p, current->parent);
index 98d62d8efeaf93192c00b40ffe7841e228f64ea5..3467097ca61ae476a74a7eb1519950acc9a8ebcf 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
 
 /*
  * Autodetection depends on the fact that any interrupt that
@@ -26,7 +27,7 @@ static DECLARE_MUTEX(probe_sem);
  */
 unsigned long probe_irq_on(void)
 {
-       unsigned long val, delay;
+       unsigned long val;
        irq_desc_t *desc;
        unsigned int i;
 
@@ -45,8 +46,7 @@ unsigned long probe_irq_on(void)
        }
 
        /* Wait for longstanding interrupts to trigger. */
-       for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
-               /* about 20ms delay */ barrier();
+       msleep(20);
 
        /*
         * enable any unassigned irqs
@@ -68,8 +68,7 @@ unsigned long probe_irq_on(void)
        /*
         * Wait for spurious interrupts to trigger
         */
-       for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
-               /* about 100ms delay */ barrier();
+       msleep(100);
 
        /*
         * Now filter out any obviously spurious interrupts
index 436c7d93c00a9555f245da72ce9efced1bffd47b..c29f83c16497cff719b118bf1a8fabfb78076cd2 100644 (file)
@@ -172,7 +172,7 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)
 
                spin_lock(&desc->lock);
                if (!noirqdebug)
-                       note_interrupt(irq, desc, action_ret);
+                       note_interrupt(irq, desc, action_ret, regs);
                if (likely(!(desc->status & IRQ_PENDING)))
                        break;
                desc->status &= ~IRQ_PENDING;
index f6297c306905536e14f0a70263e3da6a691c891e..7df9abd5ec86e2f16a72e76281b6a171c29fb1f4 100644 (file)
 #include <linux/kallsyms.h>
 #include <linux/interrupt.h>
 
+static int irqfixup;
+
+/*
+ * Recovery handler for misrouted interrupts.
+ */
+
+static int misrouted_irq(int irq, struct pt_regs *regs)
+{
+       int i;
+       irq_desc_t *desc;
+       int ok = 0;
+       int work = 0;   /* Did we do work for a real IRQ */
+
+       for(i = 1; i < NR_IRQS; i++) {
+               struct irqaction *action;
+
+               if (i == irq)   /* Already tried */
+                       continue;
+               desc = &irq_desc[i];
+               spin_lock(&desc->lock);
+               action = desc->action;
+               /* Already running on another processor */
+               if (desc->status & IRQ_INPROGRESS) {
+                       /*
+                        * Already running: If it is shared get the other
+                        * CPU to go looking for our mystery interrupt too
+                        */
+                       if (desc->action && (desc->action->flags & SA_SHIRQ))
+                               desc->status |= IRQ_PENDING;
+                       spin_unlock(&desc->lock);
+                       continue;
+               }
+               /* Honour the normal IRQ locking */
+               desc->status |= IRQ_INPROGRESS;
+               spin_unlock(&desc->lock);
+               while (action) {
+                       /* Only shared IRQ handlers are safe to call */
+                       if (action->flags & SA_SHIRQ) {
+                               if (action->handler(i, action->dev_id, regs) ==
+                                               IRQ_HANDLED)
+                                       ok = 1;
+                       }
+                       action = action->next;
+               }
+               local_irq_disable();
+               /* Now clean up the flags */
+               spin_lock(&desc->lock);
+               action = desc->action;
+
+               /*
+                * While we were looking for a fixup someone queued a real
+                * IRQ clashing with our walk
+                */
+
+               while ((desc->status & IRQ_PENDING) && action) {
+                       /*
+                        * Perform real IRQ processing for the IRQ we deferred
+                        */
+                       work = 1;
+                       spin_unlock(&desc->lock);
+                       handle_IRQ_event(i, regs, action);
+                       spin_lock(&desc->lock);
+                       desc->status &= ~IRQ_PENDING;
+               }
+               desc->status &= ~IRQ_INPROGRESS;
+               /*
+                * If we did actual work for the real IRQ line we must let the
+                * IRQ controller clean up too
+                */
+               if(work)
+                       desc->handler->end(i);
+               spin_unlock(&desc->lock);
+       }
+       /* So the caller can adjust the irq error counts */
+       return ok;
+}
+
 /*
  * If 99,900 of the previous 100,000 interrupts have not been handled
  * then assume that the IRQ is stuck in some manner. Drop a diagnostic
@@ -31,7 +108,8 @@ __report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
                printk(KERN_ERR "irq event %d: bogus return value %x\n",
                                irq, action_ret);
        } else {
-               printk(KERN_ERR "irq %d: nobody cared!\n", irq);
+               printk(KERN_ERR "irq %d: nobody cared (try booting with "
+                               "the \"irqpoll\" option)\n", irq);
        }
        dump_stack();
        printk(KERN_ERR "handlers:\n");
@@ -45,7 +123,7 @@ __report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
        }
 }
 
-void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
+static void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
 {
        static int count = 100;
 
@@ -55,7 +133,8 @@ void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
        }
 }
 
-void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
+void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret,
+                       struct pt_regs *regs)
 {
        if (action_ret != IRQ_HANDLED) {
                desc->irqs_unhandled++;
@@ -63,6 +142,15 @@ void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
                        report_bad_irq(irq, desc, action_ret);
        }
 
+       if (unlikely(irqfixup)) {
+               /* Don't punish working computers */
+               if ((irqfixup == 2 && irq == 0) || action_ret == IRQ_NONE) {
+                       int ok = misrouted_irq(irq, regs);
+                       if (action_ret == IRQ_NONE)
+                               desc->irqs_unhandled -= ok;
+               }
+       }
+
        desc->irq_count++;
        if (desc->irq_count < 100000)
                return;
@@ -94,3 +182,24 @@ int __init noirqdebug_setup(char *str)
 
 __setup("noirqdebug", noirqdebug_setup);
 
+static int __init irqfixup_setup(char *str)
+{
+       irqfixup = 1;
+       printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n");
+       printk(KERN_WARNING "This may impact system performance.\n");
+       return 1;
+}
+
+__setup("irqfixup", irqfixup_setup);
+
+static int __init irqpoll_setup(char *str)
+{
+       irqfixup = 2;
+       printk(KERN_WARNING "Misrouted IRQ fixup and polling support "
+                               "enabled\n");
+       printk(KERN_WARNING "This may significantly impact system "
+                               "performance\n");
+       return 1;
+}
+
+__setup("irqpoll", irqpoll_setup);
index 1dc988e0d2c77e962063c776b7b035800f51b9be..a72cb0e5aa4b5d6f94764e128e4f376f0dc6591e 100644 (file)
@@ -153,11 +153,15 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
 
        switch (which) {
        case ITIMER_REAL:
+again:
                spin_lock_irq(&tsk->sighand->siglock);
                interval = tsk->signal->it_real_incr;
                val = it_real_value(tsk->signal);
-               if (val)
-                       del_timer_sync(&tsk->signal->real_timer);
+               /* We are sharing ->siglock with it_real_fn() */
+               if (try_to_del_timer_sync(&tsk->signal->real_timer) < 0) {
+                       spin_unlock_irq(&tsk->sighand->siglock);
+                       goto again;
+               }
                tsk->signal->it_real_incr =
                        timeval_to_jiffies(&value->it_interval);
                it_real_arm(tsk, timeval_to_jiffies(&value->it_value));
diff --git a/kernel/kexec.c b/kernel/kexec.c
new file mode 100644 (file)
index 0000000..cdd4dcd
--- /dev/null
@@ -0,0 +1,1063 @@
+/*
+ * kexec.c - kexec system call
+ * Copyright (C) 2002-2004 Eric Biederman  <ebiederm@xmission.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/kexec.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/highmem.h>
+#include <linux/syscalls.h>
+#include <linux/reboot.h>
+#include <linux/syscalls.h>
+#include <linux/ioport.h>
+#include <linux/hardirq.h>
+
+#include <asm/page.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/semaphore.h>
+
+/* Location of the reserved area for the crash kernel */
+struct resource crashk_res = {
+       .name  = "Crash kernel",
+       .start = 0,
+       .end   = 0,
+       .flags = IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+int kexec_should_crash(struct task_struct *p)
+{
+       if (in_interrupt() || !p->pid || p->pid == 1 || panic_on_oops)
+               return 1;
+       return 0;
+}
+
+/*
+ * When kexec transitions to the new kernel there is a one-to-one
+ * mapping between physical and virtual addresses.  On processors
+ * where you can disable the MMU this is trivial, and easy.  For
+ * others it is still a simple predictable page table to setup.
+ *
+ * In that environment kexec copies the new kernel to its final
+ * resting place.  This means I can only support memory whose
+ * physical address can fit in an unsigned long.  In particular
+ * addresses where (pfn << PAGE_SHIFT) > ULONG_MAX cannot be handled.
+ * If the assembly stub has more restrictive requirements
+ * KEXEC_SOURCE_MEMORY_LIMIT and KEXEC_DEST_MEMORY_LIMIT can be
+ * defined more restrictively in <asm/kexec.h>.
+ *
+ * The code for the transition from the current kernel to the
+ * the new kernel is placed in the control_code_buffer, whose size
+ * is given by KEXEC_CONTROL_CODE_SIZE.  In the best case only a single
+ * page of memory is necessary, but some architectures require more.
+ * Because this memory must be identity mapped in the transition from
+ * virtual to physical addresses it must live in the range
+ * 0 - TASK_SIZE, as only the user space mappings are arbitrarily
+ * modifiable.
+ *
+ * The assembly stub in the control code buffer is passed a linked list
+ * of descriptor pages detailing the source pages of the new kernel,
+ * and the destination addresses of those source pages.  As this data
+ * structure is not used in the context of the current OS, it must
+ * be self-contained.
+ *
+ * The code has been made to work with highmem pages and will use a
+ * destination page in its final resting place (if it happens
+ * to allocate it).  The end product of this is that most of the
+ * physical address space, and most of RAM can be used.
+ *
+ * Future directions include:
+ *  - allocating a page table with the control code buffer identity
+ *    mapped, to simplify machine_kexec and make kexec_on_panic more
+ *    reliable.
+ */
+
+/*
+ * KIMAGE_NO_DEST is an impossible destination address..., for
+ * allocating pages whose destination address we do not care about.
+ */
+#define KIMAGE_NO_DEST (-1UL)
+
+static int kimage_is_destination_range(struct kimage *image,
+                                      unsigned long start, unsigned long end);
+static struct page *kimage_alloc_page(struct kimage *image,
+                                      unsigned int gfp_mask,
+                                      unsigned long dest);
+
+static int do_kimage_alloc(struct kimage **rimage, unsigned long entry,
+                           unsigned long nr_segments,
+                            struct kexec_segment __user *segments)
+{
+       size_t segment_bytes;
+       struct kimage *image;
+       unsigned long i;
+       int result;
+
+       /* Allocate a controlling structure */
+       result = -ENOMEM;
+       image = kmalloc(sizeof(*image), GFP_KERNEL);
+       if (!image)
+               goto out;
+
+       memset(image, 0, sizeof(*image));
+       image->head = 0;
+       image->entry = &image->head;
+       image->last_entry = &image->head;
+       image->control_page = ~0; /* By default this does not apply */
+       image->start = entry;
+       image->type = KEXEC_TYPE_DEFAULT;
+
+       /* Initialize the list of control pages */
+       INIT_LIST_HEAD(&image->control_pages);
+
+       /* Initialize the list of destination pages */
+       INIT_LIST_HEAD(&image->dest_pages);
+
+       /* Initialize the list of unuseable pages */
+       INIT_LIST_HEAD(&image->unuseable_pages);
+
+       /* Read in the segments */
+       image->nr_segments = nr_segments;
+       segment_bytes = nr_segments * sizeof(*segments);
+       result = copy_from_user(image->segment, segments, segment_bytes);
+       if (result)
+               goto out;
+
+       /*
+        * Verify we have good destination addresses.  The caller is
+        * responsible for making certain we don't attempt to load
+        * the new image into invalid or reserved areas of RAM.  This
+        * just verifies it is an address we can use.
+        *
+        * Since the kernel does everything in page size chunks ensure
+        * the destination addreses are page aligned.  Too many
+        * special cases crop of when we don't do this.  The most
+        * insidious is getting overlapping destination addresses
+        * simply because addresses are changed to page size
+        * granularity.
+        */
+       result = -EADDRNOTAVAIL;
+       for (i = 0; i < nr_segments; i++) {
+               unsigned long mstart, mend;
+
+               mstart = image->segment[i].mem;
+               mend   = mstart + image->segment[i].memsz;
+               if ((mstart & ~PAGE_MASK) || (mend & ~PAGE_MASK))
+                       goto out;
+               if (mend >= KEXEC_DESTINATION_MEMORY_LIMIT)
+                       goto out;
+       }
+
+       /* Verify our destination addresses do not overlap.
+        * If we alloed overlapping destination addresses
+        * through very weird things can happen with no
+        * easy explanation as one segment stops on another.
+        */
+       result = -EINVAL;
+       for (i = 0; i < nr_segments; i++) {
+               unsigned long mstart, mend;
+               unsigned long j;
+
+               mstart = image->segment[i].mem;
+               mend   = mstart + image->segment[i].memsz;
+               for (j = 0; j < i; j++) {
+                       unsigned long pstart, pend;
+                       pstart = image->segment[j].mem;
+                       pend   = pstart + image->segment[j].memsz;
+                       /* Do the segments overlap ? */
+                       if ((mend > pstart) && (mstart < pend))
+                               goto out;
+               }
+       }
+
+       /* Ensure our buffer sizes are strictly less than
+        * our memory sizes.  This should always be the case,
+        * and it is easier to check up front than to be surprised
+        * later on.
+        */
+       result = -EINVAL;
+       for (i = 0; i < nr_segments; i++) {
+               if (image->segment[i].bufsz > image->segment[i].memsz)
+                       goto out;
+       }
+
+       result = 0;
+out:
+       if (result == 0)
+               *rimage = image;
+       else
+               kfree(image);
+
+       return result;
+
+}
+
+static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry,
+                               unsigned long nr_segments,
+                               struct kexec_segment __user *segments)
+{
+       int result;
+       struct kimage *image;
+
+       /* Allocate and initialize a controlling structure */
+       image = NULL;
+       result = do_kimage_alloc(&image, entry, nr_segments, segments);
+       if (result)
+               goto out;
+
+       *rimage = image;
+
+       /*
+        * Find a location for the control code buffer, and add it
+        * the vector of segments so that it's pages will also be
+        * counted as destination pages.
+        */
+       result = -ENOMEM;
+       image->control_code_page = kimage_alloc_control_pages(image,
+                                          get_order(KEXEC_CONTROL_CODE_SIZE));
+       if (!image->control_code_page) {
+               printk(KERN_ERR "Could not allocate control_code_buffer\n");
+               goto out;
+       }
+
+       result = 0;
+ out:
+       if (result == 0)
+               *rimage = image;
+       else
+               kfree(image);
+
+       return result;
+}
+
+static int kimage_crash_alloc(struct kimage **rimage, unsigned long entry,
+                               unsigned long nr_segments,
+                               struct kexec_segment __user *segments)
+{
+       int result;
+       struct kimage *image;
+       unsigned long i;
+
+       image = NULL;
+       /* Verify we have a valid entry point */
+       if ((entry < crashk_res.start) || (entry > crashk_res.end)) {
+               result = -EADDRNOTAVAIL;
+               goto out;
+       }
+
+       /* Allocate and initialize a controlling structure */
+       result = do_kimage_alloc(&image, entry, nr_segments, segments);
+       if (result)
+               goto out;
+
+       /* Enable the special crash kernel control page
+        * allocation policy.
+        */
+       image->control_page = crashk_res.start;
+       image->type = KEXEC_TYPE_CRASH;
+
+       /*
+        * Verify we have good destination addresses.  Normally
+        * the caller is responsible for making certain we don't
+        * attempt to load the new image into invalid or reserved
+        * areas of RAM.  But crash kernels are preloaded into a
+        * reserved area of ram.  We must ensure the addresses
+        * are in the reserved area otherwise preloading the
+        * kernel could corrupt things.
+        */
+       result = -EADDRNOTAVAIL;
+       for (i = 0; i < nr_segments; i++) {
+               unsigned long mstart, mend;
+
+               mstart = image->segment[i].mem;
+               mend = mstart + image->segment[i].memsz - 1;
+               /* Ensure we are within the crash kernel limits */
+               if ((mstart < crashk_res.start) || (mend > crashk_res.end))
+                       goto out;
+       }
+
+       /*
+        * Find a location for the control code buffer, and add
+        * the vector of segments so that it's pages will also be
+        * counted as destination pages.
+        */
+       result = -ENOMEM;
+       image->control_code_page = kimage_alloc_control_pages(image,
+                                          get_order(KEXEC_CONTROL_CODE_SIZE));
+       if (!image->control_code_page) {
+               printk(KERN_ERR "Could not allocate control_code_buffer\n");
+               goto out;
+       }
+
+       result = 0;
+out:
+       if (result == 0)
+               *rimage = image;
+       else
+               kfree(image);
+
+       return result;
+}
+
+static int kimage_is_destination_range(struct kimage *image,
+                                       unsigned long start,
+                                       unsigned long end)
+{
+       unsigned long i;
+
+       for (i = 0; i < image->nr_segments; i++) {
+               unsigned long mstart, mend;
+
+               mstart = image->segment[i].mem;
+               mend = mstart + image->segment[i].memsz;
+               if ((end > mstart) && (start < mend))
+                       return 1;
+       }
+
+       return 0;
+}
+
+static struct page *kimage_alloc_pages(unsigned int gfp_mask,
+                                       unsigned int order)
+{
+       struct page *pages;
+
+       pages = alloc_pages(gfp_mask, order);
+       if (pages) {
+               unsigned int count, i;
+               pages->mapping = NULL;
+               pages->private = order;
+               count = 1 << order;
+               for (i = 0; i < count; i++)
+                       SetPageReserved(pages + i);
+       }
+
+       return pages;
+}
+
+static void kimage_free_pages(struct page *page)
+{
+       unsigned int order, count, i;
+
+       order = page->private;
+       count = 1 << order;
+       for (i = 0; i < count; i++)
+               ClearPageReserved(page + i);
+       __free_pages(page, order);
+}
+
+static void kimage_free_page_list(struct list_head *list)
+{
+       struct list_head *pos, *next;
+
+       list_for_each_safe(pos, next, list) {
+               struct page *page;
+
+               page = list_entry(pos, struct page, lru);
+               list_del(&page->lru);
+               kimage_free_pages(page);
+       }
+}
+
+static struct page *kimage_alloc_normal_control_pages(struct kimage *image,
+                                                       unsigned int order)
+{
+       /* Control pages are special, they are the intermediaries
+        * that are needed while we copy the rest of the pages
+        * to their final resting place.  As such they must
+        * not conflict with either the destination addresses
+        * or memory the kernel is already using.
+        *
+        * The only case where we really need more than one of
+        * these are for architectures where we cannot disable
+        * the MMU and must instead generate an identity mapped
+        * page table for all of the memory.
+        *
+        * At worst this runs in O(N) of the image size.
+        */
+       struct list_head extra_pages;
+       struct page *pages;
+       unsigned int count;
+
+       count = 1 << order;
+       INIT_LIST_HEAD(&extra_pages);
+
+       /* Loop while I can allocate a page and the page allocated
+        * is a destination page.
+        */
+       do {
+               unsigned long pfn, epfn, addr, eaddr;
+
+               pages = kimage_alloc_pages(GFP_KERNEL, order);
+               if (!pages)
+                       break;
+               pfn   = page_to_pfn(pages);
+               epfn  = pfn + count;
+               addr  = pfn << PAGE_SHIFT;
+               eaddr = epfn << PAGE_SHIFT;
+               if ((epfn >= (KEXEC_CONTROL_MEMORY_LIMIT >> PAGE_SHIFT)) ||
+                             kimage_is_destination_range(image, addr, eaddr)) {
+                       list_add(&pages->lru, &extra_pages);
+                       pages = NULL;
+               }
+       } while (!pages);
+
+       if (pages) {
+               /* Remember the allocated page... */
+               list_add(&pages->lru, &image->control_pages);
+
+               /* Because the page is already in it's destination
+                * location we will never allocate another page at
+                * that address.  Therefore kimage_alloc_pages
+                * will not return it (again) and we don't need
+                * to give it an entry in image->segment[].
+                */
+       }
+       /* Deal with the destination pages I have inadvertently allocated.
+        *
+        * Ideally I would convert multi-page allocations into single
+        * page allocations, and add everyting to image->dest_pages.
+        *
+        * For now it is simpler to just free the pages.
+        */
+       kimage_free_page_list(&extra_pages);
+
+       return pages;
+}
+
+static struct page *kimage_alloc_crash_control_pages(struct kimage *image,
+                                                     unsigned int order)
+{
+       /* Control pages are special, they are the intermediaries
+        * that are needed while we copy the rest of the pages
+        * to their final resting place.  As such they must
+        * not conflict with either the destination addresses
+        * or memory the kernel is already using.
+        *
+        * Control pages are also the only pags we must allocate
+        * when loading a crash kernel.  All of the other pages
+        * are specified by the segments and we just memcpy
+        * into them directly.
+        *
+        * The only case where we really need more than one of
+        * these are for architectures where we cannot disable
+        * the MMU and must instead generate an identity mapped
+        * page table for all of the memory.
+        *
+        * Given the low demand this implements a very simple
+        * allocator that finds the first hole of the appropriate
+        * size in the reserved memory region, and allocates all
+        * of the memory up to and including the hole.
+        */
+       unsigned long hole_start, hole_end, size;
+       struct page *pages;
+
+       pages = NULL;
+       size = (1 << order) << PAGE_SHIFT;
+       hole_start = (image->control_page + (size - 1)) & ~(size - 1);
+       hole_end   = hole_start + size - 1;
+       while (hole_end <= crashk_res.end) {
+               unsigned long i;
+
+               if (hole_end > KEXEC_CONTROL_MEMORY_LIMIT)
+                       break;
+               if (hole_end > crashk_res.end)
+                       break;
+               /* See if I overlap any of the segments */
+               for (i = 0; i < image->nr_segments; i++) {
+                       unsigned long mstart, mend;
+
+                       mstart = image->segment[i].mem;
+                       mend   = mstart + image->segment[i].memsz - 1;
+                       if ((hole_end >= mstart) && (hole_start <= mend)) {
+                               /* Advance the hole to the end of the segment */
+                               hole_start = (mend + (size - 1)) & ~(size - 1);
+                               hole_end   = hole_start + size - 1;
+                               break;
+                       }
+               }
+               /* If I don't overlap any segments I have found my hole! */
+               if (i == image->nr_segments) {
+                       pages = pfn_to_page(hole_start >> PAGE_SHIFT);
+                       break;
+               }
+       }
+       if (pages)
+               image->control_page = hole_end;
+
+       return pages;
+}
+
+
+struct page *kimage_alloc_control_pages(struct kimage *image,
+                                        unsigned int order)
+{
+       struct page *pages = NULL;
+
+       switch (image->type) {
+       case KEXEC_TYPE_DEFAULT:
+               pages = kimage_alloc_normal_control_pages(image, order);
+               break;
+       case KEXEC_TYPE_CRASH:
+               pages = kimage_alloc_crash_control_pages(image, order);
+               break;
+       }
+
+       return pages;
+}
+
+static int kimage_add_entry(struct kimage *image, kimage_entry_t entry)
+{
+       if (*image->entry != 0)
+               image->entry++;
+
+       if (image->entry == image->last_entry) {
+               kimage_entry_t *ind_page;
+               struct page *page;
+
+               page = kimage_alloc_page(image, GFP_KERNEL, KIMAGE_NO_DEST);
+               if (!page)
+                       return -ENOMEM;
+
+               ind_page = page_address(page);
+               *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION;
+               image->entry = ind_page;
+               image->last_entry = ind_page +
+                                     ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1);
+       }
+       *image->entry = entry;
+       image->entry++;
+       *image->entry = 0;
+
+       return 0;
+}
+
+static int kimage_set_destination(struct kimage *image,
+                                  unsigned long destination)
+{
+       int result;
+
+       destination &= PAGE_MASK;
+       result = kimage_add_entry(image, destination | IND_DESTINATION);
+       if (result == 0)
+               image->destination = destination;
+
+       return result;
+}
+
+
+static int kimage_add_page(struct kimage *image, unsigned long page)
+{
+       int result;
+
+       page &= PAGE_MASK;
+       result = kimage_add_entry(image, page | IND_SOURCE);
+       if (result == 0)
+               image->destination += PAGE_SIZE;
+
+       return result;
+}
+
+
+static void kimage_free_extra_pages(struct kimage *image)
+{
+       /* Walk through and free any extra destination pages I may have */
+       kimage_free_page_list(&image->dest_pages);
+
+       /* Walk through and free any unuseable pages I have cached */
+       kimage_free_page_list(&image->unuseable_pages);
+
+}
+static int kimage_terminate(struct kimage *image)
+{
+       if (*image->entry != 0)
+               image->entry++;
+
+       *image->entry = IND_DONE;
+
+       return 0;
+}
+
+#define for_each_kimage_entry(image, ptr, entry) \
+       for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \
+               ptr = (entry & IND_INDIRECTION)? \
+                       phys_to_virt((entry & PAGE_MASK)): ptr +1)
+
+static void kimage_free_entry(kimage_entry_t entry)
+{
+       struct page *page;
+
+       page = pfn_to_page(entry >> PAGE_SHIFT);
+       kimage_free_pages(page);
+}
+
+static void kimage_free(struct kimage *image)
+{
+       kimage_entry_t *ptr, entry;
+       kimage_entry_t ind = 0;
+
+       if (!image)
+               return;
+
+       kimage_free_extra_pages(image);
+       for_each_kimage_entry(image, ptr, entry) {
+               if (entry & IND_INDIRECTION) {
+                       /* Free the previous indirection page */
+                       if (ind & IND_INDIRECTION)
+                               kimage_free_entry(ind);
+                       /* Save this indirection page until we are
+                        * done with it.
+                        */
+                       ind = entry;
+               }
+               else if (entry & IND_SOURCE)
+                       kimage_free_entry(entry);
+       }
+       /* Free the final indirection page */
+       if (ind & IND_INDIRECTION)
+               kimage_free_entry(ind);
+
+       /* Handle any machine specific cleanup */
+       machine_kexec_cleanup(image);
+
+       /* Free the kexec control pages... */
+       kimage_free_page_list(&image->control_pages);
+       kfree(image);
+}
+
+static kimage_entry_t *kimage_dst_used(struct kimage *image,
+                                       unsigned long page)
+{
+       kimage_entry_t *ptr, entry;
+       unsigned long destination = 0;
+
+       for_each_kimage_entry(image, ptr, entry) {
+               if (entry & IND_DESTINATION)
+                       destination = entry & PAGE_MASK;
+               else if (entry & IND_SOURCE) {
+                       if (page == destination)
+                               return ptr;
+                       destination += PAGE_SIZE;
+               }
+       }
+
+       return NULL;
+}
+
+static struct page *kimage_alloc_page(struct kimage *image,
+                                       unsigned int gfp_mask,
+                                       unsigned long destination)
+{
+       /*
+        * Here we implement safeguards to ensure that a source page
+        * is not copied to its destination page before the data on
+        * the destination page is no longer useful.
+        *
+        * To do this we maintain the invariant that a source page is
+        * either its own destination page, or it is not a
+        * destination page at all.
+        *
+        * That is slightly stronger than required, but the proof
+        * that no problems will not occur is trivial, and the
+        * implementation is simply to verify.
+        *
+        * When allocating all pages normally this algorithm will run
+        * in O(N) time, but in the worst case it will run in O(N^2)
+        * time.   If the runtime is a problem the data structures can
+        * be fixed.
+        */
+       struct page *page;
+       unsigned long addr;
+
+       /*
+        * Walk through the list of destination pages, and see if I
+        * have a match.
+        */
+       list_for_each_entry(page, &image->dest_pages, lru) {
+               addr = page_to_pfn(page) << PAGE_SHIFT;
+               if (addr == destination) {
+                       list_del(&page->lru);
+                       return page;
+               }
+       }
+       page = NULL;
+       while (1) {
+               kimage_entry_t *old;
+
+               /* Allocate a page, if we run out of memory give up */
+               page = kimage_alloc_pages(gfp_mask, 0);
+               if (!page)
+                       return NULL;
+               /* If the page cannot be used file it away */
+               if (page_to_pfn(page) >
+                               (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) {
+                       list_add(&page->lru, &image->unuseable_pages);
+                       continue;
+               }
+               addr = page_to_pfn(page) << PAGE_SHIFT;
+
+               /* If it is the destination page we want use it */
+               if (addr == destination)
+                       break;
+
+               /* If the page is not a destination page use it */
+               if (!kimage_is_destination_range(image, addr,
+                                                 addr + PAGE_SIZE))
+                       break;
+
+               /*
+                * I know that the page is someones destination page.
+                * See if there is already a source page for this
+                * destination page.  And if so swap the source pages.
+                */
+               old = kimage_dst_used(image, addr);
+               if (old) {
+                       /* If so move it */
+                       unsigned long old_addr;
+                       struct page *old_page;
+
+                       old_addr = *old & PAGE_MASK;
+                       old_page = pfn_to_page(old_addr >> PAGE_SHIFT);
+                       copy_highpage(page, old_page);
+                       *old = addr | (*old & ~PAGE_MASK);
+
+                       /* The old page I have found cannot be a
+                        * destination page, so return it.
+                        */
+                       addr = old_addr;
+                       page = old_page;
+                       break;
+               }
+               else {
+                       /* Place the page on the destination list I
+                        * will use it later.
+                        */
+                       list_add(&page->lru, &image->dest_pages);
+               }
+       }
+
+       return page;
+}
+
+static int kimage_load_normal_segment(struct kimage *image,
+                                        struct kexec_segment *segment)
+{
+       unsigned long maddr;
+       unsigned long ubytes, mbytes;
+       int result;
+       unsigned char __user *buf;
+
+       result = 0;
+       buf = segment->buf;
+       ubytes = segment->bufsz;
+       mbytes = segment->memsz;
+       maddr = segment->mem;
+
+       result = kimage_set_destination(image, maddr);
+       if (result < 0)
+               goto out;
+
+       while (mbytes) {
+               struct page *page;
+               char *ptr;
+               size_t uchunk, mchunk;
+
+               page = kimage_alloc_page(image, GFP_HIGHUSER, maddr);
+               if (page == 0) {
+                       result  = -ENOMEM;
+                       goto out;
+               }
+               result = kimage_add_page(image, page_to_pfn(page)
+                                                               << PAGE_SHIFT);
+               if (result < 0)
+                       goto out;
+
+               ptr = kmap(page);
+               /* Start with a clear page */
+               memset(ptr, 0, PAGE_SIZE);
+               ptr += maddr & ~PAGE_MASK;
+               mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK);
+               if (mchunk > mbytes)
+                       mchunk = mbytes;
+
+               uchunk = mchunk;
+               if (uchunk > ubytes)
+                       uchunk = ubytes;
+
+               result = copy_from_user(ptr, buf, uchunk);
+               kunmap(page);
+               if (result) {
+                       result = (result < 0) ? result : -EIO;
+                       goto out;
+               }
+               ubytes -= uchunk;
+               maddr  += mchunk;
+               buf    += mchunk;
+               mbytes -= mchunk;
+       }
+out:
+       return result;
+}
+
+static int kimage_load_crash_segment(struct kimage *image,
+                                       struct kexec_segment *segment)
+{
+       /* For crash dumps kernels we simply copy the data from
+        * user space to it's destination.
+        * We do things a page at a time for the sake of kmap.
+        */
+       unsigned long maddr;
+       unsigned long ubytes, mbytes;
+       int result;
+       unsigned char __user *buf;
+
+       result = 0;
+       buf = segment->buf;
+       ubytes = segment->bufsz;
+       mbytes = segment->memsz;
+       maddr = segment->mem;
+       while (mbytes) {
+               struct page *page;
+               char *ptr;
+               size_t uchunk, mchunk;
+
+               page = pfn_to_page(maddr >> PAGE_SHIFT);
+               if (page == 0) {
+                       result  = -ENOMEM;
+                       goto out;
+               }
+               ptr = kmap(page);
+               ptr += maddr & ~PAGE_MASK;
+               mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK);
+               if (mchunk > mbytes)
+                       mchunk = mbytes;
+
+               uchunk = mchunk;
+               if (uchunk > ubytes) {
+                       uchunk = ubytes;
+                       /* Zero the trailing part of the page */
+                       memset(ptr + uchunk, 0, mchunk - uchunk);
+               }
+               result = copy_from_user(ptr, buf, uchunk);
+               kunmap(page);
+               if (result) {
+                       result = (result < 0) ? result : -EIO;
+                       goto out;
+               }
+               ubytes -= uchunk;
+               maddr  += mchunk;
+               buf    += mchunk;
+               mbytes -= mchunk;
+       }
+out:
+       return result;
+}
+
+static int kimage_load_segment(struct kimage *image,
+                               struct kexec_segment *segment)
+{
+       int result = -ENOMEM;
+
+       switch (image->type) {
+       case KEXEC_TYPE_DEFAULT:
+               result = kimage_load_normal_segment(image, segment);
+               break;
+       case KEXEC_TYPE_CRASH:
+               result = kimage_load_crash_segment(image, segment);
+               break;
+       }
+
+       return result;
+}
+
+/*
+ * Exec Kernel system call: for obvious reasons only root may call it.
+ *
+ * This call breaks up into three pieces.
+ * - A generic part which loads the new kernel from the current
+ *   address space, and very carefully places the data in the
+ *   allocated pages.
+ *
+ * - A generic part that interacts with the kernel and tells all of
+ *   the devices to shut down.  Preventing on-going dmas, and placing
+ *   the devices in a consistent state so a later kernel can
+ *   reinitialize them.
+ *
+ * - A machine specific part that includes the syscall number
+ *   and the copies the image to it's final destination.  And
+ *   jumps into the image at entry.
+ *
+ * kexec does not sync, or unmount filesystems so if you need
+ * that to happen you need to do that yourself.
+ */
+struct kimage *kexec_image = NULL;
+static struct kimage *kexec_crash_image = NULL;
+/*
+ * A home grown binary mutex.
+ * Nothing can wait so this mutex is safe to use
+ * in interrupt context :)
+ */
+static int kexec_lock = 0;
+
+asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments,
+                               struct kexec_segment __user *segments,
+                               unsigned long flags)
+{
+       struct kimage **dest_image, *image;
+       int locked;
+       int result;
+
+       /* We only trust the superuser with rebooting the system. */
+       if (!capable(CAP_SYS_BOOT))
+               return -EPERM;
+
+       /*
+        * Verify we have a legal set of flags
+        * This leaves us room for future extensions.
+        */
+       if ((flags & KEXEC_FLAGS) != (flags & ~KEXEC_ARCH_MASK))
+               return -EINVAL;
+
+       /* Verify we are on the appropriate architecture */
+       if (((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH) &&
+               ((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH_DEFAULT))
+               return -EINVAL;
+
+       /* Put an artificial cap on the number
+        * of segments passed to kexec_load.
+        */
+       if (nr_segments > KEXEC_SEGMENT_MAX)
+               return -EINVAL;
+
+       image = NULL;
+       result = 0;
+
+       /* Because we write directly to the reserved memory
+        * region when loading crash kernels we need a mutex here to
+        * prevent multiple crash  kernels from attempting to load
+        * simultaneously, and to prevent a crash kernel from loading
+        * over the top of a in use crash kernel.
+        *
+        * KISS: always take the mutex.
+        */
+       locked = xchg(&kexec_lock, 1);
+       if (locked)
+               return -EBUSY;
+
+       dest_image = &kexec_image;
+       if (flags & KEXEC_ON_CRASH)
+               dest_image = &kexec_crash_image;
+       if (nr_segments > 0) {
+               unsigned long i;
+
+               /* Loading another kernel to reboot into */
+               if ((flags & KEXEC_ON_CRASH) == 0)
+                       result = kimage_normal_alloc(&image, entry,
+                                                       nr_segments, segments);
+               /* Loading another kernel to switch to if this one crashes */
+               else if (flags & KEXEC_ON_CRASH) {
+                       /* Free any current crash dump kernel before
+                        * we corrupt it.
+                        */
+                       kimage_free(xchg(&kexec_crash_image, NULL));
+                       result = kimage_crash_alloc(&image, entry,
+                                                    nr_segments, segments);
+               }
+               if (result)
+                       goto out;
+
+               result = machine_kexec_prepare(image);
+               if (result)
+                       goto out;
+
+               for (i = 0; i < nr_segments; i++) {
+                       result = kimage_load_segment(image, &image->segment[i]);
+                       if (result)
+                               goto out;
+               }
+               result = kimage_terminate(image);
+               if (result)
+                       goto out;
+       }
+       /* Install the new kernel, and  Uninstall the old */
+       image = xchg(dest_image, image);
+
+out:
+       xchg(&kexec_lock, 0); /* Release the mutex */
+       kimage_free(image);
+
+       return result;
+}
+
+#ifdef CONFIG_COMPAT
+asmlinkage long compat_sys_kexec_load(unsigned long entry,
+                               unsigned long nr_segments,
+                               struct compat_kexec_segment __user *segments,
+                               unsigned long flags)
+{
+       struct compat_kexec_segment in;
+       struct kexec_segment out, __user *ksegments;
+       unsigned long i, result;
+
+       /* Don't allow clients that don't understand the native
+        * architecture to do anything.
+        */
+       if ((flags & KEXEC_ARCH_MASK) == KEXEC_ARCH_DEFAULT)
+               return -EINVAL;
+
+       if (nr_segments > KEXEC_SEGMENT_MAX)
+               return -EINVAL;
+
+       ksegments = compat_alloc_user_space(nr_segments * sizeof(out));
+       for (i=0; i < nr_segments; i++) {
+               result = copy_from_user(&in, &segments[i], sizeof(in));
+               if (result)
+                       return -EFAULT;
+
+               out.buf   = compat_ptr(in.buf);
+               out.bufsz = in.bufsz;
+               out.mem   = in.mem;
+               out.memsz = in.memsz;
+
+               result = copy_to_user(&ksegments[i], &out, sizeof(out));
+               if (result)
+                       return -EFAULT;
+       }
+
+       return sys_kexec_load(entry, nr_segments, ksegments, flags);
+}
+#endif
+
+void crash_kexec(struct pt_regs *regs)
+{
+       struct kimage *image;
+       int locked;
+
+
+       /* Take the kexec_lock here to prevent sys_kexec_load
+        * running on one cpu from replacing the crash kernel
+        * we are using after a panic on a different cpu.
+        *
+        * If the crash kernel was not located in a fixed area
+        * of memory the xchg(&kexec_crash_image) would be
+        * sufficient.  But since I reuse the memory...
+        */
+       locked = xchg(&kexec_lock, 1);
+       if (!locked) {
+               image = xchg(&kexec_crash_image, NULL);
+               if (image) {
+                       machine_crash_shutdown(regs);
+                       machine_kexec(image);
+               }
+               xchg(&kexec_lock, 0);
+       }
+}
index eed53d4f5230571b6bba0597bf24d8edeef4dc27..44166e3bb8afab469a61575946b46da45e215cc7 100644 (file)
@@ -120,6 +120,7 @@ struct subprocess_info {
        char *path;
        char **argv;
        char **envp;
+       struct key *ring;
        int wait;
        int retval;
 };
@@ -130,16 +131,21 @@ struct subprocess_info {
 static int ____call_usermodehelper(void *data)
 {
        struct subprocess_info *sub_info = data;
+       struct key *old_session;
        int retval;
 
-       /* Unblock all signals. */
+       /* Unblock all signals and set the session keyring. */
+       key_get(sub_info->ring);
        flush_signals(current);
        spin_lock_irq(&current->sighand->siglock);
+       old_session = __install_session_keyring(current, sub_info->ring);
        flush_signal_handlers(current, 1);
        sigemptyset(&current->blocked);
        recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
 
+       key_put(old_session);
+
        /* We can run anywhere, unlike our parent keventd(). */
        set_cpus_allowed(current, CPU_MASK_ALL);
 
@@ -211,10 +217,11 @@ static void __call_usermodehelper(void *data)
 }
 
 /**
- * call_usermodehelper - start a usermode application
+ * call_usermodehelper_keys - start a usermode application
  * @path: pathname for the application
  * @argv: null-terminated argument list
  * @envp: null-terminated environment list
+ * @session_keyring: session keyring for process (NULL for an empty keyring)
  * @wait: wait for the application to finish and return status.
  *
  * Runs a user-space application.  The application is started
@@ -224,7 +231,8 @@ static void __call_usermodehelper(void *data)
  * Must be called from process context.  Returns a negative error code
  * if program was not execed successfully, or 0.
  */
-int call_usermodehelper(char *path, char **argv, char **envp, int wait)
+int call_usermodehelper_keys(char *path, char **argv, char **envp,
+                            struct key *session_keyring, int wait)
 {
        DECLARE_COMPLETION(done);
        struct subprocess_info sub_info = {
@@ -232,6 +240,7 @@ int call_usermodehelper(char *path, char **argv, char **envp, int wait)
                .path           = path,
                .argv           = argv,
                .envp           = envp,
+               .ring           = session_keyring,
                .wait           = wait,
                .retval         = 0,
        };
@@ -247,7 +256,7 @@ int call_usermodehelper(char *path, char **argv, char **envp, int wait)
        wait_for_completion(&done);
        return sub_info.retval;
 }
-EXPORT_SYMBOL(call_usermodehelper);
+EXPORT_SYMBOL(call_usermodehelper_keys);
 
 void __init usermodehelper_init(void)
 {
index 334f37472c56af4ee808e94f3d5b0034cafec452..90c0e82b650c09d2a6c8ed2af37318a7c6afd414 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/moduleloader.h>
 #include <asm/cacheflush.h>
 #include <asm/errno.h>
 #include <asm/kdebug.h>
@@ -50,6 +51,106 @@ unsigned int kprobe_cpu = NR_CPUS;
 static DEFINE_SPINLOCK(kprobe_lock);
 static struct kprobe *curr_kprobe;
 
+/*
+ * kprobe->ainsn.insn points to the copy of the instruction to be
+ * single-stepped. x86_64, POWER4 and above have no-exec support and
+ * stepping on the instruction on a vmalloced/kmalloced/data page
+ * is a recipe for disaster
+ */
+#define INSNS_PER_PAGE (PAGE_SIZE/(MAX_INSN_SIZE * sizeof(kprobe_opcode_t)))
+
+struct kprobe_insn_page {
+       struct hlist_node hlist;
+       kprobe_opcode_t *insns;         /* Page of instruction slots */
+       char slot_used[INSNS_PER_PAGE];
+       int nused;
+};
+
+static struct hlist_head kprobe_insn_pages;
+
+/**
+ * get_insn_slot() - Find a slot on an executable page for an instruction.
+ * We allocate an executable page if there's no room on existing ones.
+ */
+kprobe_opcode_t *get_insn_slot(void)
+{
+       struct kprobe_insn_page *kip;
+       struct hlist_node *pos;
+
+       hlist_for_each(pos, &kprobe_insn_pages) {
+               kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
+               if (kip->nused < INSNS_PER_PAGE) {
+                       int i;
+                       for (i = 0; i < INSNS_PER_PAGE; i++) {
+                               if (!kip->slot_used[i]) {
+                                       kip->slot_used[i] = 1;
+                                       kip->nused++;
+                                       return kip->insns + (i * MAX_INSN_SIZE);
+                               }
+                       }
+                       /* Surprise!  No unused slots.  Fix kip->nused. */
+                       kip->nused = INSNS_PER_PAGE;
+               }
+       }
+
+       /* All out of space.  Need to allocate a new page. Use slot 0.*/
+       kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL);
+       if (!kip) {
+               return NULL;
+       }
+
+       /*
+        * Use module_alloc so this page is within +/- 2GB of where the
+        * kernel image and loaded module images reside. This is required
+        * so x86_64 can correctly handle the %rip-relative fixups.
+        */
+       kip->insns = module_alloc(PAGE_SIZE);
+       if (!kip->insns) {
+               kfree(kip);
+               return NULL;
+       }
+       INIT_HLIST_NODE(&kip->hlist);
+       hlist_add_head(&kip->hlist, &kprobe_insn_pages);
+       memset(kip->slot_used, 0, INSNS_PER_PAGE);
+       kip->slot_used[0] = 1;
+       kip->nused = 1;
+       return kip->insns;
+}
+
+void free_insn_slot(kprobe_opcode_t *slot)
+{
+       struct kprobe_insn_page *kip;
+       struct hlist_node *pos;
+
+       hlist_for_each(pos, &kprobe_insn_pages) {
+               kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
+               if (kip->insns <= slot &&
+                   slot < kip->insns + (INSNS_PER_PAGE * MAX_INSN_SIZE)) {
+                       int i = (slot - kip->insns) / MAX_INSN_SIZE;
+                       kip->slot_used[i] = 0;
+                       kip->nused--;
+                       if (kip->nused == 0) {
+                               /*
+                                * Page is no longer in use.  Free it unless
+                                * it's the last one.  We keep the last one
+                                * so as not to have to set it up again the
+                                * next time somebody inserts a probe.
+                                */
+                               hlist_del(&kip->hlist);
+                               if (hlist_empty(&kprobe_insn_pages)) {
+                                       INIT_HLIST_NODE(&kip->hlist);
+                                       hlist_add_head(&kip->hlist,
+                                               &kprobe_insn_pages);
+                               } else {
+                                       module_free(NULL, kip->insns);
+                                       kfree(kip);
+                               }
+                       }
+                       return;
+               }
+       }
+}
+
 /* Locks kprobe: irqs must be disabled */
 void lock_kprobes(void)
 {
@@ -139,12 +240,6 @@ static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
        return 0;
 }
 
-struct kprobe trampoline_p = {
-               .addr = (kprobe_opcode_t *) &kretprobe_trampoline,
-               .pre_handler = trampoline_probe_handler,
-               .post_handler = trampoline_post_handler
-};
-
 struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp)
 {
        struct hlist_node *node;
@@ -163,35 +258,18 @@ static struct kretprobe_instance *get_used_rp_inst(struct kretprobe *rp)
        return NULL;
 }
 
-struct kretprobe_instance *get_rp_inst(void *sara)
-{
-       struct hlist_head *head;
-       struct hlist_node *node;
-       struct task_struct *tsk;
-       struct kretprobe_instance *ri;
-
-       tsk = arch_get_kprobe_task(sara);
-       head = &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)];
-       hlist_for_each_entry(ri, node, head, hlist) {
-               if (ri->stack_addr == sara)
-                       return ri;
-       }
-       return NULL;
-}
-
 void add_rp_inst(struct kretprobe_instance *ri)
 {
-       struct task_struct *tsk;
        /*
         * Remove rp inst off the free list -
         * Add it back when probed function returns
         */
        hlist_del(&ri->uflist);
-       tsk = arch_get_kprobe_task(ri->stack_addr);
+
        /* Add rp inst onto table */
        INIT_HLIST_NODE(&ri->hlist);
        hlist_add_head(&ri->hlist,
-                       &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)]);
+                       &kretprobe_inst_table[hash_ptr(ri->task, KPROBE_HASH_BITS)]);
 
        /* Also add this rp inst to the used list. */
        INIT_HLIST_NODE(&ri->uflist);
@@ -218,34 +296,25 @@ struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk)
        return &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)];
 }
 
-struct kretprobe_instance *get_rp_inst_tsk(struct task_struct *tk)
-{
-       struct task_struct *tsk;
-       struct hlist_head *head;
-       struct hlist_node *node;
-       struct kretprobe_instance *ri;
-
-       head = &kretprobe_inst_table[hash_ptr(tk, KPROBE_HASH_BITS)];
-
-       hlist_for_each_entry(ri, node, head, hlist) {
-               tsk = arch_get_kprobe_task(ri->stack_addr);
-               if (tsk == tk)
-                       return ri;
-       }
-       return NULL;
-}
-
 /*
- * This function is called from do_exit or do_execv when task tk's stack is
- * about to be recycled. Recycle any function-return probe instances
- * associated with this task. These represent probed functions that have
- * been called but may never return.
+ * This function is called from exit_thread or flush_thread when task tk's
+ * stack is being recycled so that we can recycle any function-return probe
+ * instances associated with this task. These left over instances represent
+ * probed functions that have been called but will never return.
  */
 void kprobe_flush_task(struct task_struct *tk)
 {
+        struct kretprobe_instance *ri;
+        struct hlist_head *head;
+       struct hlist_node *node, *tmp;
        unsigned long flags = 0;
+
        spin_lock_irqsave(&kprobe_lock, flags);
-       arch_kprobe_flush_task(tk);
+        head = kretprobe_inst_table_head(current);
+        hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+                if (ri->task == tk)
+                        recycle_rp_inst(ri);
+        }
        spin_unlock_irqrestore(&kprobe_lock, flags);
 }
 
@@ -505,9 +574,10 @@ static int __init init_kprobes(void)
                INIT_HLIST_HEAD(&kretprobe_inst_table[i]);
        }
 
-       err = register_die_notifier(&kprobe_exceptions_nb);
-       /* Register the trampoline probe for return probe */
-       register_kprobe(&trampoline_p);
+       err = arch_init();
+       if (!err)
+               err = register_die_notifier(&kprobe_exceptions_nb);
+
        return err;
 }
 
index 1f064a63f8cfe7b7f575b82c38315bf5e79f2344..015fb69ad94da0724fcd7806aecf29405fbc7949 100644 (file)
@@ -30,12 +30,25 @@ static ssize_t hotplug_seqnum_show(struct subsystem *subsys, char *page)
 KERNEL_ATTR_RO(hotplug_seqnum);
 #endif
 
+#ifdef CONFIG_KEXEC
+#include <asm/kexec.h>
+
+static ssize_t crash_notes_show(struct subsystem *subsys, char *page)
+{
+       return sprintf(page, "%p\n", (void *)crash_notes);
+}
+KERNEL_ATTR_RO(crash_notes);
+#endif
+
 decl_subsys(kernel, NULL, NULL);
 EXPORT_SYMBOL_GPL(kernel_subsys);
 
 static struct attribute * kernel_attrs[] = {
 #ifdef CONFIG_HOTPLUG
        &hotplug_seqnum_attr.attr,
+#endif
+#ifdef CONFIG_KEXEC
+       &crash_notes_attr.attr,
 #endif
        NULL
 };
index a566745dde621a075e225c52a432316bec58afc0..068e271ab3a538761c9129ec4b5fae0fdbe50910 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/notifier.h>
 #include <linux/stop_machine.h>
 #include <linux/device.h>
+#include <linux/string.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 #include <asm/cacheflush.h>
@@ -370,6 +371,43 @@ static inline void percpu_modcopy(void *pcpudst, const void *src,
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_MODULE_UNLOAD
+#define MODINFO_ATTR(field)    \
+static void setup_modinfo_##field(struct module *mod, const char *s)  \
+{                                                                     \
+       mod->field = kstrdup(s, GFP_KERNEL);                          \
+}                                                                     \
+static ssize_t show_modinfo_##field(struct module_attribute *mattr,   \
+                       struct module *mod, char *buffer)             \
+{                                                                     \
+       return sprintf(buffer, "%s\n", mod->field);                   \
+}                                                                     \
+static int modinfo_##field##_exists(struct module *mod)               \
+{                                                                     \
+       return mod->field != NULL;                                    \
+}                                                                     \
+static void free_modinfo_##field(struct module *mod)                  \
+{                                                                     \
+        kfree(mod->field);                                            \
+        mod->field = NULL;                                            \
+}                                                                     \
+static struct module_attribute modinfo_##field = {                    \
+       .attr = { .name = __stringify(field), .mode = 0444,           \
+                 .owner = THIS_MODULE },                             \
+       .show = show_modinfo_##field,                                 \
+       .setup = setup_modinfo_##field,                               \
+       .test = modinfo_##field##_exists,                             \
+       .free = free_modinfo_##field,                                 \
+};
+
+MODINFO_ATTR(version);
+MODINFO_ATTR(srcversion);
+
+static struct module_attribute *modinfo_attrs[] = {
+       &modinfo_version,
+       &modinfo_srcversion,
+       NULL,
+};
+
 /* Init the unload section of the module. */
 static void module_unload_init(struct module *mod)
 {
@@ -692,7 +730,7 @@ static int obsparm_copy_string(const char *val, struct kernel_param *kp)
        return 0;
 }
 
-int set_obsolete(const char *val, struct kernel_param *kp)
+static int set_obsolete(const char *val, struct kernel_param *kp)
 {
        unsigned int min, max;
        unsigned int size, maxsize;
@@ -1031,6 +1069,32 @@ static void module_remove_refcnt_attr(struct module *mod)
 }
 #endif
 
+#ifdef CONFIG_MODULE_UNLOAD
+static int module_add_modinfo_attrs(struct module *mod)
+{
+       struct module_attribute *attr;
+       int error = 0;
+       int i;
+
+       for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
+               if (!attr->test ||
+                   (attr->test && attr->test(mod)))
+                       error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr);
+       }
+       return error;
+}
+
+static void module_remove_modinfo_attrs(struct module *mod)
+{
+       struct module_attribute *attr;
+       int i;
+
+       for (i = 0; (attr = modinfo_attrs[i]); i++) {
+               sysfs_remove_file(&mod->mkobj.kobj,&attr->attr);
+               attr->free(mod);
+       }
+}
+#endif
 
 static int mod_sysfs_setup(struct module *mod,
                           struct kernel_param *kparam,
@@ -1056,6 +1120,12 @@ static int mod_sysfs_setup(struct module *mod,
        if (err)
                goto out_unreg;
 
+#ifdef CONFIG_MODULE_UNLOAD
+       err = module_add_modinfo_attrs(mod);
+       if (err)
+               goto out_unreg;
+#endif
+
        return 0;
 
 out_unreg:
@@ -1066,6 +1136,9 @@ out:
 
 static void mod_kobject_remove(struct module *mod)
 {
+#ifdef CONFIG_MODULE_UNLOAD
+       module_remove_modinfo_attrs(mod);
+#endif
        module_remove_refcnt_attr(mod);
        module_param_sysfs_remove(mod);
 
@@ -1311,6 +1384,23 @@ static char *get_modinfo(Elf_Shdr *sechdrs,
        return NULL;
 }
 
+#ifdef CONFIG_MODULE_UNLOAD
+static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
+                         unsigned int infoindex)
+{
+       struct module_attribute *attr;
+       int i;
+
+       for (i = 0; (attr = modinfo_attrs[i]); i++) {
+               if (attr->setup)
+                       attr->setup(mod,
+                                   get_modinfo(sechdrs,
+                                               infoindex,
+                                               attr->attr.name));
+       }
+}
+#endif
+
 #ifdef CONFIG_KALLSYMS
 int is_exported(const char *name, const struct module *mod)
 {
@@ -1615,6 +1705,11 @@ static struct module *load_module(void __user *umod,
        /* Set up license info based on the info section */
        set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
 
+#ifdef CONFIG_MODULE_UNLOAD
+       /* Set up MODINFO_ATTR fields */
+       setup_modinfo(mod, sechdrs, infoindex);
+#endif
+
        /* Fix up syms, so that st_value is a pointer to location. */
        err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
                               mod);
index 081f7465fc8dec17d3e69a5c9ff7c29f8165ad5b..74ba5f3e46c746059b044072b7bce99f53aa3551 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/sysrq.h>
 #include <linux/interrupt.h>
 #include <linux/nmi.h>
+#include <linux/kexec.h>
 
 int panic_timeout;
 int panic_on_oops;
@@ -63,6 +64,13 @@ NORET_TYPE void panic(const char * fmt, ...)
         unsigned long caller = (unsigned long) __builtin_return_address(0);
 #endif
 
+       /*
+        * It's possible to come here directly from a panic-assertion and not
+        * have preempt disabled. Some functions called from here want
+        * preempt to be disabled. No point enabling it later though...
+        */
+       preempt_disable();
+
        bust_spinlocks(1);
        va_start(args, fmt);
        vsnprintf(buf, sizeof(buf), fmt, args);
@@ -70,7 +78,19 @@ NORET_TYPE void panic(const char * fmt, ...)
        printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
        bust_spinlocks(0);
 
+       /*
+        * If we have crashed and we have a crash kernel loaded let it handle
+        * everything else.
+        * Do we want to call this before we try to display a message?
+        */
+       crash_kexec(NULL);
+
 #ifdef CONFIG_SMP
+       /*
+        * Note smp_send_stop is the usual smp shutdown function, which
+        * unfortunately means it may not be hardened to work in a panic
+        * situation.
+        */
        smp_send_stop();
 #endif
 
@@ -79,8 +99,7 @@ NORET_TYPE void panic(const char * fmt, ...)
        if (!panic_blink)
                panic_blink = no_blink;
 
-       if (panic_timeout > 0)
-       {
+       if (panic_timeout > 0) {
                /*
                 * Delay timeout seconds before rebooting the machine. 
                 * We can't use the "normal" timers since we just panicked..
index 696387ffe49c8c0cd6c1bf71dcd08f512f6d86b5..2c7121d9bff11aff162a578bd68d7934c1030104 100644 (file)
@@ -27,8 +27,8 @@ config PM_DEBUG
        like suspend support.
 
 config SOFTWARE_SUSPEND
-       bool "Software Suspend (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && PM && SWAP
+       bool "Software Suspend"
+       depends on EXPERIMENTAL && PM && SWAP && ((X86 && SMP) || ((FVR || PPC32 || X86) && !SMP))
        ---help---
          Enable the possibility of suspending the machine.
          It doesn't need APM.
@@ -72,3 +72,7 @@ config PM_STD_PARTITION
          suspended image to. It will simply pick the first available swap 
          device.
 
+config SUSPEND_SMP
+       bool
+       depends on HOTPLUG_CPU && X86 && PM
+       default y
index fbdc634135a765a90b04eb224c2c38126747340c..2f438d0eaa13640a91ec78acc086c559bc523060 100644 (file)
@@ -3,9 +3,9 @@ ifeq ($(CONFIG_PM_DEBUG),y)
 EXTRA_CFLAGS   +=      -DDEBUG
 endif
 
-swsusp-smp-$(CONFIG_SMP)       += smp.o
-
 obj-y                          := main.o process.o console.o pm.o
-obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o $(swsusp-smp-y) disk.o
+obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o
+
+obj-$(CONFIG_SUSPEND_SMP)      += smp.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)      += poweroff.o
index 02b6764034dcbbe7781ba9e519f44e102dc9d5a7..fb8de63c29192061a6938417bac924a55e800851 100644 (file)
@@ -117,8 +117,8 @@ static void finish(void)
 {
        device_resume();
        platform_finish();
-       enable_nonboot_cpus();
        thaw_processes();
+       enable_nonboot_cpus();
        pm_restore_console();
 }
 
@@ -131,28 +131,35 @@ static int prepare_processes(void)
 
        sys_sync();
 
+       disable_nonboot_cpus();
+
        if (freeze_processes()) {
                error = -EBUSY;
-               return error;
+               goto thaw;
        }
 
        if (pm_disk_mode == PM_DISK_PLATFORM) {
                if (pm_ops && pm_ops->prepare) {
                        if ((error = pm_ops->prepare(PM_SUSPEND_DISK)))
-                               return error;
+                               goto thaw;
                }
        }
 
        /* Free memory before shutting down devices. */
        free_some_memory();
-
        return 0;
+thaw:
+       thaw_processes();
+       enable_nonboot_cpus();
+       pm_restore_console();
+       return error;
 }
 
 static void unprepare_processes(void)
 {
-       enable_nonboot_cpus();
+       platform_finish();
        thaw_processes();
+       enable_nonboot_cpus();
        pm_restore_console();
 }
 
@@ -160,15 +167,9 @@ static int prepare_devices(void)
 {
        int error;
 
-       disable_nonboot_cpus();
-       if ((error = device_suspend(PMSG_FREEZE))) {
+       if ((error = device_suspend(PMSG_FREEZE)))
                printk("Some devices failed to suspend\n");
-               platform_finish();
-               enable_nonboot_cpus();
-               return error;
-       }
-
-       return 0;
+       return error;
 }
 
 /**
@@ -185,9 +186,9 @@ int pm_suspend_disk(void)
        int error;
 
        error = prepare_processes();
-       if (!error) {
-               error = prepare_devices();
-       }
+       if (error)
+               return error;
+       error = prepare_devices();
 
        if (error) {
                unprepare_processes();
@@ -250,7 +251,7 @@ static int software_resume(void)
 
        if ((error = prepare_processes())) {
                swsusp_close();
-               goto Cleanup;
+               goto Done;
        }
 
        pr_debug("PM: Reading swsusp image.\n");
index 4cdebc972ff2a55c7fdac702dca0c36f81905558..c94cb9e95090997aa15050412f7fc6564c997d01 100644 (file)
@@ -55,6 +55,13 @@ static int suspend_prepare(suspend_state_t state)
 
        pm_prepare_console();
 
+       disable_nonboot_cpus();
+
+       if (num_online_cpus() != 1) {
+               error = -EPERM;
+               goto Enable_cpu;
+       }
+
        if (freeze_processes()) {
                error = -EAGAIN;
                goto Thaw;
@@ -75,6 +82,8 @@ static int suspend_prepare(suspend_state_t state)
                pm_ops->finish(state);
  Thaw:
        thaw_processes();
+ Enable_cpu:
+       enable_nonboot_cpus();
        pm_restore_console();
        return error;
 }
@@ -113,6 +122,7 @@ static void suspend_finish(suspend_state_t state)
        if (pm_ops && pm_ops->finish)
                pm_ops->finish(state);
        thaw_processes();
+       enable_nonboot_cpus();
        pm_restore_console();
 }
 
@@ -150,12 +160,6 @@ static int enter_state(suspend_state_t state)
                goto Unlock;
        }
 
-       /* Suspend is hard to get right on SMP. */
-       if (num_online_cpus() != 1) {
-               error = -EPERM;
-               goto Unlock;
-       }
-
        pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
        if ((error = suspend_prepare(state)))
                goto Unlock;
index 78d92dc6a1edc8119ae616bf184e83ae26ec27e8..0a086640bcfc15cce008901702549fd0061a498c 100644 (file)
@@ -32,7 +32,7 @@ static inline int freezeable(struct task_struct * p)
 }
 
 /* Refrigerator is place where frozen processes are stored :-). */
-void refrigerator(unsigned long flag)
+void refrigerator(void)
 {
        /* Hmm, should we be allowed to suspend when there are realtime
           processes around? */
@@ -41,14 +41,13 @@ void refrigerator(unsigned long flag)
        current->state = TASK_UNINTERRUPTIBLE;
        pr_debug("%s entered refrigerator\n", current->comm);
        printk("=");
-       current->flags &= ~PF_FREEZE;
 
+       frozen_process(current);
        spin_lock_irq(&current->sighand->siglock);
        recalc_sigpending(); /* We sent fake signal, clean it up */
        spin_unlock_irq(&current->sighand->siglock);
 
-       current->flags |= PF_FROZEN;
-       while (current->flags & PF_FROZEN)
+       while (frozen(current))
                schedule();
        pr_debug("%s left refrigerator\n", current->comm);
        current->state = save;
@@ -57,10 +56,10 @@ void refrigerator(unsigned long flag)
 /* 0 = success, else # of processes that we failed to stop */
 int freeze_processes(void)
 {
-       int todo;
-       unsigned long start_time;
+       int todo;
+       unsigned long start_time;
        struct task_struct *g, *p;
-       
+
        printk( "Stopping tasks: " );
        start_time = jiffies;
        do {
@@ -70,14 +69,12 @@ int freeze_processes(void)
                        unsigned long flags;
                        if (!freezeable(p))
                                continue;
-                       if ((p->flags & PF_FROZEN) ||
+                       if ((frozen(p)) ||
                            (p->state == TASK_TRACED) ||
                            (p->state == TASK_STOPPED))
                                continue;
 
-                       /* FIXME: smp problem here: we may not access other process' flags
-                          without locking */
-                       p->flags |= PF_FREEZE;
+                       freeze(p);
                        spin_lock_irqsave(&p->sighand->siglock, flags);
                        signal_wake_up(p, 0);
                        spin_unlock_irqrestore(&p->sighand->siglock, flags);
@@ -91,7 +88,7 @@ int freeze_processes(void)
                        return todo;
                }
        } while(todo);
-       
+
        printk( "|\n" );
        BUG_ON(in_atomic());
        return 0;
@@ -106,10 +103,7 @@ void thaw_processes(void)
        do_each_thread(g, p) {
                if (!freezeable(p))
                        continue;
-               if (p->flags & PF_FROZEN) {
-                       p->flags &= ~PF_FROZEN;
-                       wake_up_process(p);
-               } else
+               if (!thaw_process(p))
                        printk(KERN_INFO " Strange, %s not stopped\n", p->comm );
        } while_each_thread(g, p);
 
index 457c2302ed424bf05e516136d21c1884033ca1e9..bbe23079c62c46e306e95e2215623659e39d565b 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/suspend.h>
 #include <linux/module.h>
+#include <linux/cpu.h>
 #include <asm/atomic.h>
 #include <asm/tlbflush.h>
 
-static atomic_t cpu_counter, freeze;
-
-
-static void smp_pause(void * data)
-{
-       struct saved_context ctxt;
-       __save_processor_state(&ctxt);
-       printk("Sleeping in:\n");
-       dump_stack();
-       atomic_inc(&cpu_counter);
-       while (atomic_read(&freeze)) {
-               /* FIXME: restore takes place at random piece inside this.
-                  This should probably be written in assembly, and
-                  preserve general-purpose registers, too
-
-                  What about stack? We may need to move to new stack here.
-
-                  This should better be ran with interrupts disabled.
-                */
-               cpu_relax();
-               barrier();
-       }
-       atomic_dec(&cpu_counter);
-       __restore_processor_state(&ctxt);
-}
-
-static cpumask_t oldmask;
+/* This is protected by pm_sem semaphore */
+static cpumask_t frozen_cpus;
 
 void disable_nonboot_cpus(void)
 {
-       oldmask = current->cpus_allowed;
-       set_cpus_allowed(current, cpumask_of_cpu(0));
-       printk("Freezing CPUs (at %d)", raw_smp_processor_id());
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(HZ);
-       printk("...");
-       BUG_ON(raw_smp_processor_id() != 0);
-
-       /* FIXME: for this to work, all the CPUs must be running
-        * "idle" thread (or we deadlock). Is that guaranteed? */
+       int cpu, error;
 
-       atomic_set(&cpu_counter, 0);
-       atomic_set(&freeze, 1);
-       smp_call_function(smp_pause, NULL, 0, 0);
-       while (atomic_read(&cpu_counter) < (num_online_cpus() - 1)) {
-               cpu_relax();
-               barrier();
+       error = 0;
+       cpus_clear(frozen_cpus);
+       printk("Freezing cpus ...\n");
+       for_each_online_cpu(cpu) {
+               if (cpu == 0)
+                       continue;
+               error = cpu_down(cpu);
+               if (!error) {
+                       cpu_set(cpu, frozen_cpus);
+                       printk("CPU%d is down\n", cpu);
+                       continue;
+               }
+               printk("Error taking cpu %d down: %d\n", cpu, error);
        }
-       printk("ok\n");
+       BUG_ON(smp_processor_id() != 0);
+       if (error)
+               panic("cpus not sleeping");
 }
 
 void enable_nonboot_cpus(void)
 {
-       printk("Restarting CPUs");
-       atomic_set(&freeze, 0);
-       while (atomic_read(&cpu_counter)) {
-               cpu_relax();
-               barrier();
-       }
-       printk("...");
-       set_cpus_allowed(current, oldmask);
-       schedule();
-       printk("ok\n");
+       int cpu, error;
 
+       printk("Thawing cpus ...\n");
+       for_each_cpu_mask(cpu, frozen_cpus) {
+               error = smp_prepare_cpu(cpu);
+               if (!error)
+                       error = cpu_up(cpu);
+               if (!error) {
+                       printk("CPU%d is up\n", cpu);
+                       continue;
+               }
+               printk("Error taking cpu %d up: %d\n", cpu, error);
+               panic("Not enough cpus");
+       }
+       cpus_clear(frozen_cpus);
 }
 
-
index 90b3b68dee3f71df12ad9b7b370e9b001a403630..c285fc5a232094c9f7b5e27950525ae942bc99b1 100644 (file)
  * This file is released under the GPLv2.
  *
  * I'd like to thank the following people for their work:
- * 
+ *
  * Pavel Machek <pavel@ucw.cz>:
  * Modifications, defectiveness pointing, being with me at the very beginning,
  * suspend to swap space, stop all tasks. Port to 2.4.18-ac and 2.5.17.
  *
- * Steve Doddi <dirk@loth.demon.co.uk>: 
+ * Steve Doddi <dirk@loth.demon.co.uk>:
  * Support the possibility of hardware state restoring.
  *
  * Raph <grey.havens@earthling.net>:
@@ -81,14 +81,14 @@ static int nr_copy_pages_check;
 extern char resume_file[];
 
 /* Local variables that should not be affected by save */
-unsigned int nr_copy_pages __nosavedata = 0;
+static unsigned int nr_copy_pages __nosavedata = 0;
 
 /* Suspend pagedir is allocated before final copy, therefore it
-   must be freed after resume 
+   must be freed after resume
 
    Warning: this is evil. There are actually two pagedirs at time of
    resume. One is "pagedir_save", which is empty frame allocated at
-   time of suspend, that must be freed. Second is "pagedir_nosave", 
+   time of suspend, that must be freed. Second is "pagedir_nosave",
    allocated at time of resume, that travels through memory not to
    collide with anything.
 
@@ -132,7 +132,7 @@ static int mark_swapfiles(swp_entry_t prev)
 {
        int error;
 
-       rw_swap_page_sync(READ, 
+       rw_swap_page_sync(READ,
                          swp_entry(root_swap, 0),
                          virt_to_page((unsigned long)&swsusp_header));
        if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) ||
@@ -140,7 +140,7 @@ static int mark_swapfiles(swp_entry_t prev)
                memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
                memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
                swsusp_header.swsusp_info = prev;
-               error = rw_swap_page_sync(WRITE, 
+               error = rw_swap_page_sync(WRITE,
                                          swp_entry(root_swap, 0),
                                          virt_to_page((unsigned long)
                                                       &swsusp_header));
@@ -174,22 +174,22 @@ static int is_resume_device(const struct swap_info_struct *swap_info)
 static int swsusp_swap_check(void) /* This is called before saving image */
 {
        int i, len;
-       
+
        len=strlen(resume_file);
        root_swap = 0xFFFF;
-       
+
        swap_list_lock();
-       for(i=0; i<MAX_SWAPFILES; i++) {
+       for (i=0; i<MAX_SWAPFILES; i++) {
                if (swap_info[i].flags == 0) {
                        swapfile_used[i]=SWAPFILE_UNUSED;
                } else {
-                       if(!len) {
+                       if (!len) {
                                printk(KERN_WARNING "resume= option should be used to set suspend device" );
-                               if(root_swap == 0xFFFF) {
+                               if (root_swap == 0xFFFF) {
                                        swapfile_used[i] = SWAPFILE_SUSPEND;
                                        root_swap = i;
                                } else
-                                       swapfile_used[i] = SWAPFILE_IGNORED;                              
+                                       swapfile_used[i] = SWAPFILE_IGNORED;
                        } else {
                                /* we ignore all swap devices that are not the resume_file */
                                if (is_resume_device(&swap_info[i])) {
@@ -209,15 +209,15 @@ static int swsusp_swap_check(void) /* This is called before saving image */
  * This is called after saving image so modification
  * will be lost after resume... and that's what we want.
  * we make the device unusable. A new call to
- * lock_swapdevices can unlock the devices. 
+ * lock_swapdevices can unlock the devices.
  */
 static void lock_swapdevices(void)
 {
        int i;
 
        swap_list_lock();
-       for(i = 0; i< MAX_SWAPFILES; i++)
-               if(swapfile_used[i] == SWAPFILE_IGNORED) {
+       for (i = 0; i< MAX_SWAPFILES; i++)
+               if (swapfile_used[i] == SWAPFILE_IGNORED) {
                        swap_info[i].flags ^= 0xFF;
                }
        swap_list_unlock();
@@ -229,7 +229,7 @@ static void lock_swapdevices(void)
  *     @loc:   Place to store the entry we used.
  *
  *     Allocate a new swap entry and 'sync' it. Note we discard -EIO
- *     errors. That is an artifact left over from swsusp. It did not 
+ *     errors. That is an artifact left over from swsusp. It did not
  *     check the return of rw_swap_page_sync() at all, since most pages
  *     written back to swap would return -EIO.
  *     This is a partial improvement, since we will at least return other
@@ -241,7 +241,7 @@ static int write_page(unsigned long addr, swp_entry_t * loc)
        int error = 0;
 
        entry = get_swap_page();
-       if (swp_offset(entry) && 
+       if (swp_offset(entry) &&
            swapfile_used[swp_type(entry)] == SWAPFILE_SUSPEND) {
                error = rw_swap_page_sync(WRITE, entry,
                                          virt_to_page(addr));
@@ -257,7 +257,7 @@ static int write_page(unsigned long addr, swp_entry_t * loc)
 /**
  *     data_free - Free the swap entries used by the saved image.
  *
- *     Walk the list of used swap entries and free each one. 
+ *     Walk the list of used swap entries and free each one.
  *     This is only used for cleanup when suspend fails.
  */
 static void data_free(void)
@@ -290,7 +290,7 @@ static int data_write(void)
                mod = 1;
 
        printk( "Writing data to swap (%d pages)...     ", nr_copy_pages );
-       for_each_pbe(p, pagedir_nosave) {
+       for_each_pbe (p, pagedir_nosave) {
                if (!(i%mod))
                        printk( "\b\b\b\b%3d%%", i / mod );
                if ((error = write_page(p->address, &(p->swap_address))))
@@ -335,7 +335,7 @@ static int close_swap(void)
 
        dump_info();
        error = write_page((unsigned long)&swsusp_info, &entry);
-       if (!error) { 
+       if (!error) {
                printk( "S" );
                error = mark_swapfiles(entry);
                printk( "|\n" );
@@ -370,7 +370,7 @@ static int write_pagedir(void)
        struct pbe * pbe;
 
        printk( "Writing pagedir...");
-       for_each_pb_page(pbe, pagedir_nosave) {
+       for_each_pb_page (pbe, pagedir_nosave) {
                if ((error = write_page((unsigned long)pbe, &swsusp_info.pagedir[n++])))
                        return error;
        }
@@ -472,7 +472,7 @@ static int save_highmem(void)
        int res = 0;
 
        pr_debug("swsusp: Saving Highmem\n");
-       for_each_zone(zone) {
+       for_each_zone (zone) {
                if (is_highmem(zone))
                        res = save_highmem_zone(zone);
                if (res)
@@ -547,7 +547,7 @@ static void count_data_pages(void)
 
        nr_copy_pages = 0;
 
-       for_each_zone(zone) {
+       for_each_zone (zone) {
                if (is_highmem(zone))
                        continue;
                mark_free_pages(zone);
@@ -562,9 +562,9 @@ static void copy_data_pages(void)
        struct zone *zone;
        unsigned long zone_pfn;
        struct pbe * pbe = pagedir_nosave;
-       
+
        pr_debug("copy_data_pages(): pages to copy: %d\n", nr_copy_pages);
-       for_each_zone(zone) {
+       for_each_zone (zone) {
                if (is_highmem(zone))
                        continue;
                mark_free_pages(zone);
@@ -702,7 +702,7 @@ static void free_image_pages(void)
 {
        struct pbe * p;
 
-       for_each_pbe(p, pagedir_save) {
+       for_each_pbe (p, pagedir_save) {
                if (p->address) {
                        ClearPageNosave(virt_to_page(p->address));
                        free_page(p->address);
@@ -719,7 +719,7 @@ static int alloc_image_pages(void)
 {
        struct pbe * p;
 
-       for_each_pbe(p, pagedir_save) {
+       for_each_pbe (p, pagedir_save) {
                p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
                if (!p->address)
                        return -ENOMEM;
@@ -740,7 +740,7 @@ void swsusp_free(void)
 /**
  *     enough_free_mem - Make sure we enough free memory to snapshot.
  *
- *     Returns TRUE or FALSE after checking the number of available 
+ *     Returns TRUE or FALSE after checking the number of available
  *     free pages.
  */
 
@@ -758,11 +758,11 @@ static int enough_free_mem(void)
 /**
  *     enough_swap - Make sure we have enough swap to save the image.
  *
- *     Returns TRUE or FALSE after checking the total amount of swap 
+ *     Returns TRUE or FALSE after checking the total amount of swap
  *     space avaiable.
  *
  *     FIXME: si_swapinfo(&i) returns all swap devices information.
- *     We should only consider resume_device. 
+ *     We should only consider resume_device.
  */
 
 static int enough_swap(void)
@@ -781,18 +781,18 @@ static int swsusp_alloc(void)
 {
        int error;
 
+       pagedir_nosave = NULL;
+       nr_copy_pages = calc_nr(nr_copy_pages);
+
        pr_debug("suspend: (pages needed: %d + %d free: %d)\n",
                 nr_copy_pages, PAGES_FOR_IO, nr_free_pages());
 
-       pagedir_nosave = NULL;
        if (!enough_free_mem())
                return -ENOMEM;
 
        if (!enough_swap())
                return -ENOSPC;
 
-       nr_copy_pages = calc_nr(nr_copy_pages);
-
        if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) {
                printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
                return -ENOMEM;
@@ -827,8 +827,8 @@ static int suspend_prepare_image(void)
        error = swsusp_alloc();
        if (error)
                return error;
-       
-       /* During allocating of suspend pagedir, new cold pages may appear. 
+
+       /* During allocating of suspend pagedir, new cold pages may appear.
         * Kill them.
         */
        drain_local_pages();
@@ -929,21 +929,6 @@ int swsusp_resume(void)
        return error;
 }
 
-/* More restore stuff */
-
-/*
- * Returns true if given address/order collides with any orig_address 
- */
-static int does_collide_order(unsigned long addr, int order)
-{
-       int i;
-       
-       for (i=0; i < (1<<order); i++)
-               if (!PageNosaveFree(virt_to_page(addr + i * PAGE_SIZE)))
-                       return 1;
-       return 0;
-}
-
 /**
  *     On resume, for storing the PBE list and the image,
  *     we can only use memory pages that do not conflict with the pages
@@ -973,7 +958,7 @@ static unsigned long get_usable_page(unsigned gfp_mask)
        unsigned long m;
 
        m = get_zeroed_page(gfp_mask);
-       while (does_collide_order(m, 0)) {
+       while (!PageNosaveFree(virt_to_page(m))) {
                eat_page((void *)m);
                m = get_zeroed_page(gfp_mask);
                if (!m)
@@ -1045,7 +1030,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist)
 
        /* Set page flags */
 
-       for_each_zone(zone) {
+       for_each_zone (zone) {
                for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
                        SetPageNosaveFree(pfn_to_page(zone_pfn +
                                        zone->zone_start_pfn));
@@ -1061,7 +1046,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist)
        /* Relocate colliding pages */
 
        for_each_pb_page (pbpage, pblist) {
-               if (does_collide_order((unsigned long)pbpage, 0)) {
+               if (!PageNosaveFree(virt_to_page((unsigned long)pbpage))) {
                        m = (void *)get_usable_page(GFP_ATOMIC | __GFP_COLD);
                        if (!m) {
                                error = -ENOMEM;
@@ -1193,8 +1178,10 @@ static const char * sanity_check(void)
                return "version";
        if (strcmp(swsusp_info.uts.machine,system_utsname.machine))
                return "machine";
+#if 0
        if(swsusp_info.cpus != num_online_cpus())
                return "number of cpus";
+#endif
        return NULL;
 }
 
index 3a442bfb8beee0adfcaba1f1aca84c0f8a43db13..5092397fac29926bfab6da75fc273882b14e905d 100644 (file)
@@ -588,8 +588,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                        log_level_unknown = 1;
        }
 
-       if (!cpu_online(smp_processor_id()) &&
-           system_state != SYSTEM_RUNNING) {
+       if (!cpu_online(smp_processor_id())) {
                /*
                 * Some console drivers may assume that per-cpu resources have
                 * been allocated.  So don't allow them to be called by this
index 52f696f11adfe68bbe5785e997f290071e8d6cf1..26967e0422014a5957f4b01bbed9a4cea40098bf 100644 (file)
@@ -263,7 +263,7 @@ static int find_resource(struct resource *root, struct resource *new,
                        new->start = min;
                if (new->end > max)
                        new->end = max;
-               new->start = (new->start + align - 1) & ~(align - 1);
+               new->start = ALIGN(new->start, align);
                if (alignf)
                        alignf(alignf_data, new, size, align);
                if (new->start < new->end && new->end - new->start >= size - 1) {
index 76080d142e3d9c08897e7b713d23dd0e2f809db0..5f2182d42241d20b41a12eb9da9671927b5b36d8 100644 (file)
 #define SCALE_PRIO(x, prio) \
        max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO/2), MIN_TIMESLICE)
 
-static inline unsigned int task_timeslice(task_t *p)
+static unsigned int task_timeslice(task_t *p)
 {
        if (p->static_prio < NICE_TO_PRIO(0))
                return SCALE_PRIO(DEF_TIMESLICE*4, p->static_prio);
@@ -206,7 +206,7 @@ struct runqueue {
         */
        unsigned long nr_running;
 #ifdef CONFIG_SMP
-       unsigned long cpu_load;
+       unsigned long cpu_load[3];
 #endif
        unsigned long long nr_switches;
 
@@ -260,23 +260,87 @@ struct runqueue {
 
 static DEFINE_PER_CPU(struct runqueue, runqueues);
 
+/*
+ * The domain tree (rq->sd) is protected by RCU's quiescent state transition.
+ * See detach_destroy_domains: synchronize_sched for details.
+ *
+ * The domain tree of any CPU may only be accessed from within
+ * preempt-disabled sections.
+ */
 #define for_each_domain(cpu, domain) \
-       for (domain = cpu_rq(cpu)->sd; domain; domain = domain->parent)
+for (domain = rcu_dereference(cpu_rq(cpu)->sd); domain; domain = domain->parent)
 
 #define cpu_rq(cpu)            (&per_cpu(runqueues, (cpu)))
 #define this_rq()              (&__get_cpu_var(runqueues))
 #define task_rq(p)             cpu_rq(task_cpu(p))
 #define cpu_curr(cpu)          (cpu_rq(cpu)->curr)
 
-/*
- * Default context-switch locking:
- */
 #ifndef prepare_arch_switch
-# define prepare_arch_switch(rq, next) do { } while (0)
-# define finish_arch_switch(rq, next)  spin_unlock_irq(&(rq)->lock)
-# define task_running(rq, p)           ((rq)->curr == (p))
+# define prepare_arch_switch(next)     do { } while (0)
+#endif
+#ifndef finish_arch_switch
+# define finish_arch_switch(prev)      do { } while (0)
 #endif
 
+#ifndef __ARCH_WANT_UNLOCKED_CTXSW
+static inline int task_running(runqueue_t *rq, task_t *p)
+{
+       return rq->curr == p;
+}
+
+static inline void prepare_lock_switch(runqueue_t *rq, task_t *next)
+{
+}
+
+static inline void finish_lock_switch(runqueue_t *rq, task_t *prev)
+{
+       spin_unlock_irq(&rq->lock);
+}
+
+#else /* __ARCH_WANT_UNLOCKED_CTXSW */
+static inline int task_running(runqueue_t *rq, task_t *p)
+{
+#ifdef CONFIG_SMP
+       return p->oncpu;
+#else
+       return rq->curr == p;
+#endif
+}
+
+static inline void prepare_lock_switch(runqueue_t *rq, task_t *next)
+{
+#ifdef CONFIG_SMP
+       /*
+        * We can optimise this out completely for !SMP, because the
+        * SMP rebalancing from interrupt is the only thing that cares
+        * here.
+        */
+       next->oncpu = 1;
+#endif
+#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
+       spin_unlock_irq(&rq->lock);
+#else
+       spin_unlock(&rq->lock);
+#endif
+}
+
+static inline void finish_lock_switch(runqueue_t *rq, task_t *prev)
+{
+#ifdef CONFIG_SMP
+       /*
+        * After ->oncpu is cleared, the task can be moved to a different CPU.
+        * We must ensure this doesn't happen until the switch is completely
+        * finished.
+        */
+       smp_wmb();
+       prev->oncpu = 0;
+#endif
+#ifndef __ARCH_WANT_INTERRUPTS_ON_CTXSW
+       local_irq_enable();
+#endif
+}
+#endif /* __ARCH_WANT_UNLOCKED_CTXSW */
+
 /*
  * task_rq_lock - lock the runqueue a given task resides on and disable
  * interrupts.  Note the ordering: we can safely lookup the task_rq without
@@ -309,7 +373,7 @@ static inline void task_rq_unlock(runqueue_t *rq, unsigned long *flags)
  * bump this up when changing the output format or the meaning of an existing
  * format, so that tools can adapt (or abort)
  */
-#define SCHEDSTAT_VERSION 11
+#define SCHEDSTAT_VERSION 12
 
 static int show_schedstat(struct seq_file *seq, void *v)
 {
@@ -338,6 +402,7 @@ static int show_schedstat(struct seq_file *seq, void *v)
 
 #ifdef CONFIG_SMP
                /* domain-specific stats */
+               preempt_disable();
                for_each_domain(cpu, sd) {
                        enum idle_type itype;
                        char mask_str[NR_CPUS];
@@ -356,11 +421,13 @@ static int show_schedstat(struct seq_file *seq, void *v)
                                    sd->lb_nobusyq[itype],
                                    sd->lb_nobusyg[itype]);
                        }
-                       seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu\n",
+                       seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
                            sd->alb_cnt, sd->alb_failed, sd->alb_pushed,
-                           sd->sbe_pushed, sd->sbe_attempts,
+                           sd->sbe_cnt, sd->sbe_balanced, sd->sbe_pushed,
+                           sd->sbf_cnt, sd->sbf_balanced, sd->sbf_pushed,
                            sd->ttwu_wake_remote, sd->ttwu_move_affine, sd->ttwu_move_balance);
                }
+               preempt_enable();
 #endif
        }
        return 0;
@@ -414,22 +481,6 @@ static inline runqueue_t *this_rq_lock(void)
        return rq;
 }
 
-#ifdef CONFIG_SCHED_SMT
-static int cpu_and_siblings_are_idle(int cpu)
-{
-       int sib;
-       for_each_cpu_mask(sib, cpu_sibling_map[cpu]) {
-               if (idle_cpu(sib))
-                       continue;
-               return 0;
-       }
-
-       return 1;
-}
-#else
-#define cpu_and_siblings_are_idle(A) idle_cpu(A)
-#endif
-
 #ifdef CONFIG_SCHEDSTATS
 /*
  * Called when a process is dequeued from the active array and given
@@ -622,7 +673,7 @@ static inline void __activate_idle_task(task_t *p, runqueue_t *rq)
        rq->nr_running++;
 }
 
-static void recalc_task_prio(task_t *p, unsigned long long now)
+static int recalc_task_prio(task_t *p, unsigned long long now)
 {
        /* Caller must always ensure 'now >= p->timestamp' */
        unsigned long long __sleep_time = now - p->timestamp;
@@ -681,7 +732,7 @@ static void recalc_task_prio(task_t *p, unsigned long long now)
                }
        }
 
-       p->prio = effective_prio(p);
+       return effective_prio(p);
 }
 
 /*
@@ -704,7 +755,7 @@ static void activate_task(task_t *p, runqueue_t *rq, int local)
        }
 #endif
 
-       recalc_task_prio(p, now);
+       p->prio = recalc_task_prio(p, now);
 
        /*
         * This checks to make sure it's not an uninterruptible task
@@ -782,22 +833,12 @@ inline int task_curr(const task_t *p)
 }
 
 #ifdef CONFIG_SMP
-enum request_type {
-       REQ_MOVE_TASK,
-       REQ_SET_DOMAIN,
-};
-
 typedef struct {
        struct list_head list;
-       enum request_type type;
 
-       /* For REQ_MOVE_TASK */
        task_t *task;
        int dest_cpu;
 
-       /* For REQ_SET_DOMAIN */
-       struct sched_domain *sd;
-
        struct completion done;
 } migration_req_t;
 
@@ -819,7 +860,6 @@ static int migrate_task(task_t *p, int dest_cpu, migration_req_t *req)
        }
 
        init_completion(&req->done);
-       req->type = REQ_MOVE_TASK;
        req->task = p;
        req->dest_cpu = dest_cpu;
        list_add(&req->list, &rq->migration_queue);
@@ -886,26 +926,154 @@ void kick_process(task_t *p)
  * We want to under-estimate the load of migration sources, to
  * balance conservatively.
  */
-static inline unsigned long source_load(int cpu)
+static inline unsigned long source_load(int cpu, int type)
 {
        runqueue_t *rq = cpu_rq(cpu);
        unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE;
+       if (type == 0)
+               return load_now;
 
-       return min(rq->cpu_load, load_now);
+       return min(rq->cpu_load[type-1], load_now);
 }
 
 /*
  * Return a high guess at the load of a migration-target cpu
  */
-static inline unsigned long target_load(int cpu)
+static inline unsigned long target_load(int cpu, int type)
 {
        runqueue_t *rq = cpu_rq(cpu);
        unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE;
+       if (type == 0)
+               return load_now;
 
-       return max(rq->cpu_load, load_now);
+       return max(rq->cpu_load[type-1], load_now);
 }
 
-#endif
+/*
+ * find_idlest_group finds and returns the least busy CPU group within the
+ * domain.
+ */
+static struct sched_group *
+find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu)
+{
+       struct sched_group *idlest = NULL, *this = NULL, *group = sd->groups;
+       unsigned long min_load = ULONG_MAX, this_load = 0;
+       int load_idx = sd->forkexec_idx;
+       int imbalance = 100 + (sd->imbalance_pct-100)/2;
+
+       do {
+               unsigned long load, avg_load;
+               int local_group;
+               int i;
+
+               local_group = cpu_isset(this_cpu, group->cpumask);
+               /* XXX: put a cpus allowed check */
+
+               /* Tally up the load of all CPUs in the group */
+               avg_load = 0;
+
+               for_each_cpu_mask(i, group->cpumask) {
+                       /* Bias balancing toward cpus of our domain */
+                       if (local_group)
+                               load = source_load(i, load_idx);
+                       else
+                               load = target_load(i, load_idx);
+
+                       avg_load += load;
+               }
+
+               /* Adjust by relative CPU power of the group */
+               avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power;
+
+               if (local_group) {
+                       this_load = avg_load;
+                       this = group;
+               } else if (avg_load < min_load) {
+                       min_load = avg_load;
+                       idlest = group;
+               }
+               group = group->next;
+       } while (group != sd->groups);
+
+       if (!idlest || 100*this_load < imbalance*min_load)
+               return NULL;
+       return idlest;
+}
+
+/*
+ * find_idlest_queue - find the idlest runqueue among the cpus in group.
+ */
+static int find_idlest_cpu(struct sched_group *group, int this_cpu)
+{
+       unsigned long load, min_load = ULONG_MAX;
+       int idlest = -1;
+       int i;
+
+       for_each_cpu_mask(i, group->cpumask) {
+               load = source_load(i, 0);
+
+               if (load < min_load || (load == min_load && i == this_cpu)) {
+                       min_load = load;
+                       idlest = i;
+               }
+       }
+
+       return idlest;
+}
+
+/*
+ * sched_balance_self: balance the current task (running on cpu) in domains
+ * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and
+ * SD_BALANCE_EXEC.
+ *
+ * Balance, ie. select the least loaded group.
+ *
+ * Returns the target CPU number, or the same CPU if no balancing is needed.
+ *
+ * preempt must be disabled.
+ */
+static int sched_balance_self(int cpu, int flag)
+{
+       struct task_struct *t = current;
+       struct sched_domain *tmp, *sd = NULL;
+
+       for_each_domain(cpu, tmp)
+               if (tmp->flags & flag)
+                       sd = tmp;
+
+       while (sd) {
+               cpumask_t span;
+               struct sched_group *group;
+               int new_cpu;
+               int weight;
+
+               span = sd->span;
+               group = find_idlest_group(sd, t, cpu);
+               if (!group)
+                       goto nextlevel;
+
+               new_cpu = find_idlest_cpu(group, cpu);
+               if (new_cpu == -1 || new_cpu == cpu)
+                       goto nextlevel;
+
+               /* Now try balancing at a lower domain level */
+               cpu = new_cpu;
+nextlevel:
+               sd = NULL;
+               weight = cpus_weight(span);
+               for_each_domain(cpu, tmp) {
+                       if (weight <= cpus_weight(tmp->span))
+                               break;
+                       if (tmp->flags & flag)
+                               sd = tmp;
+               }
+               /* while loop will break here if sd == NULL */
+       }
+
+       return cpu;
+}
+
+#endif /* CONFIG_SMP */
 
 /*
  * wake_idle() will wake a task on an idle cpu if task->cpu is
@@ -927,14 +1095,14 @@ static int wake_idle(int cpu, task_t *p)
 
        for_each_domain(cpu, sd) {
                if (sd->flags & SD_WAKE_IDLE) {
-                       cpus_and(tmp, sd->span, cpu_online_map);
-                       cpus_and(tmp, tmp, p->cpus_allowed);
+                       cpus_and(tmp, sd->span, p->cpus_allowed);
                        for_each_cpu_mask(i, tmp) {
                                if (idle_cpu(i))
                                        return i;
                        }
                }
-               else break;
+               else
+                       break;
        }
        return cpu;
 }
@@ -967,7 +1135,7 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync)
        runqueue_t *rq;
 #ifdef CONFIG_SMP
        unsigned long load, this_load;
-       struct sched_domain *sd;
+       struct sched_domain *sd, *this_sd = NULL;
        int new_cpu;
 #endif
 
@@ -986,70 +1154,69 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync)
        if (unlikely(task_running(rq, p)))
                goto out_activate;
 
-#ifdef CONFIG_SCHEDSTATS
+       new_cpu = cpu;
+
        schedstat_inc(rq, ttwu_cnt);
        if (cpu == this_cpu) {
                schedstat_inc(rq, ttwu_local);
-       } else {
-               for_each_domain(this_cpu, sd) {
-                       if (cpu_isset(cpu, sd->span)) {
-                               schedstat_inc(sd, ttwu_wake_remote);
-                               break;
-                       }
+               goto out_set_cpu;
+       }
+
+       for_each_domain(this_cpu, sd) {
+               if (cpu_isset(cpu, sd->span)) {
+                       schedstat_inc(sd, ttwu_wake_remote);
+                       this_sd = sd;
+                       break;
                }
        }
-#endif
 
-       new_cpu = cpu;
-       if (cpu == this_cpu || unlikely(!cpu_isset(this_cpu, p->cpus_allowed)))
+       if (unlikely(!cpu_isset(this_cpu, p->cpus_allowed)))
                goto out_set_cpu;
 
-       load = source_load(cpu);
-       this_load = target_load(this_cpu);
-
        /*
-        * If sync wakeup then subtract the (maximum possible) effect of
-        * the currently running task from the load of the current CPU:
+        * Check for affine wakeup and passive balancing possibilities.
         */
-       if (sync)
-               this_load -= SCHED_LOAD_SCALE;
+       if (this_sd) {
+               int idx = this_sd->wake_idx;
+               unsigned int imbalance;
 
-       /* Don't pull the task off an idle CPU to a busy one */
-       if (load < SCHED_LOAD_SCALE/2 && this_load > SCHED_LOAD_SCALE/2)
-               goto out_set_cpu;
+               imbalance = 100 + (this_sd->imbalance_pct - 100) / 2;
 
-       new_cpu = this_cpu; /* Wake to this CPU if we can */
+               load = source_load(cpu, idx);
+               this_load = target_load(this_cpu, idx);
 
-       /*
-        * Scan domains for affine wakeup and passive balancing
-        * possibilities.
-        */
-       for_each_domain(this_cpu, sd) {
-               unsigned int imbalance;
-               /*
-                * Start passive balancing when half the imbalance_pct
-                * limit is reached.
-                */
-               imbalance = sd->imbalance_pct + (sd->imbalance_pct - 100) / 2;
+               new_cpu = this_cpu; /* Wake to this CPU if we can */
 
-               if ((sd->flags & SD_WAKE_AFFINE) &&
-                               !task_hot(p, rq->timestamp_last_tick, sd)) {
+               if (this_sd->flags & SD_WAKE_AFFINE) {
+                       unsigned long tl = this_load;
                        /*
-                        * This domain has SD_WAKE_AFFINE and p is cache cold
-                        * in this domain.
+                        * If sync wakeup then subtract the (maximum possible)
+                        * effect of the currently running task from the load
+                        * of the current CPU:
                         */
-                       if (cpu_isset(cpu, sd->span)) {
-                               schedstat_inc(sd, ttwu_move_affine);
+                       if (sync)
+                               tl -= SCHED_LOAD_SCALE;
+
+                       if ((tl <= load &&
+                               tl + target_load(cpu, idx) <= SCHED_LOAD_SCALE) ||
+                               100*(tl + SCHED_LOAD_SCALE) <= imbalance*load) {
+                               /*
+                                * This domain has SD_WAKE_AFFINE and
+                                * p is cache cold in this domain, and
+                                * there is no bad imbalance.
+                                */
+                               schedstat_inc(this_sd, ttwu_move_affine);
                                goto out_set_cpu;
                        }
-               } else if ((sd->flags & SD_WAKE_BALANCE) &&
-                               imbalance*this_load <= 100*load) {
-                       /*
-                        * This domain has SD_WAKE_BALANCE and there is
-                        * an imbalance.
-                        */
-                       if (cpu_isset(cpu, sd->span)) {
-                               schedstat_inc(sd, ttwu_move_balance);
+               }
+
+               /*
+                * Start passive balancing when half the imbalance_pct
+                * limit is reached.
+                */
+               if (this_sd->flags & SD_WAKE_BALANCE) {
+                       if (imbalance*this_load <= 100*load) {
+                               schedstat_inc(this_sd, ttwu_move_balance);
                                goto out_set_cpu;
                        }
                }
@@ -1120,17 +1287,19 @@ int fastcall wake_up_state(task_t *p, unsigned int state)
        return try_to_wake_up(p, state, 0);
 }
 
-#ifdef CONFIG_SMP
-static int find_idlest_cpu(struct task_struct *p, int this_cpu,
-                          struct sched_domain *sd);
-#endif
-
 /*
  * Perform scheduler related setup for a newly forked process p.
  * p is forked by current.
  */
-void fastcall sched_fork(task_t *p)
+void fastcall sched_fork(task_t *p, int clone_flags)
 {
+       int cpu = get_cpu();
+
+#ifdef CONFIG_SMP
+       cpu = sched_balance_self(cpu, SD_BALANCE_FORK);
+#endif
+       set_task_cpu(p, cpu);
+
        /*
         * We mark the process as running here, but have not actually
         * inserted it onto the runqueue yet. This guarantees that
@@ -1140,17 +1309,14 @@ void fastcall sched_fork(task_t *p)
        p->state = TASK_RUNNING;
        INIT_LIST_HEAD(&p->run_list);
        p->array = NULL;
-       spin_lock_init(&p->switch_lock);
 #ifdef CONFIG_SCHEDSTATS
        memset(&p->sched_info, 0, sizeof(p->sched_info));
 #endif
+#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
+       p->oncpu = 0;
+#endif
 #ifdef CONFIG_PREEMPT
-       /*
-        * During context-switch we hold precisely one spinlock, which
-        * schedule_tail drops. (in the common case it's this_rq()->lock,
-        * but it also can be p->switch_lock.) So we compensate with a count
-        * of 1. Also, we want to start with kernel preemption disabled.
-        */
+       /* Want to start with kernel preemption disabled. */
        p->thread_info->preempt_count = 1;
 #endif
        /*
@@ -1174,12 +1340,10 @@ void fastcall sched_fork(task_t *p)
                 * runqueue lock is not a problem.
                 */
                current->time_slice = 1;
-               preempt_disable();
                scheduler_tick();
-               local_irq_enable();
-               preempt_enable();
-       } else
-               local_irq_enable();
+       }
+       local_irq_enable();
+       put_cpu();
 }
 
 /*
@@ -1196,10 +1360,9 @@ void fastcall wake_up_new_task(task_t * p, unsigned long clone_flags)
        runqueue_t *rq, *this_rq;
 
        rq = task_rq_lock(p, &flags);
-       cpu = task_cpu(p);
-       this_cpu = smp_processor_id();
-
        BUG_ON(p->state != TASK_RUNNING);
+       this_cpu = smp_processor_id();
+       cpu = task_cpu(p);
 
        /*
         * We decrease the sleep average of forking parents
@@ -1295,23 +1458,41 @@ void fastcall sched_exit(task_t * p)
        task_rq_unlock(rq, &flags);
 }
 
+/**
+ * prepare_task_switch - prepare to switch tasks
+ * @rq: the runqueue preparing to switch
+ * @next: the task we are going to switch to.
+ *
+ * This is called with the rq lock held and interrupts off. It must
+ * be paired with a subsequent finish_task_switch after the context
+ * switch.
+ *
+ * prepare_task_switch sets up locking and calls architecture specific
+ * hooks.
+ */
+static inline void prepare_task_switch(runqueue_t *rq, task_t *next)
+{
+       prepare_lock_switch(rq, next);
+       prepare_arch_switch(next);
+}
+
 /**
  * finish_task_switch - clean up after a task-switch
  * @prev: the thread we just switched away from.
  *
- * We enter this with the runqueue still locked, and finish_arch_switch()
- * will unlock it along with doing any other architecture-specific cleanup
- * actions.
+ * finish_task_switch must be called after the context switch, paired
+ * with a prepare_task_switch call before the context switch.
+ * finish_task_switch will reconcile locking set up by prepare_task_switch,
+ * and do any other architecture-specific cleanup actions.
  *
  * Note that we may have delayed dropping an mm in context_switch(). If
  * so, we finish that here outside of the runqueue lock.  (Doing it
  * with the lock held can cause deadlocks; see schedule() for
  * details.)
  */
-static inline void finish_task_switch(task_t *prev)
+static inline void finish_task_switch(runqueue_t *rq, task_t *prev)
        __releases(rq->lock)
 {
-       runqueue_t *rq = this_rq();
        struct mm_struct *mm = rq->prev_mm;
        unsigned long prev_task_flags;
 
@@ -1329,7 +1510,8 @@ static inline void finish_task_switch(task_t *prev)
         *              Manfred Spraul <manfred@colorfullife.com>
         */
        prev_task_flags = prev->flags;
-       finish_arch_switch(rq, prev);
+       finish_arch_switch(prev);
+       finish_lock_switch(rq, prev);
        if (mm)
                mmdrop(mm);
        if (unlikely(prev_task_flags & PF_DEAD))
@@ -1343,8 +1525,12 @@ static inline void finish_task_switch(task_t *prev)
 asmlinkage void schedule_tail(task_t *prev)
        __releases(rq->lock)
 {
-       finish_task_switch(prev);
-
+       runqueue_t *rq = this_rq();
+       finish_task_switch(rq, prev);
+#ifdef __ARCH_WANT_UNLOCKED_CTXSW
+       /* In this case, finish_task_switch does not reenable preemption */
+       preempt_enable();
+#endif
        if (current->set_child_tid)
                put_user(current->pid, current->set_child_tid);
 }
@@ -1493,51 +1679,6 @@ static void double_lock_balance(runqueue_t *this_rq, runqueue_t *busiest)
        }
 }
 
-/*
- * find_idlest_cpu - find the least busy runqueue.
- */
-static int find_idlest_cpu(struct task_struct *p, int this_cpu,
-                          struct sched_domain *sd)
-{
-       unsigned long load, min_load, this_load;
-       int i, min_cpu;
-       cpumask_t mask;
-
-       min_cpu = UINT_MAX;
-       min_load = ULONG_MAX;
-
-       cpus_and(mask, sd->span, p->cpus_allowed);
-
-       for_each_cpu_mask(i, mask) {
-               load = target_load(i);
-
-               if (load < min_load) {
-                       min_cpu = i;
-                       min_load = load;
-
-                       /* break out early on an idle CPU: */
-                       if (!min_load)
-                               break;
-               }
-       }
-
-       /* add +1 to account for the new task */
-       this_load = source_load(this_cpu) + SCHED_LOAD_SCALE;
-
-       /*
-        * Would with the addition of the new task to the
-        * current CPU there be an imbalance between this
-        * CPU and the idlest CPU?
-        *
-        * Use half of the balancing threshold - new-context is
-        * a good opportunity to balance.
-        */
-       if (min_load*(100 + (sd->imbalance_pct-100)/2) < this_load*100)
-               return min_cpu;
-
-       return this_cpu;
-}
-
 /*
  * If dest_cpu is allowed for this process, migrate the task to it.
  * This is accomplished by forcing the cpu_allowed mask to only
@@ -1571,37 +1712,16 @@ out:
 }
 
 /*
- * sched_exec(): find the highest-level, exec-balance-capable
- * domain and try to migrate the task to the least loaded CPU.
- *
- * execve() is a valuable balancing opportunity, because at this point
- * the task has the smallest effective memory and cache footprint.
+ * sched_exec - execve() is a valuable balancing opportunity, because at
+ * this point the task has the smallest effective memory and cache footprint.
  */
 void sched_exec(void)
 {
-       struct sched_domain *tmp, *sd = NULL;
        int new_cpu, this_cpu = get_cpu();
-
-       /* Prefer the current CPU if there's only this task running */
-       if (this_rq()->nr_running <= 1)
-               goto out;
-
-       for_each_domain(this_cpu, tmp)
-               if (tmp->flags & SD_BALANCE_EXEC)
-                       sd = tmp;
-
-       if (sd) {
-               schedstat_inc(sd, sbe_attempts);
-               new_cpu = find_idlest_cpu(current, this_cpu, sd);
-               if (new_cpu != this_cpu) {
-                       schedstat_inc(sd, sbe_pushed);
-                       put_cpu();
-                       sched_migrate_task(current, new_cpu);
-                       return;
-               }
-       }
-out:
+       new_cpu = sched_balance_self(this_cpu, SD_BALANCE_EXEC);
        put_cpu();
+       if (new_cpu != this_cpu)
+               sched_migrate_task(current, new_cpu);
 }
 
 /*
@@ -1632,7 +1752,7 @@ void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p,
  */
 static inline
 int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu,
-                    struct sched_domain *sd, enum idle_type idle)
+            struct sched_domain *sd, enum idle_type idle, int *all_pinned)
 {
        /*
         * We do not migrate tasks that are:
@@ -1640,23 +1760,24 @@ int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu,
         * 2) cannot be migrated to this CPU due to cpus_allowed, or
         * 3) are cache-hot on their current CPU.
         */
-       if (task_running(rq, p))
-               return 0;
        if (!cpu_isset(this_cpu, p->cpus_allowed))
                return 0;
+       *all_pinned = 0;
+
+       if (task_running(rq, p))
+               return 0;
 
        /*
         * Aggressive migration if:
-        * 1) the [whole] cpu is idle, or
+        * 1) task is cache cold, or
         * 2) too many balance attempts have failed.
         */
 
-       if (cpu_and_siblings_are_idle(this_cpu) || \
-                       sd->nr_balance_failed > sd->cache_nice_tries)
+       if (sd->nr_balance_failed > sd->cache_nice_tries)
                return 1;
 
        if (task_hot(p, rq->timestamp_last_tick, sd))
-                       return 0;
+               return 0;
        return 1;
 }
 
@@ -1669,16 +1790,18 @@ int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu,
  */
 static int move_tasks(runqueue_t *this_rq, int this_cpu, runqueue_t *busiest,
                      unsigned long max_nr_move, struct sched_domain *sd,
-                     enum idle_type idle)
+                     enum idle_type idle, int *all_pinned)
 {
        prio_array_t *array, *dst_array;
        struct list_head *head, *curr;
-       int idx, pulled = 0;
+       int idx, pulled = 0, pinned = 0;
        task_t *tmp;
 
-       if (max_nr_move <= 0 || busiest->nr_running <= 1)
+       if (max_nr_move == 0)
                goto out;
 
+       pinned = 1;
+
        /*
         * We first consider expired tasks. Those will likely not be
         * executed in the near future, and they are most likely to
@@ -1717,7 +1840,7 @@ skip_queue:
 
        curr = curr->prev;
 
-       if (!can_migrate_task(tmp, busiest, this_cpu, sd, idle)) {
+       if (!can_migrate_task(tmp, busiest, this_cpu, sd, idle, &pinned)) {
                if (curr != head)
                        goto skip_queue;
                idx++;
@@ -1746,6 +1869,9 @@ out:
         * inside pull_task().
         */
        schedstat_add(sd, lb_gained[idle], pulled);
+
+       if (all_pinned)
+               *all_pinned = pinned;
        return pulled;
 }
 
@@ -1760,8 +1886,15 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
 {
        struct sched_group *busiest = NULL, *this = NULL, *group = sd->groups;
        unsigned long max_load, avg_load, total_load, this_load, total_pwr;
+       int load_idx;
 
        max_load = this_load = total_load = total_pwr = 0;
+       if (idle == NOT_IDLE)
+               load_idx = sd->busy_idx;
+       else if (idle == NEWLY_IDLE)
+               load_idx = sd->newidle_idx;
+       else
+               load_idx = sd->idle_idx;
 
        do {
                unsigned long load;
@@ -1776,9 +1909,9 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                for_each_cpu_mask(i, group->cpumask) {
                        /* Bias balancing toward cpus of our domain */
                        if (local_group)
-                               load = target_load(i);
+                               load = target_load(i, load_idx);
                        else
-                               load = source_load(i);
+                               load = source_load(i, load_idx);
 
                        avg_load += load;
                }
@@ -1792,12 +1925,10 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                if (local_group) {
                        this_load = avg_load;
                        this = group;
-                       goto nextgroup;
                } else if (avg_load > max_load) {
                        max_load = avg_load;
                        busiest = group;
                }
-nextgroup:
                group = group->next;
        } while (group != sd->groups);
 
@@ -1870,15 +2001,9 @@ nextgroup:
 
        /* Get rid of the scaling factor, rounding down as we divide */
        *imbalance = *imbalance / SCHED_LOAD_SCALE;
-
        return busiest;
 
 out_balanced:
-       if (busiest && (idle == NEWLY_IDLE ||
-                       (idle == SCHED_IDLE && max_load > SCHED_LOAD_SCALE)) ) {
-               *imbalance = 1;
-               return busiest;
-       }
 
        *imbalance = 0;
        return NULL;
@@ -1894,7 +2019,7 @@ static runqueue_t *find_busiest_queue(struct sched_group *group)
        int i;
 
        for_each_cpu_mask(i, group->cpumask) {
-               load = source_load(i);
+               load = source_load(i, 0);
 
                if (load > max_load) {
                        max_load = load;
@@ -1905,6 +2030,12 @@ static runqueue_t *find_busiest_queue(struct sched_group *group)
        return busiest;
 }
 
+/*
+ * Max backoff if we encounter pinned tasks. Pretty arbitrary value, but
+ * so long as it is large enough.
+ */
+#define MAX_PINNED_INTERVAL    512
+
 /*
  * Check this_cpu to ensure it is balanced within domain. Attempt to move
  * tasks if there is an imbalance.
@@ -1917,7 +2048,8 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
        struct sched_group *group;
        runqueue_t *busiest;
        unsigned long imbalance;
-       int nr_moved;
+       int nr_moved, all_pinned = 0;
+       int active_balance = 0;
 
        spin_lock(&this_rq->lock);
        schedstat_inc(sd, lb_cnt[idle]);
@@ -1934,15 +2066,7 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
                goto out_balanced;
        }
 
-       /*
-        * This should be "impossible", but since load
-        * balancing is inherently racy and statistical,
-        * it could happen in theory.
-        */
-       if (unlikely(busiest == this_rq)) {
-               WARN_ON(1);
-               goto out_balanced;
-       }
+       BUG_ON(busiest == this_rq);
 
        schedstat_add(sd, lb_imbalance[idle], imbalance);
 
@@ -1956,9 +2080,15 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
                 */
                double_lock_balance(this_rq, busiest);
                nr_moved = move_tasks(this_rq, this_cpu, busiest,
-                                               imbalance, sd, idle);
+                                               imbalance, sd, idle,
+                                               &all_pinned);
                spin_unlock(&busiest->lock);
+
+               /* All tasks on this runqueue were pinned by CPU affinity */
+               if (unlikely(all_pinned))
+                       goto out_balanced;
        }
+
        spin_unlock(&this_rq->lock);
 
        if (!nr_moved) {
@@ -1966,36 +2096,38 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
                sd->nr_balance_failed++;
 
                if (unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2)) {
-                       int wake = 0;
 
                        spin_lock(&busiest->lock);
                        if (!busiest->active_balance) {
                                busiest->active_balance = 1;
                                busiest->push_cpu = this_cpu;
-                               wake = 1;
+                               active_balance = 1;
                        }
                        spin_unlock(&busiest->lock);
-                       if (wake)
+                       if (active_balance)
                                wake_up_process(busiest->migration_thread);
 
                        /*
                         * We've kicked active balancing, reset the failure
                         * counter.
                         */
-                       sd->nr_balance_failed = sd->cache_nice_tries;
+                       sd->nr_balance_failed = sd->cache_nice_tries+1;
                }
-
-               /*
-                * We were unbalanced, but unsuccessful in move_tasks(),
-                * so bump the balance_interval to lessen the lock contention.
-                */
-               if (sd->balance_interval < sd->max_interval)
-                       sd->balance_interval++;
-       } else {
+       } else
                sd->nr_balance_failed = 0;
 
+       if (likely(!active_balance)) {
                /* We were unbalanced, so reset the balancing interval */
                sd->balance_interval = sd->min_interval;
+       } else {
+               /*
+                * If we've begun active balancing, start to back off. This
+                * case may not be covered by the all_pinned logic if there
+                * is only 1 task on the busy runqueue (because we don't call
+                * move_tasks).
+                */
+               if (sd->balance_interval < sd->max_interval)
+                       sd->balance_interval *= 2;
        }
 
        return nr_moved;
@@ -2005,8 +2137,10 @@ out_balanced:
 
        schedstat_inc(sd, lb_balanced[idle]);
 
+       sd->nr_balance_failed = 0;
        /* tune up the balancing interval */
-       if (sd->balance_interval < sd->max_interval)
+       if ((all_pinned && sd->balance_interval < MAX_PINNED_INTERVAL) ||
+                       (sd->balance_interval < sd->max_interval))
                sd->balance_interval *= 2;
 
        return 0;
@@ -2030,31 +2164,36 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq,
        schedstat_inc(sd, lb_cnt[NEWLY_IDLE]);
        group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE);
        if (!group) {
-               schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
                schedstat_inc(sd, lb_nobusyg[NEWLY_IDLE]);
-               goto out;
+               goto out_balanced;
        }
 
        busiest = find_busiest_queue(group);
-       if (!busiest || busiest == this_rq) {
-               schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
+       if (!busiest) {
                schedstat_inc(sd, lb_nobusyq[NEWLY_IDLE]);
-               goto out;
+               goto out_balanced;
        }
 
+       BUG_ON(busiest == this_rq);
+
        /* Attempt to move tasks */
        double_lock_balance(this_rq, busiest);
 
        schedstat_add(sd, lb_imbalance[NEWLY_IDLE], imbalance);
        nr_moved = move_tasks(this_rq, this_cpu, busiest,
-                                       imbalance, sd, NEWLY_IDLE);
+                                       imbalance, sd, NEWLY_IDLE, NULL);
        if (!nr_moved)
                schedstat_inc(sd, lb_failed[NEWLY_IDLE]);
+       else
+               sd->nr_balance_failed = 0;
 
        spin_unlock(&busiest->lock);
-
-out:
        return nr_moved;
+
+out_balanced:
+       schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
+       sd->nr_balance_failed = 0;
+       return 0;
 }
 
 /*
@@ -2086,56 +2225,42 @@ static inline void idle_balance(int this_cpu, runqueue_t *this_rq)
 static void active_load_balance(runqueue_t *busiest_rq, int busiest_cpu)
 {
        struct sched_domain *sd;
-       struct sched_group *cpu_group;
        runqueue_t *target_rq;
-       cpumask_t visited_cpus;
-       int cpu;
+       int target_cpu = busiest_rq->push_cpu;
+
+       if (busiest_rq->nr_running <= 1)
+               /* no task to move */
+               return;
+
+       target_rq = cpu_rq(target_cpu);
 
        /*
-        * Search for suitable CPUs to push tasks to in successively higher
-        * domains with SD_LOAD_BALANCE set.
+        * This condition is "impossible", if it occurs
+        * we need to fix it.  Originally reported by
+        * Bjorn Helgaas on a 128-cpu setup.
         */
-       visited_cpus = CPU_MASK_NONE;
-       for_each_domain(busiest_cpu, sd) {
-               if (!(sd->flags & SD_LOAD_BALANCE))
-                       /* no more domains to search */
-                       break;
+       BUG_ON(busiest_rq == target_rq);
 
-               schedstat_inc(sd, alb_cnt);
+       /* move a task from busiest_rq to target_rq */
+       double_lock_balance(busiest_rq, target_rq);
 
-               cpu_group = sd->groups;
-               do {
-                       for_each_cpu_mask(cpu, cpu_group->cpumask) {
-                               if (busiest_rq->nr_running <= 1)
-                                       /* no more tasks left to move */
-                                       return;
-                               if (cpu_isset(cpu, visited_cpus))
-                                       continue;
-                               cpu_set(cpu, visited_cpus);
-                               if (!cpu_and_siblings_are_idle(cpu) || cpu == busiest_cpu)
-                                       continue;
-
-                               target_rq = cpu_rq(cpu);
-                               /*
-                                * This condition is "impossible", if it occurs
-                                * we need to fix it.  Originally reported by
-                                * Bjorn Helgaas on a 128-cpu setup.
-                                */
-                               BUG_ON(busiest_rq == target_rq);
-
-                               /* move a task from busiest_rq to target_rq */
-                               double_lock_balance(busiest_rq, target_rq);
-                               if (move_tasks(target_rq, cpu, busiest_rq,
-                                               1, sd, SCHED_IDLE)) {
-                                       schedstat_inc(sd, alb_pushed);
-                               } else {
-                                       schedstat_inc(sd, alb_failed);
-                               }
-                               spin_unlock(&target_rq->lock);
-                       }
-                       cpu_group = cpu_group->next;
-               } while (cpu_group != sd->groups);
-       }
+       /* Search for an sd spanning us and the target CPU. */
+       for_each_domain(target_cpu, sd)
+               if ((sd->flags & SD_LOAD_BALANCE) &&
+                       cpu_isset(busiest_cpu, sd->span))
+                               break;
+
+       if (unlikely(sd == NULL))
+               goto out;
+
+       schedstat_inc(sd, alb_cnt);
+
+       if (move_tasks(target_rq, target_cpu, busiest_rq, 1, sd, SCHED_IDLE, NULL))
+               schedstat_inc(sd, alb_pushed);
+       else
+               schedstat_inc(sd, alb_failed);
+out:
+       spin_unlock(&target_rq->lock);
 }
 
 /*
@@ -2156,18 +2281,23 @@ static void rebalance_tick(int this_cpu, runqueue_t *this_rq,
        unsigned long old_load, this_load;
        unsigned long j = jiffies + CPU_OFFSET(this_cpu);
        struct sched_domain *sd;
+       int i;
 
-       /* Update our load */
-       old_load = this_rq->cpu_load;
        this_load = this_rq->nr_running * SCHED_LOAD_SCALE;
-       /*
-        * Round up the averaging division if load is increasing. This
-        * prevents us from getting stuck on 9 if the load is 10, for
-        * example.
-        */
-       if (this_load > old_load)
-               old_load++;
-       this_rq->cpu_load = (old_load + this_load) / 2;
+       /* Update our load */
+       for (i = 0; i < 3; i++) {
+               unsigned long new_load = this_load;
+               int scale = 1 << i;
+               old_load = this_rq->cpu_load[i];
+               /*
+                * Round up the averaging division if load is increasing. This
+                * prevents us from getting stuck on 9 if the load is 10, for
+                * example.
+                */
+               if (new_load > old_load)
+                       new_load += scale-1;
+               this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) / scale;
+       }
 
        for_each_domain(this_cpu, sd) {
                unsigned long interval;
@@ -2447,11 +2577,15 @@ out:
 #ifdef CONFIG_SCHED_SMT
 static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq)
 {
-       struct sched_domain *sd = this_rq->sd;
+       struct sched_domain *tmp, *sd = NULL;
        cpumask_t sibling_map;
        int i;
 
-       if (!(sd->flags & SD_SHARE_CPUPOWER))
+       for_each_domain(this_cpu, tmp)
+               if (tmp->flags & SD_SHARE_CPUPOWER)
+                       sd = tmp;
+
+       if (!sd)
                return;
 
        /*
@@ -2492,13 +2626,17 @@ static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq)
 
 static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq)
 {
-       struct sched_domain *sd = this_rq->sd;
+       struct sched_domain *tmp, *sd = NULL;
        cpumask_t sibling_map;
        prio_array_t *array;
        int ret = 0, i;
        task_t *p;
 
-       if (!(sd->flags & SD_SHARE_CPUPOWER))
+       for_each_domain(this_cpu, tmp)
+               if (tmp->flags & SD_SHARE_CPUPOWER)
+                       sd = tmp;
+
+       if (!sd)
                return 0;
 
        /*
@@ -2613,7 +2751,7 @@ asmlinkage void __sched schedule(void)
        struct list_head *queue;
        unsigned long long now;
        unsigned long run_time;
-       int cpu, idx;
+       int cpu, idx, new_prio;
 
        /*
         * Test if we are atomic.  Since do_exit() needs to call into
@@ -2735,9 +2873,14 @@ go_idle:
                        delta = delta * (ON_RUNQUEUE_WEIGHT * 128 / 100) / 128;
 
                array = next->array;
-               dequeue_task(next, array);
-               recalc_task_prio(next, next->timestamp + delta);
-               enqueue_task(next, array);
+               new_prio = recalc_task_prio(next, next->timestamp + delta);
+
+               if (unlikely(next->prio != new_prio)) {
+                       dequeue_task(next, array);
+                       next->prio = new_prio;
+                       enqueue_task(next, array);
+               } else
+                       requeue_task(next, array);
        }
        next->activated = 0;
 switch_tasks:
@@ -2761,11 +2904,15 @@ switch_tasks:
                rq->curr = next;
                ++*switch_count;
 
-               prepare_arch_switch(rq, next);
+               prepare_task_switch(rq, next);
                prev = context_switch(rq, prev, next);
                barrier();
-
-               finish_task_switch(prev);
+               /*
+                * this_rq must be evaluated again because prev may have moved
+                * CPUs since it called schedule(), thus the 'rq' on its stack
+                * frame will be invalid.
+                */
+               finish_task_switch(this_rq(), prev);
        } else
                spin_unlock_irq(&rq->lock);
 
@@ -3301,15 +3448,7 @@ int task_nice(const task_t *p)
 {
        return TASK_NICE(p);
 }
-
-/*
- * The only users of task_nice are binfmt_elf and binfmt_elf32.
- * binfmt_elf is no longer modular, but binfmt_elf32 still is.
- * Therefore, task_nice is needed if there is a compat_mode.
- */
-#ifdef CONFIG_COMPAT
 EXPORT_SYMBOL_GPL(task_nice);
-#endif
 
 /**
  * idle_cpu - is a given cpu idle currently?
@@ -3384,13 +3523,24 @@ recheck:
        if ((policy == SCHED_NORMAL) != (param->sched_priority == 0))
                return -EINVAL;
 
-       if ((policy == SCHED_FIFO || policy == SCHED_RR) &&
-           param->sched_priority > p->signal->rlim[RLIMIT_RTPRIO].rlim_cur &&
-           !capable(CAP_SYS_NICE))
-               return -EPERM;
-       if ((current->euid != p->euid) && (current->euid != p->uid) &&
-           !capable(CAP_SYS_NICE))
-               return -EPERM;
+       /*
+        * Allow unprivileged RT tasks to decrease priority:
+        */
+       if (!capable(CAP_SYS_NICE)) {
+               /* can't change policy */
+               if (policy != p->policy)
+                       return -EPERM;
+               /* can't increase priority */
+               if (policy != SCHED_NORMAL &&
+                   param->sched_priority > p->rt_priority &&
+                   param->sched_priority >
+                               p->signal->rlim[RLIMIT_RTPRIO].rlim_cur)
+                       return -EPERM;
+               /* can't change other user's priorities */
+               if ((current->euid != p->euid) &&
+                   (current->euid != p->uid))
+                       return -EPERM;
+       }
 
        retval = security_task_setscheduler(p, policy, param);
        if (retval)
@@ -4016,6 +4166,14 @@ void show_state(void)
        read_unlock(&tasklist_lock);
 }
 
+/**
+ * init_idle - set up an idle thread for a given CPU
+ * @idle: task in question
+ * @cpu: cpu the idle task belongs to
+ *
+ * NOTE: this function does not set the idle thread's NEED_RESCHED
+ * flag, to make booting more robust.
+ */
 void __devinit init_idle(task_t *idle, int cpu)
 {
        runqueue_t *rq = cpu_rq(cpu);
@@ -4030,7 +4188,9 @@ void __devinit init_idle(task_t *idle, int cpu)
 
        spin_lock_irqsave(&rq->lock, flags);
        rq->curr = rq->idle = idle;
-       set_tsk_need_resched(idle);
+#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
+       idle->oncpu = 1;
+#endif
        spin_unlock_irqrestore(&rq->lock, flags);
 
        /* Set the preempt count _outside_ the spinlocks! */
@@ -4174,8 +4334,7 @@ static int migration_thread(void * data)
                struct list_head *head;
                migration_req_t *req;
 
-               if (current->flags & PF_FREEZE)
-                       refrigerator(PF_FREEZE);
+               try_to_freeze();
 
                spin_lock_irq(&rq->lock);
 
@@ -4200,17 +4359,9 @@ static int migration_thread(void * data)
                req = list_entry(head->next, migration_req_t, list);
                list_del_init(head->next);
 
-               if (req->type == REQ_MOVE_TASK) {
-                       spin_unlock(&rq->lock);
-                       __migrate_task(req->task, cpu, req->dest_cpu);
-                       local_irq_enable();
-               } else if (req->type == REQ_SET_DOMAIN) {
-                       rq->sd = req->sd;
-                       spin_unlock_irq(&rq->lock);
-               } else {
-                       spin_unlock_irq(&rq->lock);
-                       WARN_ON(1);
-               }
+               spin_unlock(&rq->lock);
+               __migrate_task(req->task, cpu, req->dest_cpu);
+               local_irq_enable();
 
                complete(&req->done);
        }
@@ -4441,7 +4592,6 @@ static int migration_call(struct notifier_block *nfb, unsigned long action,
                        migration_req_t *req;
                        req = list_entry(rq->migration_queue.next,
                                         migration_req_t, list);
-                       BUG_ON(req->type != REQ_MOVE_TASK);
                        list_del_init(&req->list);
                        complete(&req->done);
                }
@@ -4472,12 +4622,17 @@ int __init migration_init(void)
 #endif
 
 #ifdef CONFIG_SMP
-#define SCHED_DOMAIN_DEBUG
+#undef SCHED_DOMAIN_DEBUG
 #ifdef SCHED_DOMAIN_DEBUG
 static void sched_domain_debug(struct sched_domain *sd, int cpu)
 {
        int level = 0;
 
+       if (!sd) {
+               printk(KERN_DEBUG "CPU%d attaching NULL sched-domain.\n", cpu);
+               return;
+       }
+
        printk(KERN_DEBUG "CPU%d attaching sched-domain:\n", cpu);
 
        do {
@@ -4560,37 +4715,81 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
 #define sched_domain_debug(sd, cpu) {}
 #endif
 
+static int sd_degenerate(struct sched_domain *sd)
+{
+       if (cpus_weight(sd->span) == 1)
+               return 1;
+
+       /* Following flags need at least 2 groups */
+       if (sd->flags & (SD_LOAD_BALANCE |
+                        SD_BALANCE_NEWIDLE |
+                        SD_BALANCE_FORK |
+                        SD_BALANCE_EXEC)) {
+               if (sd->groups != sd->groups->next)
+                       return 0;
+       }
+
+       /* Following flags don't use groups */
+       if (sd->flags & (SD_WAKE_IDLE |
+                        SD_WAKE_AFFINE |
+                        SD_WAKE_BALANCE))
+               return 0;
+
+       return 1;
+}
+
+static int sd_parent_degenerate(struct sched_domain *sd,
+                                               struct sched_domain *parent)
+{
+       unsigned long cflags = sd->flags, pflags = parent->flags;
+
+       if (sd_degenerate(parent))
+               return 1;
+
+       if (!cpus_equal(sd->span, parent->span))
+               return 0;
+
+       /* Does parent contain flags not in child? */
+       /* WAKE_BALANCE is a subset of WAKE_AFFINE */
+       if (cflags & SD_WAKE_AFFINE)
+               pflags &= ~SD_WAKE_BALANCE;
+       /* Flags needing groups don't count if only 1 group in parent */
+       if (parent->groups == parent->groups->next) {
+               pflags &= ~(SD_LOAD_BALANCE |
+                               SD_BALANCE_NEWIDLE |
+                               SD_BALANCE_FORK |
+                               SD_BALANCE_EXEC);
+       }
+       if (~cflags & pflags)
+               return 0;
+
+       return 1;
+}
+
 /*
  * Attach the domain 'sd' to 'cpu' as its base domain.  Callers must
  * hold the hotplug lock.
  */
-void __devinit cpu_attach_domain(struct sched_domain *sd, int cpu)
+void cpu_attach_domain(struct sched_domain *sd, int cpu)
 {
-       migration_req_t req;
-       unsigned long flags;
        runqueue_t *rq = cpu_rq(cpu);
-       int local = 1;
-
-       sched_domain_debug(sd, cpu);
+       struct sched_domain *tmp;
 
-       spin_lock_irqsave(&rq->lock, flags);
-
-       if (cpu == smp_processor_id() || !cpu_online(cpu)) {
-               rq->sd = sd;
-       } else {
-               init_completion(&req.done);
-               req.type = REQ_SET_DOMAIN;
-               req.sd = sd;
-               list_add(&req.list, &rq->migration_queue);
-               local = 0;
+       /* Remove the sched domains which do not contribute to scheduling. */
+       for (tmp = sd; tmp; tmp = tmp->parent) {
+               struct sched_domain *parent = tmp->parent;
+               if (!parent)
+                       break;
+               if (sd_parent_degenerate(tmp, parent))
+                       tmp->parent = parent->parent;
        }
 
-       spin_unlock_irqrestore(&rq->lock, flags);
+       if (sd && sd_degenerate(sd))
+               sd = sd->parent;
 
-       if (!local) {
-               wake_up_process(rq->migration_thread);
-               wait_for_completion(&req.done);
-       }
+       sched_domain_debug(sd, cpu);
+
+       rcu_assign_pointer(rq->sd, sd);
 }
 
 /* cpus with isolated domains */
@@ -4622,7 +4821,7 @@ __setup ("isolcpus=", isolated_cpu_setup);
  * covered by the given span, and will set each group's ->cpumask correctly,
  * and ->cpu_power to 0.
  */
-void __devinit init_sched_build_groups(struct sched_group groups[],
+void init_sched_build_groups(struct sched_group groups[],
                        cpumask_t span, int (*group_fn)(int cpu))
 {
        struct sched_group *first = NULL, *last = NULL;
@@ -4658,13 +4857,14 @@ void __devinit init_sched_build_groups(struct sched_group groups[],
 
 
 #ifdef ARCH_HAS_SCHED_DOMAIN
-extern void __devinit arch_init_sched_domains(void);
-extern void __devinit arch_destroy_sched_domains(void);
+extern void build_sched_domains(const cpumask_t *cpu_map);
+extern void arch_init_sched_domains(const cpumask_t *cpu_map);
+extern void arch_destroy_sched_domains(const cpumask_t *cpu_map);
 #else
 #ifdef CONFIG_SCHED_SMT
 static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
 static struct sched_group sched_group_cpus[NR_CPUS];
-static int __devinit cpu_to_cpu_group(int cpu)
+static int cpu_to_cpu_group(int cpu)
 {
        return cpu;
 }
@@ -4672,7 +4872,7 @@ static int __devinit cpu_to_cpu_group(int cpu)
 
 static DEFINE_PER_CPU(struct sched_domain, phys_domains);
 static struct sched_group sched_group_phys[NR_CPUS];
-static int __devinit cpu_to_phys_group(int cpu)
+static int cpu_to_phys_group(int cpu)
 {
 #ifdef CONFIG_SCHED_SMT
        return first_cpu(cpu_sibling_map[cpu]);
@@ -4685,7 +4885,7 @@ static int __devinit cpu_to_phys_group(int cpu)
 
 static DEFINE_PER_CPU(struct sched_domain, node_domains);
 static struct sched_group sched_group_nodes[MAX_NUMNODES];
-static int __devinit cpu_to_node_group(int cpu)
+static int cpu_to_node_group(int cpu)
 {
        return cpu_to_node(cpu);
 }
@@ -4716,39 +4916,28 @@ static void check_sibling_maps(void)
 #endif
 
 /*
- * Set up scheduler domains and groups.  Callers must hold the hotplug lock.
+ * Build sched domains for a given set of cpus and attach the sched domains
+ * to the individual cpus
  */
-static void __devinit arch_init_sched_domains(void)
+static void build_sched_domains(const cpumask_t *cpu_map)
 {
        int i;
-       cpumask_t cpu_default_map;
-
-#if defined(CONFIG_SCHED_SMT) && defined(CONFIG_NUMA)
-       check_sibling_maps();
-#endif
-       /*
-        * Setup mask for cpus without special case scheduling requirements.
-        * For now this just excludes isolated cpus, but could be used to
-        * exclude other special cases in the future.
-        */
-       cpus_complement(cpu_default_map, cpu_isolated_map);
-       cpus_and(cpu_default_map, cpu_default_map, cpu_online_map);
 
        /*
-        * Set up domains. Isolated domains just stay on the dummy domain.
+        * Set up domains for cpus specified by the cpu_map.
         */
-       for_each_cpu_mask(i, cpu_default_map) {
+       for_each_cpu_mask(i, *cpu_map) {
                int group;
                struct sched_domain *sd = NULL, *p;
                cpumask_t nodemask = node_to_cpumask(cpu_to_node(i));
 
-               cpus_and(nodemask, nodemask, cpu_default_map);
+               cpus_and(nodemask, nodemask, *cpu_map);
 
 #ifdef CONFIG_NUMA
                sd = &per_cpu(node_domains, i);
                group = cpu_to_node_group(i);
                *sd = SD_NODE_INIT;
-               sd->span = cpu_default_map;
+               sd->span = *cpu_map;
                sd->groups = &sched_group_nodes[group];
 #endif
 
@@ -4766,7 +4955,7 @@ static void __devinit arch_init_sched_domains(void)
                group = cpu_to_cpu_group(i);
                *sd = SD_SIBLING_INIT;
                sd->span = cpu_sibling_map[i];
-               cpus_and(sd->span, sd->span, cpu_default_map);
+               cpus_and(sd->span, sd->span, *cpu_map);
                sd->parent = p;
                sd->groups = &sched_group_cpus[group];
 #endif
@@ -4776,7 +4965,7 @@ static void __devinit arch_init_sched_domains(void)
        /* Set up CPU (sibling) groups */
        for_each_online_cpu(i) {
                cpumask_t this_sibling_map = cpu_sibling_map[i];
-               cpus_and(this_sibling_map, this_sibling_map, cpu_default_map);
+               cpus_and(this_sibling_map, this_sibling_map, *cpu_map);
                if (i != first_cpu(this_sibling_map))
                        continue;
 
@@ -4789,7 +4978,7 @@ static void __devinit arch_init_sched_domains(void)
        for (i = 0; i < MAX_NUMNODES; i++) {
                cpumask_t nodemask = node_to_cpumask(i);
 
-               cpus_and(nodemask, nodemask, cpu_default_map);
+               cpus_and(nodemask, nodemask, *cpu_map);
                if (cpus_empty(nodemask))
                        continue;
 
@@ -4799,12 +4988,12 @@ static void __devinit arch_init_sched_domains(void)
 
 #ifdef CONFIG_NUMA
        /* Set up node groups */
-       init_sched_build_groups(sched_group_nodes, cpu_default_map,
+       init_sched_build_groups(sched_group_nodes, *cpu_map,
                                        &cpu_to_node_group);
 #endif
 
        /* Calculate CPU power for physical packages and nodes */
-       for_each_cpu_mask(i, cpu_default_map) {
+       for_each_cpu_mask(i, *cpu_map) {
                int power;
                struct sched_domain *sd;
 #ifdef CONFIG_SCHED_SMT
@@ -4828,7 +5017,7 @@ static void __devinit arch_init_sched_domains(void)
        }
 
        /* Attach the domains */
-       for_each_online_cpu(i) {
+       for_each_cpu_mask(i, *cpu_map) {
                struct sched_domain *sd;
 #ifdef CONFIG_SCHED_SMT
                sd = &per_cpu(cpu_domains, i);
@@ -4838,41 +5027,85 @@ static void __devinit arch_init_sched_domains(void)
                cpu_attach_domain(sd, i);
        }
 }
+/*
+ * Set up scheduler domains and groups.  Callers must hold the hotplug lock.
+ */
+static void arch_init_sched_domains(cpumask_t *cpu_map)
+{
+       cpumask_t cpu_default_map;
+
+#if defined(CONFIG_SCHED_SMT) && defined(CONFIG_NUMA)
+       check_sibling_maps();
+#endif
+       /*
+        * Setup mask for cpus without special case scheduling requirements.
+        * For now this just excludes isolated cpus, but could be used to
+        * exclude other special cases in the future.
+        */
+       cpus_andnot(cpu_default_map, *cpu_map, cpu_isolated_map);
+
+       build_sched_domains(&cpu_default_map);
+}
 
-#ifdef CONFIG_HOTPLUG_CPU
-static void __devinit arch_destroy_sched_domains(void)
+static void arch_destroy_sched_domains(const cpumask_t *cpu_map)
 {
        /* Do nothing: everything is statically allocated. */
 }
-#endif
 
 #endif /* ARCH_HAS_SCHED_DOMAIN */
 
 /*
- * Initial dummy domain for early boot and for hotplug cpu. Being static,
- * it is initialized to zero, so all balancing flags are cleared which is
- * what we want.
+ * Detach sched domains from a group of cpus specified in cpu_map
+ * These cpus will now be attached to the NULL domain
  */
-static struct sched_domain sched_domain_dummy;
+static inline void detach_destroy_domains(const cpumask_t *cpu_map)
+{
+       int i;
+
+       for_each_cpu_mask(i, *cpu_map)
+               cpu_attach_domain(NULL, i);
+       synchronize_sched();
+       arch_destroy_sched_domains(cpu_map);
+}
+
+/*
+ * Partition sched domains as specified by the cpumasks below.
+ * This attaches all cpus from the cpumasks to the NULL domain,
+ * waits for a RCU quiescent period, recalculates sched
+ * domain information and then attaches them back to the
+ * correct sched domains
+ * Call with hotplug lock held
+ */
+void partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2)
+{
+       cpumask_t change_map;
+
+       cpus_and(*partition1, *partition1, cpu_online_map);
+       cpus_and(*partition2, *partition2, cpu_online_map);
+       cpus_or(change_map, *partition1, *partition2);
+
+       /* Detach sched domains from all of the affected cpus */
+       detach_destroy_domains(&change_map);
+       if (!cpus_empty(*partition1))
+               build_sched_domains(partition1);
+       if (!cpus_empty(*partition2))
+               build_sched_domains(partition2);
+}
 
 #ifdef CONFIG_HOTPLUG_CPU
 /*
  * Force a reinitialization of the sched domains hierarchy.  The domains
  * and groups cannot be updated in place without racing with the balancing
- * code, so we temporarily attach all running cpus to a "dummy" domain
+ * code, so we temporarily attach all running cpus to the NULL domain
  * which will prevent rebalancing while the sched domains are recalculated.
  */
 static int update_sched_domains(struct notifier_block *nfb,
                                unsigned long action, void *hcpu)
 {
-       int i;
-
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_DOWN_PREPARE:
-               for_each_online_cpu(i)
-                       cpu_attach_domain(&sched_domain_dummy, i);
-               arch_destroy_sched_domains();
+               detach_destroy_domains(&cpu_online_map);
                return NOTIFY_OK;
 
        case CPU_UP_CANCELED:
@@ -4888,7 +5121,7 @@ static int update_sched_domains(struct notifier_block *nfb,
        }
 
        /* The hotplug lock is already held by cpu_up/cpu_down */
-       arch_init_sched_domains();
+       arch_init_sched_domains(&cpu_online_map);
 
        return NOTIFY_OK;
 }
@@ -4897,7 +5130,7 @@ static int update_sched_domains(struct notifier_block *nfb,
 void __init sched_init_smp(void)
 {
        lock_cpu_hotplug();
-       arch_init_sched_domains();
+       arch_init_sched_domains(&cpu_online_map);
        unlock_cpu_hotplug();
        /* XXX: Theoretical race here - CPU may be hotplugged now */
        hotcpu_notifier(update_sched_domains, 0);
@@ -4927,13 +5160,15 @@ void __init sched_init(void)
 
                rq = cpu_rq(i);
                spin_lock_init(&rq->lock);
+               rq->nr_running = 0;
                rq->active = rq->arrays;
                rq->expired = rq->arrays + 1;
                rq->best_expired_prio = MAX_PRIO;
 
 #ifdef CONFIG_SMP
-               rq->sd = &sched_domain_dummy;
-               rq->cpu_load = 0;
+               rq->sd = NULL;
+               for (j = 1; j < 3; j++)
+                       rq->cpu_load[j] = 0;
                rq->active_balance = 0;
                rq->push_cpu = 0;
                rq->migration_thread = NULL;
index d1258729a5f9cdf6674b897b273036e1dee29291..ca1186eef9380cd5e633f644a0891d1dacc5bd16 100644 (file)
@@ -213,7 +213,7 @@ static inline int has_pending_signals(sigset_t *signal, sigset_t *blocked)
 fastcall void recalc_sigpending_tsk(struct task_struct *t)
 {
        if (t->signal->group_stop_count > 0 ||
-           (t->flags & PF_FREEZE) ||
+           (freezing(t)) ||
            PENDING(&t->pending, &t->blocked) ||
            PENDING(&t->signal->shared_pending, &t->blocked))
                set_tsk_thread_flag(t, TIF_SIGPENDING);
@@ -2231,8 +2231,7 @@ sys_rt_sigtimedwait(const sigset_t __user *uthese,
                        current->state = TASK_INTERRUPTIBLE;
                        timeout = schedule_timeout(timeout);
 
-                       if (current->flags & PF_FREEZE)
-                               refrigerator(PF_FREEZE);
+                       try_to_freeze();
                        spin_lock_irq(&current->sighand->siglock);
                        sig = dequeue_signal(current, &these, &info);
                        current->blocked = current->real_blocked;
index 5a9d6b075016546d0d72ec590a17cd77985a8947..9a24374c23bc4f69116d264991689b1aaa9c38fe 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/init.h>
 #include <linux/highuid.h>
 #include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
 #include <linux/workqueue.h>
 #include <linux/device.h>
 #include <linux/key.h>
@@ -405,6 +407,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
        case LINUX_REBOOT_CMD_HALT:
                notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL);
                system_state = SYSTEM_HALT;
+               device_suspend(PMSG_SUSPEND);
                device_shutdown();
                printk(KERN_EMERG "System halted.\n");
                machine_halt();
@@ -415,6 +418,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
        case LINUX_REBOOT_CMD_POWER_OFF:
                notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
                system_state = SYSTEM_POWER_OFF;
+               device_suspend(PMSG_SUSPEND);
                device_shutdown();
                printk(KERN_EMERG "Power down.\n");
                machine_power_off();
@@ -431,11 +435,30 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
 
                notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer);
                system_state = SYSTEM_RESTART;
+               device_suspend(PMSG_FREEZE);
                device_shutdown();
                printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer);
                machine_restart(buffer);
                break;
 
+#ifdef CONFIG_KEXEC
+       case LINUX_REBOOT_CMD_KEXEC:
+       {
+               struct kimage *image;
+               image = xchg(&kexec_image, 0);
+               if (!image) {
+                       unlock_kernel();
+                       return -EINVAL;
+               }
+               notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
+               system_state = SYSTEM_RESTART;
+               device_shutdown();
+               printk(KERN_EMERG "Starting new kernel\n");
+               machine_shutdown();
+               machine_kexec(image);
+               break;
+       }
+#endif
 #ifdef CONFIG_SOFTWARE_SUSPEND
        case LINUX_REBOOT_CMD_SW_SUSPEND:
                {
@@ -1259,7 +1282,7 @@ static void groups_sort(struct group_info *group_info)
 }
 
 /* a simple bsearch */
-static int groups_search(struct group_info *group_info, gid_t grp)
+int groups_search(struct group_info *group_info, gid_t grp)
 {
        int left, right;
 
index 6f15bea7d1a83dc363826c5bcdb2c0013feaebc0..29196ce9b40f09a9398d78e1c4ee555dd93f6c04 100644 (file)
@@ -18,6 +18,8 @@ cond_syscall(sys_acct);
 cond_syscall(sys_lookup_dcookie);
 cond_syscall(sys_swapon);
 cond_syscall(sys_swapoff);
+cond_syscall(sys_kexec_load);
+cond_syscall(compat_sys_kexec_load);
 cond_syscall(sys_init_module);
 cond_syscall(sys_delete_module);
 cond_syscall(sys_socketpair);
index 24a4d12d5aa9b40bc8e2ea57dde06f1075e70135..270ee7fadbd83d0d90ee732ffd7904c3b8c34d65 100644 (file)
@@ -1000,8 +1000,7 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol
                int error = parse_table(name, nlen, oldval, oldlenp, 
                                        newval, newlen, head->ctl_table,
                                        &context);
-               if (context)
-                       kfree(context);
+               kfree(context);
                if (error != -ENOTDIR)
                        return error;
                tmp = tmp->next;
index 51ff917c959029d8b51e13696c34df5a62ee1def..f2a11887a72680605bc9af158132a4fd104fbe24 100644 (file)
@@ -1597,7 +1597,7 @@ void msleep(unsigned int msecs)
 EXPORT_SYMBOL(msleep);
 
 /**
- * msleep_interruptible - sleep waiting for waitqueue interruptions
+ * msleep_interruptible - sleep waiting for signals
  * @msecs: Time in milliseconds to sleep for
  */
 unsigned long msleep_interruptible(unsigned int msecs)
index 2d4d4e3bc4aa47680d0e5581e4cfc4c09397b75b..eeb429a52152bf51e34c5f67f96d8404d66ddf2e 100644 (file)
@@ -63,5 +63,16 @@ config REED_SOLOMON_ENC16
 config REED_SOLOMON_DEC16
        boolean
 
-endmenu
+#
+# Textsearch support is select'ed if needed
+#
+config TEXTSEARCH
+       boolean
 
+config TEXTSEARCH_KMP
+       tristate
+
+config TEXTSEARCH_FSM
+       tristate
+
+endmenu
index dcb4231916e2ecb353c80cb1dc51ff5ca75b2b26..beed1585294c370a488ea1f85848eeffe2a5dc3d 100644 (file)
@@ -36,6 +36,10 @@ obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
 obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
 obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
 
+obj-$(CONFIG_TEXTSEARCH) += textsearch.o
+obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o
+obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o
+
 hostprogs-y    := gen_crc32table
 clean-files    := crc32table.h
 
index d1388a5ce89c37c6934a5ac8384443a902365b5e..fb9371fdd44a43c4e8e4fc9304f0ee00d3b4df8c 100644 (file)
@@ -289,7 +289,6 @@ EXPORT_SYMBOL(__bitmap_weight);
 
 #define CHUNKSZ                                32
 #define nbits_to_hold_value(val)       fls(val)
-#define roundup_power2(val,modulus)    (((val) + (modulus) - 1) & ~((modulus) - 1))
 #define unhex(c)                       (isdigit(c) ? (c - '0') : (toupper(c) - 'A' + 10))
 #define BASEDEC 10             /* fancier cpuset lists input in decimal */
 
@@ -316,7 +315,7 @@ int bitmap_scnprintf(char *buf, unsigned int buflen,
        if (chunksz == 0)
                chunksz = CHUNKSZ;
 
-       i = roundup_power2(nmaskbits, CHUNKSZ) - CHUNKSZ;
+       i = ALIGN(nmaskbits, CHUNKSZ) - CHUNKSZ;
        for (; i >= 0; i -= CHUNKSZ) {
                chunkmask = ((1ULL << chunksz) - 1);
                word = i / BITS_PER_LONG;
index 2f7f1148dfde3379921d54f44b5b41c4d167390a..1cdabe3065f932d1edde271b2421ce6844ccb84c 100644 (file)
@@ -41,7 +41,7 @@ void sha_transform(__u32 *digest, const char *in, __u32 *W)
        __u32 a, b, c, d, e, t, i;
 
        for (i = 0; i < 16; i++)
-               W[i] = be32_to_cpu(((const __u32 *)in)[i]);
+               W[i] = be32_to_cpu(((const __be32 *)in)[i]);
 
        for (i = 0; i < 64; i++)
                W[i+16] = rol32(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i], 1);
diff --git a/lib/textsearch.c b/lib/textsearch.c
new file mode 100644 (file)
index 0000000..1e934c1
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * lib/textsearch.c    Generic text search interface
+ *
+ *             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.
+ *
+ * Authors:    Thomas Graf <tgraf@suug.ch>
+ *             Pablo Neira Ayuso <pablo@eurodev.net>
+ *
+ * ==========================================================================
+ *
+ * INTRODUCTION
+ *
+ *   The textsearch infrastructure provides text searching facitilies for
+ *   both linear and non-linear data. Individual search algorithms are
+ *   implemented in modules and chosen by the user.
+ *
+ * ARCHITECTURE
+ *
+ *      User
+ *     +----------------+
+ *     |        finish()|<--------------(6)-----------------+
+ *     |get_next_block()|<--------------(5)---------------+ |
+ *     |                |                     Algorithm   | |
+ *     |                |                    +------------------------------+
+ *     |                |                    |  init()   find()   destroy() |
+ *     |                |                    +------------------------------+
+ *     |                |       Core API           ^       ^          ^
+ *     |                |      +---------------+  (2)     (4)        (8)
+ *     |             (1)|----->| prepare()     |---+       |          |
+ *     |             (3)|----->| find()/next() |-----------+          |
+ *     |             (7)|----->| destroy()     |----------------------+
+ *     +----------------+      +---------------+
+ *  
+ *   (1) User configures a search by calling _prepare() specifying the
+ *       search parameters such as the pattern and algorithm name.
+ *   (2) Core requests the algorithm to allocate and initialize a search
+ *       configuration according to the specified parameters.
+ *   (3) User starts the search(es) by calling _find() or _next() to
+ *       fetch subsequent occurrences. A state variable is provided
+ *       to the algorihtm to store persistant variables.
+ *   (4) Core eventually resets the search offset and forwards the find()
+ *       request to the algorithm.
+ *   (5) Algorithm calls get_next_block() provided by the user continously
+ *       to fetch the data to be searched in block by block.
+ *   (6) Algorithm invokes finish() after the last call to get_next_block
+ *       to clean up any leftovers from get_next_block. (Optional)
+ *   (7) User destroys the configuration by calling _destroy().
+ *   (8) Core notifies the algorithm to destroy algorithm specific
+ *       allocations. (Optional)
+ *
+ * USAGE
+ *
+ *   Before a search can be performed, a configuration must be created
+ *   by calling textsearch_prepare() specyfing the searching algorithm and
+ *   the pattern to look for. The returned configuration may then be used
+ *   for an arbitary amount of times and even in parallel as long as a
+ *   separate struct ts_state variable is provided to every instance.
+ *
+ *   The actual search is performed by either calling textsearch_find_-
+ *   continuous() for linear data or by providing an own get_next_block()
+ *   implementation and calling textsearch_find(). Both functions return
+ *   the position of the first occurrence of the patern or UINT_MAX if
+ *   no match was found. Subsequent occurences can be found by calling
+ *   textsearch_next() regardless of the linearity of the data.
+ *
+ *   Once you're done using a configuration it must be given back via
+ *   textsearch_destroy.
+ *
+ * EXAMPLE
+ *
+ *   int pos;
+ *   struct ts_config *conf;
+ *   struct ts_state state;
+ *   const char *pattern = "chicken";
+ *   const char *example = "We dance the funky chicken";
+ *
+ *   conf = textsearch_prepare("kmp", pattern, strlen(pattern),
+ *                             GFP_KERNEL, TS_AUTOLOAD);
+ *   if (IS_ERR(conf)) {
+ *       err = PTR_ERR(conf);
+ *       goto errout;
+ *   }
+ *
+ *   pos = textsearch_find_continuous(conf, &state, example, strlen(example));
+ *   if (pos != UINT_MAX)
+ *       panic("Oh my god, dancing chickens at %d\n", pos);
+ *
+ *   textsearch_destroy(conf);
+ *
+ * ==========================================================================
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/rcupdate.h>
+#include <linux/err.h>
+#include <linux/textsearch.h>
+
+static LIST_HEAD(ts_ops);
+static DEFINE_SPINLOCK(ts_mod_lock);
+
+static inline struct ts_ops *lookup_ts_algo(const char *name)
+{
+       struct ts_ops *o;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(o, &ts_ops, list) {
+               if (!strcmp(name, o->name)) {
+                       if (!try_module_get(o->owner))
+                               o = NULL;
+                       rcu_read_unlock();
+                       return o;
+               }
+       }
+       rcu_read_unlock();
+
+       return NULL;
+}
+
+/**
+ * textsearch_register - register a textsearch module
+ * @ops: operations lookup table
+ *
+ * This function must be called by textsearch modules to announce
+ * their presence. The specified &@ops must have %name set to a
+ * unique identifier and the callbacks find(), init(), get_pattern(),
+ * and get_pattern_len() must be implemented.
+ *
+ * Returns 0 or -EEXISTS if another module has already registered
+ * with same name.
+ */
+int textsearch_register(struct ts_ops *ops)
+{
+       int err = -EEXIST;
+       struct ts_ops *o;
+
+       if (ops->name == NULL || ops->find == NULL || ops->init == NULL ||
+           ops->get_pattern == NULL || ops->get_pattern_len == NULL)
+               return -EINVAL;
+
+       spin_lock(&ts_mod_lock);
+       list_for_each_entry(o, &ts_ops, list) {
+               if (!strcmp(ops->name, o->name))
+                       goto errout;
+       }
+
+       list_add_tail_rcu(&ops->list, &ts_ops);
+       err = 0;
+errout:
+       spin_unlock(&ts_mod_lock);
+       return err;
+}
+
+/**
+ * textsearch_unregister - unregister a textsearch module
+ * @ops: operations lookup table
+ *
+ * This function must be called by textsearch modules to announce
+ * their disappearance for examples when the module gets unloaded.
+ * The &ops parameter must be the same as the one during the
+ * registration.
+ *
+ * Returns 0 on success or -ENOENT if no matching textsearch
+ * registration was found.
+ */
+int textsearch_unregister(struct ts_ops *ops)
+{
+       int err = 0;
+       struct ts_ops *o;
+
+       spin_lock(&ts_mod_lock);
+       list_for_each_entry(o, &ts_ops, list) {
+               if (o == ops) {
+                       list_del_rcu(&o->list);
+                       goto out;
+               }
+       }
+
+       err = -ENOENT;
+out:
+       spin_unlock(&ts_mod_lock);
+       return err;
+}
+
+struct ts_linear_state
+{
+       unsigned int    len;
+       const void      *data;
+};
+
+static unsigned int get_linear_data(unsigned int consumed, const u8 **dst,
+                                   struct ts_config *conf,
+                                   struct ts_state *state)
+{
+       struct ts_linear_state *st = (struct ts_linear_state *) state->cb;
+
+       if (likely(consumed < st->len)) {
+               *dst = st->data + consumed;
+               return st->len - consumed;
+       }
+
+       return 0;
+}
+
+/**
+ * textsearch_find_continuous - search a pattern in continuous/linear data
+ * @conf: search configuration
+ * @state: search state
+ * @data: data to search in
+ * @len: length of data
+ *
+ * A simplified version of textsearch_find() for continuous/linear data.
+ * Call textsearch_next() to retrieve subsequent matches.
+ *
+ * Returns the position of first occurrence of the pattern or
+ * UINT_MAX if no occurrence was found.
+ */ 
+unsigned int textsearch_find_continuous(struct ts_config *conf,
+                                       struct ts_state *state,
+                                       const void *data, unsigned int len)
+{
+       struct ts_linear_state *st = (struct ts_linear_state *) state->cb;
+
+       conf->get_next_block = get_linear_data;
+       st->data = data;
+       st->len = len;
+
+       return textsearch_find(conf, state);
+}
+
+/**
+ * textsearch_prepare - Prepare a search
+ * @algo: name of search algorithm
+ * @pattern: pattern data
+ * @len: length of pattern
+ * @gfp_mask: allocation mask
+ * @flags: search flags
+ *
+ * Looks up the search algorithm module and creates a new textsearch
+ * configuration for the specified pattern. Upon completion all
+ * necessary refcnts are held and the configuration must be put back
+ * using textsearch_put() after usage.
+ *
+ * Note: The format of the pattern may not be compatible between
+ *       the various search algorithms.
+ *
+ * Returns a new textsearch configuration according to the specified
+ *         parameters or a ERR_PTR().
+ */
+struct ts_config *textsearch_prepare(const char *algo, const void *pattern,
+                                    unsigned int len, int gfp_mask, int flags)
+{
+       int err = -ENOENT;
+       struct ts_config *conf;
+       struct ts_ops *ops;
+       
+       ops = lookup_ts_algo(algo);
+#ifdef CONFIG_KMOD
+       /*
+        * Why not always autoload you may ask. Some users are
+        * in a situation where requesting a module may deadlock,
+        * especially when the module is located on a NFS mount.
+        */
+       if (ops == NULL && flags & TS_AUTOLOAD) {
+               request_module("ts_%s", algo);
+               ops = lookup_ts_algo(algo);
+       }
+#endif
+
+       if (ops == NULL)
+               goto errout;
+
+       conf = ops->init(pattern, len, gfp_mask);
+       if (IS_ERR(conf)) {
+               err = PTR_ERR(conf);
+               goto errout;
+       }
+
+       conf->ops = ops;
+       return conf;
+
+errout:
+       if (ops)
+               module_put(ops->owner);
+               
+       return ERR_PTR(err);
+}
+
+/**
+ * textsearch_destroy - destroy a search configuration
+ * @conf: search configuration
+ *
+ * Releases all references of the configuration and frees
+ * up the memory.
+ */
+void textsearch_destroy(struct ts_config *conf)
+{
+       if (conf->ops) {
+               if (conf->ops->destroy)
+                       conf->ops->destroy(conf);
+               module_put(conf->ops->owner);
+       }
+
+       kfree(conf);
+}
+
+EXPORT_SYMBOL(textsearch_register);
+EXPORT_SYMBOL(textsearch_unregister);
+EXPORT_SYMBOL(textsearch_prepare);
+EXPORT_SYMBOL(textsearch_find_continuous);
+EXPORT_SYMBOL(textsearch_destroy);
diff --git a/lib/ts_fsm.c b/lib/ts_fsm.c
new file mode 100644 (file)
index 0000000..d27c0a0
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * lib/ts_fsm.c           A naive finite state machine text search approach
+ *
+ *             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.
+ *
+ * Authors:    Thomas Graf <tgraf@suug.ch>
+ *
+ * ==========================================================================
+ *
+ *   A finite state machine consists of n states (struct ts_fsm_token)
+ *   representing the pattern as a finite automation. The data is read
+ *   sequentially on a octet basis. Every state token specifies the number
+ *   of recurrences and the type of value accepted which can be either a
+ *   specific character or ctype based set of characters. The available
+ *   type of recurrences include 1, (0|1), [0 n], and [1 n].
+ *
+ *   The algorithm differs between strict/non-strict mode specyfing
+ *   whether the pattern has to start at the first octect. Strict mode
+ *   is enabled by default and can be disabled by inserting
+ *   TS_FSM_HEAD_IGNORE as the first token in the chain.
+ *
+ *   The runtime performance of the algorithm should be around O(n),
+ *   however while in strict mode the average runtime can be better.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/textsearch.h>
+#include <linux/textsearch_fsm.h>
+
+struct ts_fsm
+{
+       unsigned int            ntokens;
+       struct ts_fsm_token     tokens[0];
+};
+
+/* other values derived from ctype.h */
+#define _A             0x100 /* ascii */
+#define _W             0x200 /* wildcard */
+
+/* Map to _ctype flags and some magic numbers */
+static u16 token_map[TS_FSM_TYPE_MAX+1] = {
+       [TS_FSM_SPECIFIC] = 0,
+       [TS_FSM_WILDCARD] = _W,
+       [TS_FSM_CNTRL]    = _C,
+       [TS_FSM_LOWER]    = _L,
+       [TS_FSM_UPPER]    = _U,
+       [TS_FSM_PUNCT]    = _P,
+       [TS_FSM_SPACE]    = _S,
+       [TS_FSM_DIGIT]    = _D,
+       [TS_FSM_XDIGIT]   = _D | _X,
+       [TS_FSM_ALPHA]    = _U | _L,
+       [TS_FSM_ALNUM]    = _U | _L | _D,
+       [TS_FSM_PRINT]    = _P | _U | _L | _D | _SP,
+       [TS_FSM_GRAPH]    = _P | _U | _L | _D,
+       [TS_FSM_ASCII]    = _A,
+};
+
+static u16 token_lookup_tbl[256] = {
+_W|_A|_C,      _W|_A|_C,     _W|_A|_C,     _W|_A|_C,           /*   0-  3 */
+_W|_A|_C,      _W|_A|_C,     _W|_A|_C,     _W|_A|_C,           /*   4-  7 */
+_W|_A|_C,      _W|_A|_C|_S,  _W|_A|_C|_S,  _W|_A|_C|_S,                /*   8- 11 */
+_W|_A|_C|_S,   _W|_A|_C|_S,  _W|_A|_C,     _W|_A|_C,           /*  12- 15 */
+_W|_A|_C,      _W|_A|_C,     _W|_A|_C,     _W|_A|_C,           /*  16- 19 */
+_W|_A|_C,      _W|_A|_C,     _W|_A|_C,     _W|_A|_C,           /*  20- 23 */
+_W|_A|_C,      _W|_A|_C,     _W|_A|_C,     _W|_A|_C,           /*  24- 27 */
+_W|_A|_C,      _W|_A|_C,     _W|_A|_C,     _W|_A|_C,           /*  28- 31 */
+_W|_A|_S|_SP,  _W|_A|_P,     _W|_A|_P,     _W|_A|_P,           /*  32- 35 */
+_W|_A|_P,      _W|_A|_P,     _W|_A|_P,     _W|_A|_P,           /*  36- 39 */
+_W|_A|_P,      _W|_A|_P,     _W|_A|_P,     _W|_A|_P,           /*  40- 43 */
+_W|_A|_P,      _W|_A|_P,     _W|_A|_P,     _W|_A|_P,           /*  44- 47 */
+_W|_A|_D,      _W|_A|_D,     _W|_A|_D,     _W|_A|_D,           /*  48- 51 */
+_W|_A|_D,      _W|_A|_D,     _W|_A|_D,     _W|_A|_D,           /*  52- 55 */
+_W|_A|_D,      _W|_A|_D,     _W|_A|_P,     _W|_A|_P,           /*  56- 59 */
+_W|_A|_P,      _W|_A|_P,     _W|_A|_P,     _W|_A|_P,           /*  60- 63 */
+_W|_A|_P,      _W|_A|_U|_X,  _W|_A|_U|_X,  _W|_A|_U|_X,                /*  64- 67 */
+_W|_A|_U|_X,   _W|_A|_U|_X,  _W|_A|_U|_X,  _W|_A|_U,           /*  68- 71 */
+_W|_A|_U,      _W|_A|_U,     _W|_A|_U,     _W|_A|_U,           /*  72- 75 */
+_W|_A|_U,      _W|_A|_U,     _W|_A|_U,     _W|_A|_U,           /*  76- 79 */
+_W|_A|_U,      _W|_A|_U,     _W|_A|_U,     _W|_A|_U,           /*  80- 83 */
+_W|_A|_U,      _W|_A|_U,     _W|_A|_U,     _W|_A|_U,           /*  84- 87 */
+_W|_A|_U,      _W|_A|_U,     _W|_A|_U,     _W|_A|_P,           /*  88- 91 */
+_W|_A|_P,      _W|_A|_P,     _W|_A|_P,     _W|_A|_P,           /*  92- 95 */
+_W|_A|_P,      _W|_A|_L|_X,  _W|_A|_L|_X,  _W|_A|_L|_X,                /*  96- 99 */
+_W|_A|_L|_X,   _W|_A|_L|_X,  _W|_A|_L|_X,  _W|_A|_L,           /* 100-103 */
+_W|_A|_L,      _W|_A|_L,     _W|_A|_L,     _W|_A|_L,           /* 104-107 */
+_W|_A|_L,      _W|_A|_L,     _W|_A|_L,     _W|_A|_L,           /* 108-111 */
+_W|_A|_L,      _W|_A|_L,     _W|_A|_L,     _W|_A|_L,           /* 112-115 */
+_W|_A|_L,      _W|_A|_L,     _W|_A|_L,     _W|_A|_L,           /* 116-119 */
+_W|_A|_L,      _W|_A|_L,     _W|_A|_L,     _W|_A|_P,           /* 120-123 */
+_W|_A|_P,      _W|_A|_P,     _W|_A|_P,     _W|_A|_C,           /* 124-127 */
+_W,            _W,           _W,           _W,                 /* 128-131 */
+_W,            _W,           _W,           _W,                 /* 132-135 */
+_W,            _W,           _W,           _W,                 /* 136-139 */
+_W,            _W,           _W,           _W,                 /* 140-143 */
+_W,            _W,           _W,           _W,                 /* 144-147 */
+_W,            _W,           _W,           _W,                 /* 148-151 */
+_W,            _W,           _W,           _W,                 /* 152-155 */
+_W,            _W,           _W,           _W,                 /* 156-159 */
+_W|_S|_SP,     _W|_P,        _W|_P,        _W|_P,              /* 160-163 */
+_W|_P,         _W|_P,        _W|_P,        _W|_P,              /* 164-167 */
+_W|_P,         _W|_P,        _W|_P,        _W|_P,              /* 168-171 */
+_W|_P,         _W|_P,        _W|_P,        _W|_P,              /* 172-175 */
+_W|_P,         _W|_P,        _W|_P,        _W|_P,              /* 176-179 */
+_W|_P,         _W|_P,        _W|_P,        _W|_P,              /* 180-183 */
+_W|_P,         _W|_P,        _W|_P,        _W|_P,              /* 184-187 */
+_W|_P,         _W|_P,        _W|_P,        _W|_P,              /* 188-191 */
+_W|_U,         _W|_U,        _W|_U,        _W|_U,              /* 192-195 */
+_W|_U,         _W|_U,        _W|_U,        _W|_U,              /* 196-199 */
+_W|_U,         _W|_U,        _W|_U,        _W|_U,              /* 200-203 */
+_W|_U,         _W|_U,        _W|_U,        _W|_U,              /* 204-207 */
+_W|_U,         _W|_U,        _W|_U,        _W|_U,              /* 208-211 */
+_W|_U,         _W|_U,        _W|_U,        _W|_P,              /* 212-215 */
+_W|_U,         _W|_U,        _W|_U,        _W|_U,              /* 216-219 */
+_W|_U,         _W|_U,        _W|_U,        _W|_L,              /* 220-223 */
+_W|_L,         _W|_L,        _W|_L,        _W|_L,              /* 224-227 */
+_W|_L,         _W|_L,        _W|_L,        _W|_L,              /* 228-231 */
+_W|_L,         _W|_L,        _W|_L,        _W|_L,              /* 232-235 */
+_W|_L,         _W|_L,        _W|_L,        _W|_L,              /* 236-239 */
+_W|_L,         _W|_L,        _W|_L,        _W|_L,              /* 240-243 */
+_W|_L,         _W|_L,        _W|_L,        _W|_P,              /* 244-247 */
+_W|_L,         _W|_L,        _W|_L,        _W|_L,              /* 248-251 */
+_W|_L,         _W|_L,        _W|_L,        _W|_L};             /* 252-255 */
+
+static inline int match_token(struct ts_fsm_token *t, u8 d)
+{
+       if (t->type)
+               return (token_lookup_tbl[d] & t->type) != 0;
+       else
+               return t->value == d;
+}
+
+static unsigned int fsm_find(struct ts_config *conf, struct ts_state *state)
+{
+       struct ts_fsm *fsm = ts_config_priv(conf);
+       struct ts_fsm_token *cur = NULL, *next;
+       unsigned int match_start, block_idx = 0, tok_idx;
+       unsigned block_len = 0, strict, consumed = state->offset;
+       const u8 *data;
+
+#define GET_NEXT_BLOCK()               \
+({     consumed += block_idx;          \
+       block_idx = 0;                  \
+       block_len = conf->get_next_block(consumed, &data, conf, state); })
+
+#define TOKEN_MISMATCH()               \
+       do {                            \
+               if (strict)             \
+                       goto no_match;  \
+               block_idx++;            \
+               goto startover;         \
+       } while(0)
+
+#define end_of_data() unlikely(block_idx >= block_len && !GET_NEXT_BLOCK())
+
+       if (end_of_data())
+               goto no_match;
+
+       strict = fsm->tokens[0].recur != TS_FSM_HEAD_IGNORE;
+
+startover:
+       match_start = consumed + block_idx;
+
+       for (tok_idx = 0; tok_idx < fsm->ntokens; tok_idx++) {
+               cur = &fsm->tokens[tok_idx];
+
+               if (likely(tok_idx < (fsm->ntokens - 1)))
+                       next = &fsm->tokens[tok_idx + 1];
+               else
+                       next = NULL;
+
+               switch (cur->recur) {
+               case TS_FSM_SINGLE:
+                       if (end_of_data())
+                               goto no_match;
+
+                       if (!match_token(cur, data[block_idx]))
+                               TOKEN_MISMATCH();
+                       break;
+
+               case TS_FSM_PERHAPS:
+                       if (end_of_data() ||
+                           !match_token(cur, data[block_idx]))
+                               continue;
+                       break;
+
+               case TS_FSM_MULTI:
+                       if (end_of_data())
+                               goto no_match;
+
+                       if (!match_token(cur, data[block_idx]))
+                               TOKEN_MISMATCH();
+
+                       block_idx++;
+                       /* fall through */
+
+               case TS_FSM_ANY:
+                       if (next == NULL)
+                               goto found_match;
+
+                       if (end_of_data())
+                               continue;
+
+                       while (!match_token(next, data[block_idx])) {
+                               if (!match_token(cur, data[block_idx]))
+                                       TOKEN_MISMATCH();
+                               block_idx++;
+                               if (end_of_data())
+                                       goto no_match;
+                       }
+                       continue;
+
+               /*
+                * Optimization: Prefer small local loop over jumping
+                * back and forth until garbage at head is munched.
+                */
+               case TS_FSM_HEAD_IGNORE:
+                       if (end_of_data())
+                               continue;
+
+                       while (!match_token(next, data[block_idx])) {
+                               /*
+                                * Special case, don't start over upon
+                                * a mismatch, give the user the
+                                * chance to specify the type of data
+                                * allowed to be ignored.
+                                */
+                               if (!match_token(cur, data[block_idx]))
+                                       goto no_match;
+
+                               block_idx++;
+                               if (end_of_data())
+                                       goto no_match;
+                       }
+
+                       match_start = consumed + block_idx;
+                       continue;
+               }
+
+               block_idx++;
+       }
+
+       if (end_of_data())
+               goto found_match;
+
+no_match:
+       return UINT_MAX;
+
+found_match:
+       state->offset = consumed + block_idx;
+       return match_start;
+}
+
+static struct ts_config *fsm_init(const void *pattern, unsigned int len,
+                                    int gfp_mask)
+{
+       int i, err = -EINVAL;
+       struct ts_config *conf;
+       struct ts_fsm *fsm;
+       struct ts_fsm_token *tokens = (struct ts_fsm_token *) pattern;
+       unsigned int ntokens = len / sizeof(*tokens);
+       size_t priv_size = sizeof(*fsm) + len;
+
+       if (len  % sizeof(struct ts_fsm_token) || ntokens < 1)
+               goto errout;
+
+       for (i = 0; i < ntokens; i++) {
+               struct ts_fsm_token *t = &tokens[i];
+
+               if (t->type > TS_FSM_TYPE_MAX || t->recur > TS_FSM_RECUR_MAX)
+                       goto errout;
+
+               if (t->recur == TS_FSM_HEAD_IGNORE &&
+                   (i != 0 || i == (ntokens - 1)))
+                       goto errout;
+       }
+
+       conf = alloc_ts_config(priv_size, gfp_mask);
+       if (IS_ERR(conf))
+               return conf;
+
+       fsm = ts_config_priv(conf);
+       fsm->ntokens = ntokens;
+       memcpy(fsm->tokens, pattern, len);
+
+       for (i = 0; i < fsm->ntokens; i++) {
+               struct ts_fsm_token *t = &fsm->tokens[i];
+               t->type = token_map[t->type];
+       }
+
+       return conf;
+
+errout:
+       return ERR_PTR(err);
+}
+
+static void *fsm_get_pattern(struct ts_config *conf)
+{
+       struct ts_fsm *fsm = ts_config_priv(conf);
+       return fsm->tokens;
+}
+
+static unsigned int fsm_get_pattern_len(struct ts_config *conf)
+{
+       struct ts_fsm *fsm = ts_config_priv(conf);
+       return fsm->ntokens * sizeof(struct ts_fsm_token);
+}
+
+static struct ts_ops fsm_ops = {
+       .name             = "fsm",
+       .find             = fsm_find,
+       .init             = fsm_init,
+       .get_pattern      = fsm_get_pattern,
+       .get_pattern_len  = fsm_get_pattern_len,
+       .owner            = THIS_MODULE,
+       .list             = LIST_HEAD_INIT(fsm_ops.list)
+};
+
+static int __init init_fsm(void)
+{
+       return textsearch_register(&fsm_ops);
+}
+
+static void __exit exit_fsm(void)
+{
+       textsearch_unregister(&fsm_ops);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(init_fsm);
+module_exit(exit_fsm);
diff --git a/lib/ts_kmp.c b/lib/ts_kmp.c
new file mode 100644 (file)
index 0000000..73266b9
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * lib/ts_kmp.c                Knuth-Morris-Pratt text search implementation
+ *
+ *             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.
+ *
+ * Authors:    Thomas Graf <tgraf@suug.ch>
+ *
+ * ==========================================================================
+ * 
+ *   Implements a linear-time string-matching algorithm due to Knuth,
+ *   Morris, and Pratt [1]. Their algorithm avoids the explicit
+ *   computation of the transition function DELTA altogether. Its
+ *   matching time is O(n), for n being length(text), using just an
+ *   auxiliary function PI[1..m], for m being length(pattern),
+ *   precomputed from the pattern in time O(m). The array PI allows
+ *   the transition function DELTA to be computed efficiently
+ *   "on the fly" as needed. Roughly speaking, for any state
+ *   "q" = 0,1,...,m and any character "a" in SIGMA, the value
+ *   PI["q"] contains the information that is independent of "a" and
+ *   is needed to compute DELTA("q", "a") [2]. Since the array PI
+ *   has only m entries, whereas DELTA has O(m|SIGMA|) entries, we
+ *   save a factor of |SIGMA| in the preprocessing time by computing
+ *   PI rather than DELTA.
+ *
+ *   [1] Cormen, Leiserson, Rivest, Stein
+ *       Introdcution to Algorithms, 2nd Edition, MIT Press
+ *   [2] See finite automation theory
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/textsearch.h>
+
+struct ts_kmp
+{
+       u8 *            pattern;
+       unsigned int    pattern_len;
+       unsigned int    prefix_tbl[0];
+};
+
+static unsigned int kmp_find(struct ts_config *conf, struct ts_state *state)
+{
+       struct ts_kmp *kmp = ts_config_priv(conf);
+       unsigned int i, q = 0, text_len, consumed = state->offset;
+       const u8 *text;
+
+       for (;;) {
+               text_len = conf->get_next_block(consumed, &text, conf, state);
+
+               if (unlikely(text_len == 0))
+                       break;
+
+               for (i = 0; i < text_len; i++) {
+                       while (q > 0 && kmp->pattern[q] != text[i])
+                               q = kmp->prefix_tbl[q - 1];
+                       if (kmp->pattern[q] == text[i])
+                               q++;
+                       if (unlikely(q == kmp->pattern_len)) {
+                               state->offset = consumed + i + 1;
+                               return state->offset - kmp->pattern_len;
+                       }
+               }
+
+               consumed += text_len;
+       }
+
+       return UINT_MAX;
+}
+
+static inline void compute_prefix_tbl(const u8 *pattern, unsigned int len,
+                                     unsigned int *prefix_tbl)
+{
+       unsigned int k, q;
+
+       for (k = 0, q = 1; q < len; q++) {
+               while (k > 0 && pattern[k] != pattern[q])
+                       k = prefix_tbl[k-1];
+               if (pattern[k] == pattern[q])
+                       k++;
+               prefix_tbl[q] = k;
+       }
+}
+
+static struct ts_config *kmp_init(const void *pattern, unsigned int len,
+                                 int gfp_mask)
+{
+       struct ts_config *conf;
+       struct ts_kmp *kmp;
+       unsigned int prefix_tbl_len = len * sizeof(unsigned int);
+       size_t priv_size = sizeof(*kmp) + len + prefix_tbl_len;
+
+       conf = alloc_ts_config(priv_size, gfp_mask);
+       if (IS_ERR(conf))
+               return conf;
+
+       kmp = ts_config_priv(conf);
+       kmp->pattern_len = len;
+       compute_prefix_tbl(pattern, len, kmp->prefix_tbl);
+       kmp->pattern = (u8 *) kmp->prefix_tbl + prefix_tbl_len;
+       memcpy(kmp->pattern, pattern, len);
+
+       return conf;
+}
+
+static void *kmp_get_pattern(struct ts_config *conf)
+{
+       struct ts_kmp *kmp = ts_config_priv(conf);
+       return kmp->pattern;
+}
+
+static unsigned int kmp_get_pattern_len(struct ts_config *conf)
+{
+       struct ts_kmp *kmp = ts_config_priv(conf);
+       return kmp->pattern_len;
+}
+
+static struct ts_ops kmp_ops = {
+       .name             = "kmp",
+       .find             = kmp_find,
+       .init             = kmp_init,
+       .get_pattern      = kmp_get_pattern,
+       .get_pattern_len  = kmp_get_pattern_len,
+       .owner            = THIS_MODULE,
+       .list             = LIST_HEAD_INIT(kmp_ops.list)
+};
+
+static int __init init_kmp(void)
+{
+       return textsearch_register(&kmp_ops);
+}
+
+static void __exit exit_kmp(void)
+{
+       textsearch_unregister(&kmp_ops);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(init_kmp);
+module_exit(exit_kmp);
index 8f70ffd763c82ecf872ca5482fee373d1313c67b..4cd69e3ce4214996108e251b3ac9c505625f3419 100644 (file)
@@ -19,3 +19,4 @@ obj-$(CONFIG_SPARSEMEM)       += sparse.o
 obj-$(CONFIG_SHMEM) += shmem.o
 obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
 
+obj-$(CONFIG_FS_XIP) += filemap_xip.o
index f82f7aebbee31be3b81469a40a070b95e5954f60..c1330cc197835ae66bffaa2baacc032ace0020b4 100644 (file)
@@ -33,6 +33,14 @@ EXPORT_SYMBOL(max_pfn);              /* This is exported so
                                 * dma_get_required_mask(), which uses
                                 * it, can be an inline function */
 
+#ifdef CONFIG_CRASH_DUMP
+/*
+ * If we have booted due to a crash, max_pfn will be a very low value. We need
+ * to know the amount of memory that the previous kernel used.
+ */
+unsigned long saved_max_pfn;
+#endif
+
 /* return the number of _pages_ that will be allocated for the boot bitmap */
 unsigned long __init bootmem_bootmap_pages (unsigned long pages)
 {
@@ -57,7 +65,7 @@ static unsigned long __init init_bootmem_core (pg_data_t *pgdat,
        pgdat->pgdat_next = pgdat_list;
        pgdat_list = pgdat;
 
-       mapsize = (mapsize + (sizeof(long) - 1UL)) & ~(sizeof(long) - 1UL);
+       mapsize = ALIGN(mapsize, sizeof(long));
        bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT);
        bdata->node_boot_start = (start << PAGE_SHIFT);
        bdata->node_low_pfn = end;
@@ -178,7 +186,7 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
        } else
                preferred = 0;
 
-       preferred = ((preferred + align - 1) & ~(align - 1)) >> PAGE_SHIFT;
+       preferred = ALIGN(preferred, align) >> PAGE_SHIFT;
        preferred += offset;
        areasize = (size+PAGE_SIZE-1)/PAGE_SIZE;
        incr = align >> PAGE_SHIFT ? : 1;
@@ -219,7 +227,7 @@ found:
         */
        if (align < PAGE_SIZE &&
            bdata->last_offset && bdata->last_pos+1 == start) {
-               offset = (bdata->last_offset+align-1) & ~(align-1);
+               offset = ALIGN(bdata->last_offset, align);
                BUG_ON(offset > PAGE_SIZE);
                remaining_size = PAGE_SIZE-offset;
                if (size < remaining_size) {
index 57264d74b8bff0528dd09456c4c81d6c6785363c..5f19e87bc5af1c86dd121d7e50dcd3e5cc1c7e94 100644 (file)
@@ -43,6 +43,10 @@ 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 */
+               goto out;
+
        /* Careful about overflows. Len == 0 means "as much as possible" */
        endbyte = offset + len;
        if (!len || endbyte < len)
index a3598b542a318609362248886027b5aabe48ba64..c11418dd94e810f4c8d9c4aa7ed2fae6d8aba290 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/blkdev.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
+#include "filemap.h"
 /*
  * FIXME: remove all knowledge of the buffer layer from the core VM
  */
@@ -1714,32 +1715,7 @@ int remove_suid(struct dentry *dentry)
 }
 EXPORT_SYMBOL(remove_suid);
 
-/*
- * Copy as much as we can into the page and return the number of bytes which
- * were sucessfully copied.  If a fault is encountered then clear the page
- * out to (offset+bytes) and return the number of bytes which were copied.
- */
-static inline size_t
-filemap_copy_from_user(struct page *page, unsigned long offset,
-                       const char __user *buf, unsigned bytes)
-{
-       char *kaddr;
-       int left;
-
-       kaddr = kmap_atomic(page, KM_USER0);
-       left = __copy_from_user_inatomic(kaddr + offset, buf, bytes);
-       kunmap_atomic(kaddr, KM_USER0);
-
-       if (left != 0) {
-               /* Do it the slow way */
-               kaddr = kmap(page);
-               left = __copy_from_user(kaddr + offset, buf, bytes);
-               kunmap(page);
-       }
-       return bytes - left;
-}
-
-static size_t
+size_t
 __filemap_copy_from_user_iovec(char *vaddr, 
                        const struct iovec *iov, size_t base, size_t bytes)
 {
@@ -1766,52 +1742,6 @@ __filemap_copy_from_user_iovec(char *vaddr,
        return copied - left;
 }
 
-/*
- * This has the same sideeffects and return value as filemap_copy_from_user().
- * The difference is that on a fault we need to memset the remainder of the
- * page (out to offset+bytes), to emulate filemap_copy_from_user()'s
- * single-segment behaviour.
- */
-static inline size_t
-filemap_copy_from_user_iovec(struct page *page, unsigned long offset,
-                       const struct iovec *iov, size_t base, size_t bytes)
-{
-       char *kaddr;
-       size_t copied;
-
-       kaddr = kmap_atomic(page, KM_USER0);
-       copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
-                                               base, bytes);
-       kunmap_atomic(kaddr, KM_USER0);
-       if (copied != bytes) {
-               kaddr = kmap(page);
-               copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
-                                                       base, bytes);
-               kunmap(page);
-       }
-       return copied;
-}
-
-static inline void
-filemap_set_next_iovec(const struct iovec **iovp, size_t *basep, size_t bytes)
-{
-       const struct iovec *iov = *iovp;
-       size_t base = *basep;
-
-       while (bytes) {
-               int copy = min(bytes, iov->iov_len - base);
-
-               bytes -= copy;
-               base += copy;
-               if (iov->iov_len == base) {
-                       iov++;
-                       base = 0;
-               }
-       }
-       *iovp = iov;
-       *basep = base;
-}
-
 /*
  * Performs necessary checks before doing a write
  *
@@ -1921,8 +1851,11 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
         * i_sem is held, which protects generic_osync_inode() from
         * livelocking.
         */
-       if (written >= 0 && file->f_flags & O_SYNC)
-               generic_osync_inode(inode, mapping, OSYNC_METADATA);
+       if (written >= 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
+               int err = generic_osync_inode(inode, mapping, OSYNC_METADATA);
+               if (err < 0)
+                       written = err;
+       }
        if (written == count && !is_sync_kiocb(iocb))
                written = -EIOCBQUEUED;
        return written;
@@ -2021,7 +1954,9 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
                                if (unlikely(nr_segs > 1)) {
                                        filemap_set_next_iovec(&cur_iov,
                                                        &iov_base, status);
-                                       buf = cur_iov->iov_base + iov_base;
+                                       if (count)
+                                               buf = cur_iov->iov_base +
+                                                       iov_base;
                                } else {
                                        iov_base += status;
                                }
diff --git a/mm/filemap.h b/mm/filemap.h
new file mode 100644 (file)
index 0000000..13793ba
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *     linux/mm/filemap.h
+ *
+ * Copyright (C) 1994-1999  Linus Torvalds
+ */
+
+#ifndef __FILEMAP_H
+#define __FILEMAP_H
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/uio.h>
+#include <linux/config.h>
+#include <asm/uaccess.h>
+
+size_t
+__filemap_copy_from_user_iovec(char *vaddr,
+                              const struct iovec *iov,
+                              size_t base,
+                              size_t bytes);
+
+/*
+ * Copy as much as we can into the page and return the number of bytes which
+ * were sucessfully copied.  If a fault is encountered then clear the page
+ * out to (offset+bytes) and return the number of bytes which were copied.
+ */
+static inline size_t
+filemap_copy_from_user(struct page *page, unsigned long offset,
+                       const char __user *buf, unsigned bytes)
+{
+       char *kaddr;
+       int left;
+
+       kaddr = kmap_atomic(page, KM_USER0);
+       left = __copy_from_user_inatomic(kaddr + offset, buf, bytes);
+       kunmap_atomic(kaddr, KM_USER0);
+
+       if (left != 0) {
+               /* Do it the slow way */
+               kaddr = kmap(page);
+               left = __copy_from_user(kaddr + offset, buf, bytes);
+               kunmap(page);
+       }
+       return bytes - left;
+}
+
+/*
+ * This has the same sideeffects and return value as filemap_copy_from_user().
+ * The difference is that on a fault we need to memset the remainder of the
+ * page (out to offset+bytes), to emulate filemap_copy_from_user()'s
+ * single-segment behaviour.
+ */
+static inline size_t
+filemap_copy_from_user_iovec(struct page *page, unsigned long offset,
+                       const struct iovec *iov, size_t base, size_t bytes)
+{
+       char *kaddr;
+       size_t copied;
+
+       kaddr = kmap_atomic(page, KM_USER0);
+       copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
+                                               base, bytes);
+       kunmap_atomic(kaddr, KM_USER0);
+       if (copied != bytes) {
+               kaddr = kmap(page);
+               copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
+                                                       base, bytes);
+               kunmap(page);
+       }
+       return copied;
+}
+
+static inline void
+filemap_set_next_iovec(const struct iovec **iovp, size_t *basep, size_t bytes)
+{
+       const struct iovec *iov = *iovp;
+       size_t base = *basep;
+
+       while (bytes) {
+               int copy = min(bytes, iov->iov_len - base);
+
+               bytes -= copy;
+               base += copy;
+               if (iov->iov_len == base) {
+                       iov++;
+                       base = 0;
+               }
+       }
+       *iovp = iov;
+       *basep = base;
+}
+#endif
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c
new file mode 100644 (file)
index 0000000..3b6e384
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ *     linux/mm/filemap_xip.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ * Author: Carsten Otte <cotte@de.ibm.com>
+ *
+ * derived from linux/mm/filemap.c - Copyright (C) Linus Torvalds
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/module.h>
+#include <linux/uio.h>
+#include <linux/rmap.h>
+#include <asm/tlbflush.h>
+#include "filemap.h"
+
+/*
+ * This is a file read routine for execute in place files, and uses
+ * the mapping->a_ops->get_xip_page() function for the actual low-level
+ * stuff.
+ *
+ * Note the struct file* is not used at all.  It may be NULL.
+ */
+static void
+do_xip_mapping_read(struct address_space *mapping,
+                   struct file_ra_state *_ra,
+                   struct file *filp,
+                   loff_t *ppos,
+                   read_descriptor_t *desc,
+                   read_actor_t actor)
+{
+       struct inode *inode = mapping->host;
+       unsigned long index, end_index, offset;
+       loff_t isize;
+
+       BUG_ON(!mapping->a_ops->get_xip_page);
+
+       index = *ppos >> PAGE_CACHE_SHIFT;
+       offset = *ppos & ~PAGE_CACHE_MASK;
+
+       isize = i_size_read(inode);
+       if (!isize)
+               goto out;
+
+       end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
+       for (;;) {
+               struct page *page;
+               unsigned long nr, ret;
+
+               /* nr is the maximum number of bytes to copy from this page */
+               nr = PAGE_CACHE_SIZE;
+               if (index >= end_index) {
+                       if (index > end_index)
+                               goto out;
+                       nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
+                       if (nr <= offset) {
+                               goto out;
+                       }
+               }
+               nr = nr - offset;
+
+               page = mapping->a_ops->get_xip_page(mapping,
+                       index*(PAGE_SIZE/512), 0);
+               if (!page)
+                       goto no_xip_page;
+               if (unlikely(IS_ERR(page))) {
+                       if (PTR_ERR(page) == -ENODATA) {
+                               /* sparse */
+                               page = virt_to_page(empty_zero_page);
+                       } else {
+                               desc->error = PTR_ERR(page);
+                               goto out;
+                       }
+               } else
+                       BUG_ON(!PageUptodate(page));
+
+               /* If users can be writing to this page using arbitrary
+                * virtual addresses, take care about potential aliasing
+                * before reading the page on the kernel side.
+                */
+               if (mapping_writably_mapped(mapping))
+                       flush_dcache_page(page);
+
+               /*
+                * Ok, we have the page, and it's up-to-date, so
+                * now we can copy it to user space...
+                *
+                * The actor routine returns how many bytes were actually used..
+                * NOTE! This may not be the same as how much of a user buffer
+                * we filled up (we may be padding etc), so we can only update
+                * "pos" here (the actor routine has to update the user buffer
+                * pointers and the remaining count).
+                */
+               ret = actor(desc, page, offset, nr);
+               offset += ret;
+               index += offset >> PAGE_CACHE_SHIFT;
+               offset &= ~PAGE_CACHE_MASK;
+
+               if (ret == nr && desc->count)
+                       continue;
+               goto out;
+
+no_xip_page:
+               /* Did not get the page. Report it */
+               desc->error = -EIO;
+               goto out;
+       }
+
+out:
+       *ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
+       if (filp)
+               file_accessed(filp);
+}
+
+ssize_t
+xip_file_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
+{
+       read_descriptor_t desc;
+
+       if (!access_ok(VERIFY_WRITE, buf, len))
+               return -EFAULT;
+
+       desc.written = 0;
+       desc.arg.buf = buf;
+       desc.count = len;
+       desc.error = 0;
+
+       do_xip_mapping_read(filp->f_mapping, &filp->f_ra, filp,
+                           ppos, &desc, file_read_actor);
+
+       if (desc.written)
+               return desc.written;
+       else
+               return desc.error;
+}
+EXPORT_SYMBOL_GPL(xip_file_read);
+
+ssize_t
+xip_file_sendfile(struct file *in_file, loff_t *ppos,
+            size_t count, read_actor_t actor, void *target)
+{
+       read_descriptor_t desc;
+
+       if (!count)
+               return 0;
+
+       desc.written = 0;
+       desc.count = count;
+       desc.arg.data = target;
+       desc.error = 0;
+
+       do_xip_mapping_read(in_file->f_mapping, &in_file->f_ra, in_file,
+                           ppos, &desc, actor);
+       if (desc.written)
+               return desc.written;
+       return desc.error;
+}
+EXPORT_SYMBOL_GPL(xip_file_sendfile);
+
+/*
+ * __xip_unmap is invoked from xip_unmap and
+ * xip_write
+ *
+ * This function walks all vmas of the address_space and unmaps the
+ * empty_zero_page when found at pgoff. Should it go in rmap.c?
+ */
+static void
+__xip_unmap (struct address_space * mapping,
+                    unsigned long pgoff)
+{
+       struct vm_area_struct *vma;
+       struct mm_struct *mm;
+       struct prio_tree_iter iter;
+       unsigned long address;
+       pte_t *pte;
+       pte_t pteval;
+
+       spin_lock(&mapping->i_mmap_lock);
+       vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
+               mm = vma->vm_mm;
+               address = vma->vm_start +
+                       ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
+               BUG_ON(address < vma->vm_start || address >= vma->vm_end);
+               /*
+                * We need the page_table_lock to protect us from page faults,
+                * munmap, fork, etc...
+                */
+               pte = page_check_address(virt_to_page(empty_zero_page), mm,
+                                        address);
+               if (!IS_ERR(pte)) {
+                       /* Nuke the page table entry. */
+                       flush_cache_page(vma, address, pte_pfn(pte));
+                       pteval = ptep_clear_flush(vma, address, pte);
+                       BUG_ON(pte_dirty(pteval));
+                       pte_unmap(pte);
+                       spin_unlock(&mm->page_table_lock);
+               }
+       }
+       spin_unlock(&mapping->i_mmap_lock);
+}
+
+/*
+ * xip_nopage() is invoked via the vma operations vector for a
+ * mapped memory region to read in file data during a page fault.
+ *
+ * This function is derived from filemap_nopage, but used for execute in place
+ */
+static struct page *
+xip_file_nopage(struct vm_area_struct * area,
+                  unsigned long address,
+                  int *type)
+{
+       struct file *file = area->vm_file;
+       struct address_space *mapping = file->f_mapping;
+       struct inode *inode = mapping->host;
+       struct page *page;
+       unsigned long size, pgoff, endoff;
+
+       pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT)
+               + area->vm_pgoff;
+       endoff = ((area->vm_end - area->vm_start) >> PAGE_CACHE_SHIFT)
+               + area->vm_pgoff;
+
+       size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       if (pgoff >= size) {
+               return NULL;
+       }
+
+       page = mapping->a_ops->get_xip_page(mapping, pgoff*(PAGE_SIZE/512), 0);
+       if (!IS_ERR(page)) {
+               BUG_ON(!PageUptodate(page));
+               return page;
+       }
+       if (PTR_ERR(page) != -ENODATA)
+               return NULL;
+
+       /* sparse block */
+       if ((area->vm_flags & (VM_WRITE | VM_MAYWRITE)) &&
+           (area->vm_flags & (VM_SHARED| VM_MAYSHARE)) &&
+           (!(mapping->host->i_sb->s_flags & MS_RDONLY))) {
+               /* maybe shared writable, allocate new block */
+               page = mapping->a_ops->get_xip_page (mapping,
+                       pgoff*(PAGE_SIZE/512), 1);
+               if (IS_ERR(page))
+                       return NULL;
+               BUG_ON(!PageUptodate(page));
+               /* unmap page at pgoff from all other vmas */
+               __xip_unmap(mapping, pgoff);
+       } else {
+               /* not shared and writable, use empty_zero_page */
+               page = virt_to_page(empty_zero_page);
+       }
+
+       return page;
+}
+
+static struct vm_operations_struct xip_file_vm_ops = {
+       .nopage         = xip_file_nopage,
+};
+
+int xip_file_mmap(struct file * file, struct vm_area_struct * vma)
+{
+       BUG_ON(!file->f_mapping->a_ops->get_xip_page);
+
+       file_accessed(file);
+       vma->vm_ops = &xip_file_vm_ops;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xip_file_mmap);
+
+static ssize_t
+__xip_file_write(struct file *filp, const char __user *buf,
+                 size_t count, loff_t pos, loff_t *ppos)
+{
+       struct address_space * mapping = filp->f_mapping;
+       struct address_space_operations *a_ops = mapping->a_ops;
+       struct inode    *inode = mapping->host;
+       long            status = 0;
+       struct page     *page;
+       size_t          bytes;
+       ssize_t         written = 0;
+
+       BUG_ON(!mapping->a_ops->get_xip_page);
+
+       do {
+               unsigned long index;
+               unsigned long offset;
+               size_t copied;
+
+               offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
+               index = pos >> PAGE_CACHE_SHIFT;
+               bytes = PAGE_CACHE_SIZE - offset;
+               if (bytes > count)
+                       bytes = count;
+
+               /*
+                * Bring in the user page that we will copy from _first_.
+                * Otherwise there's a nasty deadlock on copying from the
+                * same page as we're writing to, without it being marked
+                * up-to-date.
+                */
+               fault_in_pages_readable(buf, bytes);
+
+               page = a_ops->get_xip_page(mapping,
+                                          index*(PAGE_SIZE/512), 0);
+               if (IS_ERR(page) && (PTR_ERR(page) == -ENODATA)) {
+                       /* we allocate a new page unmap it */
+                       page = a_ops->get_xip_page(mapping,
+                                                  index*(PAGE_SIZE/512), 1);
+                       if (!IS_ERR(page))
+                               /* unmap page at pgoff from all other vmas */
+                               __xip_unmap(mapping, index);
+               }
+
+               if (IS_ERR(page)) {
+                       status = PTR_ERR(page);
+                       break;
+               }
+
+               BUG_ON(!PageUptodate(page));
+
+               copied = filemap_copy_from_user(page, offset, buf, bytes);
+               flush_dcache_page(page);
+               if (likely(copied > 0)) {
+                       status = copied;
+
+                       if (status >= 0) {
+                               written += status;
+                               count -= status;
+                               pos += status;
+                               buf += status;
+                       }
+               }
+               if (unlikely(copied != bytes))
+                       if (status >= 0)
+                               status = -EFAULT;
+               if (status < 0)
+                       break;
+       } while (count);
+       *ppos = pos;
+       /*
+        * No need to use i_size_read() here, the i_size
+        * cannot change under us because we hold i_sem.
+        */
+       if (pos > inode->i_size) {
+               i_size_write(inode, pos);
+               mark_inode_dirty(inode);
+       }
+
+       return written ? written : status;
+}
+
+ssize_t
+xip_file_write(struct file *filp, const char __user *buf, size_t len,
+              loff_t *ppos)
+{
+       struct address_space *mapping = filp->f_mapping;
+       struct inode *inode = mapping->host;
+       size_t count;
+       loff_t pos;
+       ssize_t ret;
+
+       down(&inode->i_sem);
+
+       if (!access_ok(VERIFY_READ, buf, len)) {
+               ret=-EFAULT;
+               goto out_up;
+       }
+
+       pos = *ppos;
+       count = len;
+
+       vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
+
+       /* We can write back this queue in page reclaim */
+       current->backing_dev_info = mapping->backing_dev_info;
+
+       ret = generic_write_checks(filp, &pos, &count, S_ISBLK(inode->i_mode));
+       if (ret)
+               goto out_backing;
+       if (count == 0)
+               goto out_backing;
+
+       ret = remove_suid(filp->f_dentry);
+       if (ret)
+               goto out_backing;
+
+       inode_update_time(inode, 1);
+
+       ret = __xip_file_write (filp, buf, count, pos, ppos);
+
+ out_backing:
+       current->backing_dev_info = NULL;
+ out_up:
+       up(&inode->i_sem);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xip_file_write);
+
+/*
+ * truncate a page used for execute in place
+ * functionality is analog to block_truncate_page but does use get_xip_page
+ * to get the page instead of page cache
+ */
+int
+xip_truncate_page(struct address_space *mapping, loff_t from)
+{
+       pgoff_t index = from >> PAGE_CACHE_SHIFT;
+       unsigned offset = from & (PAGE_CACHE_SIZE-1);
+       unsigned blocksize;
+       unsigned length;
+       struct page *page;
+       void *kaddr;
+
+       BUG_ON(!mapping->a_ops->get_xip_page);
+
+       blocksize = 1 << mapping->host->i_blkbits;
+       length = offset & (blocksize - 1);
+
+       /* Block boundary? Nothing to do */
+       if (!length)
+               return 0;
+
+       length = blocksize - length;
+
+       page = mapping->a_ops->get_xip_page(mapping,
+                                           index*(PAGE_SIZE/512), 0);
+       if (!page)
+               return -ENOMEM;
+       if (unlikely(IS_ERR(page))) {
+               if (PTR_ERR(page) == -ENODATA)
+                       /* Hole? No need to truncate */
+                       return 0;
+               else
+                       return PTR_ERR(page);
+       } else
+               BUG_ON(!PageUptodate(page));
+       kaddr = kmap_atomic(page, KM_USER0);
+       memset(kaddr + offset, 0, length);
+       kunmap_atomic(kaddr, KM_USER0);
+
+       flush_dcache_page(page);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xip_truncate_page);
index 54a5d3bc55d501caa3d2da3f3a9ef265ca584f2a..73180a22877ed24bcbd01fbca9a2be10c799df2f 100644 (file)
@@ -86,6 +86,11 @@ static long madvise_willneed(struct vm_area_struct * vma,
        if (!file)
                return -EBADF;
 
+       if (file->f_mapping->a_ops->get_xip_page) {
+               /* no bad return value, but ignore advice */
+               return 0;
+       }
+
        *prev = vma;
        start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
        if (end > vma->vm_end)
index 30975ef487222154ec9484972781e2874104abea..beabdefa6254a521da762d3a7c44274b29553edd 100644 (file)
@@ -1139,7 +1139,7 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
 {
        pgd_t *pgd;
        unsigned long next;
-       unsigned long end = addr + size;
+       unsigned long end = addr + PAGE_ALIGN(size);
        struct mm_struct *mm = vma->vm_mm;
        int err;
 
@@ -1458,7 +1458,7 @@ restart:
  * unmap_mapping_range - unmap the portion of all mmaps
  * in the specified address_space corresponding to the specified
  * page range in the underlying file.
- * @address_space: the address space containing mmaps to be unmapped.
+ * @mapping: the address space containing mmaps to be unmapped.
  * @holebegin: byte in first page to unmap, relative to the start of
  * the underlying file.  This will be rounded down to a PAGE_SIZE
  * boundary.  Note that this is different from vmtruncate(), which
index 613b99a55917577fd6eeb8f835fd2b67e72e5bbc..a6329fa8f862da5aea02238c687e93843ba2a80e 100644 (file)
@@ -354,7 +354,7 @@ static void background_writeout(unsigned long _min_pages)
  * the whole world.  Returns 0 if a pdflush thread was dispatched.  Returns
  * -1 if all pdflush threads were busy.
  */
-int wakeup_bdflush(long nr_pages)
+int wakeup_pdflush(long nr_pages)
 {
        if (nr_pages == 0) {
                struct writeback_state wbs;
index 7ee675ad101eb579375050fb8ff503f6fbc4cfd1..3c9f7f88112543d2e72021c576cc377a2244e295 100644 (file)
@@ -1667,9 +1667,8 @@ void __init memmap_init_zone(unsigned long size, int nid, unsigned long zone,
 #ifdef WANT_PAGE_VIRTUAL
                /* The shift won't overflow because ZONE_NORMAL is below 4G. */
                if (!is_highmem_idx(zone))
-                       set_page_address(page, __va(start_pfn << PAGE_SHIFT));
+                       set_page_address(page, __va(pfn << PAGE_SHIFT));
 #endif
-               start_pfn++;
        }
 }
 
index 667c76df1ec24a04ba73f165a51b8afc91d47b26..2e605a19ce57d0611c7a6619feeace3b03680bfb 100644 (file)
@@ -127,7 +127,7 @@ out:
        return ret;
 }
 
-#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_PM_DISK)
+#ifdef CONFIG_SOFTWARE_SUSPEND
 /*
  * A scruffy utility function to read or write an arbitrary swap page
  * and wait on the I/O.  The caller must have a ref on the page.
index 38ce279cc8cdf4fa3a83e29a8ffb509a0551c447..d6781951267eb654a522529658aaa06199d1772f 100644 (file)
@@ -105,7 +105,7 @@ static int __pdflush(struct pdflush_work *my_work)
                spin_unlock_irq(&pdflush_lock);
 
                schedule();
-               if (try_to_freeze(PF_FREEZE)) {
+               if (try_to_freeze()) {
                        spin_lock_irq(&pdflush_lock);
                        continue;
                }
index 89770bd25f31be71877813a292793fcc62e01116..08ac5c7fa91fa02b42c03515749fb43ff057554e 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -247,8 +247,8 @@ unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma)
  *
  * On success returns with mapped pte and locked mm->page_table_lock.
  */
-static pte_t *page_check_address(struct page *page, struct mm_struct *mm,
-                                       unsigned long address)
+pte_t *page_check_address(struct page *page, struct mm_struct *mm,
+                         unsigned long address)
 {
        pgd_t *pgd;
        pud_t *pud;
index 4b8e62a193708b7c12808cdb0eccfad61a38bce5..cfffe5098d538e6d54d1954c523d455924cbf7fc 100644 (file)
@@ -972,7 +972,7 @@ int try_to_free_pages(struct zone **zones, unsigned int gfp_mask)
                 * writeout.  So in laptop mode, write out the whole world.
                 */
                if (total_scanned > sc.swap_cluster_max + sc.swap_cluster_max/2) {
-                       wakeup_bdflush(laptop_mode ? 0 : total_scanned);
+                       wakeup_pdflush(laptop_mode ? 0 : total_scanned);
                        sc.may_writepage = 1;
                }
 
@@ -1216,8 +1216,8 @@ static int kswapd(void *p)
        order = 0;
        for ( ; ; ) {
                unsigned long new_order;
-               if (current->flags & PF_FREEZE)
-                       refrigerator(PF_FREEZE);
+
+               try_to_freeze();
 
                prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
                new_order = pgdat->kswapd_max_order;
index 03ae4edddac35bf6dbfa8773f9031279b9aa4dd1..2d52fee63a8cf1653e90281be1ca154c61f24d70 100644 (file)
@@ -844,7 +844,7 @@ static unsigned int ip_sabotage_out(unsigned int hook, struct sk_buff **pskb,
                 * doesn't use the bridge parent of the indev by using
                 * the BRNF_DONT_TAKE_PARENT mask. */
                if (hook == NF_IP_FORWARD && nf_bridge->physindev == NULL) {
-                       nf_bridge->mask &= BRNF_DONT_TAKE_PARENT;
+                       nf_bridge->mask |= BRNF_DONT_TAKE_PARENT;
                        nf_bridge->physindev = (struct net_device *)in;
                }
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
index e4ae34b889251890ee8a018c41e6a0299a085369..662975be3d1d1aaef6f20aecccbb9a01128cace1 100644 (file)
@@ -61,8 +61,6 @@ static void ebt_log(const struct sk_buff *skb, unsigned int hooknr,
 {
        struct ebt_log_info *info = (struct ebt_log_info *)data;
        char level_string[4] = "< >";
-       union {struct iphdr iph; struct tcpudphdr ports;
-              struct arphdr arph; struct arppayload arpp;} u;
 
        level_string[1] = '0' + info->loglevel;
        spin_lock_bh(&ebt_log_lock);
@@ -88,7 +86,7 @@ static void ebt_log(const struct sk_buff *skb, unsigned int hooknr,
                }
                printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,",
                   NIPQUAD(ih->saddr), NIPQUAD(ih->daddr));
-               printk(" IP tos=0x%02X, IP proto=%d", u.iph.tos,
+               printk(" IP tos=0x%02X, IP proto=%d", ih->tos,
                       ih->protocol);
                if (ih->protocol == IPPROTO_TCP ||
                    ih->protocol == IPPROTO_UDP) {
@@ -127,7 +125,7 @@ static void ebt_log(const struct sk_buff *skb, unsigned int hooknr,
                    ah->ar_pln == sizeof(uint32_t)) {
                        struct arppayload _arpp, *ap;
 
-                       ap = skb_header_pointer(skb, sizeof(u.arph),
+                       ap = skb_header_pointer(skb, sizeof(_arph),
                                                sizeof(_arpp), &_arpp);
                        if (ap == NULL) {
                                printk(" INCOMPLETE ARP payload");
index ab935778ce81009cadea261d289f7bd44e623850..7016e0c36b3d904abda32faa03d46c246e584915 100644 (file)
 #endif /* CONFIG_NET_RADIO */
 #include <asm/current.h>
 
-/* This define, if set, will randomly drop a packet when congestion
- * is more than moderate.  It helps fairness in the multi-interface
- * case when one of them is a hog, but it kills performance for the
- * single interface case so it is off now by default.
- */
-#undef RAND_LIE
-
-/* Setting this will sample the queue lengths and thus congestion
- * via a timer instead of as each packet is received.
- */
-#undef OFFLINE_SAMPLE
-
 /*
  *     The list of packet types we will receive (as opposed to discard)
  *     and the routines to invoke.
@@ -159,11 +147,6 @@ static DEFINE_SPINLOCK(ptype_lock);
 static struct list_head ptype_base[16];        /* 16 way hashed list */
 static struct list_head ptype_all;             /* Taps */
 
-#ifdef OFFLINE_SAMPLE
-static void sample_queue(unsigned long dummy);
-static struct timer_list samp_timer = TIMER_INITIALIZER(sample_queue, 0, 0);
-#endif
-
 /*
  * The @dev_base list is protected by @dev_base_lock and the rtln
  * semaphore.
@@ -215,7 +198,7 @@ static struct notifier_block *netdev_chain;
  *     Device drivers call our routines to queue packets here. We empty the
  *     queue in the local softnet handler.
  */
-DEFINE_PER_CPU(struct softnet_data, softnet_data) = { 0, };
+DEFINE_PER_CPU(struct softnet_data, softnet_data) = { NULL };
 
 #ifdef CONFIG_SYSFS
 extern int netdev_sysfs_init(void);
@@ -1363,71 +1346,13 @@ out:
                        Receiver routines
   =======================================================================*/
 
-int netdev_max_backlog = 300;
+int netdev_max_backlog = 1000;
+int netdev_budget = 300;
 int weight_p = 64;            /* old backlog weight */
-/* These numbers are selected based on intuition and some
- * experimentatiom, if you have more scientific way of doing this
- * please go ahead and fix things.
- */
-int no_cong_thresh = 10;
-int no_cong = 20;
-int lo_cong = 100;
-int mod_cong = 290;
 
 DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, };
 
 
-static void get_sample_stats(int cpu)
-{
-#ifdef RAND_LIE
-       unsigned long rd;
-       int rq;
-#endif
-       struct softnet_data *sd = &per_cpu(softnet_data, cpu);
-       int blog = sd->input_pkt_queue.qlen;
-       int avg_blog = sd->avg_blog;
-
-       avg_blog = (avg_blog >> 1) + (blog >> 1);
-
-       if (avg_blog > mod_cong) {
-               /* Above moderate congestion levels. */
-               sd->cng_level = NET_RX_CN_HIGH;
-#ifdef RAND_LIE
-               rd = net_random();
-               rq = rd % netdev_max_backlog;
-               if (rq < avg_blog) /* unlucky bastard */
-                       sd->cng_level = NET_RX_DROP;
-#endif
-       } else if (avg_blog > lo_cong) {
-               sd->cng_level = NET_RX_CN_MOD;
-#ifdef RAND_LIE
-               rd = net_random();
-               rq = rd % netdev_max_backlog;
-                       if (rq < avg_blog) /* unlucky bastard */
-                               sd->cng_level = NET_RX_CN_HIGH;
-#endif
-       } else if (avg_blog > no_cong)
-               sd->cng_level = NET_RX_CN_LOW;
-       else  /* no congestion */
-               sd->cng_level = NET_RX_SUCCESS;
-
-       sd->avg_blog = avg_blog;
-}
-
-#ifdef OFFLINE_SAMPLE
-static void sample_queue(unsigned long dummy)
-{
-/* 10 ms 0r 1ms -- i don't care -- JHS */
-       int next_tick = 1;
-       int cpu = smp_processor_id();
-
-       get_sample_stats(cpu);
-       next_tick += jiffies;
-       mod_timer(&samp_timer, next_tick);
-}
-#endif
-
-
 /**
  *     netif_rx        -       post buffer to the network code
  *     @skb: buffer to post
@@ -1448,7 +1373,6 @@ static void sample_queue(unsigned long dummy)
 
 int netif_rx(struct sk_buff *skb)
 {
-       int this_cpu;
        struct softnet_data *queue;
        unsigned long flags;
 
@@ -1464,38 +1388,22 @@ int netif_rx(struct sk_buff *skb)
         * short when CPU is congested, but is still operating.
         */
        local_irq_save(flags);
-       this_cpu = smp_processor_id();
        queue = &__get_cpu_var(softnet_data);
 
        __get_cpu_var(netdev_rx_stat).total++;
        if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {
                if (queue->input_pkt_queue.qlen) {
-                       if (queue->throttle)
-                               goto drop;
-
 enqueue:
                        dev_hold(skb->dev);
                        __skb_queue_tail(&queue->input_pkt_queue, skb);
-#ifndef OFFLINE_SAMPLE
-                       get_sample_stats(this_cpu);
-#endif
                        local_irq_restore(flags);
-                       return queue->cng_level;
+                       return NET_RX_SUCCESS;
                }
 
-               if (queue->throttle)
-                       queue->throttle = 0;
-
                netif_rx_schedule(&queue->backlog_dev);
                goto enqueue;
        }
 
-       if (!queue->throttle) {
-               queue->throttle = 1;
-               __get_cpu_var(netdev_rx_stat).throttled++;
-       }
-
-drop:
        __get_cpu_var(netdev_rx_stat).dropped++;
        local_irq_restore(flags);
 
@@ -1780,8 +1688,6 @@ job_done:
        smp_mb__before_clear_bit();
        netif_poll_enable(backlog_dev);
 
-       if (queue->throttle)
-               queue->throttle = 0;
        local_irq_enable();
        return 0;
 }
@@ -1790,8 +1696,7 @@ static void net_rx_action(struct softirq_action *h)
 {
        struct softnet_data *queue = &__get_cpu_var(softnet_data);
        unsigned long start_time = jiffies;
-       int budget = netdev_max_backlog;
-
+       int budget = netdev_budget;
        
        local_irq_disable();
 
@@ -2055,15 +1960,9 @@ static int softnet_seq_show(struct seq_file *seq, void *v)
        struct netif_rx_stats *s = v;
 
        seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
-                  s->total, s->dropped, s->time_squeeze, s->throttled,
-                  s->fastroute_hit, s->fastroute_success, s->fastroute_defer,
-                  s->fastroute_deferred_out,
-#if 0
-                  s->fastroute_latency_reduction
-#else
-                  s->cpu_collision
-#endif
-                 );
+                  s->total, s->dropped, s->time_squeeze, 0,
+                  0, 0, 0, 0, /* was fastroute */
+                  s->cpu_collision );
        return 0;
 }
 
@@ -3305,9 +3204,6 @@ static int __init net_dev_init(void)
 
                queue = &per_cpu(softnet_data, i);
                skb_queue_head_init(&queue->input_pkt_queue);
-               queue->throttle = 0;
-               queue->cng_level = 0;
-               queue->avg_blog = 10; /* arbitrary non-zero */
                queue->completion_queue = NULL;
                INIT_LIST_HEAD(&queue->poll_list);
                set_bit(__LINK_STATE_START, &queue->backlog_dev.state);
@@ -3316,11 +3212,6 @@ static int __init net_dev_init(void)
                atomic_set(&queue->backlog_dev.refcnt, 1);
        }
 
-#ifdef OFFLINE_SAMPLE
-       samp_timer.expires = jiffies + (10 * HZ);
-       add_timer(&samp_timer);
-#endif
-
        dev_boot_phase = 0;
 
        open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);
index 851eb927ed971da078035beca4caa77c1a406c78..1beb782ac41b6fe91eb91ddab02ef738ab7ee1d4 100644 (file)
@@ -1598,6 +1598,8 @@ static int neightbl_fill_info(struct neigh_table *tbl, struct sk_buff *skb,
 
        read_lock_bh(&tbl->lock);
        ndtmsg->ndtm_family = tbl->family;
+       ndtmsg->ndtm_pad1   = 0;
+       ndtmsg->ndtm_pad2   = 0;
 
        RTA_PUT_STRING(skb, NDTA_NAME, tbl->id);
        RTA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval);
@@ -1683,6 +1685,8 @@ static int neightbl_fill_param_info(struct neigh_table *tbl,
 
        read_lock_bh(&tbl->lock);
        ndtmsg->ndtm_family = tbl->family;
+       ndtmsg->ndtm_pad1   = 0;
+       ndtmsg->ndtm_pad2   = 0;
        RTA_PUT_STRING(skb, NDTA_NAME, tbl->id);
 
        if (neightbl_fill_parms(skb, parms) < 0)
@@ -1872,6 +1876,8 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n,
        struct ndmsg *ndm = NLMSG_DATA(nlh);
 
        ndm->ndm_family  = n->ops->family;
+       ndm->ndm_pad1    = 0;
+       ndm->ndm_pad2    = 0;
        ndm->ndm_flags   = n->flags;
        ndm->ndm_type    = n->type;
        ndm->ndm_ifindex = n->dev->ifindex;
index c57b06bc79f379cb63dbc00dcd9c0860a09a3800..975d651312dc36787edb05be5596471f1f8bbfee 100644 (file)
 #include <asm/timex.h>
 
 
-#define VERSION  "pktgen v2.61: Packet Generator for packet performance testing.\n"
+#define VERSION  "pktgen v2.62: Packet Generator for packet performance testing.\n"
 
 /* #define PG_DEBUG(a) a */
 #define PG_DEBUG(a) 
@@ -1921,6 +1921,11 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        struct iphdr *iph;
         struct pktgen_hdr *pgh = NULL;
         
+       /* Update any of the values, used when we're incrementing various
+        * fields.
+        */
+       mod_cur_headers(pkt_dev);
+
        skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16, GFP_ATOMIC);
        if (!skb) {
                sprintf(pkt_dev->result, "No memory");
@@ -1934,11 +1939,6 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
        udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
 
-        /* Update any of the values, used when we're incrementing various
-         * fields.
-         */
-        mod_cur_headers(pkt_dev);
-
        memcpy(eth, pkt_dev->hh, 12);
        *(u16*)&eth[12] = __constant_htons(ETH_P_IP);
 
@@ -2192,7 +2192,12 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        int datalen;
        struct ipv6hdr *iph;
         struct pktgen_hdr *pgh = NULL;
-        
+
+       /* Update any of the values, used when we're incrementing various
+        * fields.
+        */
+       mod_cur_headers(pkt_dev);
+
        skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16, GFP_ATOMIC);
        if (!skb) {
                sprintf(pkt_dev->result, "No memory");
@@ -2206,17 +2211,9 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr));
        udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
 
-
-        /* Update any of the values, used when we're incrementing various
-         * fields.
-         */
-       mod_cur_headers(pkt_dev);
-
-       
        memcpy(eth, pkt_dev->hh, 12);
        *(u16*)&eth[12] = __constant_htons(ETH_P_IPV6);
-       
-        
+
        datalen = pkt_dev->cur_pkt_size-14- 
                sizeof(struct ipv6hdr)-sizeof(struct udphdr); /* Eth + IPh + UDPh */
 
index e013d836a7abc3592d5fa5db0f24aca874095f52..4b1bb30e6381fb9abf82b596852ec89b3c36827c 100644 (file)
@@ -126,6 +126,7 @@ void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data
        rta->rta_type = attrtype;
        rta->rta_len = size;
        memcpy(RTA_DATA(rta), data, attrlen);
+       memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size);
 }
 
 size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size)
@@ -188,6 +189,7 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
        nlh = NLMSG_NEW(skb, pid, seq, type, sizeof(*r), flags);
        r = NLMSG_DATA(nlh);
        r->ifi_family = AF_UNSPEC;
+       r->__ifi_pad = 0;
        r->ifi_type = dev->type;
        r->ifi_index = dev->ifindex;
        r->ifi_flags = dev_get_flags(dev);
index 6d68c03bc0516291f71a3b98030d72ee8f71297f..bb73b2190ec75df9d106125f532681f22e68c58a 100644 (file)
@@ -1500,6 +1500,159 @@ void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len)
                skb_split_no_header(skb, skb1, len, pos);
 }
 
+/**
+ * skb_prepare_seq_read - Prepare a sequential read of skb data
+ * @skb: the buffer to read
+ * @from: lower offset of data to be read
+ * @to: upper offset of data to be read
+ * @st: state variable
+ *
+ * Initializes the specified state variable. Must be called before
+ * invoking skb_seq_read() for the first time.
+ */
+void skb_prepare_seq_read(struct sk_buff *skb, unsigned int from,
+                         unsigned int to, struct skb_seq_state *st)
+{
+       st->lower_offset = from;
+       st->upper_offset = to;
+       st->root_skb = st->cur_skb = skb;
+       st->frag_idx = st->stepped_offset = 0;
+       st->frag_data = NULL;
+}
+
+/**
+ * skb_seq_read - Sequentially read skb data
+ * @consumed: number of bytes consumed by the caller so far
+ * @data: destination pointer for data to be returned
+ * @st: state variable
+ *
+ * Reads a block of skb data at &consumed relative to the
+ * lower offset specified to skb_prepare_seq_read(). Assigns
+ * the head of the data block to &data and returns the length
+ * of the block or 0 if the end of the skb data or the upper
+ * offset has been reached.
+ *
+ * The caller is not required to consume all of the data
+ * returned, i.e. &consumed is typically set to the number
+ * of bytes already consumed and the next call to
+ * skb_seq_read() will return the remaining part of the block.
+ *
+ * Note: The size of each block of data returned can be arbitary,
+ *       this limitation is the cost for zerocopy seqeuental
+ *       reads of potentially non linear data.
+ *
+ * Note: Fragment lists within fragments are not implemented
+ *       at the moment, state->root_skb could be replaced with
+ *       a stack for this purpose.
+ */
+unsigned int skb_seq_read(unsigned int consumed, const u8 **data,
+                         struct skb_seq_state *st)
+{
+       unsigned int block_limit, abs_offset = consumed + st->lower_offset;
+       skb_frag_t *frag;
+
+       if (unlikely(abs_offset >= st->upper_offset))
+               return 0;
+
+next_skb:
+       block_limit = skb_headlen(st->cur_skb);
+
+       if (abs_offset < block_limit) {
+               *data = st->cur_skb->data + abs_offset;
+               return block_limit - abs_offset;
+       }
+
+       if (st->frag_idx == 0 && !st->frag_data)
+               st->stepped_offset += skb_headlen(st->cur_skb);
+
+       while (st->frag_idx < skb_shinfo(st->cur_skb)->nr_frags) {
+               frag = &skb_shinfo(st->cur_skb)->frags[st->frag_idx];
+               block_limit = frag->size + st->stepped_offset;
+
+               if (abs_offset < block_limit) {
+                       if (!st->frag_data)
+                               st->frag_data = kmap_skb_frag(frag);
+
+                       *data = (u8 *) st->frag_data + frag->page_offset +
+                               (abs_offset - st->stepped_offset);
+
+                       return block_limit - abs_offset;
+               }
+
+               if (st->frag_data) {
+                       kunmap_skb_frag(st->frag_data);
+                       st->frag_data = NULL;
+               }
+
+               st->frag_idx++;
+               st->stepped_offset += frag->size;
+       }
+
+       if (st->cur_skb->next) {
+               st->cur_skb = st->cur_skb->next;
+               st->frag_idx = 0;
+               goto next_skb;
+       } else if (st->root_skb == st->cur_skb &&
+                  skb_shinfo(st->root_skb)->frag_list) {
+               st->cur_skb = skb_shinfo(st->root_skb)->frag_list;
+               goto next_skb;
+       }
+
+       return 0;
+}
+
+/**
+ * skb_abort_seq_read - Abort a sequential read of skb data
+ * @st: state variable
+ *
+ * Must be called if skb_seq_read() was not called until it
+ * returned 0.
+ */
+void skb_abort_seq_read(struct skb_seq_state *st)
+{
+       if (st->frag_data)
+               kunmap_skb_frag(st->frag_data);
+}
+
+#define TS_SKB_CB(state)       ((struct skb_seq_state *) &((state)->cb))
+
+static unsigned int skb_ts_get_next_block(unsigned int offset, const u8 **text,
+                                         struct ts_config *conf,
+                                         struct ts_state *state)
+{
+       return skb_seq_read(offset, text, TS_SKB_CB(state));
+}
+
+static void skb_ts_finish(struct ts_config *conf, struct ts_state *state)
+{
+       skb_abort_seq_read(TS_SKB_CB(state));
+}
+
+/**
+ * skb_find_text - Find a text pattern in skb data
+ * @skb: the buffer to look in
+ * @from: search offset
+ * @to: search limit
+ * @config: textsearch configuration
+ * @state: uninitialized textsearch state variable
+ *
+ * Finds a pattern in the skb data according to the specified
+ * textsearch configuration. Use textsearch_next() to retrieve
+ * subsequent occurrences of the pattern. Returns the offset
+ * to the first occurrence or UINT_MAX if no match was found.
+ */
+unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
+                          unsigned int to, struct ts_config *config,
+                          struct ts_state *state)
+{
+       config->get_next_block = skb_ts_get_next_block;
+       config->finish = skb_ts_finish;
+
+       skb_prepare_seq_read(skb, from, to, TS_SKB_CB(state));
+
+       return textsearch_find(config, state);
+}
+
 void __init skb_init(void)
 {
        skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
@@ -1538,3 +1691,7 @@ EXPORT_SYMBOL(skb_queue_tail);
 EXPORT_SYMBOL(skb_unlink);
 EXPORT_SYMBOL(skb_append);
 EXPORT_SYMBOL(skb_split);
+EXPORT_SYMBOL(skb_prepare_seq_read);
+EXPORT_SYMBOL(skb_seq_read);
+EXPORT_SYMBOL(skb_abort_seq_read);
+EXPORT_SYMBOL(skb_find_text);
index 880a88815211e88f8310034879492d3beb16d0a4..8f817ad9f54629f61dcd5dc54115a04bf527d0f7 100644 (file)
 #ifdef CONFIG_SYSCTL
 
 extern int netdev_max_backlog;
+extern int netdev_budget;
 extern int weight_p;
-extern int no_cong_thresh;
-extern int no_cong;
-extern int lo_cong;
-extern int mod_cong;
-extern int netdev_fastroute;
 extern int net_msg_cost;
 extern int net_msg_burst;
 
@@ -85,38 +81,6 @@ ctl_table core_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec
        },
-       {
-               .ctl_name       = NET_CORE_NO_CONG_THRESH,
-               .procname       = "no_cong_thresh",
-               .data           = &no_cong_thresh,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = &proc_dointvec
-       },
-       {
-               .ctl_name       = NET_CORE_NO_CONG,
-               .procname       = "no_cong",
-               .data           = &no_cong,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = &proc_dointvec
-       },
-       {
-               .ctl_name       = NET_CORE_LO_CONG,
-               .procname       = "lo_cong",
-               .data           = &lo_cong,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = &proc_dointvec
-       },
-       {
-               .ctl_name       = NET_CORE_MOD_CONG,
-               .procname       = "mod_cong",
-               .data           = &mod_cong,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = &proc_dointvec
-       },
        {
                .ctl_name       = NET_CORE_MSG_COST,
                .procname       = "message_cost",
@@ -161,6 +125,14 @@ ctl_table core_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec
        },
+       {
+               .ctl_name       = NET_CORE_BUDGET,
+               .procname       = "netdev_budget",
+               .data           = &netdev_budget,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec
+       },
        { .ctl_name = 0 }
 };
 
index b2fe378dfbf8b941081addc3b89a6b4d475d8825..3ff5639c0b7886f77a92e42047733d6822db5e5c 100644 (file)
@@ -1102,6 +1102,7 @@ static inline int rtnetlink_fill_iwinfo(struct sk_buff *  skb,
        nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
        r = NLMSG_DATA(nlh);
        r->ifi_family = AF_UNSPEC;
+       r->__ifi_pad = 0;
        r->ifi_type = dev->type;
        r->ifi_index = dev->ifindex;
        r->ifi_flags = dev->flags;
index 6617ea47d3656a6b6c6cfa94e546c12dc9648f8e..ab60ea63688e757b99de1afcc2a60a174899774e 100644 (file)
@@ -92,10 +92,9 @@ int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
         *      Set the source hardware address. 
         */
         
-       if(saddr)
-               memcpy(eth->h_source,saddr,dev->addr_len);
-       else
-               memcpy(eth->h_source,dev->dev_addr,dev->addr_len);
+       if(!saddr)
+               saddr = dev->dev_addr;
+       memcpy(eth->h_source,saddr,dev->addr_len);
 
        /*
         *      Anyway, the loopback-device should never use this function... 
index 690e88ba24846296c8c957da52ca5966bf142584..3e63123f7bbd3b51428f62fa57d14b3bc0134e74 100644 (file)
@@ -1,32 +1,6 @@
 #
 # IP configuration
 #
-choice 
-       prompt "Choose IP: FIB lookup"
-       depends on INET
-       default IP_FIB_HASH
-
-config IP_FIB_HASH
-       bool "FIB_HASH"
-       ---help---
-       Current FIB is very proven and good enough for most users.
-
-config IP_FIB_TRIE
-       bool "FIB_TRIE"
-       ---help---
-       Use new experimental LC-trie as FIB lookup algoritm. 
-        This improves lookup performance
-       
-       LC-trie is described in:
-       
-       IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson
-       IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999
-       An experimental study of compression methods for dynamic tries
-       Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002.
-       http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/
-       
-endchoice
-
 config IP_MULTICAST
        bool "IP: multicasting"
        depends on INET
@@ -79,6 +53,44 @@ config IP_ADVANCED_ROUTER
 
          If unsure, say N here.
 
+choice 
+       prompt "Choose IP: FIB lookup algorithm (choose FIB_HASH if unsure)"
+       depends on IP_ADVANCED_ROUTER
+       default IP_FIB_HASH
+
+config IP_FIB_HASH
+       bool "FIB_HASH"
+       ---help---
+       Current FIB is very proven and good enough for most users.
+
+config IP_FIB_TRIE
+       bool "FIB_TRIE"
+       ---help---
+       Use new experimental LC-trie as FIB lookup algoritm. 
+        This improves lookup performance if you have a large
+       number of routes.
+
+       LC-trie is a longest matching prefix lookup algorithm which
+       performs better than FIB_HASH for large routing tables.
+       But, it consumes more memory and is more complex.
+       
+       LC-trie is described in:
+       
+       IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson
+       IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999
+       An experimental study of compression methods for dynamic tries
+       Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002.
+       http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/
+       
+endchoice
+
+# If the user does not enable advanced routing, he gets the safe
+# default of the fib-hash algorithm.
+config IP_FIB_HASH
+       bool
+       depends on !IP_ADVANCED_ROUTER
+       default y
+
 config IP_MULTIPLE_TABLES
        bool "IP: policy routing"
        depends on IP_ADVANCED_ROUTER
@@ -433,9 +445,21 @@ config IP_TCPDIAG
 config IP_TCPDIAG_IPV6
        def_bool (IP_TCPDIAG=y && IPV6=y) || (IP_TCPDIAG=m && IPV6)
 
+config TCP_CONG_ADVANCED
+       bool "TCP: advanced congestion control"
+       depends on INET
+       ---help---
+         Support for selection of various TCP congestion control
+         modules.
+
+         Nearly all users can safely say no here, and a safe default
+         selection will be made (BIC-TCP with new Reno as a fallback).
+
+         If unsure, say N.
+
 # TCP Reno is builtin (required as fallback)
 menu "TCP congestion control"
-       depends on INET
+       depends on TCP_CONG_ADVANCED
 
 config TCP_CONG_BIC
        tristate "Binary Increase Congestion (BIC) control"
@@ -523,5 +547,10 @@ config TCP_CONG_SCALABLE
 
 endmenu
 
+config TCP_CONG_BIC
+       tristate
+       depends on !TCP_CONG_ADVANCED
+       default y
+
 source "net/ipv4/ipvs/Kconfig"
 
index 0671569ee6f0e9ef1e824722930c47e22f64f4f1..b56e88edf1b351a10a8d83a0abf0a20f4c663e29 100644 (file)
@@ -43,7 +43,7 @@
  *             2 of the License, or (at your option) any later version.
  */
 
-#define VERSION "0.323"
+#define VERSION "0.324"
 
 #include <linux/config.h>
 #include <asm/uaccess.h>
@@ -341,8 +341,10 @@ static struct leaf *leaf_new(void)
 static struct leaf_info *leaf_info_new(int plen)
 {
        struct leaf_info *li = kmalloc(sizeof(struct leaf_info),  GFP_KERNEL);
-       li->plen = plen;
-       INIT_LIST_HEAD(&li->falh);
+       if(li) {
+               li->plen = plen;
+               INIT_LIST_HEAD(&li->falh);
+       }
        return li;
 }
 
@@ -879,8 +881,8 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
        return (struct node*) tn;
 }
 
-static struct list_head *
-fib_insert_node(struct trie *t, u32 key, int plen)
+static  struct list_head *
+fib_insert_node(struct trie *t, int *err, u32 key, int plen)
 {
        int pos, newpos;
        struct tnode *tp = NULL, *tn = NULL;
@@ -940,7 +942,6 @@ fib_insert_node(struct trie *t, u32 key, int plen)
        if(tp && IS_LEAF(tp))
                BUG();
 
-       t->revision++;
 
        /* Case 1: n is a leaf. Compare prefixes */
 
@@ -949,8 +950,10 @@ fib_insert_node(struct trie *t, u32 key, int plen)
                
                li = leaf_info_new(plen);
                
-               if(! li) 
-                       BUG();
+               if(! li) {
+                       *err = -ENOMEM;
+                       goto err;
+               }
 
                fa_head = &li->falh;
                insert_leaf_info(&l->list, li);
@@ -959,14 +962,19 @@ fib_insert_node(struct trie *t, u32 key, int plen)
        t->size++;
        l = leaf_new();
 
-       if(! l) 
-               BUG();
+       if(! l) {
+               *err = -ENOMEM;
+               goto err;
+       }
 
        l->key = key;
        li = leaf_info_new(plen);
 
-       if(! li) 
-               BUG();
+       if(! li) {
+               tnode_free((struct tnode *) l);
+               *err = -ENOMEM;
+               goto err;
+       }
 
        fa_head = &li->falh;
        insert_leaf_info(&l->list, li);
@@ -1003,9 +1011,14 @@ fib_insert_node(struct trie *t, u32 key, int plen)
                        newpos = 0;
                        tn = tnode_new(key, newpos, 1); /* First tnode */ 
                }
-               if(!tn) 
-                       trie_bug("tnode_pfx_new failed");
 
+               if(!tn) {
+                       free_leaf_info(li);
+                       tnode_free((struct tnode *) l);
+                       *err = -ENOMEM;
+                       goto err;
+               }                       
+                       
                NODE_SET_PARENT(tn, tp);
 
                missbit=tkey_extract_bits(key, newpos, 1);
@@ -1027,7 +1040,9 @@ fib_insert_node(struct trie *t, u32 key, int plen)
        }
        /* Rebalance the trie */
        t->trie = trie_rebalance(t, tp);
-done:;
+done:
+       t->revision++;
+err:;
        return fa_head;
 }
 
@@ -1156,8 +1171,12 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
         * Insert new entry to the list.
         */
 
-       if(!fa_head)
-               fa_head = fib_insert_node(t, key, plen);
+       if(!fa_head) {
+               fa_head = fib_insert_node(t, &err, key, plen);
+               err = 0;
+               if(err) 
+                       goto out_free_new_fa;
+       }
 
        write_lock_bh(&fib_lock);
 
@@ -1170,6 +1189,9 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
        rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, nlhdr, req);
 succeeded:
        return 0;
+
+out_free_new_fa:
+       kmem_cache_free(fn_alias_kmem, new_fa);
 out:
        fib_release_info(fi);
 err:;  
index af2ec88bbb2fc1ae4c841f7168780f95f2e2aedb..c703528e0bcd524751b8b4e43415e2b8e8ccadaf 100644 (file)
@@ -283,14 +283,18 @@ static inline int ip_rcv_finish(struct sk_buff *skb)
 {
        struct net_device *dev = skb->dev;
        struct iphdr *iph = skb->nh.iph;
+       int err;
 
        /*
         *      Initialise the virtual path cache for the packet. It describes
         *      how the packet travels inside Linux networking.
         */ 
        if (skb->dst == NULL) {
-               if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))
+               if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) {
+                       if (err == -EHOSTUNREACH)
+                               IP_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
                        goto drop; 
+               }
        }
 
 #ifdef CONFIG_NET_CLS_ROUTE
index ee07aec215a060fa3b980d0c88d8158a9638404b..6ce5c3292f9f74021c1fb3b8bce32dea75ade96f 100644 (file)
@@ -188,7 +188,13 @@ static inline int ip_finish_output2(struct sk_buff *skb)
                skb = skb2;
        }
 
-       nf_reset(skb);
+#ifdef CONFIG_BRIDGE_NETFILTER
+       /* bridge-netfilter defers calling some IP hooks to the bridge layer
+        * and still needs the conntrack reference.
+        */
+       if (skb->nf_bridge == NULL)
+#endif
+               nf_reset(skb);
 
        if (hh) {
                int hh_alen;
index f2509034ce72bce29573d886f59adda599e7be8e..d2bf8e1930a3709a41ce0154fabc50d0ff781b7d 100644 (file)
@@ -1149,8 +1149,10 @@ static int __init ic_dynamic(void)
                ic_rarp_cleanup();
 #endif
 
-       if (!ic_got_reply)
+       if (!ic_got_reply) {
+               ic_myaddr = INADDR_NONE;
                return -1;
+       }
 
        printk("IP-Config: Got %s answer from %u.%u.%u.%u, ",
                ((ic_got_reply & IC_RARP) ? "RARP" 
index e4f809a93f4701efbb3f68eec77e00593ad01f7c..7833d920bdba02fad46b1853374b11f01d3396b2 100644 (file)
@@ -297,6 +297,7 @@ static int vif_delete(int vifi)
 static void ipmr_destroy_unres(struct mfc_cache *c)
 {
        struct sk_buff *skb;
+       struct nlmsgerr *e;
 
        atomic_dec(&cache_resolve_queue_len);
 
@@ -306,7 +307,9 @@ static void ipmr_destroy_unres(struct mfc_cache *c)
                        nlh->nlmsg_type = NLMSG_ERROR;
                        nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
                        skb_trim(skb, nlh->nlmsg_len);
-                       ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -ETIMEDOUT;
+                       e = NLMSG_DATA(nlh);
+                       e->error = -ETIMEDOUT;
+                       memset(&e->msg, 0, sizeof(e->msg));
                        netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
                } else
                        kfree_skb(skb);
@@ -499,6 +502,7 @@ static struct mfc_cache *ipmr_cache_alloc_unres(void)
 static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c)
 {
        struct sk_buff *skb;
+       struct nlmsgerr *e;
 
        /*
         *      Play the pending entries through our router
@@ -515,7 +519,9 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c)
                                nlh->nlmsg_type = NLMSG_ERROR;
                                nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
                                skb_trim(skb, nlh->nlmsg_len);
-                               ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -EMSGSIZE;
+                               e = NLMSG_DATA(nlh);
+                               e->error = -EMSGSIZE;
+                               memset(&e->msg, 0, sizeof(e->msg));
                        }
                        err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
                } else
index fd6feb5499fe486ac32b61e61150b28529b60ae5..9f16ab309106790144d4e30bf44d38a437d1f6fc 100644 (file)
@@ -548,7 +548,6 @@ void ip_vs_conn_expire_now(struct ip_vs_conn *cp)
 {
        if (del_timer(&cp->timer))
                mod_timer(&cp->timer, jiffies);
-       __ip_vs_conn_put(cp);
 }
 
 
@@ -764,7 +763,6 @@ void ip_vs_random_dropentry(void)
 {
        int idx;
        struct ip_vs_conn *cp;
-       struct ip_vs_conn *ct;
 
        /*
         * Randomly scan 1/32 of the whole table every second
@@ -801,21 +799,12 @@ void ip_vs_random_dropentry(void)
                                        continue;
                        }
 
-                       /*
-                        * Drop the entry, and drop its ct if not referenced
-                        */
-                       atomic_inc(&cp->refcnt);
-                       ct_write_unlock(hash);
-
-                       if ((ct = cp->control))
-                               atomic_inc(&ct->refcnt);
                        IP_VS_DBG(4, "del connection\n");
                        ip_vs_conn_expire_now(cp);
-                       if (ct) {
+                       if (cp->control) {
                                IP_VS_DBG(4, "del conn template\n");
-                               ip_vs_conn_expire_now(ct);
+                               ip_vs_conn_expire_now(cp->control);
                        }
-                       ct_write_lock(hash);
                }
                ct_write_unlock(hash);
        }
@@ -829,7 +818,6 @@ static void ip_vs_conn_flush(void)
 {
        int idx;
        struct ip_vs_conn *cp;
-       struct ip_vs_conn *ct;
 
   flush_again:
        for (idx=0; idx<IP_VS_CONN_TAB_SIZE; idx++) {
@@ -839,18 +827,13 @@ static void ip_vs_conn_flush(void)
                ct_write_lock_bh(idx);
 
                list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
-                       atomic_inc(&cp->refcnt);
-                       ct_write_unlock(idx);
 
-                       if ((ct = cp->control))
-                               atomic_inc(&ct->refcnt);
                        IP_VS_DBG(4, "del connection\n");
                        ip_vs_conn_expire_now(cp);
-                       if (ct) {
+                       if (cp->control) {
                                IP_VS_DBG(4, "del conn template\n");
-                               ip_vs_conn_expire_now(ct);
+                               ip_vs_conn_expire_now(cp->control);
                        }
-                       ct_write_lock(idx);
                }
                ct_write_unlock_bh(idx);
        }
index 218d9701036e40edbaef431ef4690c01f5b18c2c..12a82e91d22ac4d31cfd62143d1b9aa7e1cdbab2 100644 (file)
@@ -2059,7 +2059,7 @@ ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
        dst->addr = src->addr;
        dst->port = src->port;
        dst->fwmark = src->fwmark;
-       strcpy(dst->sched_name, src->scheduler->name);
+       strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name));
        dst->flags = src->flags;
        dst->timeout = src->timeout / HZ;
        dst->netmask = src->netmask;
@@ -2080,6 +2080,7 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,
                list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
                        if (count >= get->num_services)
                                goto out;
+                       memset(&entry, 0, sizeof(entry));
                        ip_vs_copy_service(&entry, svc);
                        if (copy_to_user(&uptr->entrytable[count],
                                         &entry, sizeof(entry))) {
@@ -2094,6 +2095,7 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,
                list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
                        if (count >= get->num_services)
                                goto out;
+                       memset(&entry, 0, sizeof(entry));
                        ip_vs_copy_service(&entry, svc);
                        if (copy_to_user(&uptr->entrytable[count],
                                         &entry, sizeof(entry))) {
@@ -2304,12 +2306,12 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
                memset(&d, 0, sizeof(d));
                if (ip_vs_sync_state & IP_VS_STATE_MASTER) {
                        d[0].state = IP_VS_STATE_MASTER;
-                       strcpy(d[0].mcast_ifn, ip_vs_master_mcast_ifn);
+                       strlcpy(d[0].mcast_ifn, ip_vs_master_mcast_ifn, sizeof(d[0].mcast_ifn));
                        d[0].syncid = ip_vs_master_syncid;
                }
                if (ip_vs_sync_state & IP_VS_STATE_BACKUP) {
                        d[1].state = IP_VS_STATE_BACKUP;
-                       strcpy(d[1].mcast_ifn, ip_vs_backup_mcast_ifn);
+                       strlcpy(d[1].mcast_ifn, ip_vs_backup_mcast_ifn, sizeof(d[1].mcast_ifn));
                        d[1].syncid = ip_vs_backup_syncid;
                }
                if (copy_to_user(user, &d, sizeof(d)) != 0)
index 25c479550a32f32c64223fcd3fae8f827fc8f017..574d1f509b46cef77c10171c9ffe26d7bcd7cff2 100644 (file)
@@ -839,10 +839,10 @@ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
 
        ip_vs_sync_state |= state;
        if (state == IP_VS_STATE_MASTER) {
-               strcpy(ip_vs_master_mcast_ifn, mcast_ifn);
+               strlcpy(ip_vs_master_mcast_ifn, mcast_ifn, sizeof(ip_vs_master_mcast_ifn));
                ip_vs_master_syncid = syncid;
        } else {
-               strcpy(ip_vs_backup_mcast_ifn, mcast_ifn);
+               strlcpy(ip_vs_backup_mcast_ifn, mcast_ifn, sizeof(ip_vs_backup_mcast_ifn));
                ip_vs_backup_syncid = syncid;
        }
 
index 9cde8c61f525920aa36cdd422b93742f2574e02b..6706d3a1bc4fbe548746412597497ddccf895dc4 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 
-#define CLUSTERIP_VERSION "0.6"
+#define CLUSTERIP_VERSION "0.7"
 
 #define DEBUG_CLUSTERIP
 
@@ -524,8 +524,9 @@ arp_mangle(unsigned int hook,
            || arp->ar_pln != 4 || arp->ar_hln != ETH_ALEN)
                return NF_ACCEPT;
 
-       /* we only want to mangle arp replies */
-       if (arp->ar_op != htons(ARPOP_REPLY))
+       /* we only want to mangle arp requests and replies */
+       if (arp->ar_op != htons(ARPOP_REPLY)
+           && arp->ar_op != htons(ARPOP_REQUEST))
                return NF_ACCEPT;
 
        payload = (void *)(arp+1);
index 80cf633d9f4af5935547a29067e454b6822aa41b..12a1cf306f67468fc532677c647e9db9c6abd786 100644 (file)
@@ -1909,7 +1909,7 @@ static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
         */
        if ((err = fib_lookup(&fl, &res)) != 0) {
                if (!IN_DEV_FORWARD(in_dev))
-                       goto e_inval;
+                       goto e_hostunreach;
                goto no_route;
        }
        free_res = 1;
@@ -1933,7 +1933,7 @@ static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
        }
 
        if (!IN_DEV_FORWARD(in_dev))
-               goto e_inval;
+               goto e_hostunreach;
        if (res.type != RTN_UNICAST)
                goto martian_destination;
 
@@ -2025,6 +2025,11 @@ martian_destination:
                        "%u.%u.%u.%u, dev %s\n",
                        NIPQUAD(daddr), NIPQUAD(saddr), dev->name);
 #endif
+
+e_hostunreach:
+        err = -EHOSTUNREACH;
+        goto done;
+
 e_inval:
        err = -EINVAL;
        goto done;
index f3dbc8dc126346822b4a1e1f4116b5caf51c1013..882436da9a3a74da59e22def22723fb208928a6b 100644 (file)
@@ -1927,6 +1927,25 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
                return tp->af_specific->setsockopt(sk, level, optname,
                                                   optval, optlen);
 
+       /* This is a string value all the others are int's */
+       if (optname == TCP_CONGESTION) {
+               char name[TCP_CA_NAME_MAX];
+
+               if (optlen < 1)
+                       return -EINVAL;
+
+               val = strncpy_from_user(name, optval,
+                                       min(TCP_CA_NAME_MAX-1, optlen));
+               if (val < 0)
+                       return -EFAULT;
+               name[val] = 0;
+
+               lock_sock(sk);
+               err = tcp_set_congestion_control(tp, name);
+               release_sock(sk);
+               return err;
+       }
+
        if (optlen < sizeof(int))
                return -EINVAL;
 
@@ -2211,6 +2230,16 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
        case TCP_QUICKACK:
                val = !tp->ack.pingpong;
                break;
+
+       case TCP_CONGESTION:
+               if (get_user(len, optlen))
+                       return -EFAULT;
+               len = min_t(unsigned int, len, TCP_CA_NAME_MAX);
+               if (put_user(len, optlen))
+                       return -EFAULT;
+               if (copy_to_user(optval, tp->ca_ops->name, len))
+                       return -EFAULT;
+               return 0;
        default:
                return -ENOPROTOOPT;
        };
@@ -2224,7 +2253,7 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
 
 
 extern void __skb_cb_too_small_for_tcp(int, int);
-extern void tcpdiag_init(void);
+extern struct tcp_congestion_ops tcp_reno;
 
 static __initdata unsigned long thash_entries;
 static int __init set_thash_entries(char *str)
index 665394a63ae4912cfe088e079923342914050758..4970d10a7785af03276c22a29f03e8f7c90c14e9 100644 (file)
@@ -21,7 +21,7 @@ static struct tcp_congestion_ops *tcp_ca_find(const char *name)
 {
        struct tcp_congestion_ops *e;
 
-       list_for_each_entry(e, &tcp_cong_list, list) {
+       list_for_each_entry_rcu(e, &tcp_cong_list, list) {
                if (strcmp(e->name, name) == 0)
                        return e;
        }
@@ -77,6 +77,9 @@ void tcp_init_congestion_control(struct tcp_sock *tp)
 {
        struct tcp_congestion_ops *ca;
 
+       if (tp->ca_ops != &tcp_init_congestion_ops)
+               return;
+
        rcu_read_lock();
        list_for_each_entry_rcu(ca, &tcp_cong_list, list) {
                if (try_module_get(ca->owner)) {
@@ -139,6 +142,34 @@ void tcp_get_default_congestion_control(char *name)
        rcu_read_unlock();
 }
 
+/* Change congestion control for socket */
+int tcp_set_congestion_control(struct tcp_sock *tp, const char *name)
+{
+       struct tcp_congestion_ops *ca;
+       int err = 0;
+
+       rcu_read_lock();
+       ca = tcp_ca_find(name);
+       if (ca == tp->ca_ops)
+               goto out;
+
+       if (!ca)
+               err = -ENOENT;
+
+       else if (!try_module_get(ca->owner))
+               err = -EBUSY;
+
+       else {
+               tcp_cleanup_congestion_control(tp);
+               tp->ca_ops = ca;
+               if (tp->ca_ops->init)
+                       tp->ca_ops->init(tp);
+       }
+ out:
+       rcu_read_unlock();
+       return err;
+}
+
 /*
  * TCP Reno congestion control
  * This is special case used for fallback as well.
@@ -192,4 +223,15 @@ struct tcp_congestion_ops tcp_reno = {
        .min_cwnd       = tcp_reno_min_cwnd,
 };
 
-EXPORT_SYMBOL_GPL(tcp_reno);
+/* Initial congestion control used (until SYN)
+ * really reno under another name so we can tell difference
+ * during tcp_set_default_congestion_control
+ */
+struct tcp_congestion_ops tcp_init_congestion_ops  = {
+       .name           = "",
+       .owner          = THIS_MODULE,
+       .ssthresh       = tcp_reno_ssthresh,
+       .cong_avoid     = tcp_reno_cong_avoid,
+       .min_cwnd       = tcp_reno_min_cwnd,
+};
+EXPORT_SYMBOL_GPL(tcp_init_congestion_ops);
index 9122814c13ad711c5cb1f87a58c8cc18e767213d..ebf112347a97d499b29fcb4f74ad3a87d6bab26e 100644 (file)
@@ -2048,7 +2048,7 @@ static int tcp_v4_init_sock(struct sock *sk)
        tp->mss_cache_std = tp->mss_cache = 536;
 
        tp->reordering = sysctl_tcp_reordering;
-       tp->ca_ops = &tcp_reno;
+       tp->ca_ops = &tcp_init_congestion_ops;
 
        sk->sk_state = TCP_CLOSE;
 
index a54d4ef3fd35f2c7400762aa4dd87abd2f221e31..77004b9456c049f05cadbc52de47a4880c62fdd7 100644 (file)
@@ -2777,7 +2777,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
                read_lock_bh(&idev->lock);
                switch (type) {
                case UNICAST_ADDR:
-                       /* unicast address */
+                       /* unicast address incl. temp addr */
                        for (ifa = idev->addr_list; ifa;
                             ifa = ifa->if_next, ip_idx++) {
                                if (ip_idx < s_ip_idx)
@@ -2788,19 +2788,6 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
                                    NLM_F_MULTI)) <= 0)
                                        goto done;
                        }
-                       /* temp addr */
-#ifdef CONFIG_IPV6_PRIVACY
-                       for (ifa = idev->tempaddr_list; ifa; 
-                            ifa = ifa->tmp_next, ip_idx++) {
-                               if (ip_idx < s_ip_idx)
-                                       continue;
-                               if ((err = inet6_fill_ifaddr(skb, ifa, 
-                                   NETLINK_CB(cb->skb).pid, 
-                                   cb->nlh->nlmsg_seq, RTM_NEWADDR,
-                                   NLM_F_MULTI)) <= 0) 
-                                       goto done;
-                       }
-#endif
                        break;
                case MULTICAST_ADDR:
                        /* multicast address */
@@ -2923,6 +2910,7 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
        nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags);
        r = NLMSG_DATA(nlh);
        r->ifi_family = AF_INET6;
+       r->__ifi_pad = 0;
        r->ifi_type = dev->type;
        r->ifi_index = dev->ifindex;
        r->ifi_flags = dev_get_flags(dev);
@@ -3030,9 +3018,12 @@ static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev,
        nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*pmsg), flags);
        pmsg = NLMSG_DATA(nlh);
        pmsg->prefix_family = AF_INET6;
+       pmsg->prefix_pad1 = 0;
+       pmsg->prefix_pad2 = 0;
        pmsg->prefix_ifindex = idev->dev->ifindex;
        pmsg->prefix_len = pinfo->prefix_len;
        pmsg->prefix_type = pinfo->type;
+       pmsg->prefix_pad3 = 0;
        
        pmsg->prefix_flags = 0;
        if (pinfo->onlink)
index 0e5f7499debb81ce758d4e788d2182d07c5d2b53..b6c73da5ff358b5c8b803ce489e46b28a0bd5611 100644 (file)
@@ -244,7 +244,6 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space,
                opt_space->opt_nflen = 0;
        }
        opt_space->dst1opt = fopt->dst1opt;
-       opt_space->auth = fopt->auth;
        opt_space->opt_flen = fopt->opt_flen;
        return opt_space;
 }
index fce56039b0e97906c446438d2777cd1cccf86b16..9dac7fdf4726aa894157adea8f66520df2012ad3 100644 (file)
@@ -2025,7 +2025,7 @@ static int tcp_v6_init_sock(struct sock *sk)
        sk->sk_state = TCP_CLOSE;
 
        tp->af_specific = &ipv6_specific;
-       tp->ca_ops = &tcp_reno;
+       tp->ca_ops = &tcp_init_congestion_ops;
        sk->sk_write_space = sk_stream_write_space;
        sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
 
index 70bcd4744d9370e44f0389f28754df5aaaa3bee6..fc456a7aaec39bad1c147a8eff9a9d01e48b722c 100644 (file)
@@ -315,8 +315,8 @@ err:
 static void netlink_remove(struct sock *sk)
 {
        netlink_table_grab();
-       nl_table[sk->sk_protocol].hash.entries--;
-       sk_del_node_init(sk);
+       if (sk_del_node_init(sk))
+               nl_table[sk->sk_protocol].hash.entries--;
        if (nlk_sk(sk)->groups)
                __sk_del_bind_node(sk);
        netlink_table_ungrab();
@@ -429,7 +429,12 @@ retry:
        err = netlink_insert(sk, pid);
        if (err == -EADDRINUSE)
                goto retry;
-       return 0;
+
+       /* If 2 threads race to autobind, that is fine.  */
+       if (err == -EBUSY)
+               err = 0;
+
+       return err;
 }
 
 static inline int netlink_capable(struct socket *sock, unsigned int flag) 
index 2b537f425a17d6bd7d9485299cc72bc96bed2998..dada34a77b2194ab9750d2cdc518032f0fa413df 100644 (file)
@@ -138,7 +138,7 @@ static int rxrpc_krxiod(void *arg)
 
                _debug("### End Work");
 
-               try_to_freeze(PF_FREEZE);
+               try_to_freeze();
 
                 /* discard pending signals */
                rxrpc_discard_my_signals();
index 6020c89d9228846b6478e03dacd7860e7beb01ce..1aadd026d3542151e0eeb8b6c99f35a24c6779e0 100644 (file)
@@ -107,7 +107,7 @@ static int rxrpc_krxsecd(void *arg)
 
                _debug("### End Inbound Calls");
 
-               try_to_freeze(PF_FREEZE);
+               try_to_freeze();
 
                 /* discard pending signals */
                rxrpc_discard_my_signals();
index 249c2b0290bbfeae3bedccecf82af87301769b7f..3ac81cdd1211ce2c58fa4729b65fabe464097294 100644 (file)
@@ -90,7 +90,7 @@ static int krxtimod(void *arg)
                        complete_and_exit(&krxtimod_dead, 0);
                }
 
-               try_to_freeze(PF_FREEZE);
+               try_to_freeze();
 
                /* discard pending signals */
                rxrpc_discard_my_signals();
index b22c9beb604d78eb3dbf32809112802cb0b597ee..7bac249258e3a32bc91e658deaf1e335077a2b81 100644 (file)
@@ -449,6 +449,19 @@ config NET_EMATCH_META
          To compile this code as a module, choose M here: the
          module will be called em_meta.
 
+config NET_EMATCH_TEXT
+       tristate "Textsearch"
+       depends on NET_EMATCH
+       select TEXTSEARCH
+       select TEXTSEARCH_KMP
+       select TEXTSEARCH_FSM
+       ---help---
+         Say Y here if you want to be ablt to classify packets based on
+         textsearch comparisons.
+
+         To compile this code as a module, choose M here: the
+         module will be called em_text.
+
 config NET_CLS_ACT
        bool "Packet ACTION"
        depends on EXPERIMENTAL && NET_CLS && NET_QOS
index eb3fe583eba8d85aab104c9acd588d10ccab4591..8f58cecd6266eedae186f08f6eb86c31bfc7a391 100644 (file)
@@ -40,3 +40,4 @@ obj-$(CONFIG_NET_EMATCH_CMP)  += em_cmp.o
 obj-$(CONFIG_NET_EMATCH_NBYTE) += em_nbyte.o
 obj-$(CONFIG_NET_EMATCH_U32)   += em_u32.o
 obj-$(CONFIG_NET_EMATCH_META)  += em_meta.o
+obj-$(CONFIG_NET_EMATCH_TEXT)  += em_text.o
index 9594206e6035fc412fb88a8dcfa1d8f88f28ec47..249c61936ea0391f30bddb767117d928ff958625 100644 (file)
@@ -439,6 +439,8 @@ tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 pid, u32 seq,
 
        t = NLMSG_DATA(nlh);
        t->tca_family = AF_UNSPEC;
+       t->tca__pad1 = 0;
+       t->tca__pad2 = 0;
        
        x = (struct rtattr*) skb->tail;
        RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);
@@ -580,6 +582,8 @@ static int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid)
        nlh = NLMSG_PUT(skb, pid, n->nlmsg_seq, RTM_DELACTION, sizeof(*t));
        t = NLMSG_DATA(nlh);
        t->tca_family = AF_UNSPEC;
+       t->tca__pad1 = 0;
+       t->tca__pad2 = 0;
 
        x = (struct rtattr *) skb->tail;
        RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);
@@ -687,7 +691,9 @@ static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event,
        nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*t), flags);
        t = NLMSG_DATA(nlh);
        t->tca_family = AF_UNSPEC;
-       
+       t->tca__pad1 = 0;
+       t->tca__pad2 = 0;
+
        x = (struct rtattr*) skb->tail;
        RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);
 
@@ -842,6 +848,8 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
                        cb->nlh->nlmsg_type, sizeof(*t));
        t = NLMSG_DATA(nlh);
        t->tca_family = AF_UNSPEC;
+       t->tca__pad1 = 0;
+       t->tca__pad2 = 0;
 
        x = (struct rtattr *) skb->tail;
        RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);
index 1616bf5c96272774a655d1440daffd48b8a928fb..3b5714ef4d1af2463d127589d7aa8af91c166384 100644 (file)
@@ -331,6 +331,8 @@ tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp, unsigned long fh,
        nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
        tcm = NLMSG_DATA(nlh);
        tcm->tcm_family = AF_UNSPEC;
+       tcm->tcm__pad1 = 0;
+       tcm->tcm__pad1 = 0;
        tcm->tcm_ifindex = tp->q->dev->ifindex;
        tcm->tcm_parent = tp->classid;
        tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol);
index 232fb919681076f0f5c6321aad6c2fc6a747ced2..006168d6937654d7ece5493fad1b96cad9e0806b 100644 (file)
@@ -618,6 +618,7 @@ static int rsvp_dump(struct tcf_proto *tp, unsigned long fh,
        pinfo.protocol = s->protocol;
        pinfo.tunnelid = s->tunnelid;
        pinfo.tunnelhdr = f->tunnelhdr;
+       pinfo.pad = 0;
        RTA_PUT(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo);
        if (f->res.classid)
                RTA_PUT(skb, TCA_RSVP_CLASSID, 4, &f->res.classid);
diff --git a/net/sched/em_text.c b/net/sched/em_text.c
new file mode 100644 (file)
index 0000000..873840d
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * net/sched/em_text.c Textsearch ematch
+ *
+ *             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.
+ *
+ * Authors:    Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/textsearch.h>
+#include <linux/tc_ematch/tc_em_text.h>
+#include <net/pkt_cls.h>
+
+struct text_match
+{
+       u16                     from_offset;
+       u16                     to_offset;
+       u8                      from_layer;
+       u8                      to_layer;
+       struct ts_config        *config;
+};
+
+#define EM_TEXT_PRIV(m) ((struct text_match *) (m)->data)
+
+static int em_text_match(struct sk_buff *skb, struct tcf_ematch *m,
+                        struct tcf_pkt_info *info)
+{
+       struct text_match *tm = EM_TEXT_PRIV(m);
+       int from, to;
+       struct ts_state state;
+
+       from = tcf_get_base_ptr(skb, tm->from_layer) - skb->data;
+       from += tm->from_offset;
+
+       to = tcf_get_base_ptr(skb, tm->to_layer) - skb->data;
+       to += tm->to_offset;
+
+       return skb_find_text(skb, from, to, tm->config, &state) != UINT_MAX;
+}
+
+static int em_text_change(struct tcf_proto *tp, void *data, int len,
+                         struct tcf_ematch *m)
+{
+       struct text_match *tm;
+       struct tcf_em_text *conf = data;
+       struct ts_config *ts_conf;
+       int flags = 0;
+
+       printk("Configuring text: %s from %d:%d to %d:%d len %d\n", conf->algo, conf->from_offset,
+           conf->from_layer, conf->to_offset, conf->to_layer, conf->pattern_len);
+
+       if (len < sizeof(*conf) || len < (sizeof(*conf) + conf->pattern_len))
+               return -EINVAL;
+
+       if (conf->from_layer > conf->to_layer)
+               return -EINVAL;
+
+       if (conf->from_layer == conf->to_layer &&
+           conf->from_offset > conf->to_offset)
+               return -EINVAL;
+
+retry:
+       ts_conf = textsearch_prepare(conf->algo, (u8 *) conf + sizeof(*conf),
+                                    conf->pattern_len, GFP_KERNEL, flags);
+
+       if (flags & TS_AUTOLOAD)
+               rtnl_lock();
+
+       if (IS_ERR(ts_conf)) {
+               if (PTR_ERR(ts_conf) == -ENOENT && !(flags & TS_AUTOLOAD)) {
+                       rtnl_unlock();
+                       flags |= TS_AUTOLOAD;
+                       goto retry;
+               } else
+                       return PTR_ERR(ts_conf);
+       } else if (flags & TS_AUTOLOAD) {
+               textsearch_destroy(ts_conf);
+               return -EAGAIN;
+       }
+
+       tm = kmalloc(sizeof(*tm), GFP_KERNEL);
+       if (tm == NULL) {
+               textsearch_destroy(ts_conf);
+               return -ENOBUFS;
+       }
+
+       tm->from_offset = conf->from_offset;
+       tm->to_offset   = conf->to_offset;
+       tm->from_layer  = conf->from_layer;
+       tm->to_layer    = conf->to_layer;
+       tm->config      = ts_conf;
+
+       m->datalen = sizeof(*tm);
+       m->data = (unsigned long) tm;
+
+       return 0;
+}
+
+static void em_text_destroy(struct tcf_proto *tp, struct tcf_ematch *m)
+{
+       textsearch_destroy(EM_TEXT_PRIV(m)->config);
+}
+
+static int em_text_dump(struct sk_buff *skb, struct tcf_ematch *m)
+{
+       struct text_match *tm = EM_TEXT_PRIV(m);
+       struct tcf_em_text conf;
+
+       strncpy(conf.algo, tm->config->ops->name, sizeof(conf.algo) - 1);
+       conf.from_offset = tm->from_offset;
+       conf.to_offset = tm->to_offset;
+       conf.from_layer = tm->from_layer;
+       conf.to_layer = tm->to_layer;
+       conf.pattern_len = textsearch_get_pattern_len(tm->config);
+       conf.pad = 0;
+
+       RTA_PUT_NOHDR(skb, sizeof(conf), &conf);
+       RTA_APPEND(skb, conf.pattern_len, textsearch_get_pattern(tm->config));
+       return 0;
+
+rtattr_failure:
+       return -1;
+}              
+
+static struct tcf_ematch_ops em_text_ops = {
+       .kind     = TCF_EM_TEXT,
+       .change   = em_text_change,
+       .match    = em_text_match,
+       .destroy  = em_text_destroy,
+       .dump     = em_text_dump,
+       .owner    = THIS_MODULE,
+       .link     = LIST_HEAD_INIT(em_text_ops.link)
+};
+
+static int __init init_em_text(void)
+{
+       return tcf_em_register(&em_text_ops);
+}
+
+static void __exit exit_em_text(void) 
+{
+       tcf_em_unregister(&em_text_ops);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(init_em_text);
+module_exit(exit_em_text);
index 97c1c75d5c787f0b6a8d9416965e329662e7f52f..05e6e0a799da994f74681d71203c2c7fcf51f817 100644 (file)
@@ -770,6 +770,8 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
        nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
        tcm = NLMSG_DATA(nlh);
        tcm->tcm_family = AF_UNSPEC;
+       tcm->tcm__pad1 = 0;
+       tcm->tcm__pad2 = 0;
        tcm->tcm_ifindex = q->dev->ifindex;
        tcm->tcm_parent = clid;
        tcm->tcm_handle = q->handle;
index d43e3b8cbf6af27a25ab7b9d2aee82a32f8010eb..09453f997d8c3a0081e10d37066953060feafc94 100644 (file)
@@ -1528,6 +1528,7 @@ static __inline__ int cbq_dump_ovl(struct sk_buff *skb, struct cbq_class *cl)
 
        opt.strategy = cl->ovl_strategy;
        opt.priority2 = cl->priority2+1;
+       opt.pad = 0;
        opt.penalty = (cl->penalty*1000)/HZ;
        RTA_PUT(skb, TCA_CBQ_OVL_STRATEGY, sizeof(opt), &opt);
        return skb->len;
@@ -1563,6 +1564,8 @@ static __inline__ int cbq_dump_police(struct sk_buff *skb, struct cbq_class *cl)
 
        if (cl->police) {
                opt.police = cl->police;
+               opt.__res1 = 0;
+               opt.__res2 = 0;
                RTA_PUT(skb, TCA_CBQ_POLICE, sizeof(opt), &opt);
        }
        return skb->len;
index 2ec0320fac3b5634bbd62e6f8905d179314431ce..c44bf4165c6e6214d8e4a4c6b3192d2638fa95ff 100644 (file)
@@ -102,9 +102,9 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
        /* Set up the base timeout information.  */
        ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0;
        ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] =
-               SCTP_DEFAULT_TIMEOUT_T1_COOKIE;
+               msecs_to_jiffies(sp->rtoinfo.srto_initial);
        ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] =
-               SCTP_DEFAULT_TIMEOUT_T1_INIT;
+               msecs_to_jiffies(sp->rtoinfo.srto_initial);
        ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] =
                msecs_to_jiffies(sp->rtoinfo.srto_initial);
        ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0;
@@ -117,12 +117,9 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
         ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]
                = 5 * msecs_to_jiffies(sp->rtoinfo.srto_max);
 
-       ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] =
-               SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
-       ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
-               SCTP_DEFAULT_TIMEOUT_SACK;
-       ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
-               sp->autoclose * HZ;
+       ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0;
+       ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] = sctp_sack_timeout;
+       ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ;
 
        /* Use SCTP specific send buffer space queues.  */
        ep->sndbuf_policy = sctp_sndbuf_policy;
index 5135e1a25d25c1413984520c7204f6df3d7d2df4..e7f37faba7c0f8be68b432d885d1bf513d525e61 100644 (file)
@@ -1050,7 +1050,10 @@ SCTP_STATIC __init int sctp_init(void)
        sctp_sndbuf_policy              = 0;
 
        /* HB.interval              - 30 seconds */
-       sctp_hb_interval                = 30 * HZ;
+       sctp_hb_interval                = SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
+
+       /* delayed SACK timeout */
+       sctp_sack_timeout               = SCTP_DEFAULT_TIMEOUT_SACK;
 
        /* Implementation specific variables. */
 
index 058189684c7ce0dbf0cc489c1566fcd1fabf5e28..86073df418f5f00e4bf84d44b169ad5b01fe7715 100644 (file)
@@ -92,6 +92,17 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
                                             sctp_cmd_seq_t *commands);
 static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk);
 
+static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
+                                          __u16 error,
+                                          const struct sctp_association *asoc,
+                                          struct sctp_transport *transport);
+
+static sctp_disposition_t sctp_sf_violation_chunklen(
+                                    const struct sctp_endpoint *ep,
+                                    const struct sctp_association *asoc,
+                                    const sctp_subtype_t type,
+                                    void *arg,
+                                    sctp_cmd_seq_t *commands);
 
 /* Small helper function that checks if the chunk length
  * is of the appropriate length.  The 'required_length' argument
@@ -2328,7 +2339,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
  *
  * This is common code called by several sctp_sf_*_abort() functions above.
  */
-sctp_disposition_t  sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
+static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
                                           __u16 error,
                                           const struct sctp_association *asoc,
                                           struct sctp_transport *transport)
@@ -3687,7 +3698,8 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
  *
  * Generate an  ABORT chunk and terminate the association.
  */
-sctp_disposition_t sctp_sf_violation_chunklen(const struct sctp_endpoint *ep,
+static sctp_disposition_t sctp_sf_violation_chunklen(
+                                    const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
                                     void *arg,
index 7fc31849312ba85976eb1024161d057b02c672a2..dc4893474f186e68b93225cdba82ba71000f9831 100644 (file)
@@ -47,6 +47,8 @@
 static ctl_handler sctp_sysctl_jiffies_ms;
 static long rto_timer_min = 1;
 static long rto_timer_max = 86400000; /* One day */
+static long sack_timer_min = 1;
+static long sack_timer_max = 500;
 
 static ctl_table sctp_table[] = {
        {
@@ -187,6 +189,17 @@ static ctl_table sctp_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec
        },
+       {
+               .ctl_name       = NET_SCTP_SACK_TIMEOUT,
+               .procname       = "sack_timeout",
+               .data           = &sctp_sack_timeout,
+               .maxlen         = sizeof(long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_ms_jiffies_minmax,
+               .strategy       = &sctp_sysctl_jiffies_ms,
+               .extra1         = &sack_timer_min,
+               .extra2         = &sack_timer_max,
+       },
        { .ctl_name = 0 }
 };
 
index 0ec0fde6e6c596d19727fa831dd61991fa4c7a47..a63b691796074bbaa52ac24f216f75a5e46c93fa 100644 (file)
@@ -103,7 +103,6 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
 
        /* Set up the heartbeat timer. */
        init_timer(&peer->hb_timer);
-       peer->hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
        peer->hb_timer.function = sctp_generate_heartbeat_event;
        peer->hb_timer.data = (unsigned long)peer;
 
index 32e8acbc60feae1c2cc509c2ba009c2b09e9de4f..62a0734952766b56ae48e1053dce92f91ecf278c 100644 (file)
@@ -41,6 +41,7 @@ EXPORT_SYMBOL(rpc_release_task);
 
 /* RPC client functions */
 EXPORT_SYMBOL(rpc_create_client);
+EXPORT_SYMBOL(rpc_new_client);
 EXPORT_SYMBOL(rpc_clone_client);
 EXPORT_SYMBOL(rpc_bind_new_program);
 EXPORT_SYMBOL(rpc_destroy_client);
index 05907035bc96105d67fe124eef6793647b696d43..56db8f13e6cb40c4cf9ecb765923993564c16c7e 100644 (file)
@@ -1185,8 +1185,8 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
        arg->page_len = (pages-2)*PAGE_SIZE;
        arg->len = (pages-1)*PAGE_SIZE;
        arg->tail[0].iov_len = 0;
-       
-       try_to_freeze(PF_FREEZE);
+
+       try_to_freeze();
        if (signalled())
                return -EINTR;
 
@@ -1227,7 +1227,7 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
 
                schedule_timeout(timeout);
 
-               try_to_freeze(PF_FREEZE);
+               try_to_freeze();
 
                spin_lock_bh(&serv->sv_lock);
                remove_wait_queue(&rqstp->rq_wait, &wait);
index eca92405948fbfd69222f5494c40801efe99a78b..269f217918a3c736087a4577aa5389ed38c5410b 100644 (file)
@@ -970,7 +970,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc)
                goto out;
        }
 
-       dprintk("RPC:      XID %08x read %u bytes\n",
+       dprintk("RPC:      XID %08x read %Zd bytes\n",
                        ntohl(xprt->tcp_xid), r);
        dprintk("RPC:      xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n",
                        xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen);
@@ -1006,7 +1006,7 @@ tcp_read_discard(struct rpc_xprt *xprt, skb_reader_t *desc)
        desc->count -= len;
        desc->offset += len;
        xprt->tcp_offset += len;
-       dprintk("RPC:      discarded %u bytes\n", len);
+       dprintk("RPC:      discarded %Zu bytes\n", len);
        tcp_check_recm(xprt);
 }
 
index 8ca7ecdb68fbb662fbe1f470410e25ddb520980a..cb02baa63256ba691501ac65ddea70cadb1112c4 100644 (file)
@@ -52,7 +52,7 @@ FILEONLY *internalfunctions;
 FILEONLY *externalfunctions;
 FILEONLY *symbolsonly;
 
-typedef void FILELINE(char * file, signed char * line);
+typedef void FILELINE(char * file, char * line);
 FILELINE * singlefunctions;
 FILELINE * entity_system;
 
@@ -148,9 +148,9 @@ struct symfile * filename_exist(char * filename)
  * Files are separated by tabs.
  */
 void adddep(char * file)                  { printf("\t%s", file); }
-void adddep2(char * file, signed char * line)     { line = line; adddep(file); }
+void adddep2(char * file, char * line)     { line = line; adddep(file); }
 void noaction(char * line)                { line = line; }
-void noaction2(char * file, signed char * line)   { file = file; line = line; }
+void noaction2(char * file, char * line)   { file = file; line = line; }
 
 /* Echo the line without further action */
 void printline(char * line)               { printf("%s", line); }
@@ -179,8 +179,8 @@ void find_export_symbols(char * filename)
                        perror(real_filename);
                }
                while(fgets(line, MAXLINESZ, fp)) {
-                       signed char *p;
-                       signed char *e;
+                       char *p;
+                       char *e;
                        if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != 0) ||
                             ((p = strstr(line, "EXPORT_SYMBOL")) != 0)) {
                                /* Skip EXPORT_SYMBOL{_GPL} */
@@ -253,7 +253,7 @@ void extfunc(char * filename) { docfunctions(filename, FUNCTION);   }
  * Call kernel-doc with the following parameters:
  * kernel-doc -docbook -function function1 [-function function2]
  */
-void singfunc(char * filename, signed char * line)
+void singfunc(char * filename, char * line)
 {
        char *vec[200]; /* Enough for specific functions */
         int i, idx = 0;
@@ -290,7 +290,7 @@ void singfunc(char * filename, signed char * line)
 void parse_file(FILE *infile)
 {
        char line[MAXLINESZ];
-       signed char * s;
+       char * s;
        while(fgets(line, MAXLINESZ, infile)) {
                if (line[0] == '!') {
                        s = line + 2;
index 7f42c5d8a5a2f70bde413c21241fee3a1376d08e..0b61bea869f7580d0d5af1d5c56345be61a8597c 100644 (file)
@@ -212,23 +212,23 @@ void use_config(char *m, int slen)
                if (*p == '_')
                        *p = '/';
                else
-                       *p = tolower((unsigned char)*p);
+                       *p = tolower((int)*p);
        }
        printf("    $(wildcard include/config/%s.h) \\\n", s);
 }
 
-void parse_config_file(signed char *map, size_t len)
+void parse_config_file(char *map, size_t len)
 {
        int *end = (int *) (map + len);
        /* start at +1, so that p can never be < map */
        int *m   = (int *) map + 1;
-       signed char *p, *q;
+       char *p, *q;
 
        for (; m < end; m++) {
-               if (*m == INT_CONF) { p = (signed char *) m  ; goto conf; }
-               if (*m == INT_ONFI) { p = (signed char *) m-1; goto conf; }
-               if (*m == INT_NFIG) { p = (signed char *) m-2; goto conf; }
-               if (*m == INT_FIG_) { p = (signed char *) m-3; goto conf; }
+               if (*m == INT_CONF) { p = (char *) m  ; goto conf; }
+               if (*m == INT_ONFI) { p = (char *) m-1; goto conf; }
+               if (*m == INT_NFIG) { p = (char *) m-2; goto conf; }
+               if (*m == INT_FIG_) { p = (char *) m-3; goto conf; }
                continue;
        conf:
                if (p > map + len - 7)
@@ -291,9 +291,9 @@ void do_config_file(char *filename)
 
 void parse_dep_file(void *map, size_t len)
 {
-       signed char *m = map;
-       signed char *end = m + len;
-       signed char *p;
+       char *m = map;
+       char *end = m + len;
+       char *p;
        char s[PATH_MAX];
 
        p = strchr(m, ':');
index 60fc4d8ebaa9caba1f32fc8d221d8fcce14000db..459c45276cb1a4288f77f18fe327ae0c6bd312fb 100644 (file)
@@ -104,7 +104,7 @@ int main(int argc, const char * argv [])
     /* Read config lines. */
     while (fgets(line, buffer_size, fp_config))
     {
-       const signed char * str_config;
+       const char * str_config;
        int is_same;
        int itarget;
 
index 70e7264c69420427097ca27788efd31053ad632d..bc20cab9d0d6b184d9c3479d3b20584ac386b4d5 100644 (file)
@@ -31,14 +31,14 @@ char *defconfig_file;
 static int indent = 1;
 static int valid_stdin = 1;
 static int conf_cnt;
-static signed char line[128];
+static char line[128];
 static struct menu *rootEntry;
 
 static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
 
-static void strip(signed char *str)
+static void strip(char *str)
 {
-       signed char *p = str;
+       char *p = str;
        int l;
 
        while ((isspace(*p)))
index 2755c459d780b48e1c067be5d81a14528c2e3b90..02f670cc6bb9350f6db1ea2ecd14513565ca3746 100644 (file)
@@ -27,10 +27,10 @@ const char *conf_confnames[] = {
        NULL,
 };
 
-static char *conf_expand_value(const signed char *in)
+static char *conf_expand_value(const char *in)
 {
        struct symbol *sym;
-       const signed char *src;
+       const char *src;
        static char res_value[SYMBOL_MAXLENGTH];
        char *dst, name[SYMBOL_MAXLENGTH];
 
index e5db10ca956420f8a3ba8159597f3c537ef963f5..457bec29511dfb60d47428d9a18029353aef92e1 100644 (file)
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <termios.h>
 #include <unistd.h>
+#include <locale.h>
 
 #define LKC_DIRECT_LINK
 #include "lkc.h"
@@ -254,8 +255,8 @@ search_help[] = N_(
        "          USB$ => find all CONFIG_ symbols ending with USB\n"
        "\n");
 
-static signed char buf[4096], *bufptr = buf;
-static signed char input_buf[4096];
+static char buf[4096], *bufptr = buf;
+static char input_buf[4096];
 static char filename[PATH_MAX+1] = ".config";
 static char *args[1024], **argptr = args;
 static int indent;
index 32197efe67edbbd2e9619aca101c60370d4e14fd..908bff6d1eefda049420abac6f8857660f88b3e9 100644 (file)
@@ -287,6 +287,42 @@ static int do_pnp_card_entry(const char *filename,
        return 1;
 }
 
+/* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */
+static int do_pcmcia_entry(const char *filename,
+                          struct pcmcia_device_id *id, char *alias)
+{
+       unsigned int i;
+
+       id->manf_id = TO_NATIVE(id->manf_id);
+       id->card_id = TO_NATIVE(id->card_id);
+       id->func_id = TO_NATIVE(id->func_id);
+       id->function = TO_NATIVE(id->function);
+       id->device_no = TO_NATIVE(id->device_no);
+       for (i=0; i<4; i++) {
+               id->prod_id_hash[i] = TO_NATIVE(id->prod_id_hash[i]);
+       }
+
+       strcpy(alias, "pcmcia:");
+       ADD(alias, "m", id->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID,
+          id->manf_id);
+       ADD(alias, "c", id->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID,
+          id->card_id);
+       ADD(alias, "f", id->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID,
+          id->func_id);
+       ADD(alias, "fn", id->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION,
+          id->function);
+       ADD(alias, "pfn", id->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO,
+          id->device_no);
+       ADD(alias, "pa", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, id->prod_id_hash[0]);
+       ADD(alias, "pb", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, id->prod_id_hash[1]);
+       ADD(alias, "pc", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, id->prod_id_hash[2]);
+       ADD(alias, "pd", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, id->prod_id_hash[3]);
+
+       return 1;
+}
+
+
+
 /* Ignore any prefix, eg. v850 prepends _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -362,6 +398,9 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
        else if (sym_is(symname, "__mod_pnp_card_device_table"))
                do_table(symval, sym->st_size, sizeof(struct pnp_card_device_id),
                         do_pnp_card_entry, mod);
+       else if (sym_is(symname, "__mod_pcmcia_device_table"))
+               do_table(symval, sym->st_size, sizeof(struct pcmcia_device_id),
+                        do_pcmcia_entry, mod);
 }
 
 /* Now add out buffered information to the generated C source */
index ddb495d65062e819c20af5c5bfd51c86c4eda2ab..c392d750b20883129420c227e32cd350ae330b11 100644 (file)
@@ -7,8 +7,9 @@ obj-y := \
        keyring.o \
        keyctl.o \
        process_keys.o \
-       user_defined.o \
-       request_key.o
+       request_key.o \
+       request_key_auth.o \
+       user_defined.o
 
 obj-$(CONFIG_KEYS_COMPAT) += compat.o
 obj-$(CONFIG_PROC_FS) += proc.o
index aff8b22dcb5c7c9dcfbc412a95bb2c0be3e8092e..3303673c636ef3b735ae48fdf2992d0abe24c11a 100644 (file)
@@ -1,6 +1,6 @@
 /* compat.c: 32-bit compatibility syscall for 64-bit systems
  *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -24,7 +24,7 @@
  * - if you can, you should call sys_keyctl directly
  */
 asmlinkage long compat_sys_keyctl(u32 option,
-                             u32 arg2, u32 arg3, u32 arg4, u32 arg5)
+                                 u32 arg2, u32 arg3, u32 arg4, u32 arg5)
 {
        switch (option) {
        case KEYCTL_GET_KEYRING_ID:
@@ -71,6 +71,9 @@ asmlinkage long compat_sys_keyctl(u32 option,
        case KEYCTL_NEGATE:
                return keyctl_negate_key(arg2, arg3, arg4);
 
+       case KEYCTL_SET_REQKEY_KEYRING:
+               return keyctl_set_reqkey_keyring(arg2);
+
        default:
                return -EOPNOTSUPP;
        }
index 67b2b93a7489a8dfcaf5ebaab0b8d864a19170fd..46c8602661c999de31787f8eadd662759418a2e2 100644 (file)
@@ -1,6 +1,6 @@
 /* internal.h: authentication token and access key management internal defs
  *
- * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
 #include <linux/key.h>
 #include <linux/key-ui.h>
 
+#if 0
+#define kenter(FMT, a...)      printk("==> %s("FMT")\n",__FUNCTION__ , ## a)
+#define kleave(FMT, a...)      printk("<== %s()"FMT"\n",__FUNCTION__ , ## a)
+#define kdebug(FMT, a...)      printk(FMT"\n" , ## a)
+#else
+#define kenter(FMT, a...)      do {} while(0)
+#define kleave(FMT, a...)      do {} while(0)
+#define kdebug(FMT, a...)      do {} while(0)
+#endif
+
 extern struct key_type key_type_dead;
 extern struct key_type key_type_user;
 
@@ -66,20 +76,46 @@ extern struct key *__keyring_search_one(struct key *keyring,
                                        const char *description,
                                        key_perm_t perm);
 
+extern struct key *keyring_search_instkey(struct key *keyring,
+                                         key_serial_t target_id);
+
 typedef int (*key_match_func_t)(const struct key *, const void *);
 
 extern struct key *keyring_search_aux(struct key *keyring,
+                                     struct task_struct *tsk,
                                      struct key_type *type,
                                      const void *description,
                                      key_match_func_t match);
 
-extern struct key *search_process_keyrings_aux(struct key_type *type,
-                                              const void *description,
-                                              key_match_func_t match);
+extern struct key *search_process_keyrings(struct key_type *type,
+                                          const void *description,
+                                          key_match_func_t match,
+                                          struct task_struct *tsk);
 
 extern struct key *find_keyring_by_name(const char *name, key_serial_t bound);
 
 extern int install_thread_keyring(struct task_struct *tsk);
+extern int install_process_keyring(struct task_struct *tsk);
+
+extern struct key *request_key_and_link(struct key_type *type,
+                                       const char *description,
+                                       const char *callout_info,
+                                       struct key *dest_keyring);
+
+/*
+ * request_key authorisation
+ */
+struct request_key_auth {
+       struct key              *target_key;
+       struct task_struct      *context;
+       pid_t                   pid;
+};
+
+extern struct key_type key_type_request_key_auth;
+extern struct key *request_key_auth_new(struct key *target,
+                                       struct key **_rkakey);
+
+extern struct key *key_get_instantiation_authkey(key_serial_t target_id);
 
 /*
  * keyctl functions
@@ -100,6 +136,7 @@ extern long keyctl_setperm_key(key_serial_t, key_perm_t);
 extern long keyctl_instantiate_key(key_serial_t, const void __user *,
                                   size_t, key_serial_t);
 extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t);
+extern long keyctl_set_reqkey_keyring(int);
 
 
 /*
index 59402c84320319c0ee60b6f9dcd3cc7917d51568..fb89f9844465587caa5f3333eabf1a877e0e0848 100644 (file)
@@ -1,6 +1,6 @@
 /* key.c: basic authentication token and access key management
  *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -294,7 +294,6 @@ struct key *key_alloc(struct key_type *type, const char *desc,
        }
 
        atomic_set(&key->usage, 1);
-       rwlock_init(&key->lock);
        init_rwsem(&key->sem);
        key->type = type;
        key->user = user;
@@ -308,7 +307,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
        key->payload.data = NULL;
 
        if (!not_in_quota)
-               key->flags |= KEY_FLAG_IN_QUOTA;
+               key->flags |= 1 << KEY_FLAG_IN_QUOTA;
 
        memset(&key->type_data, 0, sizeof(key->type_data));
 
@@ -359,7 +358,7 @@ int key_payload_reserve(struct key *key, size_t datalen)
        key_check(key);
 
        /* contemplate the quota adjustment */
-       if (delta != 0 && key->flags & KEY_FLAG_IN_QUOTA) {
+       if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
                spin_lock(&key->user->lock);
 
                if (delta > 0 &&
@@ -392,7 +391,8 @@ EXPORT_SYMBOL(key_payload_reserve);
 static int __key_instantiate_and_link(struct key *key,
                                      const void *data,
                                      size_t datalen,
-                                     struct key *keyring)
+                                     struct key *keyring,
+                                     struct key *instkey)
 {
        int ret, awaken;
 
@@ -405,27 +405,25 @@ static int __key_instantiate_and_link(struct key *key,
        down_write(&key_construction_sem);
 
        /* can't instantiate twice */
-       if (!(key->flags & KEY_FLAG_INSTANTIATED)) {
+       if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
                /* instantiate the key */
                ret = key->type->instantiate(key, data, datalen);
 
                if (ret == 0) {
                        /* mark the key as being instantiated */
-                       write_lock(&key->lock);
-
                        atomic_inc(&key->user->nikeys);
-                       key->flags |= KEY_FLAG_INSTANTIATED;
+                       set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
 
-                       if (key->flags & KEY_FLAG_USER_CONSTRUCT) {
-                               key->flags &= ~KEY_FLAG_USER_CONSTRUCT;
+                       if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
                                awaken = 1;
-                       }
-
-                       write_unlock(&key->lock);
 
                        /* and link it into the destination keyring */
                        if (keyring)
                                ret = __key_link(keyring, key);
+
+                       /* disable the authorisation key */
+                       if (instkey)
+                               key_revoke(instkey);
                }
        }
 
@@ -446,19 +444,21 @@ static int __key_instantiate_and_link(struct key *key,
 int key_instantiate_and_link(struct key *key,
                             const void *data,
                             size_t datalen,
-                            struct key *keyring)
+                            struct key *keyring,
+                            struct key *instkey)
 {
        int ret;
 
        if (keyring)
                down_write(&keyring->sem);
 
-       ret = __key_instantiate_and_link(key, data, datalen, keyring);
+       ret = __key_instantiate_and_link(key, data, datalen, keyring, instkey);
 
        if (keyring)
                up_write(&keyring->sem);
 
        return ret;
+
 } /* end key_instantiate_and_link() */
 
 EXPORT_SYMBOL(key_instantiate_and_link);
@@ -469,7 +469,8 @@ EXPORT_SYMBOL(key_instantiate_and_link);
  */
 int key_negate_and_link(struct key *key,
                        unsigned timeout,
-                       struct key *keyring)
+                       struct key *keyring,
+                       struct key *instkey)
 {
        struct timespec now;
        int ret, awaken;
@@ -486,26 +487,26 @@ int key_negate_and_link(struct key *key,
        down_write(&key_construction_sem);
 
        /* can't instantiate twice */
-       if (!(key->flags & KEY_FLAG_INSTANTIATED)) {
+       if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
                /* mark the key as being negatively instantiated */
-               write_lock(&key->lock);
-
                atomic_inc(&key->user->nikeys);
-               key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE;
+               set_bit(KEY_FLAG_NEGATIVE, &key->flags);
+               set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
                now = current_kernel_time();
                key->expiry = now.tv_sec + timeout;
 
-               if (key->flags & KEY_FLAG_USER_CONSTRUCT) {
-                       key->flags &= ~KEY_FLAG_USER_CONSTRUCT;
+               if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
                        awaken = 1;
-               }
 
-               write_unlock(&key->lock);
                ret = 0;
 
                /* and link it into the destination keyring */
                if (keyring)
                        ret = __key_link(keyring, key);
+
+               /* disable the authorisation key */
+               if (instkey)
+                       key_revoke(instkey);
        }
 
        up_write(&key_construction_sem);
@@ -553,8 +554,10 @@ static void key_cleanup(void *data)
        rb_erase(&key->serial_node, &key_serial_tree);
        spin_unlock(&key_serial_lock);
 
+       key_check(key);
+
        /* deal with the user's key tracking and quota */
-       if (key->flags & KEY_FLAG_IN_QUOTA) {
+       if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
                spin_lock(&key->user->lock);
                key->user->qnkeys--;
                key->user->qnbytes -= key->quotalen;
@@ -562,7 +565,7 @@ static void key_cleanup(void *data)
        }
 
        atomic_dec(&key->user->nkeys);
-       if (key->flags & KEY_FLAG_INSTANTIATED)
+       if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
                atomic_dec(&key->user->nikeys);
 
        key_user_put(key->user);
@@ -631,9 +634,9 @@ struct key *key_lookup(key_serial_t id)
        goto error;
 
  found:
-       /* pretent doesn't exist if it's dead */
+       /* pretend it doesn't exist if it's dead */
        if (atomic_read(&key->usage) == 0 ||
-           (key->flags & KEY_FLAG_DEAD) ||
+           test_bit(KEY_FLAG_DEAD, &key->flags) ||
            key->type == &key_type_dead)
                goto not_found;
 
@@ -708,12 +711,9 @@ static inline struct key *__key_update(struct key *key, const void *payload,
 
        ret = key->type->update(key, payload, plen);
 
-       if (ret == 0) {
+       if (ret == 0)
                /* updating a negative key instantiates it */
-               write_lock(&key->lock);
-               key->flags &= ~KEY_FLAG_NEGATIVE;
-               write_unlock(&key->lock);
-       }
+               clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
 
        up_write(&key->sem);
 
@@ -793,7 +793,7 @@ struct key *key_create_or_update(struct key *keyring,
        }
 
        /* instantiate it and link it into the target keyring */
-       ret = __key_instantiate_and_link(key, payload, plen, keyring);
+       ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL);
        if (ret < 0) {
                key_put(key);
                key = ERR_PTR(ret);
@@ -841,12 +841,9 @@ int key_update(struct key *key, const void *payload, size_t plen)
                down_write(&key->sem);
                ret = key->type->update(key, payload, plen);
 
-               if (ret == 0) {
+               if (ret == 0)
                        /* updating a negative key instantiates it */
-                       write_lock(&key->lock);
-                       key->flags &= ~KEY_FLAG_NEGATIVE;
-                       write_unlock(&key->lock);
-               }
+                       clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
 
                up_write(&key->sem);
        }
@@ -892,10 +889,7 @@ struct key *key_duplicate(struct key *source, const char *desc)
                goto error2;
 
        atomic_inc(&key->user->nikeys);
-
-       write_lock(&key->lock);
-       key->flags |= KEY_FLAG_INSTANTIATED;
-       write_unlock(&key->lock);
+       set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
 
  error_k:
        up_read(&key_types_sem);
@@ -922,9 +916,7 @@ void key_revoke(struct key *key)
        /* make sure no one's trying to change or use the key when we mark
         * it */
        down_write(&key->sem);
-       write_lock(&key->lock);
-       key->flags |= KEY_FLAG_REVOKED;
-       write_unlock(&key->lock);
+       set_bit(KEY_FLAG_REVOKED, &key->flags);
        up_write(&key->sem);
 
 } /* end key_revoke() */
@@ -975,24 +967,33 @@ void unregister_key_type(struct key_type *ktype)
        /* withdraw the key type */
        list_del_init(&ktype->link);
 
-       /* need to withdraw all keys of this type */
+       /* mark all the keys of this type dead */
        spin_lock(&key_serial_lock);
 
        for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) {
                key = rb_entry(_n, struct key, serial_node);
 
-               if (key->type != ktype)
-                       continue;
+               if (key->type == ktype)
+                       key->type = &key_type_dead;
+       }
+
+       spin_unlock(&key_serial_lock);
+
+       /* make sure everyone revalidates their keys */
+       synchronize_rcu();
 
-               write_lock(&key->lock);
-               key->type = &key_type_dead;
-               write_unlock(&key->lock);
+       /* we should now be able to destroy the payloads of all the keys of
+        * this type with impunity */
+       spin_lock(&key_serial_lock);
+
+       for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) {
+               key = rb_entry(_n, struct key, serial_node);
 
-               /* there shouldn't be anyone looking at the description or
-                * payload now */
-               if (ktype->destroy)
-                       ktype->destroy(key);
-               memset(&key->payload, 0xbd, sizeof(key->payload));
+               if (key->type == ktype) {
+                       if (ktype->destroy)
+                               ktype->destroy(key);
+                       memset(&key->payload, 0xbd, sizeof(key->payload));
+               }
        }
 
        spin_unlock(&key_serial_lock);
@@ -1037,4 +1038,5 @@ void __init key_init(void)
 
        /* link the two root keyrings together */
        key_link(&root_session_keyring, &root_user_keyring);
+
 } /* end key_init() */
index dc0011b3fac92e8a8c623a0f8d92696d8052a241..fea262860ea01656dbe7514b4b4a301ca47424b6 100644 (file)
@@ -1,6 +1,6 @@
 /* keyctl.c: userspace keyctl operations
  *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -49,6 +49,13 @@ asmlinkage long sys_add_key(const char __user *_type,
                goto error;
        type[31] = '\0';
 
+       if (!type[0])
+               goto error;
+
+       ret = -EPERM;
+       if (type[0] == '.')
+               goto error;
+
        ret = -EFAULT;
        dlen = strnlen_user(_description, PAGE_SIZE - 1);
        if (dlen <= 0)
@@ -82,7 +89,7 @@ asmlinkage long sys_add_key(const char __user *_type,
        }
 
        /* find the target keyring (which must be writable) */
-       keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+       keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error3;
@@ -181,7 +188,7 @@ asmlinkage long sys_request_key(const char __user *_type,
        /* get the destination keyring if specified */
        dest = NULL;
        if (destringid) {
-               dest = lookup_user_key(destringid, 1, 0, KEY_WRITE);
+               dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
                if (IS_ERR(dest)) {
                        ret = PTR_ERR(dest);
                        goto error3;
@@ -196,23 +203,15 @@ asmlinkage long sys_request_key(const char __user *_type,
        }
 
        /* do the search */
-       key = request_key(ktype, description, callout_info);
+       key = request_key_and_link(ktype, description, callout_info, dest);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error5;
        }
 
-       /* link the resulting key to the destination keyring */
-       if (dest) {
-               ret = key_link(dest, key);
-               if (ret < 0)
-                       goto error6;
-       }
-
        ret = key->serial;
 
- error6:
-       key_put(key);
+       key_put(key);
  error5:
        key_type_put(ktype);
  error4:
@@ -237,7 +236,7 @@ long keyctl_get_keyring_ID(key_serial_t id, int create)
        struct key *key;
        long ret;
 
-       key = lookup_user_key(id, create, 0, KEY_SEARCH);
+       key = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error;
@@ -324,7 +323,7 @@ long keyctl_update_key(key_serial_t id,
        }
 
        /* find the target key (which must be writable) */
-       key = lookup_user_key(id, 0, 0, KEY_WRITE);
+       key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error2;
@@ -352,7 +351,7 @@ long keyctl_revoke_key(key_serial_t id)
        struct key *key;
        long ret;
 
-       key = lookup_user_key(id, 0, 0, KEY_WRITE);
+       key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error;
@@ -378,7 +377,7 @@ long keyctl_keyring_clear(key_serial_t ringid)
        struct key *keyring;
        long ret;
 
-       keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+       keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error;
@@ -404,13 +403,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
        struct key *keyring, *key;
        long ret;
 
-       keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+       keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error;
        }
 
-       key = lookup_user_key(id, 1, 0, KEY_LINK);
+       key = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error2;
@@ -438,13 +437,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
        struct key *keyring, *key;
        long ret;
 
-       keyring = lookup_user_key(ringid, 0, 0, KEY_WRITE);
+       keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error;
        }
 
-       key = lookup_user_key(id, 0, 0, 0);
+       key = lookup_user_key(NULL, id, 0, 0, 0);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error2;
@@ -475,16 +474,29 @@ long keyctl_describe_key(key_serial_t keyid,
                         char __user *buffer,
                         size_t buflen)
 {
-       struct key *key;
+       struct key *key, *instkey;
        char *tmpbuf;
        long ret;
 
-       key = lookup_user_key(keyid, 0, 1, KEY_VIEW);
+       key = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
        if (IS_ERR(key)) {
+               /* viewing a key under construction is permitted if we have the
+                * authorisation token handy */
+               if (PTR_ERR(key) == -EACCES) {
+                       instkey = key_get_instantiation_authkey(keyid);
+                       if (!IS_ERR(instkey)) {
+                               key_put(instkey);
+                               key = lookup_user_key(NULL, keyid, 0, 1, 0);
+                               if (!IS_ERR(key))
+                                       goto okay;
+                       }
+               }
+
                ret = PTR_ERR(key);
                goto error;
        }
 
+okay:
        /* calculate how much description we're going to return */
        ret = -ENOMEM;
        tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
@@ -568,7 +580,7 @@ long keyctl_keyring_search(key_serial_t ringid,
                goto error2;
 
        /* get the keyring at which to begin the search */
-       keyring = lookup_user_key(ringid, 0, 0, KEY_SEARCH);
+       keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error2;
@@ -577,7 +589,7 @@ long keyctl_keyring_search(key_serial_t ringid,
        /* get the destination keyring if specified */
        dest = NULL;
        if (destringid) {
-               dest = lookup_user_key(destringid, 1, 0, KEY_WRITE);
+               dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
                if (IS_ERR(dest)) {
                        ret = PTR_ERR(dest);
                        goto error3;
@@ -656,24 +668,23 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
        long ret;
 
        /* find the key first */
-       key = lookup_user_key(keyid, 0, 0, 0);
+       key = lookup_user_key(NULL, keyid, 0, 0, 0);
        if (!IS_ERR(key)) {
                /* see if we can read it directly */
                if (key_permission(key, KEY_READ))
                        goto can_read_key;
 
-               /* can't; see if it's searchable from this process's
-                * keyrings */
-               ret = -ENOKEY;
-               if (key_permission(key, KEY_SEARCH)) {
-                       /* okay - we do have search permission on the key
-                        * itself, but do we have the key? */
-                       skey = search_process_keyrings_aux(key->type, key,
-                                                          keyctl_read_key_same);
-                       if (!IS_ERR(skey))
-                               goto can_read_key2;
-               }
-
+               /* we can't; see if it's searchable from this process's
+                * keyrings
+                * - we automatically take account of the fact that it may be
+                *   dangling off an instantiation key
+                */
+               skey = search_process_keyrings(key->type, key,
+                                              keyctl_read_key_same, current);
+               if (!IS_ERR(skey))
+                       goto can_read_key2;
+
+               ret = PTR_ERR(skey);
                goto error2;
        }
 
@@ -719,7 +730,7 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
        if (uid == (uid_t) -1 && gid == (gid_t) -1)
                goto error;
 
-       key = lookup_user_key(id, 1, 1, 0);
+       key = lookup_user_key(NULL, id, 1, 1, 0);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error;
@@ -728,7 +739,6 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
        /* make the changes with the locks held to prevent chown/chown races */
        ret = -EACCES;
        down_write(&key->sem);
-       write_lock(&key->lock);
 
        if (!capable(CAP_SYS_ADMIN)) {
                /* only the sysadmin can chown a key to some other UID */
@@ -755,7 +765,6 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
        ret = 0;
 
  no_access:
-       write_unlock(&key->lock);
        up_write(&key->sem);
        key_put(key);
  error:
@@ -778,32 +787,25 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
        if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
                goto error;
 
-       key = lookup_user_key(id, 1, 1, 0);
+       key = lookup_user_key(NULL, id, 1, 1, 0);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error;
        }
 
-       /* make the changes with the locks held to prevent chown/chmod
-        * races */
+       /* make the changes with the locks held to prevent chown/chmod races */
        ret = -EACCES;
        down_write(&key->sem);
-       write_lock(&key->lock);
 
-       /* if we're not the sysadmin, we can only chmod a key that we
-        * own */
-       if (!capable(CAP_SYS_ADMIN) && key->uid != current->fsuid)
-               goto no_access;
-
-       /* changing the permissions mask */
-       key->perm = perm;
-       ret = 0;
+       /* if we're not the sysadmin, we can only change a key that we own */
+       if (capable(CAP_SYS_ADMIN) || key->uid == current->fsuid) {
+               key->perm = perm;
+               ret = 0;
+       }
 
- no_access:
-       write_unlock(&key->lock);
        up_write(&key->sem);
        key_put(key);
- error:
+error:
        return ret;
 
 } /* end keyctl_setperm_key() */
@@ -818,7 +820,8 @@ long keyctl_instantiate_key(key_serial_t id,
                            size_t plen,
                            key_serial_t ringid)
 {
-       struct key *key, *keyring;
+       struct request_key_auth *rka;
+       struct key *instkey, *keyring;
        void *payload;
        long ret;
 
@@ -840,18 +843,21 @@ long keyctl_instantiate_key(key_serial_t id,
                        goto error2;
        }
 
-       /* find the target key (which must be writable) */
-       key = lookup_user_key(id, 0, 1, KEY_WRITE);
-       if (IS_ERR(key)) {
-               ret = PTR_ERR(key);
+       /* find the instantiation authorisation key */
+       instkey = key_get_instantiation_authkey(id);
+       if (IS_ERR(instkey)) {
+               ret = PTR_ERR(instkey);
                goto error2;
        }
 
-       /* find the destination keyring if present (which must also be
-        * writable) */
+       rka = instkey->payload.data;
+
+       /* find the destination keyring amongst those belonging to the
+        * requesting task */
        keyring = NULL;
        if (ringid) {
-               keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+               keyring = lookup_user_key(rka->context, ringid, 1, 0,
+                                         KEY_WRITE);
                if (IS_ERR(keyring)) {
                        ret = PTR_ERR(keyring);
                        goto error3;
@@ -859,11 +865,12 @@ long keyctl_instantiate_key(key_serial_t id,
        }
 
        /* instantiate the key and link it into a keyring */
-       ret = key_instantiate_and_link(key, payload, plen, keyring);
+       ret = key_instantiate_and_link(rka->target_key, payload, plen,
+                                      keyring, instkey);
 
        key_put(keyring);
  error3:
-       key_put(key);
+       key_put(instkey);
  error2:
        kfree(payload);
  error:
@@ -878,21 +885,24 @@ long keyctl_instantiate_key(key_serial_t id,
  */
 long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
 {
-       struct key *key, *keyring;
+       struct request_key_auth *rka;
+       struct key *instkey, *keyring;
        long ret;
 
-       /* find the target key (which must be writable) */
-       key = lookup_user_key(id, 0, 1, KEY_WRITE);
-       if (IS_ERR(key)) {
-               ret = PTR_ERR(key);
+       /* find the instantiation authorisation key */
+       instkey = key_get_instantiation_authkey(id);
+       if (IS_ERR(instkey)) {
+               ret = PTR_ERR(instkey);
                goto error;
        }
 
+       rka = instkey->payload.data;
+
        /* find the destination keyring if present (which must also be
         * writable) */
        keyring = NULL;
        if (ringid) {
-               keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+               keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
                if (IS_ERR(keyring)) {
                        ret = PTR_ERR(keyring);
                        goto error2;
@@ -900,16 +910,54 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
        }
 
        /* instantiate the key and link it into a keyring */
-       ret = key_negate_and_link(key, timeout, keyring);
+       ret = key_negate_and_link(rka->target_key, timeout, keyring, instkey);
 
        key_put(keyring);
  error2:
-       key_put(key);
+       key_put(instkey);
  error:
        return ret;
 
 } /* end keyctl_negate_key() */
 
+/*****************************************************************************/
+/*
+ * set the default keyring in which request_key() will cache keys
+ * - return the old setting
+ */
+long keyctl_set_reqkey_keyring(int reqkey_defl)
+{
+       int ret;
+
+       switch (reqkey_defl) {
+       case KEY_REQKEY_DEFL_THREAD_KEYRING:
+               ret = install_thread_keyring(current);
+               if (ret < 0)
+                       return ret;
+               goto set;
+
+       case KEY_REQKEY_DEFL_PROCESS_KEYRING:
+               ret = install_process_keyring(current);
+               if (ret < 0)
+                       return ret;
+
+       case KEY_REQKEY_DEFL_DEFAULT:
+       case KEY_REQKEY_DEFL_SESSION_KEYRING:
+       case KEY_REQKEY_DEFL_USER_KEYRING:
+       case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
+       set:
+               current->jit_keyring = reqkey_defl;
+
+       case KEY_REQKEY_DEFL_NO_CHANGE:
+               return current->jit_keyring;
+
+       case KEY_REQKEY_DEFL_GROUP_KEYRING:
+       default:
+               return -EINVAL;
+       }
+
+} /* end keyctl_set_reqkey_keyring() */
+
 /*****************************************************************************/
 /*
  * the key control system call
@@ -980,6 +1028,9 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,
                                         (unsigned) arg3,
                                         (key_serial_t) arg4);
 
+       case KEYCTL_SET_REQKEY_KEYRING:
+               return keyctl_set_reqkey_keyring(arg2);
+
        default:
                return -EOPNOTSUPP;
        }
index e2ab4f8e7481d21d18efc26d0af1be273b39da8d..90a551e4da662209b411d1b90f8a5094b8f34d40 100644 (file)
@@ -1,6 +1,6 @@
 /* keyring.c: keyring handling
  *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -132,10 +132,17 @@ static int keyring_duplicate(struct key *keyring, const struct key *source)
                (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key);
 
        ret = 0;
-       sklist = source->payload.subscriptions;
 
-       if (sklist && sklist->nkeys > 0) {
+       /* find out how many keys are currently linked */
+       rcu_read_lock();
+       sklist = rcu_dereference(source->payload.subscriptions);
+       max = 0;
+       if (sklist)
                max = sklist->nkeys;
+       rcu_read_unlock();
+
+       /* allocate a new payload and stuff load with key links */
+       if (max > 0) {
                BUG_ON(max > limit);
 
                max = (max + 3) & ~3;
@@ -148,6 +155,10 @@ static int keyring_duplicate(struct key *keyring, const struct key *source)
                if (!klist)
                        goto error;
 
+               /* set links */
+               rcu_read_lock();
+               sklist = rcu_dereference(source->payload.subscriptions);
+
                klist->maxkeys = max;
                klist->nkeys = sklist->nkeys;
                memcpy(klist->keys,
@@ -157,7 +168,9 @@ static int keyring_duplicate(struct key *keyring, const struct key *source)
                for (loop = klist->nkeys - 1; loop >= 0; loop--)
                        atomic_inc(&klist->keys[loop]->usage);
 
-               keyring->payload.subscriptions = klist;
+               rcu_read_unlock();
+
+               rcu_assign_pointer(keyring->payload.subscriptions, klist);
                ret = 0;
        }
 
@@ -192,7 +205,7 @@ static void keyring_destroy(struct key *keyring)
                write_unlock(&keyring_name_lock);
        }
 
-       klist = keyring->payload.subscriptions;
+       klist = rcu_dereference(keyring->payload.subscriptions);
        if (klist) {
                for (loop = klist->nkeys - 1; loop >= 0; loop--)
                        key_put(klist->keys[loop]);
@@ -216,17 +229,20 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
                seq_puts(m, "[anon]");
        }
 
-       klist = keyring->payload.subscriptions;
+       rcu_read_lock();
+       klist = rcu_dereference(keyring->payload.subscriptions);
        if (klist)
                seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
        else
                seq_puts(m, ": empty");
+       rcu_read_unlock();
 
 } /* end keyring_describe() */
 
 /*****************************************************************************/
 /*
  * read a list of key IDs from the keyring's contents
+ * - the keyring's semaphore is read-locked
  */
 static long keyring_read(const struct key *keyring,
                         char __user *buffer, size_t buflen)
@@ -237,7 +253,7 @@ static long keyring_read(const struct key *keyring,
        int loop, ret;
 
        ret = 0;
-       klist = keyring->payload.subscriptions;
+       klist = rcu_dereference(keyring->payload.subscriptions);
 
        if (klist) {
                /* calculate how much data we could return */
@@ -292,7 +308,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
                            uid, gid, KEY_USR_ALL, not_in_quota);
 
        if (!IS_ERR(keyring)) {
-               ret = key_instantiate_and_link(keyring, NULL, 0, dest);
+               ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
                if (ret < 0) {
                        key_put(keyring);
                        keyring = ERR_PTR(ret);
@@ -310,17 +326,18 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
  * - we only find keys on which we have search permission
  * - we use the supplied match function to see if the description (or other
  *   feature of interest) matches
- * - we readlock the keyrings as we search down the tree
+ * - we rely on RCU to prevent the keyring lists from disappearing on us
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we only found negative matching keys
  */
 struct key *keyring_search_aux(struct key *keyring,
+                              struct task_struct *context,
                               struct key_type *type,
                               const void *description,
                               key_match_func_t match)
 {
        struct {
-               struct key *keyring;
+               struct keyring_list *keylist;
                int kix;
        } stack[KEYRING_SEARCH_MAX_DEPTH];
 
@@ -328,13 +345,15 @@ struct key *keyring_search_aux(struct key *keyring,
        struct timespec now;
        struct key *key;
        long err;
-       int sp, psp, kix;
+       int sp, kix;
 
        key_check(keyring);
 
+       rcu_read_lock();
+
        /* top keyring must have search permission to begin the search */
        key = ERR_PTR(-EACCES);
-       if (!key_permission(keyring, KEY_SEARCH))
+       if (!key_task_permission(keyring, context, KEY_SEARCH))
                goto error;
 
        key = ERR_PTR(-ENOTDIR);
@@ -347,11 +366,10 @@ struct key *keyring_search_aux(struct key *keyring,
 
        /* start processing a new keyring */
  descend:
-       read_lock(&keyring->lock);
-       if (keyring->flags & KEY_FLAG_REVOKED)
+       if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
                goto not_this_keyring;
 
-       keylist = keyring->payload.subscriptions;
+       keylist = rcu_dereference(keyring->payload.subscriptions);
        if (!keylist)
                goto not_this_keyring;
 
@@ -364,7 +382,7 @@ struct key *keyring_search_aux(struct key *keyring,
                        continue;
 
                /* skip revoked keys and expired keys */
-               if (key->flags & KEY_FLAG_REVOKED)
+               if (test_bit(KEY_FLAG_REVOKED, &key->flags))
                        continue;
 
                if (key->expiry && now.tv_sec >= key->expiry)
@@ -375,11 +393,11 @@ struct key *keyring_search_aux(struct key *keyring,
                        continue;
 
                /* key must have search permissions */
-               if (!key_permission(key, KEY_SEARCH))
+               if (!key_task_permission(key, context, KEY_SEARCH))
                        continue;
 
                /* we set a different error code if we find a negative key */
-               if (key->flags & KEY_FLAG_NEGATIVE) {
+               if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
                        err = -ENOKEY;
                        continue;
                }
@@ -390,48 +408,37 @@ struct key *keyring_search_aux(struct key *keyring,
        /* search through the keyrings nested in this one */
        kix = 0;
  ascend:
-       while (kix < keylist->nkeys) {
+       for (; kix < keylist->nkeys; kix++) {
                key = keylist->keys[kix];
                if (key->type != &key_type_keyring)
-                       goto next;
+                       continue;
 
                /* recursively search nested keyrings
                 * - only search keyrings for which we have search permission
                 */
                if (sp >= KEYRING_SEARCH_MAX_DEPTH)
-                       goto next;
-
-               if (!key_permission(key, KEY_SEARCH))
-                       goto next;
+                       continue;
 
-               /* evade loops in the keyring tree */
-               for (psp = 0; psp < sp; psp++)
-                       if (stack[psp].keyring == keyring)
-                               goto next;
+               if (!key_task_permission(key, context, KEY_SEARCH))
+                       continue;
 
                /* stack the current position */
-               stack[sp].keyring = keyring;
+               stack[sp].keylist = keylist;
                stack[sp].kix = kix;
                sp++;
 
                /* begin again with the new keyring */
                keyring = key;
                goto descend;
-
-       next:
-               kix++;
        }
 
        /* the keyring we're looking at was disqualified or didn't contain a
         * matching key */
  not_this_keyring:
-       read_unlock(&keyring->lock);
-
        if (sp > 0) {
                /* resume the processing of a keyring higher up in the tree */
                sp--;
-               keyring = stack[sp].keyring;
-               keylist = keyring->payload.subscriptions;
+               keylist = stack[sp].keylist;
                kix = stack[sp].kix + 1;
                goto ascend;
        }
@@ -442,16 +449,9 @@ struct key *keyring_search_aux(struct key *keyring,
        /* we found a viable match */
  found:
        atomic_inc(&key->usage);
-       read_unlock(&keyring->lock);
-
-       /* unwind the keyring stack */
-       while (sp > 0) {
-               sp--;
-               read_unlock(&stack[sp].keyring->lock);
-       }
-
        key_check(key);
  error:
+       rcu_read_unlock();
        return key;
 
 } /* end keyring_search_aux() */
@@ -469,7 +469,11 @@ struct key *keyring_search(struct key *keyring,
                           struct key_type *type,
                           const char *description)
 {
-       return keyring_search_aux(keyring, type, description, type->match);
+       if (!type->match)
+               return ERR_PTR(-ENOKEY);
+
+       return keyring_search_aux(keyring, current,
+                                 type, description, type->match);
 
 } /* end keyring_search() */
 
@@ -489,15 +493,18 @@ struct key *__keyring_search_one(struct key *keyring,
        struct key *key;
        int loop;
 
-       klist = keyring->payload.subscriptions;
+       rcu_read_lock();
+
+       klist = rcu_dereference(keyring->payload.subscriptions);
        if (klist) {
                for (loop = 0; loop < klist->nkeys; loop++) {
                        key = klist->keys[loop];
 
                        if (key->type == ktype &&
-                           key->type->match(key, description) &&
+                           (!key->type->match ||
+                            key->type->match(key, description)) &&
                            key_permission(key, perm) &&
-                           !(key->flags & KEY_FLAG_REVOKED)
+                           !test_bit(KEY_FLAG_REVOKED, &key->flags)
                            )
                                goto found;
                }
@@ -509,10 +516,56 @@ struct key *__keyring_search_one(struct key *keyring,
  found:
        atomic_inc(&key->usage);
  error:
+       rcu_read_unlock();
        return key;
 
 } /* end __keyring_search_one() */
 
+/*****************************************************************************/
+/*
+ * search for an instantiation authorisation key matching a target key
+ * - the RCU read lock must be held by the caller
+ * - a target_id of zero specifies any valid token
+ */
+struct key *keyring_search_instkey(struct key *keyring,
+                                  key_serial_t target_id)
+{
+       struct request_key_auth *rka;
+       struct keyring_list *klist;
+       struct key *instkey;
+       int loop;
+
+       klist = rcu_dereference(keyring->payload.subscriptions);
+       if (klist) {
+               for (loop = 0; loop < klist->nkeys; loop++) {
+                       instkey = klist->keys[loop];
+
+                       if (instkey->type != &key_type_request_key_auth)
+                               continue;
+
+                       rka = instkey->payload.data;
+                       if (target_id && rka->target_key->serial != target_id)
+                               continue;
+
+                       /* the auth key is revoked during instantiation */
+                       if (!test_bit(KEY_FLAG_REVOKED, &instkey->flags))
+                               goto found;
+
+                       instkey = ERR_PTR(-EKEYREVOKED);
+                       goto error;
+               }
+       }
+
+       instkey = ERR_PTR(-EACCES);
+       goto error;
+
+found:
+       atomic_inc(&instkey->usage);
+error:
+       return instkey;
+
+} /* end keyring_search_instkey() */
+
 /*****************************************************************************/
 /*
  * find a keyring with the specified name
@@ -540,7 +593,7 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound)
                                    &keyring_name_hash[bucket],
                                    type_data.link
                                    ) {
-                       if (keyring->flags & KEY_FLAG_REVOKED)
+                       if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
                                continue;
 
                        if (strcmp(keyring->description, name) != 0)
@@ -579,7 +632,7 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound)
 static int keyring_detect_cycle(struct key *A, struct key *B)
 {
        struct {
-               struct key *subtree;
+               struct keyring_list *keylist;
                int kix;
        } stack[KEYRING_SEARCH_MAX_DEPTH];
 
@@ -587,20 +640,21 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
        struct key *subtree, *key;
        int sp, kix, ret;
 
+       rcu_read_lock();
+
        ret = -EDEADLK;
        if (A == B)
-               goto error;
+               goto cycle_detected;
 
        subtree = B;
        sp = 0;
 
        /* start processing a new keyring */
  descend:
-       read_lock(&subtree->lock);
-       if (subtree->flags & KEY_FLAG_REVOKED)
+       if (test_bit(KEY_FLAG_REVOKED, &subtree->flags))
                goto not_this_keyring;
 
-       keylist = subtree->payload.subscriptions;
+       keylist = rcu_dereference(subtree->payload.subscriptions);
        if (!keylist)
                goto not_this_keyring;
        kix = 0;
@@ -619,7 +673,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
                                goto too_deep;
 
                        /* stack the current position */
-                       stack[sp].subtree = subtree;
+                       stack[sp].keylist = keylist;
                        stack[sp].kix = kix;
                        sp++;
 
@@ -632,13 +686,10 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
        /* the keyring we're looking at was disqualified or didn't contain a
         * matching key */
  not_this_keyring:
-       read_unlock(&subtree->lock);
-
        if (sp > 0) {
                /* resume the checking of a keyring higher up in the tree */
                sp--;
-               subtree = stack[sp].subtree;
-               keylist = subtree->payload.subscriptions;
+               keylist = stack[sp].keylist;
                kix = stack[sp].kix + 1;
                goto ascend;
        }
@@ -646,30 +697,36 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
        ret = 0; /* no cycles detected */
 
  error:
+       rcu_read_unlock();
        return ret;
 
  too_deep:
        ret = -ELOOP;
-       goto error_unwind;
+       goto error;
+
  cycle_detected:
        ret = -EDEADLK;
- error_unwind:
-       read_unlock(&subtree->lock);
-
-       /* unwind the keyring stack */
-       while (sp > 0) {
-               sp--;
-               read_unlock(&stack[sp].subtree->lock);
-       }
-
        goto error;
 
 } /* end keyring_detect_cycle() */
 
+/*****************************************************************************/
+/*
+ * dispose of a keyring list after the RCU grace period
+ */
+static void keyring_link_rcu_disposal(struct rcu_head *rcu)
+{
+       struct keyring_list *klist =
+               container_of(rcu, struct keyring_list, rcu);
+
+       kfree(klist);
+
+} /* end keyring_link_rcu_disposal() */
+
 /*****************************************************************************/
 /*
  * link a key into to a keyring
- * - must be called with the keyring's semaphore held
+ * - must be called with the keyring's semaphore write-locked
  */
 int __key_link(struct key *keyring, struct key *key)
 {
@@ -679,7 +736,7 @@ int __key_link(struct key *keyring, struct key *key)
        int ret;
 
        ret = -EKEYREVOKED;
-       if (keyring->flags & KEY_FLAG_REVOKED)
+       if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
                goto error;
 
        ret = -ENOTDIR;
@@ -710,9 +767,10 @@ int __key_link(struct key *keyring, struct key *key)
                /* there's sufficient slack space to add directly */
                atomic_inc(&key->usage);
 
-               write_lock(&keyring->lock);
-               klist->keys[klist->nkeys++] = key;
-               write_unlock(&keyring->lock);
+               klist->keys[klist->nkeys] = key;
+               smp_wmb();
+               klist->nkeys++;
+               smp_wmb();
 
                ret = 0;
        }
@@ -723,6 +781,8 @@ int __key_link(struct key *keyring, struct key *key)
                        max += klist->maxkeys;
 
                ret = -ENFILE;
+               if (max > 65535)
+                       goto error3;
                size = sizeof(*klist) + sizeof(*key) * max;
                if (size > PAGE_SIZE)
                        goto error3;
@@ -743,14 +803,13 @@ int __key_link(struct key *keyring, struct key *key)
 
                /* add the key into the new space */
                atomic_inc(&key->usage);
-
-               write_lock(&keyring->lock);
-               keyring->payload.subscriptions = nklist;
                nklist->keys[nklist->nkeys++] = key;
-               write_unlock(&keyring->lock);
+
+               rcu_assign_pointer(keyring->payload.subscriptions, nklist);
 
                /* dispose of the old keyring list */
-               kfree(klist);
+               if (klist)
+                       call_rcu(&klist->rcu, keyring_link_rcu_disposal);
 
                ret = 0;
        }
@@ -789,13 +848,28 @@ int key_link(struct key *keyring, struct key *key)
 
 EXPORT_SYMBOL(key_link);
 
+/*****************************************************************************/
+/*
+ * dispose of a keyring list after the RCU grace period, freeing the unlinked
+ * key
+ */
+static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
+{
+       struct keyring_list *klist =
+               container_of(rcu, struct keyring_list, rcu);
+
+       key_put(klist->keys[klist->delkey]);
+       kfree(klist);
+
+} /* end keyring_unlink_rcu_disposal() */
+
 /*****************************************************************************/
 /*
  * unlink the first link to a key from a keyring
  */
 int key_unlink(struct key *keyring, struct key *key)
 {
-       struct keyring_list *klist;
+       struct keyring_list *klist, *nklist;
        int loop, ret;
 
        key_check(keyring);
@@ -819,36 +893,69 @@ int key_unlink(struct key *keyring, struct key *key)
        ret = -ENOENT;
        goto error;
 
- key_is_present:
+key_is_present:
+       /* we need to copy the key list for RCU purposes */
+       nklist = kmalloc(sizeof(*klist) + sizeof(*key) * klist->maxkeys,
+                        GFP_KERNEL);
+       if (!nklist)
+               goto nomem;
+       nklist->maxkeys = klist->maxkeys;
+       nklist->nkeys = klist->nkeys - 1;
+
+       if (loop > 0)
+               memcpy(&nklist->keys[0],
+                      &klist->keys[0],
+                      loop * sizeof(klist->keys[0]));
+
+       if (loop < nklist->nkeys)
+               memcpy(&nklist->keys[loop],
+                      &klist->keys[loop + 1],
+                      (nklist->nkeys - loop) * sizeof(klist->keys[0]));
+
        /* adjust the user's quota */
        key_payload_reserve(keyring,
                            keyring->datalen - KEYQUOTA_LINK_BYTES);
 
-       /* shuffle down the key pointers
-        * - it might be worth shrinking the allocated memory, but that runs
-        *   the risk of ENOMEM as we would have to copy
-        */
-       write_lock(&keyring->lock);
+       rcu_assign_pointer(keyring->payload.subscriptions, nklist);
 
-       klist->nkeys--;
-       if (loop < klist->nkeys)
-               memcpy(&klist->keys[loop],
-                      &klist->keys[loop + 1],
-                      (klist->nkeys - loop) * sizeof(struct key *));
+       up_write(&keyring->sem);
 
-       write_unlock(&keyring->lock);
+       /* schedule for later cleanup */
+       klist->delkey = loop;
+       call_rcu(&klist->rcu, keyring_unlink_rcu_disposal);
 
-       up_write(&keyring->sem);
-       key_put(key);
        ret = 0;
 
- error:
+error:
        return ret;
+nomem:
+       ret = -ENOMEM;
+       up_write(&keyring->sem);
+       goto error;
 
 } /* end key_unlink() */
 
 EXPORT_SYMBOL(key_unlink);
 
+/*****************************************************************************/
+/*
+ * dispose of a keyring list after the RCU grace period, releasing the keys it
+ * links to
+ */
+static void keyring_clear_rcu_disposal(struct rcu_head *rcu)
+{
+       struct keyring_list *klist;
+       int loop;
+
+       klist = container_of(rcu, struct keyring_list, rcu);
+
+       for (loop = klist->nkeys - 1; loop >= 0; loop--)
+               key_put(klist->keys[loop]);
+
+       kfree(klist);
+
+} /* end keyring_clear_rcu_disposal() */
+
 /*****************************************************************************/
 /*
  * clear the specified process keyring
@@ -857,7 +964,7 @@ EXPORT_SYMBOL(key_unlink);
 int keyring_clear(struct key *keyring)
 {
        struct keyring_list *klist;
-       int loop, ret;
+       int ret;
 
        ret = -ENOTDIR;
        if (keyring->type == &key_type_keyring) {
@@ -870,20 +977,15 @@ int keyring_clear(struct key *keyring)
                        key_payload_reserve(keyring,
                                            sizeof(struct keyring_list));
 
-                       write_lock(&keyring->lock);
-                       keyring->payload.subscriptions = NULL;
-                       write_unlock(&keyring->lock);
+                       rcu_assign_pointer(keyring->payload.subscriptions,
+                                          NULL);
                }
 
                up_write(&keyring->sem);
 
                /* free the keys after the locks have been dropped */
-               if (klist) {
-                       for (loop = klist->nkeys - 1; loop >= 0; loop--)
-                               key_put(klist->keys[loop]);
-
-                       kfree(klist);
-               }
+               if (klist)
+                       call_rcu(&klist->rcu, keyring_clear_rcu_disposal);
 
                ret = 0;
        }
index 91343b85c39c70c81b7a209106f376073718bccb..c55cf1fd08264769b162248f8107c41575578633 100644 (file)
@@ -140,7 +140,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
 
        now = current_kernel_time();
 
-       read_lock(&key->lock);
+       rcu_read_lock();
 
        /* come up with a suitable timeout value */
        if (key->expiry == 0) {
@@ -164,14 +164,17 @@ static int proc_keys_show(struct seq_file *m, void *v)
                        sprintf(xbuf, "%luw", timo / (60*60*24*7));
        }
 
+#define showflag(KEY, LETTER, FLAG) \
+       (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-')
+
        seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %06x %5d %5d %-9.9s ",
                   key->serial,
-                  key->flags & KEY_FLAG_INSTANTIATED   ? 'I' : '-',
-                  key->flags & KEY_FLAG_REVOKED        ? 'R' : '-',
-                  key->flags & KEY_FLAG_DEAD           ? 'D' : '-',
-                  key->flags & KEY_FLAG_IN_QUOTA       ? 'Q' : '-',
-                  key->flags & KEY_FLAG_USER_CONSTRUCT ? 'U' : '-',
-                  key->flags & KEY_FLAG_NEGATIVE       ? 'N' : '-',
+                  showflag(key, 'I', KEY_FLAG_INSTANTIATED),
+                  showflag(key, 'R', KEY_FLAG_REVOKED),
+                  showflag(key, 'D', KEY_FLAG_DEAD),
+                  showflag(key, 'Q', KEY_FLAG_IN_QUOTA),
+                  showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT),
+                  showflag(key, 'N', KEY_FLAG_NEGATIVE),
                   atomic_read(&key->usage),
                   xbuf,
                   key->perm,
@@ -179,11 +182,13 @@ static int proc_keys_show(struct seq_file *m, void *v)
                   key->gid,
                   key->type->name);
 
+#undef showflag
+
        if (key->type->describe)
                key->type->describe(key, m);
        seq_putc(m, '\n');
 
-       read_unlock(&key->lock);
+       rcu_read_unlock();
 
        return 0;
 
index 2eb0e471cd40817a4ae548188dd82be73cbaca71..9b0369c5a223acbf951178e87ebbb0789458b507 100644 (file)
@@ -1,6 +1,6 @@
 /* process_keys.c: management of a process's keyrings
  *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -38,10 +38,9 @@ struct key root_user_keyring = {
        .serial         = 2,
        .type           = &key_type_keyring,
        .user           = &root_key_user,
-       .lock           = RW_LOCK_UNLOCKED,
        .sem            = __RWSEM_INITIALIZER(root_user_keyring.sem),
        .perm           = KEY_USR_ALL,
-       .flags          = KEY_FLAG_INSTANTIATED,
+       .flags          = 1 << KEY_FLAG_INSTANTIATED,
        .description    = "_uid.0",
 #ifdef KEY_DEBUGGING
        .magic          = KEY_DEBUG_MAGIC,
@@ -54,10 +53,9 @@ struct key root_session_keyring = {
        .serial         = 1,
        .type           = &key_type_keyring,
        .user           = &root_key_user,
-       .lock           = RW_LOCK_UNLOCKED,
        .sem            = __RWSEM_INITIALIZER(root_session_keyring.sem),
        .perm           = KEY_USR_ALL,
-       .flags          = KEY_FLAG_INSTANTIATED,
+       .flags          = 1 << KEY_FLAG_INSTANTIATED,
        .description    = "_uid_ses.0",
 #ifdef KEY_DEBUGGING
        .magic          = KEY_DEBUG_MAGIC,
@@ -167,7 +165,7 @@ int install_thread_keyring(struct task_struct *tsk)
 /*
  * make sure a process keyring is installed
  */
-static int install_process_keyring(struct task_struct *tsk)
+int install_process_keyring(struct task_struct *tsk)
 {
        unsigned long flags;
        struct key *keyring;
@@ -183,7 +181,7 @@ static int install_process_keyring(struct task_struct *tsk)
                        goto error;
                }
 
-               /* attach or swap keyrings */
+               /* attach keyring */
                spin_lock_irqsave(&tsk->sighand->siglock, flags);
                if (!tsk->signal->process_keyring) {
                        tsk->signal->process_keyring = keyring;
@@ -229,12 +227,14 @@ static int install_session_keyring(struct task_struct *tsk,
 
        /* install the keyring */
        spin_lock_irqsave(&tsk->sighand->siglock, flags);
-       old = tsk->signal->session_keyring;
-       tsk->signal->session_keyring = keyring;
+       old = rcu_dereference(tsk->signal->session_keyring);
+       rcu_assign_pointer(tsk->signal->session_keyring, keyring);
        spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
 
        ret = 0;
 
+       /* we're using RCU on the pointer */
+       synchronize_rcu();
        key_put(old);
  error:
        return ret;
@@ -247,8 +247,6 @@ static int install_session_keyring(struct task_struct *tsk,
  */
 int copy_thread_group_keys(struct task_struct *tsk)
 {
-       unsigned long flags;
-
        key_check(current->thread_group->session_keyring);
        key_check(current->thread_group->process_keyring);
 
@@ -256,10 +254,10 @@ int copy_thread_group_keys(struct task_struct *tsk)
        tsk->signal->process_keyring = NULL;
 
        /* same session keyring */
-       spin_lock_irqsave(&current->sighand->siglock, flags);
+       rcu_read_lock();
        tsk->signal->session_keyring =
-               key_get(current->signal->session_keyring);
-       spin_unlock_irqrestore(&current->sighand->siglock, flags);
+               key_get(rcu_dereference(current->signal->session_keyring));
+       rcu_read_unlock();
 
        return 0;
 
@@ -349,9 +347,7 @@ void key_fsuid_changed(struct task_struct *tsk)
        /* update the ownership of the thread keyring */
        if (tsk->thread_keyring) {
                down_write(&tsk->thread_keyring->sem);
-               write_lock(&tsk->thread_keyring->lock);
                tsk->thread_keyring->uid = tsk->fsuid;
-               write_unlock(&tsk->thread_keyring->lock);
                up_write(&tsk->thread_keyring->sem);
        }
 
@@ -366,9 +362,7 @@ void key_fsgid_changed(struct task_struct *tsk)
        /* update the ownership of the thread keyring */
        if (tsk->thread_keyring) {
                down_write(&tsk->thread_keyring->sem);
-               write_lock(&tsk->thread_keyring->lock);
                tsk->thread_keyring->gid = tsk->fsgid;
-               write_unlock(&tsk->thread_keyring->lock);
                up_write(&tsk->thread_keyring->sem);
        }
 
@@ -382,13 +376,13 @@ void key_fsgid_changed(struct task_struct *tsk)
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we found only negative matching keys
  */
-struct key *search_process_keyrings_aux(struct key_type *type,
-                                       const void *description,
-                                       key_match_func_t match)
+struct key *search_process_keyrings(struct key_type *type,
+                                   const void *description,
+                                   key_match_func_t match,
+                                   struct task_struct *context)
 {
-       struct task_struct *tsk = current;
-       unsigned long flags;
-       struct key *key, *ret, *err, *tmp;
+       struct request_key_auth *rka;
+       struct key *key, *ret, *err, *instkey;
 
        /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
         * searchable, but we failed to find a key or we found a negative key;
@@ -402,9 +396,9 @@ struct key *search_process_keyrings_aux(struct key_type *type,
        err = ERR_PTR(-EAGAIN);
 
        /* search the thread keyring first */
-       if (tsk->thread_keyring) {
-               key = keyring_search_aux(tsk->thread_keyring, type,
-                                        description, match);
+       if (context->thread_keyring) {
+               key = keyring_search_aux(context->thread_keyring,
+                                        context, type, description, match);
                if (!IS_ERR(key))
                        goto found;
 
@@ -422,9 +416,9 @@ struct key *search_process_keyrings_aux(struct key_type *type,
        }
 
        /* search the process keyring second */
-       if (tsk->signal->process_keyring) {
-               key = keyring_search_aux(tsk->signal->process_keyring,
-                                        type, description, match);
+       if (context->signal->process_keyring) {
+               key = keyring_search_aux(context->signal->process_keyring,
+                                        context, type, description, match);
                if (!IS_ERR(key))
                        goto found;
 
@@ -441,52 +435,93 @@ struct key *search_process_keyrings_aux(struct key_type *type,
                }
        }
 
-       /* search the session keyring last */
-       spin_lock_irqsave(&tsk->sighand->siglock, flags);
+       /* search the session keyring */
+       if (context->signal->session_keyring) {
+               rcu_read_lock();
+               key = keyring_search_aux(
+                       rcu_dereference(context->signal->session_keyring),
+                       context, type, description, match);
+               rcu_read_unlock();
 
-       tmp = tsk->signal->session_keyring;
-       if (!tmp)
-               tmp = tsk->user->session_keyring;
-       atomic_inc(&tmp->usage);
+               if (!IS_ERR(key))
+                       goto found;
 
-       spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+               switch (PTR_ERR(key)) {
+               case -EAGAIN: /* no key */
+                       if (ret)
+                               break;
+               case -ENOKEY: /* negative key */
+                       ret = key;
+                       break;
+               default:
+                       err = key;
+                       break;
+               }
+
+               /* if this process has a session keyring and that has an
+                * instantiation authorisation key in the bottom level, then we
+                * also search the keyrings of the process mentioned there */
+               if (context != current)
+                       goto no_key;
+
+               rcu_read_lock();
+               instkey = __keyring_search_one(
+                       rcu_dereference(context->signal->session_keyring),
+                       &key_type_request_key_auth, NULL, 0);
+               rcu_read_unlock();
+
+               if (IS_ERR(instkey))
+                       goto no_key;
+
+               rka = instkey->payload.data;
 
-       key = keyring_search_aux(tmp, type, description, match);
-       key_put(tmp);
-       if (!IS_ERR(key))
-               goto found;
+               key = search_process_keyrings(type, description, match,
+                                             rka->context);
+               key_put(instkey);
 
-       switch (PTR_ERR(key)) {
-       case -EAGAIN: /* no key */
-               if (ret)
+               if (!IS_ERR(key))
+                       goto found;
+
+               switch (PTR_ERR(key)) {
+               case -EAGAIN: /* no key */
+                       if (ret)
+                               break;
+               case -ENOKEY: /* negative key */
+                       ret = key;
                        break;
-       case -ENOKEY: /* negative key */
-               ret = key;
-               break;
-       default:
-               err = key;
-               break;
+               default:
+                       err = key;
+                       break;
+               }
+       }
+       /* or search the user-session keyring */
+       else {
+               key = keyring_search_aux(context->user->session_keyring,
+                                        context, type, description, match);
+               if (!IS_ERR(key))
+                       goto found;
+
+               switch (PTR_ERR(key)) {
+               case -EAGAIN: /* no key */
+                       if (ret)
+                               break;
+               case -ENOKEY: /* negative key */
+                       ret = key;
+                       break;
+               default:
+                       err = key;
+                       break;
+               }
        }
 
+
+no_key:
        /* no key - decide on the error we're going to go for */
        key = ret ? ret : err;
 
- found:
+found:
        return key;
 
-} /* end search_process_keyrings_aux() */
-
-/*****************************************************************************/
-/*
- * search the process keyrings for the first matching key
- * - we return -EAGAIN if we didn't find any matching key
- * - we return -ENOKEY if we found only negative matching keys
- */
-struct key *search_process_keyrings(struct key_type *type,
-                                   const char *description)
-{
-       return search_process_keyrings_aux(type, description, type->match);
-
 } /* end search_process_keyrings() */
 
 /*****************************************************************************/
@@ -495,72 +530,73 @@ struct key *search_process_keyrings(struct key_type *type,
  * - don't create special keyrings unless so requested
  * - partially constructed keys aren't found unless requested
  */
-struct key *lookup_user_key(key_serial_t id, int create, int partial,
-                           key_perm_t perm)
+struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
+                           int create, int partial, key_perm_t perm)
 {
-       struct task_struct *tsk = current;
-       unsigned long flags;
        struct key *key;
        int ret;
 
+       if (!context)
+               context = current;
+
        key = ERR_PTR(-ENOKEY);
 
        switch (id) {
        case KEY_SPEC_THREAD_KEYRING:
-               if (!tsk->thread_keyring) {
+               if (!context->thread_keyring) {
                        if (!create)
                                goto error;
 
-                       ret = install_thread_keyring(tsk);
+                       ret = install_thread_keyring(context);
                        if (ret < 0) {
                                key = ERR_PTR(ret);
                                goto error;
                        }
                }
 
-               key = tsk->thread_keyring;
+               key = context->thread_keyring;
                atomic_inc(&key->usage);
                break;
 
        case KEY_SPEC_PROCESS_KEYRING:
-               if (!tsk->signal->process_keyring) {
+               if (!context->signal->process_keyring) {
                        if (!create)
                                goto error;
 
-                       ret = install_process_keyring(tsk);
+                       ret = install_process_keyring(context);
                        if (ret < 0) {
                                key = ERR_PTR(ret);
                                goto error;
                        }
                }
 
-               key = tsk->signal->process_keyring;
+               key = context->signal->process_keyring;
                atomic_inc(&key->usage);
                break;
 
        case KEY_SPEC_SESSION_KEYRING:
-               if (!tsk->signal->session_keyring) {
+               if (!context->signal->session_keyring) {
                        /* always install a session keyring upon access if one
                         * doesn't exist yet */
                        ret = install_session_keyring(
-                              tsk, tsk->user->session_keyring);
+                              context, context->user->session_keyring);
                        if (ret < 0)
                                goto error;
                }
 
-               spin_lock_irqsave(&tsk->sighand->siglock, flags);
-               key = tsk->signal->session_keyring;
+               rcu_read_lock();
+               key = rcu_dereference(context->signal->session_keyring);
                atomic_inc(&key->usage);
-               spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+               rcu_read_unlock();
                break;
 
        case KEY_SPEC_USER_KEYRING:
-               key = tsk->user->uid_keyring;
+               key = context->user->uid_keyring;
                atomic_inc(&key->usage);
                break;
 
        case KEY_SPEC_USER_SESSION_KEYRING:
-               key = tsk->user->session_keyring;
+               key = context->user->session_keyring;
                atomic_inc(&key->usage);
                break;
 
@@ -580,7 +616,7 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial,
                break;
        }
 
-       /* check the status and permissions */
+       /* check the status */
        if (perm) {
                ret = key_validate(key);
                if (ret < 0)
@@ -588,11 +624,13 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial,
        }
 
        ret = -EIO;
-       if (!partial && !(key->flags & KEY_FLAG_INSTANTIATED))
+       if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
                goto invalid_key;
 
+       /* check the permissions */
        ret = -EACCES;
-       if (!key_permission(key, perm))
+
+       if (!key_task_permission(key, context, perm))
                goto invalid_key;
 
  error:
@@ -615,7 +653,6 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial,
 long join_session_keyring(const char *name)
 {
        struct task_struct *tsk = current;
-       unsigned long flags;
        struct key *keyring;
        long ret;
 
@@ -625,9 +662,9 @@ long join_session_keyring(const char *name)
                if (ret < 0)
                        goto error;
 
-               spin_lock_irqsave(&tsk->sighand->siglock, flags);
-               ret = tsk->signal->session_keyring->serial;
-               spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+               rcu_read_lock();
+               ret = rcu_dereference(tsk->signal->session_keyring)->serial;
+               rcu_read_unlock();
                goto error;
        }
 
index 9705b1aeba5deaa0d9b761996c4eba8345535faf..dfcd983af1fd88405d28c7af2a002e3e141759e5 100644 (file)
@@ -1,6 +1,6 @@
 /* request_key.c: request a key from userspace
  *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -13,6 +13,7 @@
 #include <linux/sched.h>
 #include <linux/kmod.h>
 #include <linux/err.h>
+#include <linux/keyctl.h>
 #include "internal.h"
 
 struct key_construction {
@@ -27,18 +28,26 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
 /*
  * request userspace finish the construction of a key
  * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring> <info>"
- * - if callout_info is an empty string, it'll be rendered as a "-" instead
  */
 static int call_request_key(struct key *key,
                            const char *op,
                            const char *callout_info)
 {
        struct task_struct *tsk = current;
-       unsigned long flags;
        key_serial_t prkey, sskey;
+       struct key *session_keyring, *rkakey;
        char *argv[10], *envp[3], uid_str[12], gid_str[12];
        char key_str[12], keyring_str[3][12];
-       int i;
+       int ret, i;
+
+       kenter("{%d},%s,%s", key->serial, op, callout_info);
+
+       /* generate a new session keyring with an auth key in it */
+       session_keyring = request_key_auth_new(key, &rkakey);
+       if (IS_ERR(session_keyring)) {
+               ret = PTR_ERR(session_keyring);
+               goto error;
+       }
 
        /* record the UID and GID */
        sprintf(uid_str, "%d", current->fsuid);
@@ -55,17 +64,17 @@ static int call_request_key(struct key *key,
        if (tsk->signal->process_keyring)
                prkey = tsk->signal->process_keyring->serial;
 
-       sskey = 0;
-       spin_lock_irqsave(&tsk->sighand->siglock, flags);
-       if (tsk->signal->session_keyring)
-               sskey = tsk->signal->session_keyring->serial;
-       spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
-
+       sprintf(keyring_str[1], "%d", prkey);
 
-       if (!sskey)
+       if (tsk->signal->session_keyring) {
+               rcu_read_lock();
+               sskey = rcu_dereference(tsk->signal->session_keyring)->serial;
+               rcu_read_unlock();
+       }
+       else {
                sskey = tsk->user->session_keyring->serial;
+       }
 
-       sprintf(keyring_str[1], "%d", prkey);
        sprintf(keyring_str[2], "%d", sskey);
 
        /* set up a minimal environment */
@@ -84,11 +93,20 @@ static int call_request_key(struct key *key,
        argv[i++] = keyring_str[0];
        argv[i++] = keyring_str[1];
        argv[i++] = keyring_str[2];
-       argv[i++] = callout_info[0] ? (char *) callout_info : "-";
+       argv[i++] = (char *) callout_info;
        argv[i] = NULL;
 
        /* do it */
-       return call_usermodehelper(argv[0], argv, envp, 1);
+       ret = call_usermodehelper_keys(argv[0], argv, envp, session_keyring, 1);
+
+       /* dispose of the special keys */
+       key_revoke(rkakey);
+       key_put(rkakey);
+       key_put(session_keyring);
+
+ error:
+       kleave(" = %d", ret);
+       return ret;
 
 } /* end call_request_key() */
 
@@ -105,7 +123,9 @@ static struct key *__request_key_construction(struct key_type *type,
        struct key_construction cons;
        struct timespec now;
        struct key *key;
-       int ret, negative;
+       int ret, negated;
+
+       kenter("%s,%s,%s", type->name, description, callout_info);
 
        /* create a key and add it to the queue */
        key = key_alloc(type, description,
@@ -113,9 +133,7 @@ static struct key *__request_key_construction(struct key_type *type,
        if (IS_ERR(key))
                goto alloc_failed;
 
-       write_lock(&key->lock);
-       key->flags |= KEY_FLAG_USER_CONSTRUCT;
-       write_unlock(&key->lock);
+       set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
 
        cons.key = key;
        list_add_tail(&cons.link, &key->user->consq);
@@ -130,7 +148,7 @@ static struct key *__request_key_construction(struct key_type *type,
 
        /* if the key wasn't instantiated, then we want to give an error */
        ret = -ENOKEY;
-       if (!(key->flags & KEY_FLAG_INSTANTIATED))
+       if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
                goto request_failed;
 
        down_write(&key_construction_sem);
@@ -139,12 +157,13 @@ static struct key *__request_key_construction(struct key_type *type,
 
        /* also give an error if the key was negatively instantiated */
  check_not_negative:
-       if (key->flags & KEY_FLAG_NEGATIVE) {
+       if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
                key_put(key);
                key = ERR_PTR(-ENOKEY);
        }
 
  out:
+       kleave(" = %p", key);
        return key;
 
  request_failed:
@@ -152,24 +171,23 @@ static struct key *__request_key_construction(struct key_type *type,
         * - remove from construction queue
         * - mark the key as dead
         */
-       negative = 0;
+       negated = 0;
        down_write(&key_construction_sem);
 
        list_del(&cons.link);
 
-       write_lock(&key->lock);
-       key->flags &= ~KEY_FLAG_USER_CONSTRUCT;
-
        /* check it didn't get instantiated between the check and the down */
-       if (!(key->flags & KEY_FLAG_INSTANTIATED)) {
-               key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE;
-               negative = 1;
+       if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
+               set_bit(KEY_FLAG_NEGATIVE, &key->flags);
+               set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
+               negated = 1;
        }
 
-       write_unlock(&key->lock);
+       clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
+
        up_write(&key_construction_sem);
 
-       if (!negative)
+       if (!negated)
                goto check_not_negative; /* surprisingly, the key got
                                          * instantiated */
 
@@ -178,13 +196,12 @@ static struct key *__request_key_construction(struct key_type *type,
        key->expiry = now.tv_sec + key_negative_timeout;
 
        if (current->signal->session_keyring) {
-               unsigned long flags;
                struct key *keyring;
 
-               spin_lock_irqsave(&current->sighand->siglock, flags);
-               keyring = current->signal->session_keyring;
+               rcu_read_lock();
+               keyring = rcu_dereference(current->signal->session_keyring);
                atomic_inc(&keyring->usage);
-               spin_unlock_irqrestore(&current->sighand->siglock, flags);
+               rcu_read_unlock();
 
                key_link(keyring, key);
                key_put(keyring);
@@ -220,6 +237,9 @@ static struct key *request_key_construction(struct key_type *type,
 
        DECLARE_WAITQUEUE(myself, current);
 
+       kenter("%s,%s,{%d},%s",
+              type->name, description, user->uid, callout_info);
+
        /* see if there's such a key under construction already */
        down_write(&key_construction_sem);
 
@@ -236,6 +256,7 @@ static struct key *request_key_construction(struct key_type *type,
        /* see about getting userspace to construct the key */
        key = __request_key_construction(type, description, callout_info);
  error:
+       kleave(" = %p", key);
        return key;
 
        /* someone else has the same key under construction
@@ -249,8 +270,10 @@ static struct key *request_key_construction(struct key_type *type,
        add_wait_queue(&request_key_conswq, &myself);
 
        for (;;) {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               if (!(ckey->flags & KEY_FLAG_USER_CONSTRUCT))
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (!test_bit(KEY_FLAG_USER_CONSTRUCT, &ckey->flags))
+                       break;
+               if (signal_pending(current))
                        break;
                schedule();
        }
@@ -269,23 +292,85 @@ static struct key *request_key_construction(struct key_type *type,
 
 } /* end request_key_construction() */
 
+/*****************************************************************************/
+/*
+ * link a freshly minted key to an appropriate destination keyring
+ */
+static void request_key_link(struct key *key, struct key *dest_keyring)
+{
+       struct task_struct *tsk = current;
+       struct key *drop = NULL;
+
+       kenter("{%d},%p", key->serial, dest_keyring);
+
+       /* find the appropriate keyring */
+       if (!dest_keyring) {
+               switch (tsk->jit_keyring) {
+               case KEY_REQKEY_DEFL_DEFAULT:
+               case KEY_REQKEY_DEFL_THREAD_KEYRING:
+                       dest_keyring = tsk->thread_keyring;
+                       if (dest_keyring)
+                               break;
+
+               case KEY_REQKEY_DEFL_PROCESS_KEYRING:
+                       dest_keyring = tsk->signal->process_keyring;
+                       if (dest_keyring)
+                               break;
+
+               case KEY_REQKEY_DEFL_SESSION_KEYRING:
+                       rcu_read_lock();
+                       dest_keyring = key_get(
+                               rcu_dereference(tsk->signal->session_keyring));
+                       rcu_read_unlock();
+                       drop = dest_keyring;
+
+                       if (dest_keyring)
+                               break;
+
+               case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
+                       dest_keyring = current->user->session_keyring;
+                       break;
+
+               case KEY_REQKEY_DEFL_USER_KEYRING:
+                       dest_keyring = current->user->uid_keyring;
+                       break;
+
+               case KEY_REQKEY_DEFL_GROUP_KEYRING:
+               default:
+                       BUG();
+               }
+       }
+
+       /* and attach the key to it */
+       key_link(dest_keyring, key);
+
+       key_put(drop);
+
+       kleave("");
+
+} /* end request_key_link() */
+
 /*****************************************************************************/
 /*
  * request a key
  * - search the process's keyrings
  * - check the list of keys being created or updated
- * - call out to userspace for a key if requested (supplementary info can be
- *   passed)
+ * - call out to userspace for a key if supplementary info was provided
+ * - cache the key in an appropriate keyring
  */
-struct key *request_key(struct key_type *type,
-                       const char *description,
-                       const char *callout_info)
+struct key *request_key_and_link(struct key_type *type,
+                                const char *description,
+                                const char *callout_info,
+                                struct key *dest_keyring)
 {
        struct key_user *user;
        struct key *key;
 
+       kenter("%s,%s,%s,%p",
+              type->name, description, callout_info, dest_keyring);
+
        /* search all the process keyrings for a key */
-       key = search_process_keyrings_aux(type, description, type->match);
+       key = search_process_keyrings(type, description, type->match, current);
 
        if (PTR_ERR(key) == -EAGAIN) {
                /* the search failed, but the keyrings were searchable, so we
@@ -296,12 +381,13 @@ struct key *request_key(struct key_type *type,
 
                /* - get hold of the user's construction queue */
                user = key_user_lookup(current->fsuid);
-               if (!user) {
-                       key = ERR_PTR(-ENOMEM);
-                       goto error;
-               }
+               if (!user)
+                       goto nomem;
+
+               do {
+                       if (signal_pending(current))
+                               goto interrupted;
 
-               for (;;) {
                        /* ask userspace (returns NULL if it waited on a key
                         * being constructed) */
                        key = request_key_construction(type, description,
@@ -311,18 +397,46 @@ struct key *request_key(struct key_type *type,
 
                        /* someone else made the key we want, so we need to
                         * search again as it might now be available to us */
-                       key = search_process_keyrings_aux(type, description,
-                                                         type->match);
-                       if (PTR_ERR(key) != -EAGAIN)
-                               break;
-               }
+                       key = search_process_keyrings(type, description,
+                                                     type->match, current);
+
+               } while (PTR_ERR(key) == -EAGAIN);
 
                key_user_put(user);
+
+               /* link the new key into the appropriate keyring */
+               if (!PTR_ERR(key))
+                       request_key_link(key, dest_keyring);
        }
 
- error:
+error:
+       kleave(" = %p", key);
        return key;
 
+nomem:
+       key = ERR_PTR(-ENOMEM);
+       goto error;
+
+interrupted:
+       key_user_put(user);
+       key = ERR_PTR(-EINTR);
+       goto error;
+
+} /* end request_key_and_link() */
+
+/*****************************************************************************/
+/*
+ * request a key
+ * - search the process's keyrings
+ * - check the list of keys being created or updated
+ * - call out to userspace for a key if supplementary info was provided
+ */
+struct key *request_key(struct key_type *type,
+                       const char *description,
+                       const char *callout_info)
+{
+       return request_key_and_link(type, description, callout_info, NULL);
+
 } /* end request_key() */
 
 EXPORT_SYMBOL(request_key);
@@ -339,7 +453,8 @@ int key_validate(struct key *key)
        if (key) {
                /* check it's still accessible */
                ret = -EKEYREVOKED;
-               if (key->flags & (KEY_FLAG_REVOKED | KEY_FLAG_DEAD))
+               if (test_bit(KEY_FLAG_REVOKED, &key->flags) ||
+                   test_bit(KEY_FLAG_DEAD, &key->flags))
                        goto error;
 
                /* check it hasn't expired */
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
new file mode 100644 (file)
index 0000000..f222646
--- /dev/null
@@ -0,0 +1,180 @@
+/* request_key_auth.c: request key authorisation controlling key def
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/seq_file.h>
+#include "internal.h"
+
+static int request_key_auth_instantiate(struct key *, const void *, size_t);
+static void request_key_auth_describe(const struct key *, struct seq_file *);
+static void request_key_auth_destroy(struct key *);
+
+/*
+ * the request-key authorisation key type definition
+ */
+struct key_type key_type_request_key_auth = {
+       .name           = ".request_key_auth",
+       .def_datalen    = sizeof(struct request_key_auth),
+       .instantiate    = request_key_auth_instantiate,
+       .describe       = request_key_auth_describe,
+       .destroy        = request_key_auth_destroy,
+};
+
+/*****************************************************************************/
+/*
+ * instantiate a request-key authorisation record
+ */
+static int request_key_auth_instantiate(struct key *key,
+                                       const void *data,
+                                       size_t datalen)
+{
+       struct request_key_auth *rka, *irka;
+       struct key *instkey;
+       int ret;
+
+       ret = -ENOMEM;
+       rka = kmalloc(sizeof(*rka), GFP_KERNEL);
+       if (rka) {
+               /* see if the calling process is already servicing the key
+                * request of another process */
+               instkey = key_get_instantiation_authkey(0);
+               if (!IS_ERR(instkey)) {
+                       /* it is - use that instantiation context here too */
+                       irka = instkey->payload.data;
+                       rka->context = irka->context;
+                       rka->pid = irka->pid;
+                       key_put(instkey);
+               }
+               else {
+                       /* it isn't - use this process as the context */
+                       rka->context = current;
+                       rka->pid = current->pid;
+               }
+
+               rka->target_key = key_get((struct key *) data);
+               key->payload.data = rka;
+               ret = 0;
+       }
+
+       return ret;
+
+} /* end request_key_auth_instantiate() */
+
+/*****************************************************************************/
+/*
+ *
+ */
+static void request_key_auth_describe(const struct key *key,
+                                     struct seq_file *m)
+{
+       struct request_key_auth *rka = key->payload.data;
+
+       seq_puts(m, "key:");
+       seq_puts(m, key->description);
+       seq_printf(m, " pid:%d", rka->pid);
+
+} /* end request_key_auth_describe() */
+
+/*****************************************************************************/
+/*
+ * destroy an instantiation authorisation token key
+ */
+static void request_key_auth_destroy(struct key *key)
+{
+       struct request_key_auth *rka = key->payload.data;
+
+       kenter("{%d}", key->serial);
+
+       key_put(rka->target_key);
+
+} /* end request_key_auth_destroy() */
+
+/*****************************************************************************/
+/*
+ * create a session keyring to be for the invokation of /sbin/request-key and
+ * stick an authorisation token in it
+ */
+struct key *request_key_auth_new(struct key *target, struct key **_rkakey)
+{
+       struct key *keyring, *rkakey = NULL;
+       char desc[20];
+       int ret;
+
+       kenter("%d,", target->serial);
+
+       /* allocate a new session keyring */
+       sprintf(desc, "_req.%u", target->serial);
+
+       keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL);
+       if (IS_ERR(keyring)) {
+               kleave("= %ld", PTR_ERR(keyring));
+               return keyring;
+       }
+
+       /* allocate the auth key */
+       sprintf(desc, "%x", target->serial);
+
+       rkakey = key_alloc(&key_type_request_key_auth, desc,
+                          current->fsuid, current->fsgid,
+                          KEY_USR_VIEW, 1);
+       if (IS_ERR(rkakey)) {
+               key_put(keyring);
+               kleave("= %ld", PTR_ERR(rkakey));
+               return rkakey;
+       }
+
+       /* construct and attach to the keyring */
+       ret = key_instantiate_and_link(rkakey, target, 0, keyring, NULL);
+       if (ret < 0) {
+               key_revoke(rkakey);
+               key_put(rkakey);
+               key_put(keyring);
+               kleave("= %d", ret);
+               return ERR_PTR(ret);
+       }
+
+       *_rkakey = rkakey;
+       kleave(" = {%d} ({%d})", keyring->serial, rkakey->serial);
+       return keyring;
+
+} /* end request_key_auth_new() */
+
+/*****************************************************************************/
+/*
+ * get the authorisation key for instantiation of a specific key if attached to
+ * the current process's keyrings
+ * - this key is inserted into a keyring and that is set as /sbin/request-key's
+ *   session keyring
+ * - a target_id of zero specifies any valid token
+ */
+struct key *key_get_instantiation_authkey(key_serial_t target_id)
+{
+       struct task_struct *tsk = current;
+       struct key *instkey;
+
+       /* we must have our own personal session keyring */
+       if (!tsk->signal->session_keyring)
+               return ERR_PTR(-EACCES);
+
+       /* and it must contain a suitable request authorisation key
+        * - lock RCU against session keyring changing
+        */
+       rcu_read_lock();
+
+       instkey = keyring_search_instkey(
+               rcu_dereference(tsk->signal->session_keyring), target_id);
+
+       rcu_read_unlock();
+       return instkey;
+
+} /* end key_get_instantiation_authkey() */
index 8d65b3a281297e60e09bccb4724092b31406dd7a..e446acba73d325a1d222a0a130c7f23f6a4232a9 100644 (file)
@@ -42,12 +42,21 @@ struct key_type key_type_user = {
        .read           = user_read,
 };
 
+struct user_key_payload {
+       struct rcu_head rcu;            /* RCU destructor */
+       unsigned short  datalen;        /* length of this data */
+       char            data[0];        /* actual data */
+};
+
+EXPORT_SYMBOL_GPL(key_type_user);
+
 /*****************************************************************************/
 /*
  * instantiate a user defined key
  */
 static int user_instantiate(struct key *key, const void *data, size_t datalen)
 {
+       struct user_key_payload *upayload;
        int ret;
 
        ret = -EINVAL;
@@ -58,13 +67,15 @@ static int user_instantiate(struct key *key, const void *data, size_t datalen)
        if (ret < 0)
                goto error;
 
-       /* attach the data */
        ret = -ENOMEM;
-       key->payload.data = kmalloc(datalen, GFP_KERNEL);
-       if (!key->payload.data)
+       upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
+       if (!upayload)
                goto error;
 
-       memcpy(key->payload.data, data, datalen);
+       /* attach the data */
+       upayload->datalen = datalen;
+       memcpy(upayload->data, data, datalen);
+       rcu_assign_pointer(key->payload.data, upayload);
        ret = 0;
 
  error:
@@ -75,18 +86,25 @@ static int user_instantiate(struct key *key, const void *data, size_t datalen)
 /*****************************************************************************/
 /*
  * duplicate a user defined key
+ * - both keys' semaphores are locked against further modification
+ * - the new key cannot yet be accessed
  */
 static int user_duplicate(struct key *key, const struct key *source)
 {
+       struct user_key_payload *upayload, *spayload;
        int ret;
 
        /* just copy the payload */
        ret = -ENOMEM;
-       key->payload.data = kmalloc(source->datalen, GFP_KERNEL);
+       upayload = kmalloc(sizeof(*upayload) + source->datalen, GFP_KERNEL);
+       if (upayload) {
+               spayload = rcu_dereference(source->payload.data);
+               BUG_ON(source->datalen != spayload->datalen);
+
+               upayload->datalen = key->datalen = spayload->datalen;
+               memcpy(upayload->data, spayload->data, key->datalen);
 
-       if (key->payload.data) {
-               key->datalen = source->datalen;
-               memcpy(key->payload.data, source->payload.data, source->datalen);
+               key->payload.data = upayload;
                ret = 0;
        }
 
@@ -94,42 +112,56 @@ static int user_duplicate(struct key *key, const struct key *source)
 
 } /* end user_duplicate() */
 
+/*****************************************************************************/
+/*
+ * dispose of the old data from an updated user defined key
+ */
+static void user_update_rcu_disposal(struct rcu_head *rcu)
+{
+       struct user_key_payload *upayload;
+
+       upayload = container_of(rcu, struct user_key_payload, rcu);
+
+       kfree(upayload);
+
+} /* end user_update_rcu_disposal() */
+
 /*****************************************************************************/
 /*
  * update a user defined key
+ * - the key's semaphore is write-locked
  */
 static int user_update(struct key *key, const void *data, size_t datalen)
 {
-       void *new, *zap;
+       struct user_key_payload *upayload, *zap;
        int ret;
 
        ret = -EINVAL;
        if (datalen <= 0 || datalen > 32767 || !data)
                goto error;
 
-       /* copy the data */
+       /* construct a replacement payload */
        ret = -ENOMEM;
-       new = kmalloc(datalen, GFP_KERNEL);
-       if (!new)
+       upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
+       if (!upayload)
                goto error;
 
-       memcpy(new, data, datalen);
+       upayload->datalen = datalen;
+       memcpy(upayload->data, data, datalen);
 
        /* check the quota and attach the new data */
-       zap = new;
-       write_lock(&key->lock);
+       zap = upayload;
 
        ret = key_payload_reserve(key, datalen);
 
        if (ret == 0) {
                /* attach the new data, displacing the old */
                zap = key->payload.data;
-               key->payload.data = new;
+               rcu_assign_pointer(key->payload.data, upayload);
                key->expiry = 0;
        }
 
-       write_unlock(&key->lock);
-       kfree(zap);
+       call_rcu(&zap->rcu, user_update_rcu_disposal);
 
  error:
        return ret;
@@ -152,13 +184,15 @@ static int user_match(const struct key *key, const void *description)
  */
 static void user_destroy(struct key *key)
 {
-       kfree(key->payload.data);
+       struct user_key_payload *upayload = key->payload.data;
+
+       kfree(upayload);
 
 } /* end user_destroy() */
 
 /*****************************************************************************/
 /*
- * describe the user
+ * describe the user key
  */
 static void user_describe(const struct key *key, struct seq_file *m)
 {
@@ -171,18 +205,23 @@ static void user_describe(const struct key *key, struct seq_file *m)
 /*****************************************************************************/
 /*
  * read the key data
+ * - the key's semaphore is read-locked
  */
 static long user_read(const struct key *key,
                      char __user *buffer, size_t buflen)
 {
-       long ret = key->datalen;
+       struct user_key_payload *upayload;
+       long ret;
+
+       upayload = rcu_dereference(key->payload.data);
+       ret = upayload->datalen;
 
        /* we can return the data as is */
        if (buffer && buflen > 0) {
-               if (buflen > key->datalen)
-                       buflen = key->datalen;
+               if (buflen > upayload->datalen)
+                       buflen = upayload->datalen;
 
-               if (copy_to_user(buffer, key->payload.data, buflen) != 0)
+               if (copy_to_user(buffer, upayload->data, buflen) != 0)
                        ret = -EFAULT;
        }
 
index 87302a49067bd091d3bfa970524088b929f5e298..6be273851144b0840c79f7a100cc53f269a6390d 100644 (file)
@@ -68,6 +68,7 @@
 #include <linux/personality.h>
 #include <linux/sysctl.h>
 #include <linux/audit.h>
+#include <linux/string.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -1658,9 +1659,8 @@ static int selinux_bprm_secureexec (struct linux_binprm *bprm)
 
 static void selinux_bprm_free_security(struct linux_binprm *bprm)
 {
-       struct bprm_security_struct *bsec = bprm->security;
+       kfree(bprm->security);
        bprm->security = NULL;
-       kfree(bsec);
 }
 
 extern struct vfsmount *selinuxfs_mount;
@@ -1944,7 +1944,7 @@ static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void
                }
        } while (*in_end++);
 
-       copy_page(in_save, nosec_save);
+       strcpy(in_save, nosec_save);
        free_page((unsigned long)nosec_save);
 out:
        return rc;
@@ -2477,6 +2477,17 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
                prot = reqprot;
 
 #ifndef CONFIG_PPC32
+       if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXECUTABLE) &&
+          (vma->vm_start >= vma->vm_mm->start_brk &&
+           vma->vm_end <= vma->vm_mm->brk)) {
+               /*
+                * We are making an executable mapping in the brk region.
+                * This has an additional execheap check.
+                */
+               rc = task_has_perm(current, current, PROCESS__EXECHEAP);
+               if (rc)
+                       return rc;
+       }
        if (vma->vm_file != NULL && vma->anon_vma != NULL && (prot & PROT_EXEC)) {
                /*
                 * We are making executable a file mapping that has
@@ -2488,6 +2499,16 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
                if (rc)
                        return rc;
        }
+       if (!vma->vm_file && (prot & PROT_EXEC) &&
+               vma->vm_start <= vma->vm_mm->start_stack &&
+               vma->vm_end >= vma->vm_mm->start_stack) {
+               /* Attempt to make the process stack executable.
+                * This has an additional execstack check.
+                */
+               rc = task_has_perm(current, current, PROCESS__EXECSTACK);
+               if (rc)
+                       return rc;
+       }
 #endif
 
        return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
index 8928bb4d3c538145e41e8db8c92ba1d67b4f0504..1deb59e1b76257dab1129f0050ce0f727aceeb30 100644 (file)
@@ -70,6 +70,8 @@
    S_(SECCLASS_PROCESS, PROCESS__DYNTRANSITION, "dyntransition")
    S_(SECCLASS_PROCESS, PROCESS__SETCURRENT, "setcurrent")
    S_(SECCLASS_PROCESS, PROCESS__EXECMEM, "execmem")
+   S_(SECCLASS_PROCESS, PROCESS__EXECSTACK, "execstack")
+   S_(SECCLASS_PROCESS, PROCESS__EXECHEAP, "execheap")
    S_(SECCLASS_MSGQ, MSGQ__ENQUEUE, "enqueue")
    S_(SECCLASS_MSG, MSG__SEND, "send")
    S_(SECCLASS_MSG, MSG__RECEIVE, "receive")
index bdfce4ca8f8e06366f7d831f8637b3af755a02b9..a78b5d59c9fc008f638200a1764c3a1e2e7a646e 100644 (file)
 #define PROCESS__DYNTRANSITION                    0x00800000UL
 #define PROCESS__SETCURRENT                       0x01000000UL
 #define PROCESS__EXECMEM                          0x02000000UL
+#define PROCESS__EXECSTACK                        0x04000000UL
+#define PROCESS__EXECHEAP                         0x08000000UL
 
 #define IPC__CREATE                               0x00000001UL
 #define IPC__DESTROY                              0x00000002UL
index 07221568b5059dac724b8a2c19cae9ccee6982d8..8eb140dd2e4b3bda4906f717491bb740b4450e50 100644 (file)
@@ -951,8 +951,7 @@ static int sel_make_bools(void)
        u32 sid;
 
        /* remove any existing files */
-       if (bool_pending_values)
-               kfree(bool_pending_values);
+       kfree(bool_pending_values);
 
        sel_remove_bools(dir);
 
@@ -997,10 +996,8 @@ static int sel_make_bools(void)
 out:
        free_page((unsigned long)page);
        if (names) {
-               for (i = 0; i < num; i++) {
-                       if (names[i])
-                               kfree(names[i]);
-               }
+               for (i = 0; i < num; i++)
+                       kfree(names[i]);
                kfree(names);
        }
        return ret;
index b53441184aca727a5a2ba15c14969004cc6c9a15..e2057f5a411a470372efcf919bfa502daa5149d9 100644 (file)
@@ -166,16 +166,14 @@ static void cond_list_destroy(struct cond_node *list)
 
 void cond_policydb_destroy(struct policydb *p)
 {
-       if (p->bool_val_to_struct != NULL)
-               kfree(p->bool_val_to_struct);
+       kfree(p->bool_val_to_struct);
        avtab_destroy(&p->te_cond_avtab);
        cond_list_destroy(p->cond_list);
 }
 
 int cond_init_bool_indexes(struct policydb *p)
 {
-       if (p->bool_val_to_struct)
-               kfree(p->bool_val_to_struct);
+       kfree(p->bool_val_to_struct);
        p->bool_val_to_struct = (struct cond_bool_datum**)
                kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum*), GFP_KERNEL);
        if (!p->bool_val_to_struct)
@@ -185,8 +183,7 @@ int cond_init_bool_indexes(struct policydb *p)
 
 int cond_destroy_bool(void *key, void *datum, void *p)
 {
-       if (key)
-               kfree(key);
+       kfree(key);
        kfree(datum);
        return 0;
 }
index 14190efbf333b83c8d270ec83af2d5e7628f21a6..785c33cf486491afc6b2d50d568d5db884b31723 100644 (file)
@@ -590,17 +590,12 @@ void policydb_destroy(struct policydb *p)
                hashtab_destroy(p->symtab[i].table);
        }
 
-       for (i = 0; i < SYM_NUM; i++) {
-               if (p->sym_val_to_name[i])
-                       kfree(p->sym_val_to_name[i]);
-       }
+       for (i = 0; i < SYM_NUM; i++)
+               kfree(p->sym_val_to_name[i]);
 
-       if (p->class_val_to_struct)
-               kfree(p->class_val_to_struct);
-       if (p->role_val_to_struct)
-               kfree(p->role_val_to_struct);
-       if (p->user_val_to_struct)
-               kfree(p->user_val_to_struct);
+       kfree(p->class_val_to_struct);
+       kfree(p->role_val_to_struct);
+       kfree(p->user_val_to_struct);
 
        avtab_destroy(&p->te_avtab);
 
index b6149147d5cb6ef585f09846d03819f454259e45..922bb45054aa415acd3d4efaa24242d85f39d072 100644 (file)
@@ -1705,11 +1705,9 @@ out:
 err:
        if (*names) {
                for (i = 0; i < *len; i++)
-                       if ((*names)[i])
-                               kfree((*names)[i]);
+                       kfree((*names)[i]);
        }
-       if (*values)
-               kfree(*values);
+       kfree(*values);
        goto out;
 }
 
index e537bd66a707795e1e2edcec4483fbe0977f87dd..7bd95ceab7cc62ab59339a4854dc0bc834b0eebd 100644 (file)
@@ -6,7 +6,7 @@
 # Prompt user for primary drivers.
 config SOUND_BT878
        tristate "BT878 audio dma"
-       depends on SOUND_PRIME!=n && SOUND
+       depends on SOUND_PRIME
        ---help---
          Audio DMA support for bt878 based grabber boards.  As you might have
          already noticed, bt878 is listed with two functions in /proc/pci.
@@ -22,7 +22,7 @@ config SOUND_BT878
 
 config SOUND_CMPCI
        tristate "C-Media PCI (CMI8338/8738)"
-       depends on SOUND_PRIME!=n && SOUND && PCI
+       depends on SOUND_PRIME && PCI
        help
          Say Y or M if you have a PCI sound card using the CMI8338
          or the CMI8738 chipset.  Data on these chips are available at
@@ -52,7 +52,7 @@ config SOUND_CMPCI_MIDI
 
 config SOUND_CMPCI_JOYSTICK
        bool "Enable joystick"
-       depends on SOUND_CMPCI && X86
+       depends on SOUND_CMPCI && X86 && (GAMEPORT=y || SOUND_CMPCI=GAMEPORT)
        help
          Say Y here in order to enable the joystick port on a sound card using
          the CMI8338 or the CMI8738 chipset.  You need to config the
@@ -61,7 +61,7 @@ config SOUND_CMPCI_JOYSTICK
 
 config SOUND_EMU10K1
        tristate "Creative SBLive! (EMU10K1)"
-       depends on SOUND_PRIME!=n && SOUND && PCI
+       depends on SOUND_PRIME && PCI
        ---help---
          Say Y or M if you have a PCI sound card using the EMU10K1 chipset,
          such as the Creative SBLive!, SB PCI512 or Emu-APS.
@@ -87,7 +87,7 @@ config MIDI_EMU10K1
 
 config SOUND_FUSION
        tristate "Crystal SoundFusion (CS4280/461x)"
-       depends on SOUND_PRIME!=n && SOUND
+       depends on SOUND_PRIME
        help
          This module drives the Crystal SoundFusion devices (CS4280/46xx
          series) when wired as native sound drivers with AC97 codecs.  If
@@ -95,14 +95,14 @@ config SOUND_FUSION
 
 config SOUND_CS4281
        tristate "Crystal Sound CS4281"
-       depends on SOUND_PRIME!=n && SOUND
+       depends on SOUND_PRIME
        help
          Picture and feature list at
          <http://www.pcbroker.com/crystal4281.html>.
 
 config SOUND_BCM_CS4297A
        tristate "Crystal Sound CS4297a (for Swarm)"
-       depends on SOUND_PRIME!=n && SIBYTE_SWARM && SOUND
+       depends on SOUND_PRIME && SIBYTE_SWARM
        help
          The BCM91250A has a Crystal CS4297a on synchronous serial
          port B (in addition to the DB-9 serial port).  Say Y or M
@@ -112,7 +112,7 @@ config SOUND_BCM_CS4297A
 
 config SOUND_ES1370
        tristate "Ensoniq AudioPCI (ES1370)"
-       depends on SOUND_PRIME!=n && SOUND && PCI
+       depends on SOUND_PRIME && PCI
        help
          Say Y or M if you have a PCI sound card utilizing the Ensoniq
          ES1370 chipset, such as Ensoniq's AudioPCI (non-97). To find
@@ -125,7 +125,7 @@ config SOUND_ES1370
 
 config SOUND_ES1371
        tristate "Creative Ensoniq AudioPCI 97 (ES1371)"
-       depends on SOUND_PRIME!=n && SOUND && PCI
+       depends on SOUND_PRIME && PCI
        help
          Say Y or M if you have a PCI sound card utilizing the Ensoniq
          ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if
@@ -138,7 +138,7 @@ config SOUND_ES1371
 
 config SOUND_ESSSOLO1
        tristate "ESS Technology Solo1" 
-       depends on SOUND_PRIME!=n && SOUND && PCI
+       depends on SOUND_PRIME && PCI
        help
          Say Y or M if you have a PCI sound card utilizing the ESS Technology
          Solo1 chip. To find out if your sound card uses a
@@ -149,7 +149,7 @@ config SOUND_ESSSOLO1
 
 config SOUND_MAESTRO
        tristate "ESS Maestro, Maestro2, Maestro2E driver"
-       depends on SOUND_PRIME!=n && SOUND && PCI
+       depends on SOUND_PRIME && PCI
        help
          Say Y or M if you have a sound system driven by ESS's Maestro line
          of PCI sound chips.  These include the Maestro 1, Maestro 2, and
@@ -158,28 +158,28 @@ config SOUND_MAESTRO
 
 config SOUND_MAESTRO3
        tristate "ESS Maestro3/Allegro driver (EXPERIMENTAL)"
-       depends on SOUND_PRIME!=n && SOUND && PCI && EXPERIMENTAL
+       depends on SOUND_PRIME && PCI && EXPERIMENTAL
        help
          Say Y or M if you have a sound system driven by ESS's Maestro 3
          PCI sound chip.
 
 config SOUND_ICH
        tristate "Intel ICH (i8xx) audio support"
-       depends on SOUND_PRIME!=n && PCI
+       depends on SOUND_PRIME && PCI
        help
          Support for integral audio in Intel's I/O Controller Hub (ICH)
          chipset, as used on the 810/820/840 motherboards.
 
 config SOUND_HARMONY
        tristate "PA Harmony audio driver"
-       depends on GSC_LASI && SOUND_PRIME!=n
+       depends on GSC_LASI && SOUND_PRIME
        help
          Say 'Y' or 'M' to include support for Harmony soundchip
          on HP 712, 715/new and many other GSC based machines.
 
 config SOUND_SONICVIBES
        tristate "S3 SonicVibes"
-       depends on SOUND_PRIME!=n && SOUND
+       depends on SOUND_PRIME
        help
          Say Y or M if you have a PCI sound card utilizing the S3
          SonicVibes chipset. To find out if your sound card uses a
@@ -190,7 +190,7 @@ config SOUND_SONICVIBES
 
 config SOUND_VWSND
        tristate "SGI Visual Workstation Sound"
-       depends on SOUND_PRIME!=n && X86_VISWS && SOUND
+       depends on SOUND_PRIME && X86_VISWS
        help
          Say Y or M if you have an SGI Visual Workstation and you want to be
          able to use its on-board audio.  Read
@@ -199,18 +199,18 @@ config SOUND_VWSND
 
 config SOUND_HAL2
        tristate "SGI HAL2 sound (EXPERIMENTAL)"
-       depends on SOUND_PRIME!=n && SOUND && SGI_IP22 && EXPERIMENTAL
+       depends on SOUND_PRIME && SGI_IP22 && EXPERIMENTAL
        help
          Say Y or M if you have an SGI Indy system and want to be able to
          use it's on-board A2 audio system.
 
 config SOUND_IT8172
        tristate "IT8172G Sound"
-       depends on SOUND_PRIME!=n && (MIPS_ITE8172 || MIPS_IVR) && SOUND
+       depends on SOUND_PRIME && (MIPS_ITE8172 || MIPS_IVR)
 
 config SOUND_VRC5477
        tristate "NEC Vrc5477 AC97 sound"
-       depends on SOUND_PRIME!=n && DDB5477 && SOUND
+       depends on SOUND_PRIME && DDB5477
        help
          Say Y here to enable sound support for the NEC Vrc5477 chip, an
          integrated, multi-function controller chip for MIPS CPUs.  Works
@@ -218,15 +218,15 @@ config SOUND_VRC5477
 
 config SOUND_AU1000
        tristate "Au1000 Sound"
-       depends on SOUND_PRIME!=n && (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) && SOUND
+       depends on SOUND_PRIME && (SOC_AU1000 || SOC_AU1100 || SOC_AU1500)
 
 config SOUND_AU1550_AC97
        tristate "Au1550 AC97 Sound"
-       depends on SOUND_PRIME!=n && SOC_AU1550 && SOUND
+       depends on SOUND_PRIME && SOC_AU1550
 
 config SOUND_TRIDENT
        tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core"
-       depends on SOUND_PRIME!=n && SOUND
+       depends on SOUND_PRIME
        ---help---
          Say Y or M if you have a PCI sound card utilizing the Trident
          4DWave-DX/NX chipset or your mother board chipset has SiS 7018
@@ -267,7 +267,7 @@ config SOUND_TRIDENT
 
 config SOUND_MSNDCLAS
        tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
-       depends on SOUND_PRIME!=n && SOUND && (m || !STANDALONE)
+       depends on SOUND_PRIME && (m || !STANDALONE)
        help
          Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
          Monterey (not for the Pinnacle or Fiji).
@@ -331,7 +331,7 @@ config MSNDCLAS_IO
 
 config SOUND_MSNDPIN
        tristate "Support for Turtle Beach MultiSound Pinnacle, Fiji"
-       depends on SOUND_PRIME!=n && SOUND && (m || !STANDALONE)
+       depends on SOUND_PRIME && (m || !STANDALONE)
        help
          Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji.
          See <file:Documentation/sound/oss/MultiSound> for important information
@@ -492,7 +492,7 @@ config MSND_FIFOSIZE
 
 config SOUND_VIA82CXXX
        tristate "VIA 82C686 Audio Codec"
-       depends on SOUND_PRIME!=n && PCI
+       depends on SOUND_PRIME && PCI
        help
          Say Y here to include support for the audio codec found on VIA
          82Cxxx-based chips. Typically these are built into a motherboard.
@@ -512,7 +512,7 @@ config MIDI_VIA82CXXX
 
 config SOUND_OSS
        tristate "OSS sound modules"
-       depends on SOUND_PRIME!=n && SOUND
+       depends on SOUND_PRIME
        help
          OSS is the Open Sound System suite of sound card drivers.  They make
          sound programming easier since they provide a common API.  Say Y or
@@ -1077,7 +1077,7 @@ config SOUND_WAVEARTIST
 
 config SOUND_TVMIXER
        tristate "TV card (bt848) mixer support"
-       depends on SOUND_PRIME!=n && SOUND && I2C
+       depends on SOUND_PRIME && I2C
        help
          Support for audio mixer facilities on the BT848 TV frame-grabber
          card.
@@ -1088,11 +1088,11 @@ config SOUND_KAHLUA
 
 config SOUND_ALI5455
        tristate "ALi5455 audio support"
-       depends on SOUND_PRIME!=n && PCI
+       depends on SOUND_PRIME && PCI
 
 config SOUND_FORTE
        tristate "ForteMedia FM801 driver"
-       depends on SOUND_PRIME!=n && PCI
+       depends on SOUND_PRIME && PCI
        help
          Say Y or M if you want driver support for the ForteMedia FM801 PCI
          audio controller (Abit AU10, Genius Sound Maker, HP Workstation
@@ -1100,7 +1100,7 @@ config SOUND_FORTE
 
 config SOUND_RME96XX
        tristate "RME Hammerfall (RME96XX) support"
-       depends on SOUND_PRIME!=n && PCI
+       depends on SOUND_PRIME && PCI
        help
          Say Y or M if you have a Hammerfall or Hammerfall light
          multichannel card from RME. If you want to access advanced
@@ -1108,11 +1108,11 @@ config SOUND_RME96XX
 
 config SOUND_AD1980
        tristate "AD1980 front/back switch plugin"
-       depends on SOUND_PRIME!=n
+       depends on SOUND_PRIME
 
 config SOUND_SH_DAC_AUDIO
        tristate "SuperH DAC audio support"
-       depends on SOUND_PRIME!=n && SOUND && CPU_SH3
+       depends on SOUND_PRIME && CPU_SH3
 
 config SOUND_SH_DAC_AUDIO_CHANNEL
        int "    DAC channel"
index 22dae5d0fda3f392f787b46cc5f0fc943fdc4207..95586de02028cf57d4a628044885953b92ba57f0 100644 (file)
@@ -592,7 +592,7 @@ typedef struct mixer_def mixer_ent;
   {{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r}}
 
 
-mixer_ent mix_devices[SOUND_MIXER_NRDEVICES][2] = {
+static mixer_ent mix_devices[SOUND_MIXER_NRDEVICES][2] = {
 MIX_ENT(SOUND_MIXER_VOLUME,    14, 1, 8, 5,    14, 1, 0, 5),
 MIX_ENT(SOUND_MIXER_BASS,       0, 0, 0, 0,     0, 0, 0, 0),
 MIX_ENT(SOUND_MIXER_TREBLE,     0, 0, 0, 0,     0, 0, 0, 0),
index 4384dac3f7949008285e71f94eec5123e27050b9..7c835abd99bc9ab2abc919b3cb8da9c48341004c 100644 (file)
@@ -2178,8 +2178,7 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int
                
        if (devc != NULL)
        {
-               if(audio_devs[dev]->portc!=NULL)
-                       kfree(audio_devs[dev]->portc);
+               kfree(audio_devs[dev]->portc);
                release_region(devc->base, 4);
 
                if (!share_dma)
index b767c621fd09060ebd5575e4b8a3a9382c69e0ea..2cfd214e4c2a42e0b48f6f4c134e131bc8a03166 100644 (file)
@@ -277,8 +277,7 @@ static void ad1889_free_dev(ad1889_dev_t *dev)
 
        for (j = 0; j < AD_MAX_STATES; j++) {
                dmabuf = &dev->state[j].dmabuf;
-               if (dmabuf->rawbuf != NULL) 
-                       kfree(dmabuf->rawbuf);
+               kfree(dmabuf->rawbuf);
        }
 
        kfree(dev);
index 34720e66dae1b1f6e071427c3a410d044e9ff5b1..74dcca78c6c0c8c7697bf038450ccc1258f5ba4a 100644 (file)
 #include <linux/smp_lock.h>
 #include <linux/bitops.h>
 #include <linux/wait.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/page.h>
@@ -3058,7 +3059,7 @@ static int __devinit cm_probe(struct pci_dev *pcidev, const struct pci_device_id
                return -ENODEV;
        if (pcidev->irq == 0)
                return -ENODEV;
-       i = pci_set_dma_mask(pcidev, 0xffffffff);
+       i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
        if (i) {
                printk(KERN_WARNING "cmpci: architecture does not support 32bit PCI busmaster DMA\n");
                return i;
index 5281b88987f35bc30f56c0bbe3b5633f24ec2116..2704e1598addd4438a9bb1bd7d8b0c1611e1d08b 100644 (file)
@@ -255,7 +255,7 @@ static int awacs_burgundy_read_mvolume(unsigned address);
 
 static volatile struct dbdma_cmd *emergency_dbdma_cmd;
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 /*
  * Stuff for restoring after a sleep.
  */
@@ -263,7 +263,7 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
 struct pmu_sleep_notifier awacs_sleep_notifier = {
        awacs_sleep_notify, SLEEP_LEVEL_SOUND,
 };
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
 /* for (soft) sample rate translations */
 int expand_bal;                /* Balance factor for expanding (not volume!) */
@@ -671,15 +671,11 @@ static void PMacIrqCleanup(void)
        release_OF_resource(awacs_node, 1);
        release_OF_resource(awacs_node, 2);
 
-       if (awacs_tx_cmd_space)
-               kfree(awacs_tx_cmd_space);
-       if (awacs_rx_cmd_space)
-               kfree(awacs_rx_cmd_space);
-       if (beep_dbdma_cmd_space)
-               kfree(beep_dbdma_cmd_space);
-       if (beep_buf)
-               kfree(beep_buf);
-#ifdef CONFIG_PMAC_PBOOK
+       kfree(awacs_tx_cmd_space);
+       kfree(awacs_rx_cmd_space);
+       kfree(beep_dbdma_cmd_space);
+       kfree(beep_buf);
+#ifdef CONFIG_PM
        pmu_unregister_sleep_notifier(&awacs_sleep_notifier);
 #endif
 }
@@ -1419,7 +1415,7 @@ load_awacs(void)
        }
 }
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 /*
  * Save state when going to sleep, restore it afterwards.
  */
@@ -1555,7 +1551,7 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
        }
        return PBOOK_SLEEP_OK;
 }
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
 
 /* All the burgundy functions: */
@@ -2301,8 +2297,7 @@ if (count <= 0)
 #endif
 
        if ((write_sq.max_count + 1) > number_of_tx_cmd_buffers) {
-               if (awacs_tx_cmd_space)
-                       kfree(awacs_tx_cmd_space);
+               kfree(awacs_tx_cmd_space);
                number_of_tx_cmd_buffers = 0;
 
                /* we need nbufs + 1 (for the loop) and we should request + 1
@@ -2360,8 +2355,7 @@ if (count <= 0)
 #endif
 
        if ((read_sq.max_count+1) > number_of_rx_cmd_buffers ) {
-               if (awacs_rx_cmd_space)
-                       kfree(awacs_rx_cmd_space);
+               kfree(awacs_rx_cmd_space);
                number_of_rx_cmd_buffers = 0;
 
                /* we need nbufs + 1 (for the loop) and we should request + 1 again
@@ -2805,7 +2799,7 @@ __init setup_beep(void)
        beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
        if (beep_buf == NULL) {
                printk(KERN_ERR "dmasound_pmac: no memory for beep buffer\n");
-               if( beep_dbdma_cmd_space ) kfree(beep_dbdma_cmd_space) ;
+               kfree(beep_dbdma_cmd_space) ;
                return -ENOMEM ;
        }
        return 0 ;
@@ -3059,9 +3053,9 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev);
        if ((res=setup_beep()))
                return res ;
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
        pmu_register_sleep_notifier(&awacs_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
        /* Powerbooks have odd ways of enabling inputs such as
           an expansion-bay CD or sound from an internal modem
index 33dea3d56c1e138bdc461e8f255bce857104766a..b40b5f97aacea3a5240b845e10745dcc77c22cf3 100644 (file)
@@ -523,10 +523,8 @@ void emu10k1_seq_midi_close(int dev)
        card = midi_devs[dev]->devc;
        emu10k1_mpuout_close(card);
 
-       if (card->seq_mididev) {
-               kfree(card->seq_mididev);
-               card->seq_mididev = NULL;
-       }
+       kfree(card->seq_mididev);
+       card->seq_mididev = NULL;
 }
 
 int emu10k1_seq_midi_out(int dev, unsigned char midi_byte)
index 4094be55f3be335338fd120224a0fba22c6ce711..4e3baca7d41f3d2856accd469e0292d749a07e47 100644 (file)
@@ -213,8 +213,7 @@ void emu10k1_pt_stop(struct emu10k1_card *card)
                                sblive_writeptr(card, SPCS0 + i, 0, pt->old_spcs[i]);
                }
                pt->state = PT_STATE_INACTIVE;
-               if(pt->buf)
-                       kfree(pt->buf);
+               kfree(pt->buf);
        }
 }
 
index 056091cff2663343938d139245b1e5bb0e6708d1..8538085086e7c1e47f562d3d8d237286ebebab7a 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/gameport.h>
 #include <linux/wait.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/page.h>
 #include <asm/uaccess.h>
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK
+#endif
+
 /* --------------------------------------------------------------------- */
 
 #undef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -384,7 +389,10 @@ struct es1370_state {
                unsigned char obuf[MIDIOUTBUF];
        } midi;
 
+#ifdef SUPPORT_JOYSTICK
        struct gameport *gameport;
+#endif
+
        struct semaphore sem;
 };
 
@@ -2553,10 +2561,55 @@ static struct initvol {
        { SOUND_MIXER_WRITE_OGAIN, 0x4040 }
 };
 
+#ifdef SUPPORT_JOYSTICK
+
+static int __devinit es1370_register_gameport(struct es1370_state *s)
+{
+       struct gameport *gp;
+
+       if (!request_region(0x200, JOY_EXTENT, "es1370")) {
+               printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
+               return -EBUSY;
+       }
+
+       s->gameport = gp = gameport_allocate_port();
+       if (!gp) {
+               printk(KERN_ERR "es1370: can not allocate memory for gameport\n");
+               release_region(0x200, JOY_EXTENT);
+               return -ENOMEM;
+       }
+
+       gameport_set_name(gp, "ESS1370");
+       gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
+       gp->dev.parent = &s->dev->dev;
+       gp->io = 0x200;
+
+       s->ctrl |= CTRL_JYSTK_EN;
+       outl(s->ctrl, s->io + ES1370_REG_CONTROL);
+
+       gameport_register_port(gp);
+
+       return 0;
+}
+
+static inline void es1370_unregister_gameport(struct es1370_state *s)
+{
+       if (s->gameport) {
+               int gpio = s->gameport->io;
+               gameport_unregister_port(s->gameport);
+               release_region(gpio, JOY_EXTENT);
+
+       }
+}
+
+#else
+static inline int es1370_register_gameport(struct es1370_state *s) { return -ENOSYS; }
+static inline void es1370_unregister_gameport(struct es1370_state *s) { }
+#endif /* SUPPORT_JOYSTICK */
+
 static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
        struct es1370_state *s;
-       struct gameport *gp = NULL;
        mm_segment_t fs;
        int i, val, ret;
 
@@ -2569,7 +2622,7 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic
                return -ENODEV;
        if (pcidev->irq == 0) 
                return -ENODEV;
-       i = pci_set_dma_mask(pcidev, 0xffffffff);
+       i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
        if (i) {
                printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n");
                return i;
@@ -2605,28 +2658,14 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic
        /* note: setting CTRL_SERR_DIS is reported to break
         * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
        s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
-       if (!request_region(0x200, JOY_EXTENT, "es1370")) {
-               printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
-       } else if (!(s->gameport = gp = gameport_allocate_port())) {
-               printk(KERN_ERR "es1370: can not allocate memory for gameport\n");
-               release_region(0x200, JOY_EXTENT);
-       } else {
-               gameport_set_name(gp, "ESS1370");
-               gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
-               gp->dev.parent = &s->dev->dev;
-               gp->io = 0x200;
-               s->ctrl |= CTRL_JYSTK_EN;
-       }
        if (lineout[devindex])
                s->ctrl |= CTRL_XCTL0;
        if (micbias[devindex])
                s->ctrl |= CTRL_XCTL1;
        s->sctrl = 0;
-       printk(KERN_INFO "es1370: found adapter at io %#lx irq %u\n"
-              KERN_INFO "es1370: features: joystick %s, line %s, mic impedance %s\n",
-              s->io, s->irq, (s->ctrl & CTRL_JYSTK_EN) ? "on" : "off",
-              (s->ctrl & CTRL_XCTL0) ? "out" : "in",
-                      (s->ctrl & CTRL_XCTL1) ? "1" : "0");
+       printk(KERN_INFO "es1370: adapter at io %#lx irq %u, line %s, mic impedance %s\n",
+              s->io, s->irq, (s->ctrl & CTRL_XCTL0) ? "out" : "in",
+              (s->ctrl & CTRL_XCTL1) ? "1" : "0");
        /* register devices */
        if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops, -1)) < 0) {
                ret = s->dev_audio;
@@ -2672,9 +2711,7 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic
        }
        set_fs(fs);
 
-       /* register gameport */
-       if (gp)
-               gameport_register_port(gp);
+       es1370_register_gameport(s);
 
        /* store it in the driver field */
        pci_set_drvdata(pcidev, s);
@@ -2696,10 +2733,6 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic
  err_dev1:
        printk(KERN_ERR "es1370: cannot register misc device\n");
        free_irq(s->irq, s);
-       if (s->gameport) {
-               release_region(s->gameport->io, JOY_EXTENT);
-               gameport_free_port(s->gameport);
-       }
  err_irq:
        release_region(s->io, ES1370_EXTENT);
  err_region:
@@ -2718,11 +2751,7 @@ static void __devexit es1370_remove(struct pci_dev *dev)
        outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */
        synchronize_irq(s->irq);
        free_irq(s->irq, s);
-       if (s->gameport) {
-               int gpio = s->gameport->io;
-               gameport_unregister_port(s->gameport);
-               release_region(gpio, JOY_EXTENT);
-       }
+       es1370_unregister_gameport(s);
        release_region(s->io, ES1370_EXTENT);
        unregister_sound_dsp(s->dev_audio);
        unregister_sound_mixer(s->dev_mixer);
index a50fddaeea2163c94cab2eaea8144fe42c207941..12a56d5ab4985e34cda8996aba25a2221e9b439e 100644 (file)
 #include <linux/ac97_codec.h>
 #include <linux/gameport.h>
 #include <linux/wait.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/page.h>
 #include <asm/uaccess.h>
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK
+#endif
+
 /* --------------------------------------------------------------------- */
 
 #undef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -453,7 +458,10 @@ struct es1371_state {
                unsigned char obuf[MIDIOUTBUF];
        } midi;
 
+#ifdef SUPPORT_JOYSTICK
        struct gameport *gameport;
+#endif
+
        struct semaphore sem;
 };
 
@@ -2786,12 +2794,63 @@ static struct
        { PCI_ANY_ID, PCI_ANY_ID }
 };
 
+#ifdef SUPPORT_JOYSTICK
+
+static int __devinit es1371_register_gameport(struct es1371_state *s)
+{
+       struct gameport *gp;
+       int gpio;
+
+       for (gpio = 0x218; gpio >= 0x200; gpio -= 0x08)
+               if (request_region(gpio, JOY_EXTENT, "es1371"))
+                       break;
+
+       if (gpio < 0x200) {
+               printk(KERN_ERR PFX "no free joystick address found\n");
+               return -EBUSY;
+       }
+
+       s->gameport = gp = gameport_allocate_port();
+       if (!gp) {
+               printk(KERN_ERR PFX "can not allocate memory for gameport\n");
+               release_region(gpio, JOY_EXTENT);
+               return -ENOMEM;
+       }
+
+       gameport_set_name(gp, "ESS1371 Gameport");
+       gameport_set_phys(gp, "isa%04x/gameport0", gpio);
+       gp->dev.parent = &s->dev->dev;
+       gp->io = gpio;
+
+       s->ctrl |= CTRL_JYSTK_EN | (((gpio >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
+       outl(s->ctrl, s->io + ES1371_REG_CONTROL);
+
+       gameport_register_port(gp);
+
+       return 0;
+}
+
+static inline void es1371_unregister_gameport(struct es1371_state *s)
+{
+       if (s->gameport) {
+               int gpio = s->gameport->io;
+               gameport_unregister_port(s->gameport);
+               release_region(gpio, JOY_EXTENT);
+
+       }
+}
+
+#else
+static inline int es1371_register_gameport(struct es1371_state *s) { return -ENOSYS; }
+static inline void es1371_unregister_gameport(struct es1371_state *s) { }
+#endif /* SUPPORT_JOYSTICK */
+
+
 static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
        struct es1371_state *s;
-       struct gameport *gp;
        mm_segment_t fs;
-       int i, gpio, val, res = -1;
+       int i, val, res = -1;
        int idx;
        unsigned long tmo;
        signed long tmo2;
@@ -2804,7 +2863,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
                return -ENODEV;
        if (pcidev->irq == 0) 
                return -ENODEV;
-       i = pci_set_dma_mask(pcidev, 0xffffffff);
+       i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
        if (i) {
                printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n");
                return i;
@@ -2882,23 +2941,6 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
                }
        }
 
-       for (gpio = 0x218; gpio >= 0x200; gpio -= 0x08)
-               if (request_region(gpio, JOY_EXTENT, "es1371"))
-                       break;
-
-       if (gpio < 0x200) {
-               printk(KERN_ERR PFX "no free joystick address found\n");
-       } else if (!(s->gameport = gp = gameport_allocate_port())) {
-               printk(KERN_ERR PFX "can not allocate memory for gameport\n");
-               release_region(gpio, JOY_EXTENT);
-       } else {
-               gameport_set_name(gp, "ESS1371 Gameport");
-               gameport_set_phys(gp, "isa%04x/gameport0", gpio);
-               gp->dev.parent = &s->dev->dev;
-               gp->io = gpio;
-               s->ctrl |= CTRL_JYSTK_EN | (((gpio >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
-       }
-
        s->sctrl = 0;
        cssr = 0;
        s->spdif_volume = -1;
@@ -2968,9 +3010,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
        /* turn on S/PDIF output driver if requested */
        outl(cssr, s->io+ES1371_REG_STATUS);
 
-       /* register gameport */
-       if (s->gameport)
-               gameport_register_port(s->gameport);
+       es1371_register_gameport(s);
 
        /* store it in the driver field */
        pci_set_drvdata(pcidev, s);
@@ -2979,13 +3019,9 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
        /* increment devindex */
        if (devindex < NR_DEVICE-1)
                devindex++;
-               return 0;
+       return 0;
 
  err_gp:
-       if (s->gameport) {
-               release_region(s->gameport->io, JOY_EXTENT);
-               gameport_free_port(s->gameport);
-       }
 #ifdef ES1371_DEBUG
        if (s->ps)
                remove_proc_entry("es1371", NULL);
@@ -3024,11 +3060,7 @@ static void __devexit es1371_remove(struct pci_dev *dev)
        outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
        synchronize_irq(s->irq);
        free_irq(s->irq, s);
-       if (s->gameport) {
-               int gpio = s->gameport->io;
-               gameport_unregister_port(s->gameport);
-               release_region(gpio, JOY_EXTENT);
-       }
+       es1371_unregister_gameport(s);
        release_region(s->io, ES1371_EXTENT);
        unregister_sound_dsp(s->dev_audio);
        unregister_sound_mixer(s->codec->dev_mixer);
index 6b3b9a99579dbf8fb05490e889a05d8dbcf4a3c3..a4ecab2f05226255028aa06a7ac26197d848bc20 100644 (file)
 #include <linux/smp_lock.h>
 #include <linux/gameport.h>
 #include <linux/wait.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/page.h>
 
 #define FMODE_DMFM 0x10
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
 static struct pci_driver solo1_driver;
 
 /* --------------------------------------------------------------------- */
@@ -226,7 +231,9 @@ struct solo1_state {
                unsigned char obuf[MIDIOUTBUF];
        } midi;
 
+#if SUPPORT_JOYSTICK
        struct gameport *gameport;
+#endif
 };
 
 /* --------------------------------------------------------------------- */
@@ -2280,6 +2287,7 @@ solo1_resume(struct pci_dev *pci_dev) {
        return 0;
 }
 
+#ifdef SUPPORT_JOYSTICK
 static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port)
 {
        struct gameport *gp;
@@ -2306,6 +2314,19 @@ static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port)
        return 0;
 }
 
+static inline void solo1_unregister_gameport(struct solo1_state *s)
+{
+       if (s->gameport) {
+               int gpio = s->gameport->io;
+               gameport_unregister_port(s->gameport);
+               release_region(gpio, GAMEPORT_EXTENT);
+       }
+}
+#else
+static inline int solo1_register_gameport(struct solo1_state *s, int io_port) { return -ENOSYS; }
+static inline void solo1_unregister_gameport(struct solo1_state *s) { }
+#endif /* SUPPORT_JOYSTICK */
+
 static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
        struct solo1_state *s;
@@ -2326,7 +2347,7 @@ static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device
         * to 24 bits first, then 32 bits (playback only) if that fails.
         */
        if (pci_set_dma_mask(pcidev, 0x00ffffff) &&
-           pci_set_dma_mask(pcidev, 0xffffffff)) {
+           pci_set_dma_mask(pcidev, DMA_32BIT_MASK)) {
                printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n");
                return -ENODEV;
        }
@@ -2437,11 +2458,7 @@ static void __devexit solo1_remove(struct pci_dev *dev)
        synchronize_irq(s->irq);
        pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */
        free_irq(s->irq, s);
-       if (s->gameport) {
-               int gpio = s->gameport->io;
-               gameport_unregister_port(s->gameport);
-               release_region(gpio, GAMEPORT_EXTENT);
-       }
+       solo1_unregister_gameport(s);
        release_region(s->iobase, IOBASE_EXTENT);
        release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
        release_region(s->ddmabase, DDMABASE_EXTENT);
index a7067f169919c0b163c2ab4ad48b51136143634e..aa3c50db66c49d589102e6b68bd4f4c5b9075c47 100644 (file)
 #include "sb.h"
 #include "mpu401.h"
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
 static int      mad16_conf;
 static int      mad16_cdsel;
-static struct gameport *gameport;
 static DEFINE_SPINLOCK(lock);
 
 #define C928   1
@@ -902,6 +905,10 @@ static int __initdata irq_map[16] =
        -1, -1, -1, -1
 };
 
+#ifdef SUPPORT_JOYSTICK
+
+static struct gameport *gameport;
+
 static int __devinit mad16_register_gameport(int io_port)
 {
        if (!request_region(io_port, 1, "mad16 gameport")) {
@@ -925,6 +932,20 @@ static int __devinit mad16_register_gameport(int io_port)
        return 0;
 }
 
+static inline void mad16_unregister_gameport(void)
+{
+       if (gameport) {
+               /* the gameport was initialized so we must free it up */
+               gameport_unregister_port(gameport);
+               gameport = NULL;
+               release_region(0x201, 1);
+       }
+}
+#else
+static inline int mad16_register_gameport(int io_port) { return -ENOSYS; }
+static inline void mad16_unregister_gameport(void) { }
+#endif
+
 static int __devinit init_mad16(void)
 {
        int dmatype = 0;
@@ -1060,12 +1081,7 @@ static void __exit cleanup_mad16(void)
 {
        if (found_mpu)
                unload_mad16_mpu(&cfg_mpu);
-       if (gameport) {
-               /* the gameport was initialized so we must free it up */
-               gameport_unregister_port(gameport);
-               gameport = NULL;
-               release_region(0x201, 1);
-       }
+       mad16_unregister_gameport();
        unload_mad16(&cfg);
        release_region(MC0_PORT, 12);
 }
index 52d2db4bc312fadeddff95c9f1d8d0f3fba80823..3dce504e6d6d764ee330e47392238553e7fccf8a 100644 (file)
@@ -2356,7 +2356,7 @@ ess_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
        }
 
 rec_return_free:
-       if(combbuf) kfree(combbuf);
+       kfree(combbuf);
        return ret;
 }
 
index b66f53fa8db03ca57296ba6ea091579440f82639..0aac54c68f01fa13c124ee5715c4f6f0b9b23124 100644 (file)
@@ -1240,8 +1240,7 @@ void unload_mpu401(struct address_info *hw_config)
                p=mpu401_synth_operations[n];
                sound_unload_mididev(n);
                sound_unload_timerdev(hw_config->slots[2]);
-               if(p)
-                       kfree(p);
+               kfree(p);
        }
 }
 
index eae7d99d6826300d94cd82d5d1850654c196d5b9..21e07b5081f2bdb5ad44fc453bd0c7ca60ec5ac8 100644 (file)
@@ -128,9 +128,6 @@ struct nm256_info
     struct nm256_info *next_card;
 };
 
-/* Debug flag--bigger numbers mean more output. */
-extern int nm256_debug;
-
 /* The BIOS signature. */
 #define NM_SIGNATURE 0x4e4d0000
 /* Signature mask. */
@@ -284,7 +281,7 @@ nm256_readBuffer8 (struct nm256_info *card, u8 *dst, int port, int offset,
 }
 
 /* Returns a non-zero value if we should use the coefficient cache. */
-extern int nm256_cachedCoefficients (struct nm256_info *card);
+static int nm256_cachedCoefficients (struct nm256_info *card);
 
 #endif
 \f
index f9166e13519201f9118185e919489b1e2d1cbc66..66970062eb363a3bd48493039d4e0f239525f798 100644 (file)
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include "sound_config.h"
-#include "nm256.h"
-#include "nm256_coeff.h"
 
-int nm256_debug;
+static int nm256_debug;
 static int force_load;
 
+#include "nm256.h"
+#include "nm256_coeff.h"
+
 /* 
  * The size of the playback reserve.  When the playback buffer has less
  * than NM256_PLAY_WMARK_SIZE bytes to output, we request a new
@@ -138,7 +139,7 @@ static int usecache;
 static int buffertop;
 
 /* Check to see if we're using the bank of cached coefficients. */
-int
+static int
 nm256_cachedCoefficients (struct nm256_info *card)
 {
     return usecache;
index 0ceecc20077ba75aef3412529bf8fde1a9530391..6fc07f3cb33b79cc258363445762ab4bce2bbb92 100644 (file)
@@ -4650,7 +4650,7 @@ nm256_loadAllCoefficients (struct nm256_info *card)
     card->coeffsCurrent = 1;
 }
 
-void
+static void
 nm256_loadCoefficient (struct nm256_info *card, int which, int number)
 {
     static u16 addrs[3] = { 0x1c, 0x21c, 0x408 };
index b4278eecc9171dc0123809589249d236b4111b30..7609c68a89f44ca4fab2b2a4c9f915a29bcb72fe 100644 (file)
@@ -1750,9 +1750,7 @@ static unsigned int rme96xx_poll(struct file *file, struct poll_table_struct *wa
 
 
 static struct file_operations rme96xx_audio_fops = {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
        .owner   = THIS_MODULE,
-#endif
        .read    = rme96xx_read,
        .write   = rme96xx_write,
        .poll    = rme96xx_poll,
@@ -1852,9 +1850,7 @@ static int rme96xx_mixer_release(struct inode *inode, struct file *file)
 }
 
 static /*const*/ struct file_operations rme96xx_mixer_fops = {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
        .owner   = THIS_MODULE,
-#endif
        .ioctl   = rme96xx_mixer_ioctl,
        .open    = rme96xx_mixer_open,
        .release = rme96xx_mixer_release,
index ce359e6c933aa0ae3962a202e2c253492899093d..5f955e3d2e26926e6e59612416466d78bced3db3 100644 (file)
@@ -915,8 +915,8 @@ void sb_dsp_unload(struct address_info *hw_config, int sbmpu)
        }
        else
                release_region(hw_config->io_base, 16);
-       if(detected_devc)
-               kfree(detected_devc);
+
+       kfree(detected_devc);
 }
 
 /*
index 06047e7979af240e73cc6252ddcb1706c1156149..17d0e461f8d862dcc8b331389b67941feb7f6db7 100644 (file)
 
 #include "dm.h"
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
 
 /* --------------------------------------------------------------------- */
 
@@ -365,7 +368,9 @@ struct sv_state {
                unsigned char obuf[MIDIOUTBUF];
        } midi;
 
+#if SUPPORT_JOYSTICK
        struct gameport *gameport;
+#endif
 };
 
 /* --------------------------------------------------------------------- */
@@ -2485,6 +2490,7 @@ static struct initvol {
 #define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \
                                 (pci_resource_flags((dev), (num)) & IORESOURCE_IO))
 
+#ifdef SUPPORT_JOYSTICK
 static int __devinit sv_register_gameport(struct sv_state *s, int io_port)
 {
        struct gameport *gp;
@@ -2511,6 +2517,19 @@ static int __devinit sv_register_gameport(struct sv_state *s, int io_port)
        return 0;
 }
 
+static inline void sv_unregister_gameport(struct sv_state *s)
+{
+       if (s->gameport) {
+               int gpio = s->gameport->io;
+               gameport_unregister_port(s->gameport);
+               release_region(gpio, SV_EXTENT_GAME);
+       }
+}
+#else
+static inline int sv_register_gameport(struct sv_state *s, int io_port) { return -ENOSYS; }
+static inline void sv_unregister_gameport(struct sv_state *s) { }
+#endif /* SUPPORT_JOYSTICK */
+
 static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
        static char __devinitdata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller";
@@ -2711,11 +2730,7 @@ static void __devexit sv_remove(struct pci_dev *dev)
        /*outb(0, s->iodmaa + SV_DMA_RESET);*/
        /*outb(0, s->iodmac + SV_DMA_RESET);*/
        free_irq(s->irq, s);
-       if (s->gameport) {
-               int gpio = s->gameport->io;
-               gameport_unregister_port(s->gameport);
-               release_region(gpio, SV_EXTENT_GAME);
-       }
+       sv_unregister_gameport(s);
        release_region(s->iodmac, SV_EXTENT_DMA);
        release_region(s->iodmaa, SV_EXTENT_DMA);
        release_region(s->ioenh, SV_EXTENT_ENH);
index 50ca646294502a4e1d5dbf84d757684bfcc5e77f..9ed5211c3168156f05f8d0f9e89d4191c9f48c2e 100644 (file)
@@ -991,7 +991,6 @@ static void __init sscape_pnp_init_hw(sscape_info* devc)
        unsigned i;
        static  char code_file_name[23] = "/sndscape/sndscape.cox";
        
-       int sscape_sb_enable            = 0;
        int sscape_joystic_enable       = 0x7f;
        int sscape_mic_enable           = 0;
        int sscape_ext_midi             = 0;            
@@ -1015,14 +1014,9 @@ static void __init sscape_pnp_init_hw(sscape_info* devc)
        sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40);
        sscape_write( devc, 3, ( devc -> dma << 4) | 0x80);
 
-       if ( sscape_sb_enable )
-               sscape_write (devc, 4, 0xF0 | (sb_irq << 2) | midi_irq);
-       else    
-               sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq);
+       sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq);
 
        i = 0x10; //sscape_read(devc, 9) & (devc->ic_type == IC_ODIE ? 0xf0 : 0xc0);
-       if ( sscape_sb_enable )
-               i |= devc->ic_type == IC_ODIE ? 0x05 : 0x07;        
        if (sscape_joystic_enable) i |= 8;
        
        sscape_write (devc, 9, i);
index 47537f0a5b058195279271ce8aae4148e56222d0..5f0ad6bb43b9f5adc0fbc09bc75b76c9d8a68580 100644 (file)
 
 #define DRIVER_VERSION "0.14.10j-2.6"
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
 /* magic numbers to protect our data structures */
 #define TRIDENT_CARD_MAGIC     0x5072696E      /* "Prin" */
 #define TRIDENT_STATE_MAGIC    0x63657373      /* "cess" */
@@ -4252,24 +4256,25 @@ trident_ac97_init(struct trident_card *card)
        return num_ac97 + 1;
 }
 
+#ifdef SUPPORT_JOYSTICK
 /* Gameport functions for the cards ADC gameport */
 
-static unsigned char
-trident_game_read(struct gameport *gameport)
+static unsigned char trident_game_read(struct gameport *gameport)
 {
        struct trident_card *card = gameport->port_data;
+
        return inb(TRID_REG(card, T4D_GAME_LEG));
 }
 
-static void
-trident_game_trigger(struct gameport *gameport)
+static void trident_game_trigger(struct gameport *gameport)
 {
        struct trident_card *card = gameport->port_data;
+
        outb(0xff, TRID_REG(card, T4D_GAME_LEG));
 }
 
-static int
-trident_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+static int trident_game_cooked_read(struct gameport *gameport,
+                                   int *axes, int *buttons)
 {
        struct trident_card *card = gameport->port_data;
        int i;
@@ -4285,8 +4290,7 @@ trident_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
        return 0;
 }
 
-static int
-trident_game_open(struct gameport *gameport, int mode)
+static int trident_game_open(struct gameport *gameport, int mode)
 {
        struct trident_card *card = gameport->port_data;
 
@@ -4305,8 +4309,7 @@ trident_game_open(struct gameport *gameport, int mode)
        return 0;
 }
 
-static int __devinit
-trident_register_gameport(struct trident_card *card)
+static int __devinit trident_register_gameport(struct trident_card *card)
 {
        struct gameport *gp;
 
@@ -4330,6 +4333,17 @@ trident_register_gameport(struct trident_card *card)
        return 0;
 }
 
+static inline void trident_unregister_gameport(struct trident_card *card)
+{
+       if (card->gameport)
+               gameport_unregister_port(card->gameport);
+}
+
+#else
+static inline int trident_register_gameport(struct trident_card *card) { return -ENOSYS; }
+static inline void trident_unregister_gameport(struct trident_card *card) { }
+#endif /* SUPPORT_JOYSTICK */
+
 /* install the driver, we do not allocate hardware channel nor DMA buffer */ 
 /* now, they are defered until "ACCESS" time (in prog_dmabuf called by */ 
 /* open/read/write/ioctl/mmap) */
@@ -4569,8 +4583,7 @@ trident_remove(struct pci_dev *pci_dev)
        }
 
        /* Unregister gameport */
-       if (card->gameport)
-               gameport_unregister_port(card->gameport);
+       trident_unregister_gameport(card);
 
        /* Kill interrupts, and SP/DIF */
        trident_disable_loop_interrupts(card);
index 077b7679766590c52bd0d2390fd117f919aa8f39..a7ef04fab075b1a7bd7dd7e377d26f1555380f8e 100644 (file)
@@ -39,8 +39,6 @@ static void *midi_mem = NULL;
  */
 
 
-void            (*midi_input_intr) (int dev, unsigned char data);
-
 static int v_midi_open (int dev, int mode,
              void            (*input) (int dev, unsigned char data),
              void            (*output) (int dev)
index b387e1e524859ce38a8c1dddf2a247d3a6381ed0..83edda93f0b478fd9c05ff3928610027c01e38ed 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/smp_lock.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
@@ -3391,10 +3392,10 @@ static int __devinit via_init_one (struct pci_dev *pdev, const struct pci_device
        if (rc)
                goto err_out_disable;
 
-       rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+       rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
        if (rc)
                goto err_out_res;
-       rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL);
+       rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
        if (rc)
                goto err_out_res;
 
index cce1278dc487c419f8752382e0f2f47b8c8c5743..b92ba89216389ad4bc9b2896964fc856e5de6b00 100644 (file)
@@ -151,11 +151,11 @@ static int (*midi_load_patch) (int devno, int format, const char __user *addr,
 
 /*** Module-accessible parameters ***************************************/
 
-int wf_raw;     /* we normally check for "raw state" to firmware
-                  loading. if set, then during driver loading, the
-                  state of the board is ignored, and we reset the
-                  board and load the firmware anyway.
-               */
+static int wf_raw;     /* we normally check for "raw state" to firmware
+                          loading. if set, then during driver loading, the
+                          state of the board is ignored, and we reset the
+                          board and load the firmware anyway.
+                       */
                   
 static int fx_raw = 1; /* if this is zero, we'll leave the FX processor in
                          whatever state it is when the driver is loaded.
@@ -2911,7 +2911,7 @@ int __init detect_wffx (void)
        return 0;
 }      
 
-void
+static void
 wffx_mute (int onoff)
     
 {
index b6e1854e938980e4678cdb89da4da1d3cd2f9b48..eb3c52b03af309bf0f14edd9ceba833583bc0355 100644 (file)
@@ -1338,11 +1338,6 @@ static inline int snd_cs4281_create_gameport(cs4281_t *chip) { return -ENOSYS; }
 static inline void snd_cs4281_free_gameport(cs4281_t *chip) { }
 #endif /* CONFIG_GAMEPORT || (MODULE && CONFIG_GAMEPORT_MODULE) */
 
-
-/*
-
- */
-
 static int snd_cs4281_free(cs4281_t *chip)
 {
        snd_cs4281_free_gameport(chip);
index f72c81cc9952705d11415bcd553ca57a00d0f19a..2d4f8e28478b037183ef34db38b49ce3d5e22571 100644 (file)
@@ -380,13 +380,20 @@ static int pdacf_event(event_t event, int priority, event_callback_args_t *args)
 /*
  * Module entry points
  */
+static struct pcmcia_device_id snd_pdacf_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x015d, 0x4c45),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, snd_pdacf_ids);
+
 static struct pcmcia_driver pdacf_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
                .name   = "snd-pdaudiocf",
        },
        .attach         = snd_pdacf_attach,
-       .detach         = snd_pdacf_detach
+       .detach         = snd_pdacf_detach,
+       .id_table       = snd_pdacf_ids,
 };
 
 static int __init init_pdacf(void)
index fce2ad04fd8b9de26546404091438906fb2a28b1..5f4c1326415912018ce590b5f0c6ba9e5f339c98 100644 (file)
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-/*
- please add the following as /etc/pcmcia/vxpocket.conf:
-  device "snd-vxpocket"
-     class "audio" module "snd-vxpocket"
-
-  card "Digigram VX-POCKET"
-    manfid 0x01f1, 0x0100
-    bind "snd-vxpocket"
-
- */
 
 #include <sound/driver.h>
 #include <linux/init.h>
@@ -140,13 +129,20 @@ static void vxp_detach(dev_link_t *link)
  * Module entry points
  */
 
+static struct pcmcia_device_id vxp_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x01f1, 0x0100),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, vxp_ids);
+
 static struct pcmcia_driver vxp_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
                .name   = DEV_INFO,
        },
        .attach         = vxp_attach,
-       .detach         = vxp_detach
+       .detach         = vxp_detach,
+       .id_table       = vxp_ids,
 };
 
 static int __init init_vxpocket(void)
index e052bd071e5bf1875af5732995e7871e26045d1c..061e52d3d771b4e39226a07de44bf58d4b606825 100644 (file)
@@ -90,7 +90,7 @@ snd_pmac_awacs_write_noreg(pmac_t *chip, int reg, int val)
        snd_pmac_awacs_write(chip, val | (reg << 12));
 }
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 /* Recalibrate chip */
 static void screamer_recalibrate(pmac_t *chip)
 {
@@ -642,7 +642,7 @@ static void awacs_restore_all_regs(pmac_t *chip)
        }
 }
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 static void snd_pmac_awacs_suspend(pmac_t *chip)
 {
        snd_pmac_awacs_write_noreg(chip, 1, (chip->awacs_reg[1]
@@ -676,7 +676,7 @@ static void snd_pmac_awacs_resume(pmac_t *chip)
        }
 #endif
 }
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
 #ifdef PMAC_SUPPORT_AUTOMUTE
 /*
@@ -883,7 +883,7 @@ snd_pmac_awacs_init(pmac_t *chip)
         * set lowlevel callbacks
         */
        chip->set_format = snd_pmac_awacs_set_format;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
        chip->suspend = snd_pmac_awacs_suspend;
        chip->resume = snd_pmac_awacs_resume;
 #endif
index f24a91693616f622925988adcf23f970651537e6..a737f298e77da31228d766e8676d65454590ee63 100644 (file)
@@ -218,7 +218,7 @@ static snd_kcontrol_new_t daca_mixers[] = {
 };
 
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 static void daca_resume(pmac_t *chip)
 {
        pmac_daca_t *mix = chip->mixer_data;
@@ -227,7 +227,7 @@ static void daca_resume(pmac_t *chip)
                                  mix->amp_on ? 0x05 : 0x04);
        daca_set_volume(mix);
 }
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
 
 static void daca_cleanup(pmac_t *chip)
@@ -275,7 +275,7 @@ int __init snd_pmac_daca_init(pmac_t *chip)
                        return err;
        }
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
        chip->resume = daca_resume;
 #endif
 
index 080ef3928465cd1c55256b131d4cb9eaf2fee089..75b8b74230367cc1f4bc7c9c0ec1c656d0705044 100644 (file)
@@ -36,7 +36,7 @@
 #include <asm/pci-bridge.h>
 
 
-#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
+#ifdef CONFIG_PM
 static int snd_pmac_register_sleep_notifier(pmac_t *chip);
 static int snd_pmac_unregister_sleep_notifier(pmac_t *chip);
 static int snd_pmac_suspend(snd_card_t *card, pm_message_t state);
@@ -782,7 +782,7 @@ static int snd_pmac_free(pmac_t *chip)
        }
 
        snd_pmac_sound_feature(chip, 0);
-#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
+#ifdef CONFIG_PM
        snd_pmac_unregister_sleep_notifier(chip);
 #endif
 
@@ -1292,7 +1292,7 @@ int __init snd_pmac_new(snd_card_t *card, pmac_t **chip_return)
        /* Reset dbdma channels */
        snd_pmac_dbdma_reset(chip);
 
-#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
+#ifdef CONFIG_PM
        /* add sleep notifier */
        if (! snd_pmac_register_sleep_notifier(chip))
                snd_card_set_pm_callback(chip->card, snd_pmac_suspend, snd_pmac_resume, chip);
@@ -1316,7 +1316,7 @@ int __init snd_pmac_new(snd_card_t *card, pmac_t **chip_return)
  * sleep notify for powerbook
  */
 
-#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
+#ifdef CONFIG_PM
 
 /*
  * Save state when going to sleep, restore it afterwards.
@@ -1414,4 +1414,5 @@ static int snd_pmac_unregister_sleep_notifier(pmac_t *chip)
        return 0;
 }
 
-#endif /* CONFIG_PM && CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
+
index 0a84c05f714b2c27ff40b3e3f02ed61c925a94b2..582db522011978849a8f0f2deb09a6e8a30d7d31 100644 (file)
@@ -167,7 +167,7 @@ struct snd_pmac {
        void (*set_format)(pmac_t *chip);
        void (*update_automute)(pmac_t *chip, int do_notify);
        int (*detect_headphone)(pmac_t *chip);
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
        void (*suspend)(pmac_t *chip);
        void (*resume)(pmac_t *chip);
 #endif
index 9332237cb6a46ed290daf1df57597e2030339fcc..36c5d5d45bb1302bf0765f73ff2c41a8358a6005 100644 (file)
@@ -1128,7 +1128,7 @@ static void tumbler_reset_audio(pmac_t *chip)
        }
 }
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 /* suspend mixer */
 static void tumbler_suspend(pmac_t *chip)
 {
@@ -1370,7 +1370,7 @@ int __init snd_pmac_tumbler_init(pmac_t *chip)
        if ((err = snd_ctl_add(chip->card, chip->drc_sw_ctl)) < 0)
                return err;
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
        chip->suspend = tumbler_suspend;
        chip->resume = tumbler_resume;
 #endif